mirror of
https://github.com/harness/drone.git
synced 2025-05-12 23:20:10 +08:00
Merge branch 'add-delete-secret-modal' of _OKE5H2PQKOUfzFFDuD4FA/default/CODE/gitness (#444)
This commit is contained in:
commit
0c7f62d444
@ -21,7 +21,7 @@ import { useStrings } from 'framework/strings'
|
||||
import type { OpenapiCreateSecretRequest, TypesSecret } from 'services/code'
|
||||
import { getErrorMessage } from 'utils/Utils'
|
||||
|
||||
interface SecretFormData {
|
||||
export interface SecretFormData {
|
||||
value: string
|
||||
description: string
|
||||
name: string
|
||||
@ -82,10 +82,7 @@ export const NewSecretModalButton: React.FC<NewSecretModalButtonProps> = ({
|
||||
onClose={hideModal}
|
||||
title={''}
|
||||
style={{ width: 700, maxHeight: '95vh', overflow: 'auto' }}>
|
||||
<Layout.Vertical
|
||||
padding={{ left: 'xxlarge' }}
|
||||
style={{ height: '100%' }}
|
||||
data-testid="add-target-to-flag-modal">
|
||||
<Layout.Vertical padding={{ left: 'xxlarge' }} style={{ height: '100%' }} data-testid="add-secret-modal">
|
||||
<Heading level={3} font={{ variation: FontVariation.H3 }} margin={{ bottom: 'xlarge' }}>
|
||||
{modalTitle}
|
||||
</Heading>
|
||||
|
156
web/src/components/UpdateSecretModal/UpdateSecretModal.tsx
Normal file
156
web/src/components/UpdateSecretModal/UpdateSecretModal.tsx
Normal file
@ -0,0 +1,156 @@
|
||||
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
|
||||
} 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<Function>()
|
||||
|
||||
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={''}
|
||||
style={{ width: 700, maxHeight: '95vh', overflow: 'auto' }}>
|
||||
<Layout.Vertical padding={{ left: 'xxlarge' }} style={{ height: '100%' }} data-testid="add-secret-modal">
|
||||
<Heading level={3} font={{ variation: FontVariation.H3 }} margin={{ bottom: 'xlarge' }}>
|
||||
{getString('secrets.updateSecret')}
|
||||
</Heading>
|
||||
|
||||
<Container margin={{ right: 'xxlarge' }}>
|
||||
<Formik
|
||||
initialValues={{ name: secret?.uid || '', description: secret?.description || '', value: '' }}
|
||||
formName="addSecret"
|
||||
enableReinitialize={true}
|
||||
validationSchema={yup.object().shape({
|
||||
name: yup.string().trim().required(),
|
||||
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' }}
|
||||
/>
|
||||
<FormInput.Text
|
||||
name="description"
|
||||
label={getString('description')}
|
||||
placeholder={getString('enterDescription')}
|
||||
tooltipProps={{
|
||||
dataTooltipId: 'secretDescriptionTextField'
|
||||
}}
|
||||
isOptional
|
||||
/>
|
||||
|
||||
<Layout.Horizontal
|
||||
spacing="small"
|
||||
padding={{ right: 'xxlarge', top: 'xxxlarge', bottom: 'large' }}
|
||||
style={{ alignItems: 'center' }}>
|
||||
<Button
|
||||
type="submit"
|
||||
text={getString('secrets.updateSecret')}
|
||||
intent={Intent.PRIMARY}
|
||||
disabled={loading}
|
||||
/>
|
||||
<Button text={getString('cancel')} minimal 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
|
@ -496,10 +496,13 @@ export interface StringsMap {
|
||||
'secrets.enterSecretName': string
|
||||
'secrets.failedToCreate': string
|
||||
'secrets.failedToDeleteSecret': string
|
||||
'secrets.failedToUpdateSecret': string
|
||||
'secrets.name': string
|
||||
'secrets.newSecretButton': string
|
||||
'secrets.noData': string
|
||||
'secrets.secretDeleted': string
|
||||
'secrets.secretUpdated': string
|
||||
'secrets.updateSecret': string
|
||||
'secrets.value': string
|
||||
selectBranchPlaceHolder: string
|
||||
selectRange: string
|
||||
|
@ -666,9 +666,12 @@ secrets:
|
||||
createSecret: Create Secret
|
||||
createSuccess: Secret created successfully
|
||||
secretDeleted: Secret {uid} deleted.
|
||||
secretUpdated: Secret {uid} updated.
|
||||
deleteSecretConfirm: Are you sure you want to delete secret <strong>{{uid}}</strong>? You can't undo this action.
|
||||
failedToDeleteSecret: Failed to delete Secret. Please try again.
|
||||
deleteSecret: Delete Secrets
|
||||
failedToUpdateSecret: Failed to update Secret. Please try again.
|
||||
deleteSecret: Delete secret
|
||||
updateSecret: Update secret
|
||||
userUpdateSuccess: 'User updated successfully'
|
||||
viewFile: View File
|
||||
searchResult: 'Search Result {count}'
|
||||
|
@ -8,14 +8,13 @@ import {
|
||||
PageBody,
|
||||
TableV2 as Table,
|
||||
Text,
|
||||
Utils,
|
||||
useToaster
|
||||
Utils
|
||||
} from '@harnessio/uicore'
|
||||
import { Color } from '@harnessio/design-system'
|
||||
import cx from 'classnames'
|
||||
import type { CellProps, Column } from 'react-table'
|
||||
import { useHistory, useParams } from 'react-router-dom'
|
||||
import { useGet, useMutate } from 'restful-react'
|
||||
import { useGet } from 'restful-react'
|
||||
import { Timer, Calendar } from 'iconoir-react'
|
||||
import { useStrings } from 'framework/strings'
|
||||
import { LoadingSpinner } from 'components/LoadingSpinner/LoadingSpinner'
|
||||
@ -33,6 +32,7 @@ import { ExecutionStatus } from 'components/ExecutionStatus/ExecutionStatus'
|
||||
import { getStatus } from 'utils/PipelineUtils'
|
||||
import useSpaceSSE from 'hooks/useSpaceSSE'
|
||||
import { ExecutionText, ExecutionTrigger } from 'components/ExecutionText/ExecutionText'
|
||||
import useRunPipelineModal from 'components/RunPipelineModal/RunPipelineModal'
|
||||
import noExecutionImage from '../RepositoriesListing/no-repo.svg'
|
||||
import css from './ExecutionList.module.scss'
|
||||
|
||||
@ -44,7 +44,6 @@ const ExecutionList = () => {
|
||||
const pageBrowser = useQueryParams<PageBrowserProps>()
|
||||
const pageInit = pageBrowser.page ? parseInt(pageBrowser.page) : 1
|
||||
const [page, setPage] = usePageIndex(pageInit)
|
||||
const { showError, showSuccess } = useToaster()
|
||||
|
||||
const { repoMetadata, error, loading, refetch, space } = useGetRepositoryMetadata()
|
||||
|
||||
@ -84,19 +83,11 @@ const ExecutionList = () => {
|
||||
}
|
||||
})
|
||||
|
||||
const { mutate, loading: mutateLoading } = useMutate<TypesExecution>({
|
||||
verb: 'POST',
|
||||
path: `/api/v1/repos/${repoMetadata?.path}/+/pipelines/${pipeline}/executions`
|
||||
})
|
||||
const { openModal: openRunPipelineModal } = useRunPipelineModal()
|
||||
|
||||
const handleClick = async () => {
|
||||
try {
|
||||
//TODO - this should NOT be hardcoded to master branch - need a modal to insert branch - but useful for testing until then
|
||||
await mutate({ branch: 'master' })
|
||||
showSuccess('Build started')
|
||||
executionsRefetch()
|
||||
} catch {
|
||||
showError('Failed to start build')
|
||||
if (repoMetadata && pipeline) {
|
||||
openRunPipelineModal({ repoMetadata, pipeline })
|
||||
}
|
||||
}
|
||||
|
||||
@ -105,7 +96,6 @@ const ExecutionList = () => {
|
||||
text={getString('executions.newExecutionButton')}
|
||||
variation={ButtonVariation.PRIMARY}
|
||||
icon="play-outline"
|
||||
disabled={mutateLoading}
|
||||
onClick={handleClick}></Button>
|
||||
)
|
||||
|
||||
|
@ -29,6 +29,7 @@ import { ResourceListingPagination } from 'components/ResourceListingPagination/
|
||||
import { NewSecretModalButton } from 'components/NewSecretModalButton/NewSecretModalButton'
|
||||
import { useConfirmAct } from 'hooks/useConfirmAction'
|
||||
import { OptionsMenuButton } from 'components/OptionsMenuButton/OptionsMenuButton'
|
||||
import useUpdateSecretModal from 'components/UpdateSecretModal/UpdateSecretModal'
|
||||
import noSecretsImage from '../RepositoriesListing/no-repo.svg'
|
||||
import css from './SecretList.module.scss'
|
||||
|
||||
@ -61,6 +62,8 @@ const SecretList = () => {
|
||||
onSuccess={() => refetch()}></NewSecretModalButton>
|
||||
)
|
||||
|
||||
const { openModal: openUpdateSecretModal } = useUpdateSecretModal()
|
||||
|
||||
const columns: Column<TypesSecret>[] = useMemo(
|
||||
() => [
|
||||
{
|
||||
@ -113,6 +116,11 @@ const SecretList = () => {
|
||||
isDark
|
||||
width="100px"
|
||||
items={[
|
||||
{
|
||||
text: getString('edit'),
|
||||
isDanger: true,
|
||||
onClick: () => openUpdateSecretModal({ secretToUpdate: row.original, openSecretUpdate: refetch })
|
||||
},
|
||||
{
|
||||
text: getString('delete'),
|
||||
isDanger: true,
|
||||
|
Loading…
Reference in New Issue
Block a user