diff --git a/pkg/app/web/src/components/sealed-secret-dialog.stories.tsx b/pkg/app/web/src/components/sealed-secret-dialog.stories.tsx index 1813d81971..a4fff55be4 100644 --- a/pkg/app/web/src/components/sealed-secret-dialog.stories.tsx +++ b/pkg/app/web/src/components/sealed-secret-dialog.stories.tsx @@ -6,7 +6,7 @@ import { Provider } from "react-redux"; import { createStore } from "../../test-utils"; export default { - title: "SealedSecretDialog", + title: "APPLICATION/SealedSecretDialog", component: SealedSecretDialog, }; diff --git a/pkg/app/web/src/components/sealed-secret-dialog.tsx b/pkg/app/web/src/components/sealed-secret-dialog.tsx index 202c2c2280..38f64abf41 100644 --- a/pkg/app/web/src/components/sealed-secret-dialog.tsx +++ b/pkg/app/web/src/components/sealed-secret-dialog.tsx @@ -1,31 +1,33 @@ import { Button, + Checkbox, Dialog, DialogActions, DialogContent, DialogTitle, + FormControlLabel, IconButton, makeStyles, TextField, Typography, } from "@material-ui/core"; import CopyIcon from "@material-ui/icons/FileCopyOutlined"; -import React, { FC, useRef, useState } from "react"; +import React, { FC, memo, useCallback, useRef } from "react"; import { useDispatch, useSelector } from "react-redux"; import { AppState } from "../modules"; import { Application, selectById } from "../modules/applications"; import { generateSealedSecret, - SealedSecret, clearSealedSecret, } from "../modules/sealed-secret"; import copy from "copy-to-clipboard"; import { addToast } from "../modules/toasts"; +import { useFormik } from "formik"; +import * as Yup from "yup"; +import { AppDispatch } from "../store"; +import { UI_TEXT_CANCEL, UI_TEXT_CLOSE } from "../constants/ui-text"; const useStyles = makeStyles((theme) => ({ - description: { - marginBottom: theme.spacing(2), - }, targetApp: { color: theme.palette.text.primary, fontWeight: theme.typography.fontWeightMedium, @@ -42,35 +44,56 @@ interface Props { } const DIALOG_TITLE = "Encrypting secret data for application"; +const BASE64_CHECKBOX_LABEL = + "Use base64 encoding before encrypting the secret"; + +const validationSchema = Yup.object({ + secretData: Yup.string().required(), + base64: Yup.bool(), +}); -export const SealedSecretDialog: FC = ({ +export const SealedSecretDialog: FC = memo(function SealedSecretDialog({ open, applicationId, onClose, -}) => { +}) { const classes = useStyles(); - const dispatch = useDispatch(); - const [data, setData] = useState(""); + const dispatch = useDispatch(); const secretRef = useRef(null); - const [application, sealedSecret] = useSelector< + const [application, isLoading, sealedSecret] = useSelector< AppState, - [Application | undefined, SealedSecret] + [Application | undefined, boolean, string | null] >((state) => [ applicationId ? selectById(state.applications, applicationId) : undefined, - state.sealedSecret, + state.sealedSecret.isLoading, + state.sealedSecret.data, ]); - const handleGenerate = (e: React.FormEvent): void => { - e.preventDefault(); - if (application) { - dispatch(generateSealedSecret({ data, pipedId: application.pipedId, base64Encoding: false })); - } - }; + const formik = useFormik({ + initialValues: { + secretData: "", + base64: false, + }, + validationSchema, + validateOnMount: true, + async onSubmit(values) { + if (!application) { + return; + } + await dispatch( + generateSealedSecret({ + data: values.secretData, + pipedId: application.pipedId, + base64Encoding: values.base64, + }) + ); + }, + }); - const handleOnEnter = (): void => { - setData(""); - }; + const handleOnEnter = useCallback(() => { + formik.resetForm(); + }, [formik]); const handleOnExited = (): void => { // Clear state after closed dialog @@ -79,12 +102,12 @@ export const SealedSecretDialog: FC = ({ }, 200); }; - const handleOnClickCopy = (): void => { - if (sealedSecret.data) { - copy(sealedSecret.data); + const handleOnClickCopy = useCallback(() => { + if (sealedSecret) { + copy(sealedSecret); dispatch(addToast({ message: "Secret copied to clipboard" })); } - }; + }, [dispatch, sealedSecret]); if (!application) { return null; @@ -97,17 +120,19 @@ export const SealedSecretDialog: FC = ({ onExit={handleOnExited} onClose={onClose} > - {sealedSecret.data ? ( + {sealedSecret ? ( <> {DIALOG_TITLE} - Encrypted secret data + + Encrypted secret data + - {sealedSecret.data} + {sealedSecret} = ({ - + ) : ( -
+ {DIALOG_TITLE} - Application + + Application + {application.name} = ({ rows={4} required autoFocus - onChange={(e) => setData(e.currentTarget.value)} + onChange={formik.handleChange} + /> + + } + disabled={formik.isSubmitting} + label={BASE64_CHECKBOX_LABEL} /> - @@ -159,4 +200,4 @@ export const SealedSecretDialog: FC = ({ )} ); -}; +}); diff --git a/pkg/app/web/src/constants/ui-text.ts b/pkg/app/web/src/constants/ui-text.ts index 3cb6bca2fc..ff1516f91b 100644 --- a/pkg/app/web/src/constants/ui-text.ts +++ b/pkg/app/web/src/constants/ui-text.ts @@ -3,3 +3,4 @@ export const UI_TEXT_CANCEL = "Cancel"; export const UI_TEXT_ADD = "Add"; export const UI_TEXT_EDIT = "Edit"; export const UI_TEXT_REFRESH = "REFRESH"; +export const UI_TEXT_CLOSE = "Close";