changes secret value to text area with password font & fixes copy and paste for logs (#687)

This commit is contained in:
Dan Wilson 2023-10-18 15:28:29 +00:00 committed by Harness
parent 1a07ee90d2
commit d2b971c49a
12 changed files with 204 additions and 120 deletions

View File

@ -37,3 +37,10 @@
} }
} }
} }
@font-face {
font-family: 'password';
font-style: normal;
font-weight: 400;
src: local('password'), url('./assets/fonts/password.ttf') format('truetype');
}

Binary file not shown.

View File

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { FlexExpander, Layout, Text } from '@harnessio/uicore' import { FlexExpander, Layout } from '@harnessio/uicore'
import React, { FC } from 'react' import React, { FC } from 'react'
import type { LivelogLine } from 'services/code' import type { LivelogLine } from 'services/code'
import css from './ConsoleLogs.module.scss' import css from './ConsoleLogs.module.scss'
@ -57,10 +57,10 @@ const ConsoleLogs: FC<ConsoleLogsProps> = ({ logs }) => {
{logs.map((log, index) => { {logs.map((log, index) => {
return ( return (
<Layout.Horizontal key={index} spacing={'small'} className={css.logLayout}> <Layout.Horizontal key={index} spacing={'small'} className={css.logLayout}>
{typeof log.pos === 'number' && <Text className={css.lineNumber}>{log.pos + 1}</Text>} {typeof log.pos === 'number' && <span className={css.lineNumber}>{log.pos + 1}</span>}
<Text className={css.log}>{log.out}</Text> <span className={css.log}>{log.out}</span>
<FlexExpander /> <FlexExpander />
<Text className={css.time}>{log.time}s</Text> <span className={css.time}>{log.time}s</span>
</Layout.Horizontal> </Layout.Horizontal>
) )
})} })}

View File

@ -0,0 +1,6 @@
.textArea textarea {
font-family: 'password' !important;
width: 250px;
font-weight: normal;
font-style: normal;
}

View File

@ -0,0 +1,19 @@
/*
* Copyright 2023 Harness, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* eslint-disable */
// This is an auto-generated file
export declare const textArea: string

View File

@ -37,17 +37,20 @@ import { useModalHook } from 'hooks/useModalHook'
import { useStrings } from 'framework/strings' import { useStrings } from 'framework/strings'
import type { OpenapiCreateSecretRequest, TypesSecret } from 'services/code' import type { OpenapiCreateSecretRequest, TypesSecret } from 'services/code'
import { getErrorMessage } from 'utils/Utils' import { getErrorMessage } from 'utils/Utils'
import css from './NewSecretModalButton.module.scss'
export interface SecretFormData { export interface SecretFormData {
value: string value: string
description: string description: string
name: string name: string
showValue: boolean
} }
const formInitialValues: SecretFormData = { const formInitialValues: SecretFormData = {
value: '', value: '',
description: '', description: '',
name: '' name: '',
showValue: false
} }
export interface NewSecretModalButtonProps extends Omit<ButtonProps, 'onClick' | 'onSubmit'> { export interface NewSecretModalButtonProps extends Omit<ButtonProps, 'onClick' | 'onSubmit'> {
@ -122,57 +125,66 @@ export const NewSecretModalButton: React.FC<NewSecretModalButtonProps> = ({
validateOnChange validateOnChange
validateOnBlur validateOnBlur
onSubmit={handleSubmit}> onSubmit={handleSubmit}>
<FormikForm> {formik => (
<Container> <FormikForm>
<FormInput.Text <Container>
name="name" <FormInput.Text
label={getString('name')} name="name"
placeholder={getString('secrets.enterSecretName')} label={getString('name')}
tooltipProps={{ placeholder={getString('secrets.enterSecretName')}
dataTooltipId: 'secretNameTextField' tooltipProps={{
}} dataTooltipId: 'secretNameTextField'
inputGroup={{ autoFocus: true }} }}
/> inputGroup={{ autoFocus: true }}
<FormInput.Text />
name="value" <FormInput.TextArea
label={getString('value')} name="value"
placeholder={getString('secrets.value')} label={getString('value')}
tooltipProps={{ tooltipProps={{
dataTooltipId: 'secretDescriptionTextField' dataTooltipId: 'secretDescriptionTextField'
}} }}
inputGroup={{ type: 'password', autoComplete: 'new-password' }} autoComplete="off"
/> className={formik.values.showValue ? '' : css.textArea}
<FormInput.Text />
name="description" <FormInput.CheckBox
label={getString('description')} name="showValue"
placeholder={getString('enterDescription')} label={getString('secrets.showValue')}
tooltipProps={{ tooltipProps={{
dataTooltipId: 'secretDescriptionTextField' dataTooltipId: 'secretDescriptionTextField'
}} }}
isOptional />
/> <FormInput.Text
</Container> name="description"
label={getString('description')}
placeholder={getString('enterDescription')}
tooltipProps={{
dataTooltipId: 'secretDescriptionTextField'
}}
isOptional
/>
</Container>
<Layout.Horizontal <Layout.Horizontal
spacing="small" spacing="small"
padding={{ right: 'xxlarge', top: 'xxxlarge' }} padding={{ right: 'xxlarge', top: 'xxxlarge' }}
style={{ alignItems: 'center' }}> style={{ alignItems: 'center' }}>
<Button <Button
type="submit" type="submit"
text={getString('secrets.createSecret')} text={getString('secrets.createSecret')}
variation={ButtonVariation.PRIMARY} variation={ButtonVariation.PRIMARY}
disabled={loading} disabled={loading}
/> />
<Button <Button
text={cancelButtonTitle || getString('cancel')} text={cancelButtonTitle || getString('cancel')}
minimal minimal
onClick={hideModal} onClick={hideModal}
variation={ButtonVariation.SECONDARY} variation={ButtonVariation.SECONDARY}
/> />
<FlexExpander /> <FlexExpander />
{loading && <Icon intent={Intent.PRIMARY} name="steps-spinner" size={16} />} {loading && <Icon intent={Intent.PRIMARY} name="steps-spinner" size={16} />}
</Layout.Horizontal> </Layout.Horizontal>
</FormikForm> </FormikForm>
)}
</Formik> </Formik>
</Container> </Container>
</Layout.Vertical> </Layout.Vertical>

View File

@ -58,33 +58,28 @@ const useRunPipelineModal = () => {
path: `/api/v1/repos/${repoPath}/+/pipelines/${pipeline}/executions` path: `/api/v1/repos/${repoPath}/+/pipelines/${pipeline}/executions`
}) })
const runPipeline = (formData: FormData): void => { const runPipeline = async (formData: FormData): Promise<void> => {
const { branch } = formData const { branch } = formData
try { try {
startExecution( const response = await startExecution(
{}, {},
{ {
pathParams: { path: `/api/v1/repos/${repoPath}/+/pipelines/${pipeline}/executions` }, pathParams: { path: `/api/v1/repos/${repoPath}/+/pipelines/${pipeline}/executions` },
queryParams: { branch } as CreateExecutionQueryParams queryParams: { branch } as CreateExecutionQueryParams
} }
) )
.then(response => { clearToaster()
clearToaster() showSuccess(getString('pipelines.executionStarted'))
showSuccess(getString('pipelines.executionStarted')) if (response?.number && !isNaN(response.number)) {
if (response?.number && !isNaN(response.number)) { history.push(routes.toCODEExecution({ repoPath, pipeline, execution: response.number.toString() }))
history.push(routes.toCODEExecution({ repoPath, pipeline, execution: response.number.toString() })) }
} hideModal()
hideModal() } catch (error) {
}) const errorMssg = getErrorMessage(error)
.catch(error => { const pipelineDoesNotExistOnGit = errorMssg === getString('pipelines.failedToFindPath')
const errorMssg = getErrorMessage(error) pipelineDoesNotExistOnGit
const pipelineDoesNotExistOnGit = errorMssg === getString('pipelines.failedToFindPath') ? showError(`${getString('pipelines.executionCouldNotStart')}, ${errorMssg}.`)
pipelineDoesNotExistOnGit : showError(getErrorMessage(error), 0, 'pipelines.executionCouldNotStart')
? showError(`${getString('pipelines.executionCouldNotStart')}, ${errorMssg}.`)
: showError(getErrorMessage(error), 0, 'pipelines.executionCouldNotStart')
})
} catch (exception) {
showError(getErrorMessage(exception), 0, 'pipelines.executionCouldNotStart')
} }
} }

View File

@ -0,0 +1,6 @@
.textArea textarea {
font-family: 'password' !important;
width: 250px;
font-weight: normal;
font-style: normal;
}

View File

@ -0,0 +1,19 @@
/*
* Copyright 2023 Harness, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* eslint-disable */
// This is an auto-generated file
export declare const textArea: string

View File

@ -39,6 +39,7 @@ import { useGetSpaceParam } from 'hooks/useGetSpaceParam'
import type { OpenapiUpdateSecretRequest, TypesSecret } from 'services/code' import type { OpenapiUpdateSecretRequest, TypesSecret } from 'services/code'
import type { SecretFormData } from 'components/NewSecretModalButton/NewSecretModalButton' import type { SecretFormData } from 'components/NewSecretModalButton/NewSecretModalButton'
import { getErrorMessage, truncateString } from 'utils/Utils' import { getErrorMessage, truncateString } from 'utils/Utils'
import css from './UpdateSecretModal.module.scss'
const useUpdateSecretModal = () => { const useUpdateSecretModal = () => {
const { getString } = useStrings() const { getString } = useStrings()
@ -94,7 +95,12 @@ const useUpdateSecretModal = () => {
<Layout.Vertical style={{ height: '100%' }} data-testid="add-secret-modal"> <Layout.Vertical style={{ height: '100%' }} data-testid="add-secret-modal">
<Container> <Container>
<Formik <Formik
initialValues={{ name: secret?.uid || '', description: secret?.description || '', value: '' }} initialValues={{
name: secret?.uid || '',
description: secret?.description || '',
value: '',
showValue: false
}}
formName="addSecret" formName="addSecret"
enableReinitialize={true} enableReinitialize={true}
validationSchema={yup.object().shape({ validationSchema={yup.object().shape({
@ -110,50 +116,64 @@ const useUpdateSecretModal = () => {
validateOnChange validateOnChange
validateOnBlur validateOnBlur
onSubmit={handleSubmit}> onSubmit={handleSubmit}>
<FormikForm> {formik => (
<FormInput.Text <FormikForm>
name="name" <FormInput.Text
label={getString('name')} name="name"
placeholder={getString('secrets.enterSecretName')} label={getString('name')}
tooltipProps={{ placeholder={getString('secrets.enterSecretName')}
dataTooltipId: 'secretNameTextField' tooltipProps={{
}} dataTooltipId: 'secretNameTextField'
inputGroup={{ autoFocus: true }} }}
/> 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} /> <FormInput.TextArea
<FlexExpander /> name="value"
{loading && <Icon intent={Intent.PRIMARY} name="steps-spinner" size={16} />} label={getString('value')}
</Layout.Horizontal> tooltipProps={{
</FormikForm> dataTooltipId: 'secretDescriptionTextField'
}}
autoComplete="off"
className={formik.values.showValue ? '' : css.textArea}
/>
<FormInput.CheckBox
name="showValue"
label={getString('secrets.showValue')}
tooltipProps={{
dataTooltipId: 'secretDescriptionTextField'
}}
/>
<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> </Formik>
</Container> </Container>
</Layout.Vertical> </Layout.Vertical>

View File

@ -618,8 +618,8 @@ export interface StringsMap {
'secrets.noData': string 'secrets.noData': string
'secrets.secretDeleted': string 'secrets.secretDeleted': string
'secrets.secretUpdated': string 'secrets.secretUpdated': string
'secrets.showValue': string
'secrets.updateSecret': string 'secrets.updateSecret': string
'secrets.value': string
selectBranchPlaceHolder: string selectBranchPlaceHolder: string
selectRange: string selectRange: string
selectSpace: string selectSpace: string

View File

@ -694,7 +694,6 @@ secrets:
name: Secret Name name: Secret Name
failedToCreate: Failed to create Secret. Please try again. failedToCreate: Failed to create Secret. Please try again.
enterSecretName: Enter Secret name enterSecretName: Enter Secret name
value: Secret Value
createSecret: Create Secret createSecret: Create Secret
createSuccess: Secret created successfully createSuccess: Secret created successfully
secretDeleted: Secret {uid} deleted. secretDeleted: Secret {uid} deleted.
@ -704,6 +703,7 @@ secrets:
failedToUpdateSecret: Failed to update Secret. Please try again. failedToUpdateSecret: Failed to update Secret. Please try again.
deleteSecret: Delete secret deleteSecret: Delete secret
updateSecret: Update secret updateSecret: Update secret
showValue: Show Value?
userUpdateSuccess: 'User updated successfully' userUpdateSuccess: 'User updated successfully'
viewFile: View File viewFile: View File
searchResult: 'Search Result {count}' searchResult: 'Search Result {count}'