feat: [CODE-615]: Show Token after Creation (#233)

This commit is contained in:
Hitesh Aringa 2023-07-25 21:04:34 +00:00 committed by Harness
parent c24d2d1795
commit ef9a0f28d4
6 changed files with 86 additions and 26 deletions

View File

@ -216,6 +216,7 @@ export const FormInputWithCopyButton: React.FC<
return ( return (
<FormInput.Text <FormInput.Text
{...props} {...props}
className={css.inputWrapper}
inputGroup={{ inputGroup={{
...props.inputGroup, ...props.inputGroup,
rightElement: ( rightElement: (

View File

@ -1,12 +1,6 @@
.dialogCtn { .dialogCtn {
overflow: unset !important; overflow: unset !important;
button#copyBtn {
border-radius: 0 !important;
border-left: 1px solid var(--grey-200) !important;
margin-left: var(--spacing-small) !important;
}
:global { :global {
.bp3-form-group, .bp3-form-group,
.TextInput--main { .TextInput--main {
@ -45,3 +39,11 @@
} }
} }
} }
.inputWrapper {
button#copyBtn {
border-radius: 0 !important;
border-left: 1px solid var(--grey-200) !important;
margin-left: var(--spacing-small) !important;
}
}

View File

@ -2,10 +2,11 @@
// this is an auto-generated file // this is an auto-generated file
declare const styles: { declare const styles: {
readonly dialogCtn: string readonly dialogCtn: string
readonly copyBtn: string
readonly passwordCtn: string readonly passwordCtn: string
readonly layout: string readonly layout: string
readonly text: string readonly text: string
readonly formikForm: string readonly formikForm: string
readonly inputWrapper: string
readonly copyBtn: string
} }
export default styles export default styles

View File

@ -218,6 +218,7 @@ export interface StringsMap {
'newToken.generateToken': string 'newToken.generateToken': string
'newToken.namePlaceholder': string 'newToken.namePlaceholder': string
'newToken.text': string 'newToken.text': string
'newToken.tokenHelptext': string
'newUserModal.displayNamePlaceholder': string 'newUserModal.displayNamePlaceholder': string
'newUserModal.emailPlaceholder': string 'newUserModal.emailPlaceholder': string
'newUserModal.passwordHelptext': string 'newUserModal.passwordHelptext': string

View File

@ -518,6 +518,9 @@ newToken:
namePlaceholder: Enter the name namePlaceholder: Enter the name
expireOn: Token will expire on {{date}} expireOn: Token will expire on {{date}}
generateToken: Generate Token generateToken: Generate Token
tokenHelptext:
Your token has been generated. Please make sure to copy and store your token somewhere safe, you wont be
able to see it again.
deleteToken: Delete token deleteToken: Delete token
deleteTokenMsg: Token deleted successfully deleteTokenMsg: Token deleted successfully
userProfile: userProfile:

View File

@ -1,9 +1,11 @@
import React, { useMemo } from 'react' import React, { useMemo, useState } from 'react'
import { import {
Button, Button,
ButtonVariation, ButtonVariation,
Color, Color,
Container,
Dialog, Dialog,
FlexExpander,
FontVariation, FontVariation,
FormikForm, FormikForm,
FormInput, FormInput,
@ -15,15 +17,23 @@ import { Formik } from 'formik'
import { useMutate } from 'restful-react' import { useMutate } from 'restful-react'
import moment from 'moment' import moment from 'moment'
import * as Yup from 'yup' import * as Yup from 'yup'
import { Else, Match, Render, Truthy } from 'react-jsx-match'
import { REGEX_VALID_REPO_NAME } from 'utils/Utils'
import { useStrings } from 'framework/strings' import { useStrings } from 'framework/strings'
import { REGEX_VALID_REPO_NAME } from 'utils/Utils'
import { CodeIcon } from 'utils/GitUtils'
import { CopyButton } from 'components/CopyButton/CopyButton'
import { FormInputWithCopyButton } from 'components/UserManagementFlows/AddUserModal'
import css from 'components/CloneCredentialDialog/CloneCredentialDialog.module.scss'
const useNewToken = ({ onClose }: { onClose: () => void }) => { const useNewToken = ({ onClose }: { onClose: () => void }) => {
const { getString } = useStrings() const { getString } = useStrings()
const { mutate } = useMutate({ path: '/api/v1/user/tokens', verb: 'POST' }) const { mutate } = useMutate({ path: '/api/v1/user/tokens', verb: 'POST' })
const [generatedToken, setGeneratedToken] = useState<string>()
const isTokenGenerated = Boolean(generatedToken)
const lifeTimeOptions = useMemo( const lifeTimeOptions = useMemo(
() => [ () => [
{ label: getString('nDays', { number: 7 }), value: 604800000000000 }, { label: getString('nDays', { number: 7 }), value: 604800000000000 },
@ -34,9 +44,15 @@ const useNewToken = ({ onClose }: { onClose: () => void }) => {
[getString] [getString]
) )
const onModalClose = () => {
hideModal()
onClose()
setGeneratedToken()
}
const [openModal, hideModal] = useModalHook(() => { const [openModal, hideModal] = useModalHook(() => {
return ( return (
<Dialog isOpen enforceFocus={false} onClose={hideModal} title={getString('createNewToken')}> <Dialog isOpen enforceFocus={false} onClose={onModalClose} title={getString('createNewToken')}>
<Formik <Formik
initialValues={{ initialValues={{
uid: '', uid: '',
@ -49,9 +65,8 @@ const useNewToken = ({ onClose }: { onClose: () => void }) => {
lifeTime: Yup.number().required(getString('validation.expirationDateRequired')) lifeTime: Yup.number().required(getString('validation.expirationDateRequired'))
})} })}
onSubmit={async values => { onSubmit={async values => {
await mutate(values) const res = await mutate(values)
hideModal() setGeneratedToken(res?.access_token)
onClose()
}}> }}>
{formikProps => { {formikProps => {
const expiresAtString = moment(Date.now() + formikProps.values.lifeTime / 1000000).format( const expiresAtString = moment(Date.now() + formikProps.values.lifeTime / 1000000).format(
@ -60,32 +75,69 @@ const useNewToken = ({ onClose }: { onClose: () => void }) => {
return ( return (
<FormikForm> <FormikForm>
<FormInput.Text <FormInputWithCopyButton
name="uid" name="uid"
label={getString('name')} label={getString('name')}
placeholder={getString('newToken.namePlaceholder')} placeholder={getString('newToken.namePlaceholder')}
disabled={isTokenGenerated}
/>
<FormInput.Select
name="lifeTime"
label={getString('expiration')}
items={lifeTimeOptions}
usePortal
disabled={isTokenGenerated}
/> />
<FormInput.Select name="lifeTime" label={getString('expiration')} items={lifeTimeOptions} usePortal />
{formikProps.values.lifeTime ? ( {formikProps.values.lifeTime ? (
<Text font={{ variation: FontVariation.SMALL_SEMI }} color={Color.GREY_400}> <Text
font={{ variation: FontVariation.SMALL_SEMI }}
color={Color.GREY_400}
margin={{ bottom: 'medium' }}>
{getString('newToken.expireOn', { date: expiresAtString })} {getString('newToken.expireOn', { date: expiresAtString })}
</Text> </Text>
) : null} ) : null}
<Layout.Horizontal margin={{ top: 'xxxlarge' }} spacing="medium"> <Render when={isTokenGenerated}>
<Button <Text padding={{ bottom: 'small' }} font={{ variation: FontVariation.FORM_LABEL, size: 'small' }}>
text={getString('newToken.generateToken')} {getString('token')}
type="submit" </Text>
variation={ButtonVariation.PRIMARY} <Container padding={{ bottom: 'medium' }}>
/> <Layout.Horizontal className={css.layout}>
<Button text={getString('cancel')} onClick={hideModal} variation={ButtonVariation.TERTIARY} /> <Text className={css.url}>{generatedToken}</Text>
</Layout.Horizontal> <FlexExpander />
<CopyButton
content={generatedToken || ''}
id={css.cloneCopyButton}
icon={CodeIcon.Copy}
iconProps={{ size: 14 }}
/>
</Layout.Horizontal>
</Container>
<Text padding={{ bottom: 'medium' }} font={{ variation: FontVariation.BODY2_SEMI, size: 'small' }}>
{getString('newToken.tokenHelptext')}
</Text>
</Render>
<Match expr={isTokenGenerated}>
<Truthy>
<Button text={getString('close')} variation={ButtonVariation.TERTIARY} onClick={onModalClose} />
</Truthy>
<Else>
<Layout.Horizontal margin={{ top: 'xxxlarge' }} spacing="medium">
<Button
text={getString('newToken.generateToken')}
type="submit"
variation={ButtonVariation.PRIMARY}
/>
<Button text={getString('cancel')} onClick={hideModal} variation={ButtonVariation.TERTIARY} />
</Layout.Horizontal>
</Else>
</Match>
</FormikForm> </FormikForm>
) )
}} }}
</Formik> </Formik>
</Dialog> </Dialog>
) )
}, []) }, [generatedToken])
return { return {
openModal, openModal,