[CODE-1159] UI to disable public repo creation with a flag - GITNESS_PUBLIC_RESOURCE_CREATION_ENABLED (#895)

This commit is contained in:
Ritik Kapoor 2023-12-18 08:42:38 +00:00 committed by Harness
parent b24729d608
commit cb817bf2ad
4 changed files with 171 additions and 198 deletions

View File

@ -18,20 +18,11 @@ import React, { useState } from 'react'
import { Intent } from '@blueprintjs/core' import { Intent } from '@blueprintjs/core'
import * as yup from 'yup' import * as yup from 'yup'
import { Color } from '@harnessio/design-system' import { Color } from '@harnessio/design-system'
import { Button, Container, Layout, FlexExpander, Formik, FormikForm, FormInput, Text } from '@harnessio/uicore' import { Button, Layout, FlexExpander, Formik, FormikForm, FormInput, Text } from '@harnessio/uicore'
import { Icon } from '@harnessio/icons' import { Icon } from '@harnessio/icons'
import { FontVariation } from '@harnessio/design-system'
import { useStrings } from 'framework/strings' import { useStrings } from 'framework/strings'
import { REGEX_VALID_REPO_NAME } from 'utils/Utils' import { REGEX_VALID_REPO_NAME } from 'utils/Utils'
import { import { ImportFormData, GitProviders, getProviders, getOrgLabel, getOrgPlaceholder } from 'utils/GitUtils'
ImportFormData,
RepoVisibility,
GitProviders,
getProviders,
getOrgLabel,
getOrgPlaceholder
} from 'utils/GitUtils'
import Private from '../../../icons/private.svg'
import css from '../NewRepoModalButton.module.scss' import css from '../NewRepoModalButton.module.scss'
interface ImportFormProps { interface ImportFormProps {
@ -56,8 +47,7 @@ const ImportForm = (props: ImportFormProps) => {
username: '', username: '',
password: '', password: '',
name: '', name: '',
description: '', description: ''
isPublic: RepoVisibility.PRIVATE
} }
const validationSchemaStepOne = yup.object().shape({ const validationSchemaStepOne = yup.object().shape({
@ -244,56 +234,6 @@ const ImportForm = (props: ImportFormProps) => {
}} }}
/> />
<hr className={css.dividerContainer} />
<Container>
<FormInput.RadioGroup
name="isPublic"
label=""
items={[
{
label: (
<Container>
<Layout.Horizontal>
<Icon name="git-clone-step" size={20} margin={{ right: 'medium' }} />
<Container>
<Layout.Vertical spacing="xsmall">
<Text>{getString('public')}</Text>
<Text font={{ variation: FontVariation.TINY }}>
{getString('createRepoModal.publicLabel')}
</Text>
</Layout.Vertical>
</Container>
</Layout.Horizontal>
</Container>
),
value: RepoVisibility.PUBLIC
},
{
label: (
<Container>
<Layout.Horizontal>
<Container margin={{ right: 'medium' }}>
<img width={20} height={20} src={Private} />
</Container>
{/* <Icon name="git-clone-step" size={20} margin={{ right: 'medium' }} /> */}
<Container margin={{ left: 'small' }}>
<Layout.Vertical spacing="xsmall">
<Text>{getString('private')}</Text>
<Text font={{ variation: FontVariation.TINY }}>
{getString('createRepoModal.privateLabel')}
</Text>
</Layout.Vertical>
</Container>
</Layout.Horizontal>
</Container>
),
value: RepoVisibility.PRIVATE
}
]}
/>
</Container>
<Layout.Horizontal <Layout.Horizontal
spacing="small" spacing="small"
padding={{ right: 'xxlarge', top: 'xlarge', bottom: 'large' }} padding={{ right: 'xxlarge', top: 'xlarge', bottom: 'large' }}

View File

@ -46,6 +46,7 @@ import {
import { Icon } from '@harnessio/icons' import { Icon } from '@harnessio/icons'
import { Color, FontVariation } from '@harnessio/design-system' import { Color, FontVariation } from '@harnessio/design-system'
import { useGet, useMutate } from 'restful-react' import { useGet, useMutate } from 'restful-react'
import { Render } from 'react-jsx-match'
import { get } from 'lodash-es' import { get } from 'lodash-es'
import { useModalHook } from 'hooks/useModalHook' import { useModalHook } from 'hooks/useModalHook'
import { useStrings } from 'framework/strings' import { useStrings } from 'framework/strings'
@ -107,6 +108,7 @@ export const NewRepoModalButton: React.FC<NewRepoModalButtonProps> = ({
const ModalComponent: React.FC = () => { const ModalComponent: React.FC = () => {
const { getString } = useStrings() const { getString } = useStrings()
const [branchName, setBranchName] = useState(DEFAULT_BRANCH_NAME) const [branchName, setBranchName] = useState(DEFAULT_BRANCH_NAME)
const [enablePublicRepo, setEnablePublicRepo] = useState(false)
const { showError } = useToaster() const { showError } = useToaster()
const { mutate: createRepo, loading: submitLoading } = useMutate<TypesRepository>({ const { mutate: createRepo, loading: submitLoading } = useMutate<TypesRepository>({
@ -141,13 +143,31 @@ export const NewRepoModalButton: React.FC<NewRepoModalButtonProps> = ({
loading: licenseLoading, loading: licenseLoading,
error: licenseError error: licenseError
} = useGet({ path: '/api/v1/resources/license' }) } = useGet({ path: '/api/v1/resources/license' })
const loading = submitLoading || gitIgnoreLoading || licenseLoading || importRepoLoading || submitImportLoading const {
data: systemConfig,
loading: systemConfigLoading,
error: systemConfigError
} = useGet({ path: 'api/v1/system/config' })
const loading =
submitLoading ||
gitIgnoreLoading ||
licenseLoading ||
importRepoLoading ||
submitImportLoading ||
systemConfigLoading
useEffect(() => { useEffect(() => {
if (gitIgnoreError || licenseError) { if (gitIgnoreError || licenseError || systemConfigError) {
showError(getErrorMessage(gitIgnoreError || licenseError), 0) showError(getErrorMessage(gitIgnoreError || licenseError || systemConfigError), 0)
} }
}, [gitIgnoreError, licenseError, showError]) }, [gitIgnoreError, licenseError, systemConfigError, showError])
useEffect(() => {
if (systemConfig) {
setEnablePublicRepo(systemConfig.public_resource_creation_enabled)
}
}, [systemConfig])
const handleSubmit = (formData: RepoFormData) => { const handleSubmit = (formData: RepoFormData) => {
try { try {
const payload: OpenapiCreateRepositoryRequest = { const payload: OpenapiCreateRepositoryRequest = {
@ -309,54 +329,56 @@ export const NewRepoModalButton: React.FC<NewRepoModalButtonProps> = ({
{getString('createRepoModal.branch')} {getString('createRepoModal.branch')}
</Text> </Text>
</Container> </Container>
<hr className={css.dividerContainer} /> <Render when={enablePublicRepo}>
<Container> <hr className={css.dividerContainer} />
<FormInput.RadioGroup <Container>
name="isPublic" <FormInput.RadioGroup
label="" name="isPublic"
items={[ label=""
{ items={[
label: ( {
<Container> label: (
<Layout.Horizontal> <Container>
<Icon name="git-clone-step" size={20} margin={{ right: 'medium' }} /> <Layout.Horizontal>
<Container> <Icon name="git-clone-step" size={20} margin={{ right: 'medium' }} />
<Layout.Vertical spacing="xsmall"> <Container>
<Text>{getString('public')}</Text> <Layout.Vertical spacing="xsmall">
<Text font={{ variation: FontVariation.TINY }}> <Text>{getString('public')}</Text>
{getString('createRepoModal.publicLabel')} <Text font={{ variation: FontVariation.TINY }}>
</Text> {getString('createRepoModal.publicLabel')}
</Layout.Vertical> </Text>
</Container> </Layout.Vertical>
</Layout.Horizontal> </Container>
</Container> </Layout.Horizontal>
), </Container>
value: RepoVisibility.PUBLIC ),
}, value: RepoVisibility.PUBLIC
{ },
label: ( {
<Container> label: (
<Layout.Horizontal> <Container>
<Container margin={{ right: 'medium' }}> <Layout.Horizontal>
<img width={20} height={20} src={Private} /> <Container margin={{ right: 'medium' }}>
</Container> <img width={20} height={20} src={Private} />
{/* <Icon name="git-clone-step" size={20} margin={{ right: 'medium' }} /> */} </Container>
<Container margin={{ left: 'small' }}> {/* <Icon name="git-clone-step" size={20} margin={{ right: 'medium' }} /> */}
<Layout.Vertical spacing="xsmall"> <Container margin={{ left: 'small' }}>
<Text>{getString('private')}</Text> <Layout.Vertical spacing="xsmall">
<Text font={{ variation: FontVariation.TINY }}> <Text>{getString('private')}</Text>
{getString('createRepoModal.privateLabel')} <Text font={{ variation: FontVariation.TINY }}>
</Text> {getString('createRepoModal.privateLabel')}
</Layout.Vertical> </Text>
</Container> </Layout.Vertical>
</Layout.Horizontal> </Container>
</Container> </Layout.Horizontal>
), </Container>
value: RepoVisibility.PRIVATE ),
} value: RepoVisibility.PRIVATE
]} }
/> ]}
</Container> />
</Container>
</Render>
<hr className={css.dividerContainer} /> <hr className={css.dividerContainer} />
<FormInput.Select <FormInput.Select

View File

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
import React, { useState } from 'react' import React, { useState, useEffect } from 'react'
import { import {
Container, Container,
Layout, Layout,
@ -33,7 +33,8 @@ import cx from 'classnames'
import { Color, FontVariation, Intent } from '@harnessio/design-system' import { Color, FontVariation, Intent } from '@harnessio/design-system'
import { Icon } from '@harnessio/icons' import { Icon } from '@harnessio/icons'
import { noop } from 'lodash-es' import { noop } from 'lodash-es'
import { useMutate } from 'restful-react' import { useMutate, useGet } from 'restful-react'
import { Render } from 'react-jsx-match'
import { ACCESS_MODES, getErrorMessage, permissionProps, voidFn } from 'utils/Utils' import { ACCESS_MODES, getErrorMessage, permissionProps, voidFn } from 'utils/Utils'
import { useStrings } from 'framework/strings' import { useStrings } from 'framework/strings'
import type { TypesRepository } from 'services/code' import type { TypesRepository } from 'services/code'
@ -64,6 +65,7 @@ const GeneralSettingsContent = (props: GeneralSettingsProps) => {
const currRepoVisibility = repoMetadata?.is_public === true ? RepoVisibility.PUBLIC : RepoVisibility.PRIVATE const currRepoVisibility = repoMetadata?.is_public === true ? RepoVisibility.PUBLIC : RepoVisibility.PRIVATE
const [repoVis, setRepoVis] = useState<RepoVisibility>(currRepoVisibility) const [repoVis, setRepoVis] = useState<RepoVisibility>(currRepoVisibility)
const [enablePublicRepo, setEnablePublicRepo] = useState(false)
const { mutate } = useMutate({ const { mutate } = useMutate({
verb: 'PATCH', verb: 'PATCH',
path: `/api/v1/repos/${repoMetadata?.path}/+/` path: `/api/v1/repos/${repoMetadata?.path}/+/`
@ -87,6 +89,14 @@ const GeneralSettingsContent = (props: GeneralSettingsProps) => {
}, },
[space] [space]
) )
const { data: systemConfig } = useGet({ path: 'api/v1/system/config' })
useEffect(() => {
if (systemConfig) {
setEnablePublicRepo(systemConfig.public_resource_creation_enabled)
}
}, [systemConfig])
const ModalComponent: React.FC = () => { const ModalComponent: React.FC = () => {
return ( return (
<Dialog <Dialog
@ -231,87 +241,89 @@ const GeneralSettingsContent = (props: GeneralSettingsProps) => {
</Container> </Container>
</Layout.Horizontal> </Layout.Horizontal>
</Container> </Container>
<Container padding="large" margin={{ bottom: 'medium' }} className={css.generalContainer}> <Render when={enablePublicRepo}>
<Layout.Horizontal padding={{ bottom: 'medium' }}> <Container padding="large" margin={{ bottom: 'medium' }} className={css.generalContainer}>
<Container className={css.label}> <Layout.Horizontal padding={{ bottom: 'medium' }}>
<Text color={Color.GREY_600} font={{ size: 'small' }}> <Container className={css.label}>
{getString('repoVisibility')} <Text color={Color.GREY_600} font={{ size: 'small' }}>
</Text> {getString('repoVisibility')}
</Container> </Text>
<Container className={css.content}> </Container>
<FormInput.RadioGroup <Container className={css.content}>
name="isPublic" <FormInput.RadioGroup
label="" name="isPublic"
onChange={evt => { label=""
setRepoVis((evt.target as HTMLInputElement).value as RepoVisibility) onChange={evt => {
}} setRepoVis((evt.target as HTMLInputElement).value as RepoVisibility)
className={css.radioContainer} }}
items={[ className={css.radioContainer}
{ items={[
label: ( {
<Container> label: (
<Layout.Horizontal> <Container>
<Icon <Layout.Horizontal>
className={css.iconContainer} <Icon
name="git-clone-step" className={css.iconContainer}
size={20} name="git-clone-step"
margin={{ left: 'small', right: 'medium' }} size={20}
/> margin={{ left: 'small', right: 'medium' }}
<Container> />
<Layout.Vertical spacing="xsmall"> <Container>
<Text font={{ size: 'small' }}>{getString('public')}</Text> <Layout.Vertical spacing="xsmall">
<Text font={{ variation: FontVariation.TINY }}> <Text font={{ size: 'small' }}>{getString('public')}</Text>
{getString('createRepoModal.publicLabel')} <Text font={{ variation: FontVariation.TINY }}>
</Text> {getString('createRepoModal.publicLabel')}
</Layout.Vertical> </Text>
</Container> </Layout.Vertical>
</Layout.Horizontal> </Container>
</Container> </Layout.Horizontal>
), </Container>
),
value: RepoVisibility.PUBLIC value: RepoVisibility.PUBLIC
}, },
{ {
label: ( label: (
<Container> <Container>
<Layout.Horizontal> <Layout.Horizontal>
<Container className={css.iconContainer} margin={{ left: 'small', right: 'medium' }}> <Container className={css.iconContainer} margin={{ left: 'small', right: 'medium' }}>
<img width={20} height={20} src={Private} /> <img width={20} height={20} src={Private} />
</Container> </Container>
<Container margin={{ left: 'small' }}> <Container margin={{ left: 'small' }}>
<Layout.Vertical spacing="xsmall"> <Layout.Vertical spacing="xsmall">
<Text font={{ size: 'small' }}>{getString('private')}</Text> <Text font={{ size: 'small' }}>{getString('private')}</Text>
<Text font={{ variation: FontVariation.TINY }}> <Text font={{ variation: FontVariation.TINY }}>
{getString('createRepoModal.privateLabel')} {getString('createRepoModal.privateLabel')}
</Text> </Text>
</Layout.Vertical> </Layout.Vertical>
</Container> </Container>
</Layout.Horizontal> </Layout.Horizontal>
</Container> </Container>
), ),
value: RepoVisibility.PRIVATE value: RepoVisibility.PRIVATE
} }
]} ]}
/> />
<hr className={css.dividerContainer} /> <hr className={css.dividerContainer} />
<Layout.Horizontal className={css.buttonContainer}> <Layout.Horizontal className={css.buttonContainer}>
{repoVis !== currRepoVisibility ? ( {repoVis !== currRepoVisibility ? (
<Button <Button
margin={{ right: 'medium' }} margin={{ right: 'medium' }}
type="submit" type="submit"
text={getString('save')} text={getString('save')}
variation={ButtonVariation.PRIMARY} variation={ButtonVariation.PRIMARY}
size={ButtonSize.SMALL} size={ButtonSize.SMALL}
onClick={() => { onClick={() => {
setRepoVis(formik.values.isPublic) setRepoVis(formik.values.isPublic)
openModal() openModal()
}} }}
/> />
) : null} ) : null}
</Layout.Horizontal> </Layout.Horizontal>
</Container> </Container>
</Layout.Horizontal> </Layout.Horizontal>
</Container> </Container>
</Render>
<Container padding="medium" className={css.generalContainer}> <Container padding="medium" className={css.generalContainer}>
<Container className={css.deleteContainer}> <Container className={css.deleteContainer}>
<Text icon="main-trash" color={Color.GREY_600} font={{ size: 'small' }}> <Text icon="main-trash" color={Color.GREY_600} font={{ size: 'small' }}>

View File

@ -58,7 +58,6 @@ export interface ImportFormData {
password: string password: string
name: string name: string
description: string description: string
isPublic: RepoVisibility
} }
export interface ExportFormData { export interface ExportFormData {