diff --git a/public/apps/account/password-reset-panel.tsx b/public/apps/account/password-reset-panel.tsx index 6119a3966..97d45400e 100644 --- a/public/apps/account/password-reset-panel.tsx +++ b/public/apps/account/password-reset-panel.tsx @@ -32,6 +32,7 @@ import { logout, updateNewPassword } from './utils'; import { PASSWORD_INSTRUCTION } from '../apps-constants'; import { constructErrorMessageAndLog } from '../error-utils'; import { validateCurrentPassword } from '../../utils/login-utils'; +import { getDashboardsInfo } from '../../utils/dashboards-info-utils'; interface PasswordResetPanelProps { coreStart: CoreStart; @@ -57,6 +58,22 @@ export function PasswordResetPanel(props: PasswordResetPanelProps) { const [errorCallOut, setErrorCallOut] = React.useState(''); + const [passwordHelpText, setPasswordHelpText] = React.useState(PASSWORD_INSTRUCTION); + + React.useEffect(() => { + const fetchData = async () => { + try { + setPasswordHelpText( + (await getDashboardsInfo(props.coreStart.http)).password_validation_error_message + ); + } catch (e) { + console.error(e); + } + }; + + fetchData(); + }, [props.coreStart.http]); + const handleReset = async () => { const http = props.coreStart.http; // validate the current password @@ -107,7 +124,7 @@ export function PasswordResetPanel(props: PasswordResetPanelProps) { - + diff --git a/public/apps/configuration/utils/password-edit-panel.tsx b/public/apps/configuration/utils/password-edit-panel.tsx index 7f7b7f558..0a52347ae 100644 --- a/public/apps/configuration/utils/password-edit-panel.tsx +++ b/public/apps/configuration/utils/password-edit-panel.tsx @@ -14,17 +14,35 @@ */ import React from 'react'; +import { CoreStart } from 'opensearch-dashboards/public'; import { EuiFieldText, EuiIcon } from '@elastic/eui'; import { FormRow } from './form-row'; import { PASSWORD_INSTRUCTION } from '../../apps-constants'; +import { getDashboardsInfo } from '../../../utils/dashboards-info-utils'; export function PasswordEditPanel(props: { + coreStart: CoreStart; updatePassword: (p: string) => void; updateIsInvalid: (v: boolean) => void; }) { const [password, setPassword] = React.useState(''); const [repeatPassword, setRepeatPassword] = React.useState(''); const [isRepeatPasswordInvalid, setIsRepeatPasswordInvalid] = React.useState(false); + const [passwordHelpText, setPasswordHelpText] = React.useState(PASSWORD_INSTRUCTION); + + React.useEffect(() => { + const fetchData = async () => { + try { + setPasswordHelpText( + (await getDashboardsInfo(props.coreStart.http)).password_validation_error_message + ); + } catch (e) { + console.error(e); + } + }; + + fetchData(); + }, [props.coreStart.http]); React.useEffect(() => { props.updatePassword(password); @@ -43,7 +61,7 @@ export function PasswordEditPanel(props: { return ( <> - + } diff --git a/public/apps/configuration/utils/test/password-edit-panel.test.tsx b/public/apps/configuration/utils/test/password-edit-panel.test.tsx index e44b91268..49ab94b65 100644 --- a/public/apps/configuration/utils/test/password-edit-panel.test.tsx +++ b/public/apps/configuration/utils/test/password-edit-panel.test.tsx @@ -13,9 +13,24 @@ * permissions and limitations under the License. */ -import { shallow } from 'enzyme'; +import { mount, shallow } from 'enzyme'; import React from 'react'; import { PasswordEditPanel } from '../password-edit-panel'; +import { getDashboardsInfo } from '../../../../utils/dashboards-info-utils'; + +const mockDashboardsInfo = { + multitenancy_enabled: true, + private_tenant_enabled: true, + default_tenant: '', + password_validation_error_message: + 'Password must be minimum 5 characters long and must contain at least one uppercase letter, one lowercase letter, one digit, and one special character.', +}; + +jest.mock('../../../../utils/dashboards-info-utils', () => ({ + getDashboardsInfo: jest.fn().mockImplementation(() => { + return mockDashboardsInfo; + }), +})); describe('Password edit panel', () => { let component; @@ -24,21 +39,43 @@ describe('Password edit panel', () => { const updateIsInvalid = jest.fn(); const useState = jest.spyOn(React, 'useState'); const useEffect = jest.spyOn(React, 'useEffect'); + const mockCoreStart = { + http: 1, + }; beforeEach(() => { useEffect.mockImplementationOnce((f) => f()); useState.mockImplementation((initialValue) => [initialValue, setState]); - component = shallow( - - ); }); - it('renders', () => { - expect(updatePassword).toHaveBeenCalledTimes(1); - expect(updateIsInvalid).toHaveBeenCalledTimes(1); + afterEach(() => { + jest.clearAllMocks(); + }); + + it('renders', (done) => { + mount( + + ); + process.nextTick(() => { + expect(updatePassword).toHaveBeenCalledTimes(1); + expect(updateIsInvalid).toHaveBeenCalledTimes(1); + expect(setState).toBeCalledWith(mockDashboardsInfo.password_validation_error_message); + done(); + }); }); it('password field update', () => { + component = shallow( + + ); const event = { target: { value: 'dummy' }, } as React.ChangeEvent; @@ -47,6 +84,13 @@ describe('Password edit panel', () => { }); it('repeat password field update', () => { + component = shallow( + + ); const event = { target: { value: 'dummy' }, } as React.ChangeEvent; diff --git a/public/types.ts b/public/types.ts index 7169b893a..4acfc442f 100644 --- a/public/types.ts +++ b/public/types.ts @@ -46,6 +46,7 @@ export interface DashboardsInfo { multitenancy_enabled?: boolean; private_tenant_enabled?: boolean; default_tenant: string; + password_validation_error_message: string; } export interface ClientConfigType {