mirror of
https://github.com/harness/drone.git
synced 2025-05-17 01:20:13 +08:00
feat: [CODE-1072] Support for importing multiple repositories (#788)
This commit is contained in:
parent
972c7d6c67
commit
bd48d92ff5
@ -0,0 +1,370 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import React, { useState } from 'react'
|
||||
import { Intent } from '@blueprintjs/core'
|
||||
import * as yup from 'yup'
|
||||
import { Color } from '@harnessio/design-system'
|
||||
import { Button, Container, Label, Layout, FlexExpander, Formik, FormikForm, FormInput, Text } from '@harnessio/uicore'
|
||||
import { Icon } from '@harnessio/icons'
|
||||
import { useStrings } from 'framework/strings'
|
||||
import { type ImportSpaceFormData, GitProviders, getProviders, getOrgLabel, getOrgPlaceholder } from 'utils/GitUtils'
|
||||
import css from '../../NewSpaceModalButton/NewSpaceModalButton.module.scss'
|
||||
|
||||
interface ImportReposProps {
|
||||
handleSubmit: (data: ImportSpaceFormData) => void
|
||||
loading: boolean
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
hideModal: any
|
||||
spaceRef: string
|
||||
}
|
||||
|
||||
const getHostPlaceHolder = (gitProvider: string) => {
|
||||
switch (gitProvider) {
|
||||
case GitProviders.GITHUB:
|
||||
case GitProviders.GITHUB_ENTERPRISE:
|
||||
return 'enterGithubPlaceholder'
|
||||
case GitProviders.GITLAB:
|
||||
case GitProviders.GITLAB_SELF_HOSTED:
|
||||
return 'enterGitlabPlaceholder'
|
||||
case GitProviders.BITBUCKET:
|
||||
case GitProviders.BITBUCKET_SERVER:
|
||||
return 'enterBitbucketPlaceholder'
|
||||
default:
|
||||
return 'enterAddress'
|
||||
}
|
||||
}
|
||||
|
||||
const ImportReposForm = (props: ImportReposProps) => {
|
||||
const { handleSubmit, loading, hideModal, spaceRef } = props
|
||||
const { getString } = useStrings()
|
||||
const [auth, setAuth] = useState(false)
|
||||
const [step, setStep] = useState(0)
|
||||
const [buttonLoading, setButtonLoading] = useState(false)
|
||||
|
||||
const formInitialValues: ImportSpaceFormData = {
|
||||
gitProvider: GitProviders.GITHUB,
|
||||
username: '',
|
||||
password: '',
|
||||
name: spaceRef,
|
||||
description: '',
|
||||
organization: '',
|
||||
host: ''
|
||||
}
|
||||
|
||||
const validationSchemaStepOne = yup.object().shape({
|
||||
gitProvider: yup.string().trim().required(getString('importSpace.providerRequired'))
|
||||
})
|
||||
|
||||
const validationSchemaStepTwo = yup.object().shape({
|
||||
organization: yup.string().trim().required(getString('importSpace.orgRequired')),
|
||||
name: yup.string().trim().required(getString('importSpace.spaceNameRequired'))
|
||||
})
|
||||
|
||||
return (
|
||||
<Formik
|
||||
initialValues={formInitialValues}
|
||||
formName="importReposForm"
|
||||
enableReinitialize={true}
|
||||
validateOnBlur
|
||||
onSubmit={handleSubmit}>
|
||||
{formik => {
|
||||
const { values } = formik
|
||||
const handleValidationClick = async () => {
|
||||
try {
|
||||
if (step === 0) {
|
||||
await validationSchemaStepOne.validate(formik.values, { abortEarly: false })
|
||||
setStep(1)
|
||||
} else if (step === 1) {
|
||||
await validationSchemaStepTwo.validate(formik.values, { abortEarly: false })
|
||||
setButtonLoading(true)
|
||||
} // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
} catch (err: any) {
|
||||
formik.setErrors(
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
err.inner.reduce((acc: { [x: string]: any }, current: { path: string | number; message: string }) => {
|
||||
acc[current.path] = current.message
|
||||
return acc
|
||||
}, {})
|
||||
)
|
||||
}
|
||||
}
|
||||
const handleImport = async () => {
|
||||
await handleSubmit(formik.values)
|
||||
setButtonLoading(false)
|
||||
}
|
||||
|
||||
return (
|
||||
<Container className={css.hideContainer} width={'97%'}>
|
||||
<FormikForm>
|
||||
{step === 0 ? (
|
||||
<>
|
||||
<Container width={'70%'}>
|
||||
<Layout.Horizontal>
|
||||
<Text padding={{ left: 'small' }} font={{ size: 'small' }}>
|
||||
{getString('importRepos.content')}
|
||||
</Text>
|
||||
</Layout.Horizontal>
|
||||
</Container>
|
||||
<hr className={css.dividerContainer} />
|
||||
<Container className={css.textContainer} width={'70%'}>
|
||||
<FormInput.Select
|
||||
name={'gitProvider'}
|
||||
label={getString('importSpace.gitProvider')}
|
||||
items={getProviders()}
|
||||
className={css.selectBox}
|
||||
/>
|
||||
{formik.errors.gitProvider ? (
|
||||
<Text
|
||||
margin={{ top: 'small', bottom: 'small' }}
|
||||
color={Color.RED_500}
|
||||
icon="circle-cross"
|
||||
iconProps={{ color: Color.RED_500 }}>
|
||||
{formik.errors.gitProvider}
|
||||
</Text>
|
||||
) : null}
|
||||
{![GitProviders.GITHUB, GitProviders.GITLAB, GitProviders.BITBUCKET].includes(
|
||||
values.gitProvider
|
||||
) && (
|
||||
<FormInput.Text
|
||||
name="host"
|
||||
label={getString('importRepo.url')}
|
||||
placeholder={getString(getHostPlaceHolder(values.gitProvider))}
|
||||
tooltipProps={{
|
||||
dataTooltipId: 'spaceUserTextField'
|
||||
}}
|
||||
className={css.hostContainer}
|
||||
/>
|
||||
)}
|
||||
{formik.errors.host ? (
|
||||
<Text
|
||||
margin={{ top: 'small', bottom: 'small' }}
|
||||
color={Color.RED_500}
|
||||
icon="circle-cross"
|
||||
iconProps={{ color: Color.RED_500 }}>
|
||||
{formik.errors.host}
|
||||
</Text>
|
||||
) : null}
|
||||
<Layout.Horizontal flex>
|
||||
{getString('importSpace.authorization')}
|
||||
<Container padding={{ left: 'small' }} width={'100%'}>
|
||||
<hr className={css.dividerContainer} />
|
||||
</Container>
|
||||
</Layout.Horizontal>
|
||||
{formik.values.gitProvider === GitProviders.BITBUCKET && (
|
||||
<FormInput.Text
|
||||
name="username"
|
||||
label={getString('userName')}
|
||||
placeholder={getString('importRepo.userPlaceholder')}
|
||||
tooltipProps={{
|
||||
dataTooltipId: 'spaceUserTextField'
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{formik.errors.username ? (
|
||||
<Text
|
||||
margin={{ top: 'small', bottom: 'small' }}
|
||||
color={Color.RED_500}
|
||||
icon="circle-cross"
|
||||
iconProps={{ color: Color.RED_500 }}>
|
||||
{formik.errors.username}
|
||||
</Text>
|
||||
) : null}
|
||||
<FormInput.Text
|
||||
name="password"
|
||||
label={
|
||||
formik.values.gitProvider === GitProviders.BITBUCKET
|
||||
? getString('importRepo.appPassword')
|
||||
: getString('importRepo.passToken')
|
||||
}
|
||||
placeholder={
|
||||
formik.values.gitProvider === GitProviders.BITBUCKET
|
||||
? getString('importRepo.appPasswordPlaceholder')
|
||||
: getString('importRepo.passTokenPlaceholder')
|
||||
}
|
||||
tooltipProps={{
|
||||
dataTooltipId: 'spacePasswordTextField'
|
||||
}}
|
||||
inputGroup={{ type: 'password' }}
|
||||
/>
|
||||
{formik.errors.password ? (
|
||||
<Text
|
||||
margin={{ top: 'small', bottom: 'small' }}
|
||||
color={Color.RED_500}
|
||||
icon="circle-cross"
|
||||
iconProps={{ color: Color.RED_500 }}>
|
||||
{formik.errors.password}
|
||||
</Text>
|
||||
) : null}
|
||||
</Container>
|
||||
</>
|
||||
) : null}
|
||||
{step === 1 ? (
|
||||
<>
|
||||
<Layout.Horizontal flex>
|
||||
<Text className={css.detailsLabel} font={{ size: 'small' }} flex>
|
||||
{getString('importSpace.details')}
|
||||
</Text>
|
||||
<Container padding={{ left: 'small' }} width={'100%'}>
|
||||
<hr className={css.dividerContainer} />
|
||||
</Container>
|
||||
</Layout.Horizontal>
|
||||
<Container className={css.textContainer} width={'70%'}>
|
||||
<FormInput.Text
|
||||
name="organization"
|
||||
label={getString(getOrgLabel(values.gitProvider))}
|
||||
placeholder={getString(getOrgPlaceholder(values.gitProvider))}
|
||||
tooltipProps={{
|
||||
dataTooltipId: 'importSpaceOrgName'
|
||||
}}
|
||||
onChange={event => {
|
||||
const target = event.target as HTMLInputElement
|
||||
formik.setFieldValue('organization', target.value)
|
||||
if (target.value) {
|
||||
formik.validateField('organization')
|
||||
}
|
||||
}}
|
||||
/>
|
||||
{formik.errors.organization ? (
|
||||
<Text
|
||||
margin={{ bottom: 'small' }}
|
||||
color={Color.RED_500}
|
||||
icon="circle-cross"
|
||||
iconProps={{ color: Color.RED_500 }}>
|
||||
{formik.errors.organization}
|
||||
</Text>
|
||||
) : null}
|
||||
<Layout.Horizontal>
|
||||
<Label>{getString('importSpace.importLabel')}</Label>
|
||||
<Icon padding={{ left: 'small' }} className={css.icon} name="code-info" size={16} />
|
||||
</Layout.Horizontal>
|
||||
|
||||
<Container className={css.importContainer} padding={'medium'}>
|
||||
<Layout.Horizontal>
|
||||
<FormInput.CheckBox
|
||||
name="repositories"
|
||||
label={getString('pageTitle.repositories')}
|
||||
tooltipProps={{
|
||||
dataTooltipId: 'authorization'
|
||||
}}
|
||||
defaultChecked
|
||||
onClick={() => {
|
||||
setAuth(!auth)
|
||||
}}
|
||||
disabled
|
||||
padding={{ right: 'small' }}
|
||||
className={css.checkbox}
|
||||
/>
|
||||
<Container padding={{ left: 'xxxlarge' }}>
|
||||
<FormInput.CheckBox
|
||||
name="pipelines"
|
||||
label={getString('pageTitle.pipelines')}
|
||||
tooltipProps={{
|
||||
dataTooltipId: 'pipelines'
|
||||
}}
|
||||
onClick={() => {
|
||||
setAuth(!auth)
|
||||
}}
|
||||
/>
|
||||
</Container>
|
||||
</Layout.Horizontal>
|
||||
</Container>
|
||||
<Container>
|
||||
<hr className={css.dividerContainer} />
|
||||
<FormInput.Text
|
||||
name="name"
|
||||
label={getString('importSpace.spaceName')}
|
||||
placeholder={getString('enterName')}
|
||||
tooltipProps={{
|
||||
dataTooltipId: 'importSpaceName'
|
||||
}}
|
||||
/>
|
||||
{formik.errors.name ? (
|
||||
<Text
|
||||
margin={{ bottom: 'small' }}
|
||||
color={Color.RED_500}
|
||||
icon="circle-cross"
|
||||
iconProps={{ color: Color.RED_500 }}>
|
||||
{formik.errors.name}
|
||||
</Text>
|
||||
) : null}
|
||||
</Container>
|
||||
</Container>
|
||||
</>
|
||||
) : null}
|
||||
|
||||
<hr className={css.dividerContainer} />
|
||||
|
||||
<Layout.Horizontal
|
||||
spacing="small"
|
||||
padding={{ right: 'xxlarge', bottom: 'large' }}
|
||||
style={{ alignItems: 'center' }}>
|
||||
{step === 1 ? (
|
||||
<Button
|
||||
disabled={buttonLoading}
|
||||
text={
|
||||
buttonLoading ? (
|
||||
<>
|
||||
<Container className={css.loadingIcon} width={93.5} flex={{ alignItems: 'center' }}>
|
||||
<Icon className={css.loadingIcon} name="steps-spinner" size={16} />
|
||||
</Container>
|
||||
</>
|
||||
) : (
|
||||
getString('importRepos.title')
|
||||
)
|
||||
}
|
||||
intent={Intent.PRIMARY}
|
||||
onClick={() => {
|
||||
handleValidationClick()
|
||||
if (formik.values.name !== '' && formik.values.organization !== '') {
|
||||
handleImport()
|
||||
setButtonLoading(false)
|
||||
}
|
||||
formik.setErrors({})
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<Button
|
||||
text={getString('importSpace.next')}
|
||||
intent={Intent.PRIMARY}
|
||||
onClick={() => {
|
||||
handleValidationClick()
|
||||
if (
|
||||
(!formik.errors.gitProvider && formik.touched.gitProvider) ||
|
||||
(!formik.errors.username && formik.touched.username) ||
|
||||
(!formik.errors.password && formik.touched.password)
|
||||
) {
|
||||
formik.setErrors({})
|
||||
setStep(1)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
<Button text={getString('cancel')} minimal onClick={hideModal} />
|
||||
<FlexExpander />
|
||||
|
||||
{loading && <Icon intent={Intent.PRIMARY} name="steps-spinner" size={16} />}
|
||||
</Layout.Horizontal>
|
||||
</FormikForm>
|
||||
</Container>
|
||||
)
|
||||
}}
|
||||
</Formik>
|
||||
)
|
||||
}
|
||||
|
||||
export default ImportReposForm
|
@ -59,15 +59,17 @@ import {
|
||||
import {
|
||||
GitProviders,
|
||||
ImportFormData,
|
||||
ImportSpaceFormData,
|
||||
RepoCreationType,
|
||||
RepoFormData,
|
||||
RepoVisibility,
|
||||
isGitBranchNameValid,
|
||||
getProviderTypeMapping
|
||||
} from 'utils/GitUtils'
|
||||
import type { TypesRepository, OpenapiCreateRepositoryRequest } from 'services/code'
|
||||
import type { TypesSpace, TypesRepository, OpenapiCreateRepositoryRequest } from 'services/code'
|
||||
import { useAppContext } from 'AppContext'
|
||||
import ImportForm from './ImportForm/ImportForm'
|
||||
import ImportReposForm from './ImportReposForm/ImportReposForm'
|
||||
import Private from '../../icons/private.svg'
|
||||
import css from './NewRepoModalButton.module.scss'
|
||||
|
||||
@ -120,6 +122,10 @@ export const NewRepoModalButton: React.FC<NewRepoModalButtonProps> = ({
|
||||
space_path: space
|
||||
}
|
||||
})
|
||||
const { mutate: importMultipleRepositories, loading: submitImportLoading } = useMutate<TypesSpace>({
|
||||
verb: 'POST',
|
||||
path: `/api/v1/spaces/${space}/+/import`
|
||||
})
|
||||
const {
|
||||
data: gitignores,
|
||||
loading: gitIgnoreLoading,
|
||||
@ -130,7 +136,7 @@ export const NewRepoModalButton: React.FC<NewRepoModalButtonProps> = ({
|
||||
loading: licenseLoading,
|
||||
error: licenseError
|
||||
} = useGet({ path: '/api/v1/resources/license' })
|
||||
const loading = submitLoading || gitIgnoreLoading || licenseLoading || importRepoLoading
|
||||
const loading = submitLoading || gitIgnoreLoading || licenseLoading || importRepoLoading || submitImportLoading
|
||||
|
||||
useEffect(() => {
|
||||
if (gitIgnoreError || licenseError) {
|
||||
@ -192,6 +198,36 @@ export const NewRepoModalButton: React.FC<NewRepoModalButtonProps> = ({
|
||||
showError(getErrorMessage(_error), 0, getString('importRepo.failedToImportRepo'))
|
||||
})
|
||||
}
|
||||
|
||||
const handleMultiRepoImportSubmit = async (formData: ImportSpaceFormData) => {
|
||||
const type = getProviderTypeMapping(formData.gitProvider)
|
||||
|
||||
const provider = {
|
||||
type,
|
||||
username: formData.username,
|
||||
password: formData.password,
|
||||
host: ''
|
||||
}
|
||||
|
||||
if (![GitProviders.GITHUB, GitProviders.GITLAB, GitProviders.BITBUCKET].includes(formData.gitProvider)) {
|
||||
provider.host = formData.host
|
||||
}
|
||||
|
||||
try {
|
||||
const importPayload = {
|
||||
description: (formData.description || '').trim(),
|
||||
parent_ref: space,
|
||||
uid: formData.name.trim(),
|
||||
provider,
|
||||
provider_space: formData.organization
|
||||
}
|
||||
const response = await importMultipleRepositories(importPayload)
|
||||
hideModal()
|
||||
onSubmit(response)
|
||||
} catch (exception) {
|
||||
showError(getErrorMessage(exception), 0, getString('failedToImportSpace'))
|
||||
}
|
||||
}
|
||||
return (
|
||||
<Dialog
|
||||
isOpen
|
||||
@ -204,12 +240,23 @@ export const NewRepoModalButton: React.FC<NewRepoModalButtonProps> = ({
|
||||
style={{ height: '100%' }}
|
||||
data-testid="add-target-to-flag-modal">
|
||||
<Heading level={3} font={{ variation: FontVariation.H3 }} margin={{ bottom: 'xlarge' }}>
|
||||
{repoOption.type === RepoCreationType.IMPORT ? getString('importRepo.title') : modalTitle}
|
||||
{repoOption.type === RepoCreationType.IMPORT
|
||||
? getString('importRepo.title')
|
||||
: repoOption.type === RepoCreationType.IMPORT_MULTIPLE
|
||||
? getString('importRepos.title')
|
||||
: modalTitle}
|
||||
</Heading>
|
||||
|
||||
<Container margin={{ right: 'xxlarge' }}>
|
||||
{repoOption.type === RepoCreationType.IMPORT ? (
|
||||
<ImportForm hideModal={hideModal} handleSubmit={handleImportSubmit} loading={false} />
|
||||
) : repoOption.type === RepoCreationType.IMPORT_MULTIPLE ? (
|
||||
<ImportReposForm
|
||||
hideModal={hideModal}
|
||||
handleSubmit={handleMultiRepoImportSubmit}
|
||||
loading={false}
|
||||
spaceRef={space}
|
||||
/>
|
||||
) : (
|
||||
<Formik
|
||||
initialValues={formInitialValues}
|
||||
@ -361,6 +408,11 @@ export const NewRepoModalButton: React.FC<NewRepoModalButtonProps> = ({
|
||||
type: RepoCreationType.IMPORT,
|
||||
title: getString('importGitRepo'),
|
||||
desc: getString('importGitRepo')
|
||||
},
|
||||
{
|
||||
type: RepoCreationType.IMPORT_MULTIPLE,
|
||||
title: getString('importGitRepos'),
|
||||
desc: getString('importGitRepos')
|
||||
}
|
||||
]
|
||||
const [repoOption, setRepoOption] = useState<RepoCreationOption>(repoCreateOptions[0])
|
||||
@ -399,14 +451,14 @@ export const NewRepoModalButton: React.FC<NewRepoModalButtonProps> = ({
|
||||
setRepoOption(repoCreateOptions[0])
|
||||
setTimeout(() => openModal(), 0)
|
||||
}}>
|
||||
{[repoCreateOptions[1]].map(option => {
|
||||
{[repoCreateOptions[1], repoCreateOptions[2]].map(option => {
|
||||
return (
|
||||
<Menu.Item
|
||||
className={css.menuItem}
|
||||
key={option.type}
|
||||
text={<Text font={{ variation: FontVariation.BODY2 }}>{option.desc}</Text>}
|
||||
onClick={() => {
|
||||
setRepoOption(repoCreateOptions[1])
|
||||
setRepoOption(option)
|
||||
setTimeout(() => openModal(), 0)
|
||||
}}
|
||||
/>
|
||||
|
@ -321,6 +321,7 @@ export interface StringsMap {
|
||||
'imageUpload.title': string
|
||||
'imageUpload.upload': string
|
||||
importGitRepo: string
|
||||
importGitRepos: string
|
||||
importProgress: string
|
||||
'importRepo.appPassword': string
|
||||
'importRepo.appPasswordPlaceholder': string
|
||||
@ -347,6 +348,8 @@ export interface StringsMap {
|
||||
'importRepo.validation': string
|
||||
'importRepo.workspace': string
|
||||
'importRepo.workspacePlaceholder': string
|
||||
'importRepos.content': string
|
||||
'importRepos.title': string
|
||||
'importSpace.authorization': string
|
||||
'importSpace.content': string
|
||||
'importSpace.createASpace': string
|
||||
|
@ -106,7 +106,7 @@ repos:
|
||||
activities: Monthly Activities
|
||||
updated: Updated Date
|
||||
lastChange: Last Change
|
||||
noDataMessage: There are no repositories in this project. Create a new repository, or import an existing Git repository by clicking below
|
||||
noDataMessage: There are no repositories in this project. Create a new repository, or import an existing Git repository by clicking below.
|
||||
enterBranchName: Enter a branch name
|
||||
createRepoModal:
|
||||
branchLabel: 'Your repository will be initialized with a '
|
||||
@ -748,6 +748,7 @@ pluginsPanel:
|
||||
ifNotExists: If not exists
|
||||
createNewRepo: Create New repository
|
||||
importGitRepo: Import Repository
|
||||
importGitRepos: Import Repositories
|
||||
importRepo:
|
||||
title: Import Repository
|
||||
url: Host URL
|
||||
@ -774,6 +775,9 @@ importRepo:
|
||||
spaceNameReq: Enter a name for the new project
|
||||
usernameReq: Username is required
|
||||
passwordReq: Password is required
|
||||
importRepos:
|
||||
title: Import Repositories
|
||||
content: Import multiple repositories from GitLab Group, GitHub Org or Bitbucket Project to this project in Gitness.
|
||||
importSpace:
|
||||
title: Import Project
|
||||
createASpace: Create a project
|
||||
|
@ -35,7 +35,7 @@ import { useHistory } from 'react-router-dom'
|
||||
import { useStrings } from 'framework/strings'
|
||||
import { voidFn, formatDate, getErrorMessage, LIST_FETCHING_LIMIT, PageBrowserProps } from 'utils/Utils'
|
||||
import { NewRepoModalButton } from 'components/NewRepoModalButton/NewRepoModalButton'
|
||||
import type { TypesRepository } from 'services/code'
|
||||
import type { TypesRepository, SpaceImportRepositoriesOutput } from 'services/code'
|
||||
import { usePageIndex } from 'hooks/usePageIndex'
|
||||
import { useQueryParams } from 'hooks/useQueryParams'
|
||||
import { useUpdateQueryParams } from 'hooks/useUpdateQueryParams'
|
||||
@ -176,8 +176,14 @@ export default function RepositoriesListing() {
|
||||
onSubmit={repoInfo => {
|
||||
if (repoInfo.importing) {
|
||||
refetch()
|
||||
} else if (repoInfo) {
|
||||
const multipleImportRepoInfo = repoInfo as SpaceImportRepositoriesOutput
|
||||
if (multipleImportRepoInfo.importing_repos) {
|
||||
history.push(routes.toCODERepositories({ space: space as string }))
|
||||
refetch()
|
||||
}
|
||||
} else {
|
||||
history.push(routes.toCODERepository({ repoPath: repoInfo.path as string }))
|
||||
history.push(routes.toCODERepository({ repoPath: (repoInfo as TypesRepository).path as string }))
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
@ -585,6 +585,11 @@ export interface SpaceExportProgressOutput {
|
||||
repos?: TypesJobProgress[] | null
|
||||
}
|
||||
|
||||
export interface SpaceImportRepositoriesOutput {
|
||||
duplicate_repos?: TypesRepository[] | null
|
||||
importing_repos?: TypesRepository[] | null
|
||||
}
|
||||
|
||||
export interface SystemConfigOutput {
|
||||
user_signup_allowed?: boolean
|
||||
}
|
||||
|
@ -7887,6 +7887,19 @@ components:
|
||||
nullable: true
|
||||
type: array
|
||||
type: object
|
||||
SpaceImportRepositoriesOutput:
|
||||
properties:
|
||||
duplicate_repos:
|
||||
items:
|
||||
$ref: '#/components/schemas/TypesRepository'
|
||||
nullable: true
|
||||
type: array
|
||||
importing_repos:
|
||||
items:
|
||||
$ref: '#/components/schemas/TypesRepository'
|
||||
nullable: true
|
||||
type: array
|
||||
type: object
|
||||
SystemConfigOutput:
|
||||
properties:
|
||||
user_signup_allowed:
|
||||
|
@ -88,7 +88,8 @@ export enum RepoVisibility {
|
||||
|
||||
export enum RepoCreationType {
|
||||
IMPORT = 'import',
|
||||
CREATE = 'create'
|
||||
CREATE = 'create',
|
||||
IMPORT_MULTIPLE = 'import_multiple'
|
||||
}
|
||||
|
||||
export enum SpaceCreationType {
|
||||
|
Loading…
Reference in New Issue
Block a user