From a99391a86f27baa899c5bb50850fe2715f6f1167 Mon Sep 17 00:00:00 2001 From: Yaacov Zamir Date: Tue, 26 Mar 2024 11:45:40 +0200 Subject: [PATCH] Refactor provider credentials store Signed-off-by: Yaacov Zamir --- .../components/BaseCredentialsSection.tsx | 68 +++---------------- .../components/state/index.ts | 3 + .../components/state/reducer.ts | 64 +++++++++++++++++ 3 files changed, 78 insertions(+), 57 deletions(-) create mode 100644 packages/forklift-console-plugin/src/modules/Providers/views/details/components/CredentialsSection/components/state/index.ts create mode 100644 packages/forklift-console-plugin/src/modules/Providers/views/details/components/CredentialsSection/components/state/reducer.ts diff --git a/packages/forklift-console-plugin/src/modules/Providers/views/details/components/CredentialsSection/components/BaseCredentialsSection.tsx b/packages/forklift-console-plugin/src/modules/Providers/views/details/components/CredentialsSection/components/BaseCredentialsSection.tsx index d82631299..5f793d137 100644 --- a/packages/forklift-console-plugin/src/modules/Providers/views/details/components/CredentialsSection/components/BaseCredentialsSection.tsx +++ b/packages/forklift-console-plugin/src/modules/Providers/views/details/components/CredentialsSection/components/BaseCredentialsSection.tsx @@ -1,6 +1,6 @@ -import React, { ReactNode, useReducer, useState } from 'react'; +import React, { useReducer, useState } from 'react'; import { AlertMessageForModals } from 'src/modules/Providers/modals'; -import { isSecretDataChanged, ValidationMsg } from 'src/modules/Providers/utils'; +import { ValidationMsg } from 'src/modules/Providers/utils'; import { useForkliftTranslation } from 'src/utils/i18n'; import { IoK8sApiCoreV1Secret } from '@kubev2v/types'; @@ -18,6 +18,7 @@ import EyeSlashIcon from '@patternfly/react-icons/dist/esm/icons/eye-slash-icon' import Pencil from '@patternfly/react-icons/dist/esm/icons/pencil-alt-icon'; import { patchSecretData } from './edit'; +import { baseCredentialsSectionReducerFactory, BaseCredentialsSectionState } from './state'; import './BaseCredentialsSection.style.css'; @@ -31,26 +32,6 @@ export interface EditComponentProps { onChange: (newValue: IoK8sApiCoreV1Secret) => void; } -/** - * Represents the state of the secret edit form. - * - * @typedef {Object} BaseCredentialsSecretState - * @property {boolean} reveal - Determines whether the secret's values are visible. - * @property {boolean} edit - Determines whether the secret is currently being edited. - * @property {IoK8sApiCoreV1Secret} newSecret - The new version of the secret being edited. - * @property {boolean} dataChanged - Determines whether the secret's data has changed. - * @property {boolean} dataIsValid - Determines whether the new secret's data is valid. - * @property {ReactNode} alertMessage - The message to display when a validation error occurs. - */ -export interface BaseCredentialsSecretState { - reveal: boolean; - edit: boolean; - newSecret: IoK8sApiCoreV1Secret; - dataChanged: boolean; - dataError: ValidationMsg; - alertMessage: ReactNode; -} - export type BaseCredentialsSectionProps = { secret: IoK8sApiCoreV1Secret; validator: (secret: IoK8sApiCoreV1Secret) => ValidationMsg; @@ -75,7 +56,7 @@ export const BaseCredentialsSection: React.FC = ({ name: secret.metadata.name, }); - const initialState: BaseCredentialsSecretState = { + const initialState: BaseCredentialsSectionState = { reveal: false, edit: false, newSecret: secret, @@ -84,37 +65,10 @@ export const BaseCredentialsSection: React.FC = ({ alertMessage: null, }; - function reducer( - state: BaseCredentialsSecretState, - action: { type: string; payload?: IoK8sApiCoreV1Secret }, - ): BaseCredentialsSecretState { - switch (action.type) { - case 'TOGGLE_REVEAL': - return { ...state, reveal: !state.reveal }; - case 'TOGGLE_EDIT': - return { ...state, edit: !state.edit }; - case 'RESET_DATA_CHANGED': { - return { ...state, dataChanged: false }; - } - case 'SET_NEW_SECRET': { - const dataChanged = isSecretDataChanged(secret, action.payload); - const validationError = validator(action.payload); - - return { - ...state, - dataChanged, - dataError: validationError, - newSecret: action.payload, - alertMessage: null, - }; - } - case 'SET_ALERT_MESSAGE': - return { ...state, alertMessage: action.payload }; - default: - return state; - } - } - const [state, dispatch] = useReducer(reducer, initialState); + const [state, dispatch] = useReducer( + baseCredentialsSectionReducerFactory(secret, validator), + initialState, + ); if (!secret?.data) { return {t('No credentials found.')}; @@ -153,12 +107,12 @@ export const BaseCredentialsSection: React.FC = ({ setIsLoading(true); try { - // Patch provider secret, set clean to `true` - // to remove old values from the secret + // Patch provider secret, set clean to `true` to remove old values from the secret + // if successful reset data change await patchSecretData(state.newSecret, true); + resetDataChanged(); setIsLoading(false); - resetDataChanged(); toggleEdit(); } catch (err) { dispatch({ diff --git a/packages/forklift-console-plugin/src/modules/Providers/views/details/components/CredentialsSection/components/state/index.ts b/packages/forklift-console-plugin/src/modules/Providers/views/details/components/CredentialsSection/components/state/index.ts new file mode 100644 index 000000000..d79f304c6 --- /dev/null +++ b/packages/forklift-console-plugin/src/modules/Providers/views/details/components/CredentialsSection/components/state/index.ts @@ -0,0 +1,3 @@ +// @index(['./*', /style/g], f => `export * from '${f.path}';`) +export * from './reducer'; +// @endindex diff --git a/packages/forklift-console-plugin/src/modules/Providers/views/details/components/CredentialsSection/components/state/reducer.ts b/packages/forklift-console-plugin/src/modules/Providers/views/details/components/CredentialsSection/components/state/reducer.ts new file mode 100644 index 000000000..a1b670bea --- /dev/null +++ b/packages/forklift-console-plugin/src/modules/Providers/views/details/components/CredentialsSection/components/state/reducer.ts @@ -0,0 +1,64 @@ +import { ReactNode } from 'react'; +import { isSecretDataChanged, ValidationMsg } from 'src/modules/Providers/utils'; + +import { IoK8sApiCoreV1Secret } from '@kubev2v/types'; + +/** + * Represents the state of the secret edit form. + * + * @typedef {Object} BaseCredentialsSectionState + * @property {boolean} reveal - Determines whether the secret's values are visible. + * @property {boolean} edit - Determines whether the secret is currently being edited. + * @property {IoK8sApiCoreV1Secret} newSecret - The new version of the secret being edited. + * @property {boolean} dataChanged - Determines whether the secret's data has changed. + * @property {boolean} dataIsValid - Determines whether the new secret's data is valid. + * @property {ReactNode} alertMessage - The message to display when a validation error occurs. + */ +export interface BaseCredentialsSectionState { + reveal: boolean; + edit: boolean; + newSecret: IoK8sApiCoreV1Secret; + dataChanged: boolean; + dataError: ValidationMsg; + alertMessage: ReactNode; +} + +export type BaseCredentialsAction = + | { type: 'TOGGLE_REVEAL' } + | { type: 'TOGGLE_EDIT' } + | { type: 'RESET_DATA_CHANGED' } + | { type: 'SET_NEW_SECRET'; payload: IoK8sApiCoreV1Secret } + | { type: 'SET_ALERT_MESSAGE'; payload: ReactNode }; + +export function baseCredentialsSectionReducerFactory(secret, validator) { + return function baseCredentialsSectionReducer( + state: BaseCredentialsSectionState, + action: BaseCredentialsAction, + ): BaseCredentialsSectionState { + switch (action.type) { + case 'TOGGLE_REVEAL': + return { ...state, reveal: !state.reveal }; + case 'TOGGLE_EDIT': + return { ...state, edit: !state.edit }; + case 'RESET_DATA_CHANGED': { + return { ...state, dataChanged: false }; + } + case 'SET_NEW_SECRET': { + const dataChanged = isSecretDataChanged(secret, action.payload); + const validationError = validator(action.payload); + + return { + ...state, + dataChanged, + dataError: validationError, + newSecret: action.payload, + alertMessage: null, + }; + } + case 'SET_ALERT_MESSAGE': + return { ...state, alertMessage: action.payload }; + default: + return state; + } + }; +}