drone/web/src/components/UpdateSecretModal/UpdateSecretModal.tsx

162 lines
5.2 KiB
TypeScript

import React, { useRef, useState } from 'react'
import * as yup from 'yup'
import { useMutate } from 'restful-react'
import { FontVariation, Intent } from '@harnessio/design-system'
import {
Button,
Dialog,
Layout,
Heading,
Container,
Formik,
FormikForm,
FormInput,
FlexExpander,
useToaster,
StringSubstitute,
ButtonVariation
} from '@harnessio/uicore'
import { Icon } from '@harnessio/icons'
import { useStrings } from 'framework/strings'
import { useModalHook } from 'hooks/useModalHook'
import { useGetSpaceParam } from 'hooks/useGetSpaceParam'
import type { OpenapiUpdateSecretRequest, TypesSecret } from 'services/code'
import type { SecretFormData } from 'components/NewSecretModalButton/NewSecretModalButton'
import { getErrorMessage } from 'utils/Utils'
const useUpdateSecretModal = () => {
const { getString } = useStrings()
const space = useGetSpaceParam()
const { showError, showSuccess } = useToaster()
const [secret, setSecret] = useState<TypesSecret>()
const postUpdate = useRef<() => Promise<void>>()
const { mutate: updateSecret, loading } = useMutate<TypesSecret>({
verb: 'PATCH',
path: `/api/v1/secrets/${space}/${secret?.uid}/+`
})
const handleSubmit = async (formData: SecretFormData) => {
try {
const payload: OpenapiUpdateSecretRequest = {
data: formData.value,
description: formData.description,
uid: formData.name
}
await updateSecret(payload)
hideModal()
showSuccess(
<StringSubstitute
str={getString('secrets.secretUpdated')}
vars={{
uid: formData.name
}}
/>
)
postUpdate.current?.()
} catch (exception) {
showError(getErrorMessage(exception), 0, getString('secrets.failedToUpdateSecret'))
}
}
const [openModal, hideModal] = useModalHook(() => {
const onClose = () => {
hideModal()
}
return (
<Dialog
isOpen
enforceFocus={false}
onClose={hideModal}
title={
<Heading level={3} font={{ variation: FontVariation.H3 }}>
{getString('secrets.updateSecret')}
</Heading>
}
style={{ width: 700, maxHeight: '95vh', overflow: 'auto' }}>
<Layout.Vertical style={{ height: '100%' }} data-testid="add-secret-modal">
<Container>
<Formik
initialValues={{ name: secret?.uid || '', description: secret?.description || '', value: '' }}
formName="addSecret"
enableReinitialize={true}
validationSchema={yup.object().shape({
name: yup
.string()
.trim()
.required()
.matches(/^[a-zA-Z_][a-zA-Z0-9-_.]*$/, getString('validation.nameLogic')),
value: yup.string().trim().required()
})}
validateOnChange
validateOnBlur
onSubmit={handleSubmit}>
<FormikForm>
<FormInput.Text
name="name"
label={getString('name')}
placeholder={getString('secrets.enterSecretName')}
tooltipProps={{
dataTooltipId: 'secretNameTextField'
}}
inputGroup={{ autoFocus: true }}
/>
<FormInput.Text
name="value"
label={getString('value')}
placeholder={getString('secrets.value')}
tooltipProps={{
dataTooltipId: 'secretDescriptionTextField'
}}
inputGroup={{ type: 'password', autoComplete: 'new-password' }}
/>
<FormInput.Text
name="description"
label={getString('description')}
placeholder={getString('enterDescription')}
tooltipProps={{
dataTooltipId: 'secretDescriptionTextField'
}}
isOptional
/>
<Layout.Horizontal
spacing="small"
padding={{ right: 'xxlarge', top: 'xxxlarge' }}
style={{ alignItems: 'center' }}>
<Button
type="submit"
text={getString('secrets.updateSecret')}
variation={ButtonVariation.PRIMARY}
disabled={loading}
/>
<Button text={getString('cancel')} minimal variation={ButtonVariation.SECONDARY} onClick={onClose} />
<FlexExpander />
{loading && <Icon intent={Intent.PRIMARY} name="steps-spinner" size={16} />}
</Layout.Horizontal>
</FormikForm>
</Formik>
</Container>
</Layout.Vertical>
</Dialog>
)
}, [secret])
return {
openModal: ({
secretToUpdate,
openSecretUpdate
}: {
secretToUpdate: TypesSecret
openSecretUpdate: () => Promise<void>
}) => {
setSecret(secretToUpdate)
postUpdate.current = openSecretUpdate
openModal()
}
}
}
export default useUpdateSecretModal