From 9f6bfc01d94e4100e790857985bf2e1b648160af Mon Sep 17 00:00:00 2001 From: Manideep Pabba <109986843+mpabba3003@users.noreply.github.com> Date: Mon, 10 Oct 2022 15:29:17 -0500 Subject: [PATCH 1/2] [MD] new UX changes for password fields and update password modal in data source management (#2532) * nex ux changes for password fields and update password modal in data source management Signed-off-by: mpabba3003 * update change log Signed-off-by: mpabba3003 Signed-off-by: mpabba3003 --- CHANGELOG.md | 1 + .../edit_form/edit_data_source_form.tsx | 5 +- .../update_password_modal.tsx | 72 ++++++++++++++++--- .../components/text_content/text_content.ts | 21 +++++- 4 files changed, 89 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0dd139a81baf..e9d0a86f196b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -54,6 +54,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) * [Viz Builder] Create a new wizard directly on a dashboard ([#2384](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2384)) * [Multi DataSource] UX enhacement on index pattern management stack ([#2505](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2505)) * [Multi DataSource] UX enhancement on Data source management stack ([#2521](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2521)) +* [Multi DataSource] UX enhancement on Update stored password modal for Data source management stack ([#2532](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2532)) ### 🐛 Bug Fixes diff --git a/src/plugins/data_source_management/public/components/edit_data_source/components/edit_form/edit_data_source_form.tsx b/src/plugins/data_source_management/public/components/edit_data_source/components/edit_form/edit_data_source_form.tsx index 3edc2b1b7371..424d4cb9f5a8 100644 --- a/src/plugins/data_source_management/public/components/edit_data_source/components/edit_form/edit_data_source_form.tsx +++ b/src/plugins/data_source_management/public/components/edit_data_source/components/edit_form/edit_data_source_form.tsx @@ -9,6 +9,7 @@ import { EuiButton, EuiButtonEmpty, EuiDescribedFormGroup, + EuiFieldPassword, EuiFieldText, EuiFlexGroup, EuiFlexItem, @@ -459,8 +460,9 @@ export class EditDataSourceForm extends React.Component - {this.props.existingDataSource.auth.type !== AuthType.NoAuth ? ( diff --git a/src/plugins/data_source_management/public/components/edit_data_source/components/update_password_modal/update_password_modal.tsx b/src/plugins/data_source_management/public/components/edit_data_source/components/update_password_modal/update_password_modal.tsx index a77e67f148ad..5e7307abc7db 100644 --- a/src/plugins/data_source_management/public/components/edit_data_source/components/update_password_modal/update_password_modal.tsx +++ b/src/plugins/data_source_management/public/components/edit_data_source/components/update_password_modal/update_password_modal.tsx @@ -15,9 +15,18 @@ import { EuiModalFooter, EuiModalHeader, EuiModalHeaderTitle, + EuiSpacer, EuiText, } from '@elastic/eui'; -import { NEW_PASSWORD_TEXT, UPDATE_STORED_PASSWORD, USERNAME } from '../../../text_content'; +import { + CANCEL_TEXT, + CONFIRM_NEW_PASSWORD_TEXT, + NEW_PASSWORD_TEXT, + PASSWORD_NO_MATCH, + UPDATE_STORED_PASSWORD, + UPDATE_STORED_PASSWORD_DESCRIPTION, + USERNAME, +} from '../../../text_content'; export interface UpdatePasswordModalProps { username: string; @@ -32,13 +41,34 @@ export const UpdatePasswordModal = ({ }: UpdatePasswordModalProps) => { /* State Variables */ const [newPassword, setNewPassword] = useState(''); + const [confirmNewPassword, setConfirmNewPassword] = useState(''); + const [isNewPasswordValid, setIsNewPasswordValid] = useState(true); + const [isConfirmNewPasswordValid, setIsConfirmNewPasswordValid] = useState([]); const onClickUpdatePassword = () => { - if (!!newPassword) { + if (isFormValid()) { handleUpdatePassword(newPassword); } }; + const isFormValid = () => { + return !!(newPassword && confirmNewPassword && confirmNewPassword === newPassword); + }; + + const validateNewPassword = () => { + setIsNewPasswordValid(!!newPassword); + }; + + const validateConfirmNewPassword = () => { + const invalidReason: string[] = []; + if (!confirmNewPassword) { + invalidReason.push(''); + } else if (confirmNewPassword !== newPassword) { + invalidReason.push(PASSWORD_NO_MATCH); + } + setIsConfirmNewPasswordValid(invalidReason); + }; + const renderUpdatePasswordModal = () => { return ( @@ -49,33 +79,59 @@ export const UpdatePasswordModal = ({ + + + {UPDATE_STORED_PASSWORD_DESCRIPTION} + + + + {/* Username */} {username} - {/* Password */} - + {/* updated Password */} + setNewPassword(e.target.value)} + onBlur={validateNewPassword} + /> + + {/* Password */} + + setConfirmNewPassword(e.target.value)} + onBlur={validateConfirmNewPassword} /> - Cancel + {CANCEL_TEXT} - Update + {UPDATE_STORED_PASSWORD} diff --git a/src/plugins/data_source_management/public/components/text_content/text_content.ts b/src/plugins/data_source_management/public/components/text_content/text_content.ts index 56a2ea93be15..8cf536c72fa5 100644 --- a/src/plugins/data_source_management/public/components/text_content/text_content.ts +++ b/src/plugins/data_source_management/public/components/text_content/text_content.ts @@ -163,7 +163,19 @@ export const DELETE_THIS_DATA_SOURCE = i18n.translate( export const NEW_PASSWORD_TEXT = i18n.translate( 'dataSourcesManagement.editDataSource.newPassword', { - defaultMessage: 'New password', + defaultMessage: 'Updated password', + } +); +export const CONFIRM_NEW_PASSWORD_TEXT = i18n.translate( + 'dataSourcesManagement.editDataSource.confirmNewPassword', + { + defaultMessage: 'Confirm Updated password', + } +); +export const PASSWORD_NO_MATCH = i18n.translate( + 'dataSourcesManagement.editDataSource.passwordNoMatch', + { + defaultMessage: 'Passwords do not match', } ); export const UPDATE_STORED_PASSWORD = i18n.translate( @@ -172,6 +184,13 @@ export const UPDATE_STORED_PASSWORD = i18n.translate( defaultMessage: 'Update stored password', } ); +export const UPDATE_STORED_PASSWORD_DESCRIPTION = i18n.translate( + 'dataSourcesManagement.editDataSource.updateStoredPasswordDescription', + { + defaultMessage: + 'Update credential password to reflect accurate password to gain access to the endpoint.', + } +); export const CONNECTION_DETAILS_TITLE = i18n.translate( 'dataSourcesManagement.editDataSource.connectionDetailsText', { From d6197a7827cc6858fb31af98154f8e8324b80fe3 Mon Sep 17 00:00:00 2001 From: "Qingyang(Abby) Hu" Date: Mon, 10 Oct 2022 14:19:17 -0700 Subject: [PATCH 2/2] Edit wizard directly on dashboard (#2508) Signed-off-by: abbyhu2000 Signed-off-by: abbyhu2000 --- CHANGELOG.md | 1 + .../application/utils/get_top_nav_config.tsx | 69 ++++++++++++++++--- 2 files changed, 61 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e9d0a86f196b..747ef858cb9c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -52,6 +52,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) * Add updated_at column to objects' tables ([#1218](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/1218)) * [Viz Builder] State validation before dispatching and loading ([#2351](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2351)) * [Viz Builder] Create a new wizard directly on a dashboard ([#2384](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2384)) +* [Viz Builder] Edit wizard directly on dashboard ([#2508](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2508)) * [Multi DataSource] UX enhacement on index pattern management stack ([#2505](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2505)) * [Multi DataSource] UX enhancement on Data source management stack ([#2521](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2521)) * [Multi DataSource] UX enhancement on Update stored password modal for Data source management stack ([#2532](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2532)) diff --git a/src/plugins/wizard/public/application/utils/get_top_nav_config.tsx b/src/plugins/wizard/public/application/utils/get_top_nav_config.tsx index 1afd9358d50d..965357e84158 100644 --- a/src/plugins/wizard/public/application/utils/get_top_nav_config.tsx +++ b/src/plugins/wizard/public/application/utils/get_top_nav_config.tsx @@ -32,8 +32,8 @@ import React from 'react'; import { i18n } from '@osd/i18n'; import { TopNavMenuData } from '../../../../navigation/public'; import { - OnSaveProps, SavedObjectSaveModalOrigin, + SavedObjectSaveOpts, showSaveModal, } from '../../../../saved_objects/public'; import { WizardServices } from '../..'; @@ -58,7 +58,7 @@ export const getTopNavConfig = ( scopedHistory, } = services; - const { originatingApp } = + const { originatingApp, embeddableId } = embeddable .getStateTransfer(scopedHistory) .getIncomingEditorState({ keysToRemoveAfterFetch: ['id', 'input'] }) || {}; @@ -67,15 +67,20 @@ export const getTopNavConfig = ( const topNavConfig: TopNavMenuData[] = [ { id: 'save', - iconType: 'save', + iconType: savedWizardVis?.id && originatingApp ? undefined : ('save' as const), emphasize: savedWizardVis && !savedWizardVis.id, description: i18n.translate('wizard.topNavMenu.saveVisualizationButtonAriaLabel', { defaultMessage: 'Save Visualization', }), - className: 'saveButton', - label: i18n.translate('wizard.topNavMenu.saveVisualizationButtonLabel', { - defaultMessage: 'save', - }), + className: savedWizardVis?.id && originatingApp ? 'saveAsButton' : '', + label: + savedWizardVis?.id && originatingApp + ? i18n.translate('wizard.topNavMenu.saveVisualizationAsButtonLabel', { + defaultMessage: 'save as', + }) + : i18n.translate('wizard.topNavMenu.saveVisualizationButtonLabel', { + defaultMessage: 'save', + }), testId: 'wizardSaveButton', disableButton: !!saveDisabledReason, tooltip: saveDisabledReason, @@ -100,6 +105,46 @@ export const getTopNavConfig = ( showSaveModal(saveModal, I18nContext); }, }, + ...(originatingApp && ((savedWizardVis && savedWizardVis.id) || embeddableId) + ? [ + { + id: 'saveAndReturn', + label: i18n.translate('visualize.topNavMenu.saveAndReturnVisualizationButtonLabel', { + defaultMessage: 'Save and return', + }), + emphasize: true, + iconType: 'checkInCircleFilled' as const, + description: i18n.translate( + 'wizard.topNavMenu.saveAndReturnVisualizationButtonAriaLabel', + { + defaultMessage: 'Finish editing wizard and return to the last app', + } + ), + testId: 'wizardsaveAndReturnButton', + disableButton: !!saveDisabledReason, + tooltip: saveDisabledReason, + run: async () => { + const saveOptions = { + newTitle: savedWizardVis.title, + newCopyOnSave: false, + isTitleDuplicateConfirmed: false, + newDescription: savedWizardVis.description, + returnToOrigin: true, + }; + + const onSave = getOnSave( + savedWizardVis, + originatingApp, + visualizationIdFromUrl, + dispatch, + services + ); + + return onSave(saveOptions); + }, + }, + ] + : []), ]; return topNavConfig; @@ -119,18 +164,24 @@ export const getOnSave = ( onTitleDuplicate, newDescription, returnToOrigin, - }: OnSaveProps & { returnToOrigin: boolean }) => { + }: SavedObjectSaveOpts & { + newTitle: string; + newCopyOnSave: boolean; + returnToOrigin: boolean; + newDescription?: string; + }) => { const { embeddable, toastNotifications, application, history } = services; const stateTransfer = embeddable.getStateTransfer(); if (!savedWizardVis) { return; } - const newlyCreated = !savedWizardVis.id || savedWizardVis.copyOnSave; + const currentTitle = savedWizardVis.title; savedWizardVis.title = newTitle; savedWizardVis.description = newDescription; savedWizardVis.copyOnSave = newCopyOnSave; + const newlyCreated = !savedWizardVis.id || savedWizardVis.copyOnSave; try { const id = await savedWizardVis.save({