diff --git a/web/src/components/NewSecretModalButton/NewSecretModalButton.tsx b/web/src/components/NewSecretModalButton/NewSecretModalButton.tsx index ff63e36c8..e82862761 100644 --- a/web/src/components/NewSecretModalButton/NewSecretModalButton.tsx +++ b/web/src/components/NewSecretModalButton/NewSecretModalButton.tsx @@ -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 = ({ onClose={hideModal} title={''} style={{ width: 700, maxHeight: '95vh', overflow: 'auto' }}> - + {modalTitle} diff --git a/web/src/components/UpdateSecretModal/UpdateSecretModal.tsx b/web/src/components/UpdateSecretModal/UpdateSecretModal.tsx new file mode 100644 index 000000000..4b8b0f9c4 --- /dev/null +++ b/web/src/components/UpdateSecretModal/UpdateSecretModal.tsx @@ -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() + const postUpdate = useRef() + + const { mutate: updateSecret, loading } = useMutate({ + 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( + + ) + postUpdate.current?.() + } catch (exception) { + showError(getErrorMessage(exception), 0, getString('secrets.failedToUpdateSecret')) + } + } + + const [openModal, hideModal] = useModalHook(() => { + const onClose = () => { + hideModal() + } + + return ( + + + + {getString('secrets.updateSecret')} + + + + + + + + + + + + ) + }, [secret]) + + return { + openModal: ({ + secretToUpdate, + openSecretUpdate + }: { + secretToUpdate: TypesSecret + openSecretUpdate: () => Promise + }) => { + setSecret(secretToUpdate) + postUpdate.current = openSecretUpdate + openModal() + } + } +} + +export default useUpdateSecretModal diff --git a/web/src/framework/strings/stringTypes.ts b/web/src/framework/strings/stringTypes.ts index afa659c1e..0b3ac30a1 100644 --- a/web/src/framework/strings/stringTypes.ts +++ b/web/src/framework/strings/stringTypes.ts @@ -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 diff --git a/web/src/i18n/strings.en.yaml b/web/src/i18n/strings.en.yaml index 885170f15..83cd7d5a5 100644 --- a/web/src/i18n/strings.en.yaml +++ b/web/src/i18n/strings.en.yaml @@ -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 {{uid}}? 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}' diff --git a/web/src/pages/ExecutionList/ExecutionList.tsx b/web/src/pages/ExecutionList/ExecutionList.tsx index 277bc2312..aa051a7bc 100644 --- a/web/src/pages/ExecutionList/ExecutionList.tsx +++ b/web/src/pages/ExecutionList/ExecutionList.tsx @@ -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() 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({ - 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}> ) diff --git a/web/src/pages/SecretList/SecretList.tsx b/web/src/pages/SecretList/SecretList.tsx index a0b162639..aca84b286 100644 --- a/web/src/pages/SecretList/SecretList.tsx +++ b/web/src/pages/SecretList/SecretList.tsx @@ -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()}> ) + const { openModal: openUpdateSecretModal } = useUpdateSecretModal() + const columns: Column[] = 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,