mirror of https://github.com/harness/drone.git
fix: public repo config and labels flicker (#2571)
* fix lint * label fixes and minor ui fix * udpate: label values api to use query params * fix: public repo config and labels flickerpull/3545/head
parent
e18a8c410f
commit
81b10ba01c
|
@ -72,6 +72,7 @@ export interface AppProps {
|
|||
useLogsStreaming: Unknown
|
||||
useFeatureFlags: Unknown
|
||||
useGetSettingValue: Unknown
|
||||
useGetAuthSettings: Unknown
|
||||
useGetUserSourceCodeManagers?: Unknown
|
||||
useListAggregatedTokens?: Unknown
|
||||
useDeleteToken?: Unknown
|
||||
|
|
|
@ -21,6 +21,7 @@ import { routes } from 'RouteDefinitions'
|
|||
import { defaultCurrentUser } from 'AppContext'
|
||||
import { useFeatureFlags } from 'hooks/useFeatureFlag'
|
||||
import { useGetSettingValue } from 'hooks/useGetSettingValue'
|
||||
import { useGetAuthSettings } from 'hooks/useGetAuthSettings'
|
||||
import { defaultUsefulOrNot } from 'components/DefaultUsefulOrNot/UsefulOrNot'
|
||||
import App from './App'
|
||||
import './bootstrap.scss'
|
||||
|
@ -41,7 +42,8 @@ ReactDOM.render(
|
|||
useLogsContent: noop,
|
||||
useLogsStreaming: noop,
|
||||
useFeatureFlags,
|
||||
useGetSettingValue
|
||||
useGetSettingValue,
|
||||
useGetAuthSettings
|
||||
}}
|
||||
currentUser={defaultCurrentUser}
|
||||
customComponents={{
|
||||
|
|
|
@ -93,6 +93,6 @@
|
|||
}
|
||||
.valuesList {
|
||||
flex-wrap: wrap;
|
||||
gap: 7px;
|
||||
gap: 8px;
|
||||
width: 100%;
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ import cx from 'classnames'
|
|||
import { Button, ButtonSize, ButtonVariation, Container, Layout, Tag, Text } from '@harnessio/uicore'
|
||||
import { FontVariation } from '@harnessio/design-system'
|
||||
import { useGet } from 'restful-react'
|
||||
import { Menu } from '@blueprintjs/core'
|
||||
import { Menu, Spinner } from '@blueprintjs/core'
|
||||
import { Icon } from '@harnessio/icons'
|
||||
import { isEmpty } from 'lodash-es'
|
||||
import { ColorName, LabelType, getColorsObj, getScopeData, getScopeIcon } from 'utils/Utils'
|
||||
|
@ -329,7 +329,59 @@ export const LabelValuesList: React.FC<{
|
|||
/>
|
||||
))
|
||||
) : (
|
||||
<Icon name="steps-spinner" size={16} />
|
||||
<Spinner size={16} />
|
||||
)}
|
||||
</Layout.Horizontal>
|
||||
)
|
||||
}
|
||||
|
||||
// ToDo : Remove LabelValuesListQuery component when Encoding is handled by BE for Harness
|
||||
export const LabelValuesListQuery: React.FC<{
|
||||
name: string
|
||||
scope: number
|
||||
repoMetadata?: RepoRepositoryOutput
|
||||
space?: string
|
||||
standalone: boolean
|
||||
}> = ({ name, scope, repoMetadata, space = '', standalone }) => {
|
||||
const { scopeRef } = getScopeData(space as string, scope, standalone)
|
||||
|
||||
const getPath = () =>
|
||||
scope === 0
|
||||
? `/repos/${repoMetadata?.identifier}/labels/${encodeURIComponent(name)}/values`
|
||||
: `/labels/${encodeURIComponent(name)}/values`
|
||||
|
||||
const {
|
||||
data: labelValues,
|
||||
refetch: refetchLabelValues,
|
||||
loading: loadingLabelValues
|
||||
} = useGet<TypesLabelValue[]>({
|
||||
base: getConfig('code/api/v1'),
|
||||
path: getPath(),
|
||||
queryParams: {
|
||||
accountIdentifier: scopeRef?.split('/')[0],
|
||||
orgIdentifier: scopeRef?.split('/')[1],
|
||||
projectIdentifier: scopeRef?.split('/')[2]
|
||||
},
|
||||
lazy: true
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
refetchLabelValues()
|
||||
}, [name, scope, space, repoMetadata])
|
||||
|
||||
return (
|
||||
<Layout.Horizontal className={css.valuesList}>
|
||||
{!loadingLabelValues && labelValues && !isEmpty(labelValues) ? (
|
||||
labelValues.map(value => (
|
||||
<Label
|
||||
key={`${name}-${value.value}`}
|
||||
name={name}
|
||||
scope={scope}
|
||||
label_value={{ name: value.value, color: value.color as ColorName }}
|
||||
/>
|
||||
))
|
||||
) : (
|
||||
<Spinner size={16} />
|
||||
)}
|
||||
</Layout.Horizontal>
|
||||
)
|
||||
|
|
|
@ -129,45 +129,47 @@ export const LabelFilter = (props: LabelFilterProps) => {
|
|||
const getLabelValuesPromise = async (key: string, scope: number): Promise<SelectOption[]> => {
|
||||
setLoadingLabelValues(true)
|
||||
const { scopeRef } = getScopeData(spaceRef, scope, standalone)
|
||||
if (scope === 0) {
|
||||
try {
|
||||
const fetchedValues: TypesLabelValue[] = await getUsingFetch(
|
||||
getConfig('code/api/v1'),
|
||||
`/repos/${encodeURIComponent(repoMetadata?.path as string)}/labels/${encodeURIComponent(key)}/values`,
|
||||
bearerToken,
|
||||
{}
|
||||
)
|
||||
const updatedValuesList = mapToSelectOptions(fetchedValues)
|
||||
setLoadingLabelValues(false)
|
||||
return updatedValuesList
|
||||
} catch (error) {
|
||||
setLoadingLabelValues(false)
|
||||
showError(getErrorMessage(error))
|
||||
return []
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
const fetchedValues: TypesLabelValue[] = await getUsingFetch(
|
||||
getConfig('code/api/v1'),
|
||||
`/spaces/${encodeURIComponent(scopeRef)}/labels/${encodeURIComponent(key)}/values`,
|
||||
bearerToken,
|
||||
{}
|
||||
)
|
||||
const updatedValuesList = Array.isArray(fetchedValues)
|
||||
? ([
|
||||
...(fetchedValues || []).map(item => ({
|
||||
label: JSON.stringify(item),
|
||||
value: String(item?.id)
|
||||
}))
|
||||
] as SelectOption[])
|
||||
: ([] as SelectOption[])
|
||||
setLoadingLabelValues(false)
|
||||
return updatedValuesList
|
||||
} catch (error) {
|
||||
setLoadingLabelValues(false)
|
||||
showError(getErrorMessage(error))
|
||||
return []
|
||||
}
|
||||
const getPath = () =>
|
||||
scope === 0
|
||||
? `/repos/${encodeURIComponent(repoMetadata?.path as string)}/labels/${encodeURIComponent(key)}/values`
|
||||
: `/spaces/${encodeURIComponent(scopeRef)}/labels/${encodeURIComponent(key)}/values`
|
||||
|
||||
try {
|
||||
const fetchedValues: TypesLabelValue[] = await getUsingFetch(getConfig('code/api/v1'), getPath(), bearerToken, {})
|
||||
const updatedValuesList = mapToSelectOptions(fetchedValues)
|
||||
setLoadingLabelValues(false)
|
||||
return updatedValuesList
|
||||
} catch (error) {
|
||||
setLoadingLabelValues(false)
|
||||
showError(getErrorMessage(error))
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
// ToDo : Remove getLabelValuesPromiseQuery component when Encoding is handled by BE for Harness
|
||||
const getLabelValuesPromiseQuery = async (key: string, scope: number): Promise<SelectOption[]> => {
|
||||
setLoadingLabelValues(true)
|
||||
const { scopeRef } = getScopeData(spaceRef, scope, standalone)
|
||||
const getPath = () =>
|
||||
scope === 0
|
||||
? `/repos/${repoMetadata?.identifier}/labels/${encodeURIComponent(key)}/values`
|
||||
: `/labels/${encodeURIComponent(key)}/values`
|
||||
|
||||
try {
|
||||
const fetchedValues: TypesLabelValue[] = await getUsingFetch(getConfig('code/api/v1'), getPath(), bearerToken, {
|
||||
queryParams: {
|
||||
accountIdentifier: scopeRef?.split('/')[0],
|
||||
orgIdentifier: scopeRef?.split('/')[1],
|
||||
projectIdentifier: scopeRef?.split('/')[2]
|
||||
}
|
||||
})
|
||||
const updatedValuesList = mapToSelectOptions(fetchedValues)
|
||||
setLoadingLabelValues(false)
|
||||
return updatedValuesList
|
||||
} catch (error) {
|
||||
setLoadingLabelValues(false)
|
||||
showError(getErrorMessage(error))
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -320,11 +322,20 @@ export const LabelFilter = (props: LabelFilterProps) => {
|
|||
setIsVisible(true)
|
||||
setValueQuery('')
|
||||
setHighlightItem(item.label as string)
|
||||
getLabelValuesPromise(itemObj.key, itemObj.scope)
|
||||
.then(res => setLabelValues(res))
|
||||
.catch(err => {
|
||||
showError(getErrorMessage(err))
|
||||
})
|
||||
// ToDo : Remove this check once BE has support for encoding
|
||||
if (standalone) {
|
||||
getLabelValuesPromise(itemObj.key, itemObj.scope)
|
||||
.then(res => setLabelValues(res))
|
||||
.catch(err => {
|
||||
showError(getErrorMessage(err))
|
||||
})
|
||||
} else {
|
||||
getLabelValuesPromiseQuery(itemObj.key, itemObj.scope)
|
||||
.then(res => setLabelValues(res))
|
||||
.catch(err => {
|
||||
showError(getErrorMessage(err))
|
||||
})
|
||||
}
|
||||
}}
|
||||
tooltip={
|
||||
labelsValueList && !loadingLabelValues ? (
|
||||
|
|
|
@ -56,6 +56,7 @@ export interface LabelSelectorProps {
|
|||
setQuery: React.Dispatch<React.SetStateAction<string>>
|
||||
query: string
|
||||
labelListLoading: boolean
|
||||
refetchActivities: () => void
|
||||
}
|
||||
|
||||
export interface LabelSelectProps extends Omit<ButtonProps, 'onSelect'> {
|
||||
|
@ -87,6 +88,7 @@ export const LabelSelector: React.FC<LabelSelectorProps> = ({
|
|||
query,
|
||||
setQuery,
|
||||
labelListLoading,
|
||||
refetchActivities,
|
||||
...props
|
||||
}) => {
|
||||
const [popoverDialogOpen, setPopoverDialogOpen] = useState<boolean>(false)
|
||||
|
@ -110,7 +112,7 @@ export const LabelSelector: React.FC<LabelSelectorProps> = ({
|
|||
resourceType: 'CODE_REPOSITORY',
|
||||
resourceIdentifier: repoMetadata?.identifier as string
|
||||
},
|
||||
permissions: ['code_repo_edit']
|
||||
permissions: ['code_repo_push']
|
||||
},
|
||||
[space]
|
||||
)
|
||||
|
@ -121,6 +123,7 @@ export const LabelSelector: React.FC<LabelSelectorProps> = ({
|
|||
text={<span className={css.prefix}>{getString('add')}</span>}
|
||||
variation={ButtonVariation.TERTIARY}
|
||||
minimal
|
||||
disabled={labelListLoading}
|
||||
size={ButtonSize.SMALL}
|
||||
tooltip={
|
||||
<PopoverContent
|
||||
|
@ -139,6 +142,7 @@ export const LabelSelector: React.FC<LabelSelectorProps> = ({
|
|||
setQuery('')
|
||||
setPopoverDialogOpen(false)
|
||||
showSuccess(`Applied '${label.key}' label`)
|
||||
refetchActivities()
|
||||
})
|
||||
.catch(error => showError(getErrorMessage(error)))
|
||||
} catch (exception) {
|
||||
|
@ -161,6 +165,7 @@ export const LabelSelector: React.FC<LabelSelectorProps> = ({
|
|||
setCurrentLabel({ key: '', id: -1 })
|
||||
setPopoverDialogOpen(false)
|
||||
showSuccess(`Applied '${labelKey}:${valueKey}' label`)
|
||||
refetchActivities()
|
||||
})
|
||||
.catch(error => showError(getErrorMessage(error)))
|
||||
} catch (exception) {
|
||||
|
@ -185,6 +190,7 @@ export const LabelSelector: React.FC<LabelSelectorProps> = ({
|
|||
setCurrentLabel({ key: '', id: -1 })
|
||||
setPopoverDialogOpen(false)
|
||||
setQuery('')
|
||||
refetchActivities()
|
||||
})
|
||||
.catch(error => showError(getErrorMessage(error)))
|
||||
} catch (exception) {
|
||||
|
@ -266,60 +272,62 @@ const PopoverContent: React.FC<LabelSelectProps> = ({
|
|||
}
|
||||
}, [menuItemIndex, menuState, labelsList, labelsValueList])
|
||||
|
||||
const handleKeyDownLabels: React.KeyboardEventHandler<HTMLInputElement> = e => {
|
||||
if (labelsList && labelsList.length !== 0) {
|
||||
switch (e.key) {
|
||||
case 'ArrowDown':
|
||||
setMenuItemIndex((index: number) => {
|
||||
return index + 1 > labelsList.length ? 1 : index + 1
|
||||
})
|
||||
break
|
||||
case 'ArrowUp':
|
||||
setMenuItemIndex((index: number) => {
|
||||
return index - 1 > 0 ? index - 1 : labelsList.length
|
||||
})
|
||||
break
|
||||
case 'Enter':
|
||||
if (labelsList[menuItemIndex - 1]) {
|
||||
onSelectLabel(labelsList[menuItemIndex - 1])
|
||||
setQuery('')
|
||||
}
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
// const handleKeyDownLabels: React.KeyboardEventHandler<HTMLInputElement> = e => {
|
||||
// if (labelsList && labelsList.length !== 0) {
|
||||
// e.preventDefault()
|
||||
// switch (e.key) {
|
||||
// case 'ArrowDown':
|
||||
// setMenuItemIndex((index: number) => {
|
||||
// return index + 1 > labelsList.length ? 1 : index + 1
|
||||
// })
|
||||
// break
|
||||
// case 'ArrowUp':
|
||||
// setMenuItemIndex((index: number) => {
|
||||
// return index - 1 > 0 ? index - 1 : labelsList.length
|
||||
// })
|
||||
// break
|
||||
// case 'Enter':
|
||||
// if (labelsList[menuItemIndex - 1]) {
|
||||
// onSelectLabel(labelsList[menuItemIndex - 1])
|
||||
// setQuery('')
|
||||
// }
|
||||
// break
|
||||
// default:
|
||||
// break
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
const handleKeyDownValue: React.KeyboardEventHandler<HTMLInputElement> = e => {
|
||||
if (e.key === 'Backspace' && !query && currentLabel) {
|
||||
setQuery('')
|
||||
handleValueRemove && handleValueRemove()
|
||||
} else if (labelsValueList && labelsValueList.length !== 0) {
|
||||
switch (e.key) {
|
||||
case 'ArrowDown':
|
||||
setMenuItemIndex((index: number) => {
|
||||
return index + 1 > labelsValueList.length ? 1 : index + 1
|
||||
})
|
||||
break
|
||||
case 'ArrowUp':
|
||||
setMenuItemIndex((index: number) => {
|
||||
return index - 1 > 0 ? index - 1 : labelsValueList.length
|
||||
})
|
||||
break
|
||||
case 'Enter':
|
||||
onSelectValue(
|
||||
currentLabel.id ?? -1,
|
||||
labelsValueList[menuItemIndex - 1].id ?? -1,
|
||||
currentLabel.key ?? '',
|
||||
labelsValueList[menuItemIndex - 1].value ?? ''
|
||||
)
|
||||
setQuery('')
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
// } else if (labelsValueList && labelsValueList.length !== 0) {
|
||||
// switch (e.key) {
|
||||
// case 'ArrowDown':
|
||||
// setMenuItemIndex((index: number) => {
|
||||
// return index + 1 > labelsValueList.length ? 1 : index + 1
|
||||
// })
|
||||
// break
|
||||
// case 'ArrowUp':
|
||||
// setMenuItemIndex((index: number) => {
|
||||
// return index - 1 > 0 ? index - 1 : labelsValueList.length
|
||||
// })
|
||||
// break
|
||||
// case 'Enter':
|
||||
// onSelectValue(
|
||||
// currentLabel.id ?? -1,
|
||||
// labelsValueList[menuItemIndex - 1].id ?? -1,
|
||||
// currentLabel.key ?? '',
|
||||
// labelsValueList[menuItemIndex - 1].value ?? ''
|
||||
// )
|
||||
// setQuery('')
|
||||
// break
|
||||
// default:
|
||||
// break
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -343,7 +351,7 @@ const PopoverContent: React.FC<LabelSelectProps> = ({
|
|||
className: css.closeBtn,
|
||||
size: 20
|
||||
}}
|
||||
onKeyDown={handleKeyDownLabels}
|
||||
// onKeyDown={handleKeyDownLabels}
|
||||
/>
|
||||
) : (
|
||||
currentLabel &&
|
||||
|
|
|
@ -76,6 +76,7 @@ import type {
|
|||
} from 'services/code'
|
||||
import { useAppContext } from 'AppContext'
|
||||
import type { TypesRepository } from 'cde-gitness/services'
|
||||
import { usePublicResourceConfig } from 'hooks/usePublicResourceConfig'
|
||||
import ImportForm from './ImportForm/ImportForm'
|
||||
import ImportReposForm from './ImportReposForm/ImportReposForm'
|
||||
import Private from '../../icons/private.svg?url'
|
||||
|
@ -112,7 +113,8 @@ export const NewRepoModalButton: React.FC<NewRepoModalButtonProps> = ({
|
|||
const ModalComponent: React.FC = () => {
|
||||
const { getString } = useStrings()
|
||||
const [branchName, setBranchName] = useState(DEFAULT_BRANCH_NAME)
|
||||
const [enablePublicRepo, setEnablePublicRepo] = useState(false)
|
||||
const { allowPublicResourceCreation, configLoading, systemConfigError, errorWhileFetchingAuthSettings } =
|
||||
usePublicResourceConfig()
|
||||
const { showError } = useToaster()
|
||||
|
||||
const { mutate: createRepo, loading: submitLoading } = useMutate<RepoRepositoryOutput>({
|
||||
|
@ -147,31 +149,19 @@ export const NewRepoModalButton: React.FC<NewRepoModalButtonProps> = ({
|
|||
loading: licenseLoading,
|
||||
error: licenseError
|
||||
} = useGet({ path: '/api/v1/resources/license' })
|
||||
const {
|
||||
data: systemConfig,
|
||||
loading: systemConfigLoading,
|
||||
error: systemConfigError
|
||||
} = useGet({ path: 'api/v1/system/config' })
|
||||
|
||||
const loading =
|
||||
submitLoading ||
|
||||
gitIgnoreLoading ||
|
||||
licenseLoading ||
|
||||
importRepoLoading ||
|
||||
submitImportLoading ||
|
||||
systemConfigLoading
|
||||
submitLoading || gitIgnoreLoading || licenseLoading || importRepoLoading || submitImportLoading || configLoading
|
||||
|
||||
useEffect(() => {
|
||||
if (gitIgnoreError || licenseError || systemConfigError) {
|
||||
showError(getErrorMessage(gitIgnoreError || licenseError || systemConfigError), 0)
|
||||
if (gitIgnoreError || licenseError || systemConfigError || errorWhileFetchingAuthSettings) {
|
||||
showError(
|
||||
getErrorMessage(gitIgnoreError || licenseError || systemConfigError || errorWhileFetchingAuthSettings),
|
||||
0
|
||||
)
|
||||
}
|
||||
}, [gitIgnoreError, licenseError, systemConfigError, showError])
|
||||
}, [gitIgnoreError, licenseError, systemConfigError, errorWhileFetchingAuthSettings, showError])
|
||||
|
||||
useEffect(() => {
|
||||
if (systemConfig) {
|
||||
setEnablePublicRepo(systemConfig.public_resource_creation_enabled)
|
||||
}
|
||||
}, [systemConfig])
|
||||
const handleSubmit = (formData: RepoFormData) => {
|
||||
try {
|
||||
const payload: OpenapiCreateRepositoryRequest = {
|
||||
|
@ -354,7 +344,7 @@ export const NewRepoModalButton: React.FC<NewRepoModalButtonProps> = ({
|
|||
{getString('createRepoModal.branch')}
|
||||
</Text>
|
||||
</Container>
|
||||
<Render when={enablePublicRepo}>
|
||||
<Render when={allowPublicResourceCreation}>
|
||||
<hr className={css.dividerContainer} />
|
||||
<Container>
|
||||
<FormInput.RadioGroup
|
||||
|
|
|
@ -651,8 +651,11 @@ export interface StringsMap {
|
|||
'labels.createdIn': string
|
||||
'labels.deleteLabel': string
|
||||
'labels.deleteLabelConfirm': string
|
||||
'labels.deletedLabel': string
|
||||
'labels.descriptionOptional': string
|
||||
'labels.failedToDeleteLabel': string
|
||||
'labels.failedtoFetchLabels': string
|
||||
'labels.failedtoFetchValues': string
|
||||
'labels.filterByLabels': string
|
||||
'labels.findALabel': string
|
||||
'labels.findOrAdd': string
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
||||
export function useGetAuthSettings<T = Record<string, boolean>>() {
|
||||
return {} as T
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* 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 { useEffect, useMemo } from 'react'
|
||||
import { useGet } from 'restful-react'
|
||||
import { useAppContext } from 'AppContext'
|
||||
|
||||
export function usePublicResourceConfig() {
|
||||
const { standalone, hooks } = useAppContext()
|
||||
const { refetchAuthSettings, authSettings, fetchingAuthSettings, errorWhileFetchingAuthSettings } =
|
||||
hooks.useGetAuthSettings()
|
||||
const {
|
||||
data: systemConfig,
|
||||
loading: systemConfigLoading,
|
||||
error: systemConfigError
|
||||
} = useGet({ path: 'api/v1/system/config' })
|
||||
|
||||
useEffect(() => {
|
||||
if (!standalone) refetchAuthSettings()
|
||||
}, [refetchAuthSettings])
|
||||
|
||||
const allowPublicResourceCreation = useMemo(() => {
|
||||
if (systemConfigLoading || fetchingAuthSettings) {
|
||||
return false
|
||||
}
|
||||
if (standalone) {
|
||||
return systemConfig?.public_resource_creation_enabled
|
||||
}
|
||||
return !!(systemConfig?.public_resource_creation_enabled && authSettings?.resource?.publicAccessEnabled)
|
||||
}, [authSettings, systemConfig, standalone, systemConfigLoading, fetchingAuthSettings])
|
||||
|
||||
return {
|
||||
allowPublicResourceCreation,
|
||||
configLoading: fetchingAuthSettings || systemConfigLoading,
|
||||
systemConfigError,
|
||||
errorWhileFetchingAuthSettings
|
||||
}
|
||||
}
|
|
@ -128,9 +128,9 @@ repos:
|
|||
createRepoModal:
|
||||
branchLabel: 'Your repository will be initialized with a '
|
||||
branch: ' branch.'
|
||||
publicLabel: Anyone with access to the Gitness environment can clone this repo.
|
||||
publicLabel: Anyone who can view the repository can clone it.
|
||||
privateLabel: You choose who can see and commit to this repository.
|
||||
publicWarning: Please note that anyone with access to the Gitness environment can clone this repo.
|
||||
publicWarning: Please note that anyone who can view the repository can clone it.
|
||||
validation:
|
||||
repoNamePatternIsNotValid: Registry name should be 1~255 characters long with lower case characters, numbers and ._- and must be start with numbers or characters
|
||||
gitBranchNameInvalid: Branch name is invalid.
|
||||
|
@ -1315,6 +1315,7 @@ labels:
|
|||
addValue: 'Add value'
|
||||
removeLabel: Remove Label
|
||||
deleteLabel: Delete Label
|
||||
deletedLabel: 'Deleted Label : {tag}'
|
||||
provideLabelName: Provide Label name
|
||||
labelCreated: Label created
|
||||
labelUpdated: Label updated
|
||||
|
@ -1347,6 +1348,8 @@ labels:
|
|||
deleteLabelConfirm: Are you sure you want to delete label <strong>{{name}}</strong>? You can't undo this action.
|
||||
intentText: Editing/deleting a label or its values will impact all the areas it has been used.
|
||||
prCount: 'Showing {count} {count|1:result,results}'
|
||||
failedtoFetchLabels: Failed to fetch labels
|
||||
failedtoFetchValues: Failed to fetch label values
|
||||
noResults: No results found
|
||||
labelPreview: Label Preview
|
||||
filterByLabels: Filter by Label/s
|
||||
|
|
|
@ -33,7 +33,7 @@ import {
|
|||
} from '@harnessio/uicore'
|
||||
import { Icon } from '@harnessio/icons'
|
||||
import { Color, FontVariation } from '@harnessio/design-system'
|
||||
import { Menu, MenuItem, PopoverInteractionKind, Position } from '@blueprintjs/core'
|
||||
import { Menu, MenuItem, PopoverInteractionKind, Position, Spinner } from '@blueprintjs/core'
|
||||
import * as Yup from 'yup'
|
||||
import { FieldArray } from 'formik'
|
||||
import { useGet, useMutate } from 'restful-react'
|
||||
|
@ -181,30 +181,51 @@ const useLabelModal = ({ refetchlabelsList }: LabelModalProps) => {
|
|||
path: updateLabel?.scope ? `/spaces/${scopeRef as string}/+/labels` : `/spaces/${space as string}/+/labels`
|
||||
})
|
||||
|
||||
const getPath = () =>
|
||||
updateLabel?.scope === 0 && repoMetadata
|
||||
? `/repos/${encodeURIComponent(repoMetadata?.path as string)}/labels/${encodeURIComponent(
|
||||
updateLabel?.key ? updateLabel?.key : ''
|
||||
)}/values`
|
||||
: `/spaces/${encodeURIComponent(scopeRef)}/labels/${encodeURIComponent(
|
||||
updateLabel?.key ? updateLabel?.key : ''
|
||||
)}/values`
|
||||
|
||||
const {
|
||||
data: repoLabelValues,
|
||||
loading: repoValueListLoading,
|
||||
refetch: refetchRepoValuesList
|
||||
data: initLabelValues,
|
||||
loading: initValueListLoading,
|
||||
refetch: refetchInitValuesList
|
||||
} = useGet<TypesLabelValue[]>({
|
||||
base: getConfig('code/api/v1'),
|
||||
path: `/repos/${encodeURIComponent(repoMetadata?.path as string)}/labels/${encodeURIComponent(
|
||||
updateLabel?.key ? updateLabel?.key : ''
|
||||
)}/values`,
|
||||
path: getPath(),
|
||||
lazy: true
|
||||
})
|
||||
|
||||
//ToDo : Remove getLabelValuesPromiseQuery component when Encoding is handled by BE for Harness
|
||||
|
||||
const getPathHarness = () =>
|
||||
updateLabel?.scope === 0 && repoMetadata
|
||||
? `/repos/${repoMetadata?.identifier}/labels/${encodeURIComponent(
|
||||
updateLabel?.key ? updateLabel?.key : ''
|
||||
)}/values`
|
||||
: `/labels/${encodeURIComponent(updateLabel?.key ? updateLabel?.key : '')}/values`
|
||||
|
||||
const {
|
||||
data: spaceLabelValues,
|
||||
loading: spaceValueListLoading,
|
||||
refetch: refetchSpaceValuesList
|
||||
data: initLabelValuesQuery,
|
||||
loading: initValueListLoadingQuery,
|
||||
refetch: refetchInitValuesListQuery
|
||||
} = useGet<TypesLabelValue[]>({
|
||||
base: getConfig('code/api/v1'),
|
||||
path: `/spaces/${encodeURIComponent(scopeRef)}/labels/${encodeURIComponent(
|
||||
updateLabel?.key ? updateLabel?.key : ''
|
||||
)}/values`,
|
||||
path: getPathHarness(),
|
||||
queryParams: {
|
||||
accountIdentifier: scopeRef?.split('/')[0],
|
||||
orgIdentifier: scopeRef?.split('/')[1],
|
||||
projectIdentifier: scopeRef?.split('/')[2]
|
||||
},
|
||||
lazy: true
|
||||
})
|
||||
|
||||
//ToDo: Remove all references of suffix with Query when Encoding is handled by BE for Harness
|
||||
|
||||
const [openModal, hideModal] = useModalHook(() => {
|
||||
const handleLabelSubmit = (formData: LabelFormData) => {
|
||||
const { labelName, color, labelValues, description, allowDynamicValues, id } = formData
|
||||
|
@ -329,20 +350,20 @@ const useLabelModal = ({ refetchlabelsList }: LabelModalProps) => {
|
|||
return { ...baseValues, color: ColorName.Blue }
|
||||
}
|
||||
|
||||
if (repoMetadata && updateLabel?.scope === 0) {
|
||||
return { ...baseValues, labelValues: getLabelValues(repoLabelValues ?? undefined) }
|
||||
}
|
||||
if (modalMode === ModalMode.UPDATE && updateLabel?.value_count === 0) return baseValues
|
||||
|
||||
return { ...baseValues, labelValues: getLabelValues(spaceLabelValues ?? undefined) }
|
||||
if (standalone) {
|
||||
return { ...baseValues, labelValues: getLabelValues(initLabelValues ?? undefined) }
|
||||
}
|
||||
return { ...baseValues, labelValues: getLabelValues(initLabelValuesQuery ?? undefined) }
|
||||
})()
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
isOpen
|
||||
onOpening={() => {
|
||||
if (modalMode === ModalMode.UPDATE) {
|
||||
if (repoMetadata && updateLabel?.scope === 0) refetchRepoValuesList()
|
||||
else refetchSpaceValuesList()
|
||||
if (modalMode === ModalMode.UPDATE && updateLabel?.value_count !== 0) {
|
||||
standalone ? refetchInitValuesList() : refetchInitValuesListQuery()
|
||||
}
|
||||
}}
|
||||
enforceFocus={false}
|
||||
|
@ -408,68 +429,75 @@ const useLabelModal = ({ refetchlabelsList }: LabelModalProps) => {
|
|||
<FieldArray
|
||||
name="labelValues"
|
||||
render={({ push, remove }) => {
|
||||
return (
|
||||
<Layout.Vertical>
|
||||
{formik.values.labelValues?.map((_, index) => (
|
||||
<Layout.Horizontal
|
||||
key={`labelValue + ${index}`}
|
||||
flex={{
|
||||
alignItems: formik.isValid ? 'center' : 'flex-start',
|
||||
justifyContent: 'flex-start'
|
||||
}}
|
||||
style={{ gap: '4px', margin: '4px' }}>
|
||||
<ColorSelectorDropdown
|
||||
key={`labelValueColor + ${index}`}
|
||||
currentColorName={
|
||||
formik.values.labelValues &&
|
||||
index !== undefined &&
|
||||
(formik.values.labelValues[index].color as ColorName)
|
||||
}
|
||||
onClick={(colorName: ColorName) => {
|
||||
formik.setFieldValue(
|
||||
'labelValues',
|
||||
formik.values.labelValues?.map((value, i) =>
|
||||
i === index ? { ...value, color: colorName } : value
|
||||
)
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<FormInput.Text
|
||||
key={`labelValueKey + ${index}`}
|
||||
style={{ flexGrow: '1', margin: 0 }}
|
||||
name={`${'labelValues'}[${index}].value`}
|
||||
placeholder={getString('labels.provideLabelValue')}
|
||||
tooltipProps={{
|
||||
dataTooltipId: 'labels.newLabel'
|
||||
}}
|
||||
inputGroup={{ autoFocus: true }}
|
||||
/>
|
||||
<Button
|
||||
key={`removeValue + ${index}`}
|
||||
style={{ marginRight: 'auto', color: 'var(--grey-300)' }}
|
||||
variation={ButtonVariation.ICON}
|
||||
icon={'code-close'}
|
||||
onClick={() => {
|
||||
remove(index)
|
||||
}}
|
||||
/>
|
||||
</Layout.Horizontal>
|
||||
))}
|
||||
<Button
|
||||
style={{ marginRight: 'auto' }}
|
||||
variation={ButtonVariation.LINK}
|
||||
disabled={!formik.isValid || formik.values.labelName?.length === 0}
|
||||
text={getString('labels.addValue')}
|
||||
icon={CodeIcon.Add}
|
||||
onClick={() =>
|
||||
push({
|
||||
name: '',
|
||||
color: formik.values.color
|
||||
})
|
||||
}
|
||||
/>
|
||||
</Layout.Vertical>
|
||||
if (
|
||||
modalMode === ModalMode.UPDATE &&
|
||||
updateLabel?.value_count !== 0 &&
|
||||
(initValueListLoading || initValueListLoadingQuery)
|
||||
)
|
||||
return <Spinner size={20} />
|
||||
else
|
||||
return (
|
||||
<Layout.Vertical>
|
||||
{formik.values.labelValues?.map((_, index) => (
|
||||
<Layout.Horizontal
|
||||
key={`labelValue + ${index}`}
|
||||
flex={{
|
||||
alignItems: formik.isValid ? 'center' : 'flex-start',
|
||||
justifyContent: 'flex-start'
|
||||
}}
|
||||
style={{ gap: '4px', margin: '4px' }}>
|
||||
<ColorSelectorDropdown
|
||||
key={`labelValueColor + ${index}`}
|
||||
currentColorName={
|
||||
formik.values.labelValues &&
|
||||
index !== undefined &&
|
||||
(formik.values.labelValues[index].color as ColorName)
|
||||
}
|
||||
onClick={(colorName: ColorName) => {
|
||||
formik.setFieldValue(
|
||||
'labelValues',
|
||||
formik.values.labelValues?.map((value, i) =>
|
||||
i === index ? { ...value, color: colorName } : value
|
||||
)
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<FormInput.Text
|
||||
key={`labelValueKey + ${index}`}
|
||||
style={{ flexGrow: '1', margin: 0 }}
|
||||
name={`${'labelValues'}[${index}].value`}
|
||||
placeholder={getString('labels.provideLabelValue')}
|
||||
tooltipProps={{
|
||||
dataTooltipId: 'labels.newLabel'
|
||||
}}
|
||||
inputGroup={{ autoFocus: true }}
|
||||
/>
|
||||
<Button
|
||||
key={`removeValue + ${index}`}
|
||||
style={{ marginRight: 'auto', color: 'var(--grey-300)' }}
|
||||
variation={ButtonVariation.ICON}
|
||||
icon={'code-close'}
|
||||
onClick={() => {
|
||||
remove(index)
|
||||
}}
|
||||
/>
|
||||
</Layout.Horizontal>
|
||||
))}
|
||||
<Button
|
||||
style={{ marginRight: 'auto' }}
|
||||
variation={ButtonVariation.LINK}
|
||||
disabled={!formik.isValid || formik.values.labelName?.length === 0}
|
||||
text={getString('labels.addValue')}
|
||||
icon={CodeIcon.Add}
|
||||
onClick={() =>
|
||||
push({
|
||||
name: '',
|
||||
color: formik.values.color
|
||||
})
|
||||
}
|
||||
/>
|
||||
</Layout.Vertical>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</Container>
|
||||
|
@ -498,37 +526,43 @@ const useLabelModal = ({ refetchlabelsList }: LabelModalProps) => {
|
|||
<Layout.Vertical
|
||||
style={{ width: '45%', padding: '25px 35px 25px 35px', borderLeft: '1px solid var(--grey-100)' }}>
|
||||
<Text>{getString('labels.labelPreview')}</Text>
|
||||
<Layout.Vertical spacing={'medium'}>
|
||||
{formik.values.labelValues?.length
|
||||
? formik.values.labelValues?.map((valueObj, i) => (
|
||||
<Label
|
||||
key={`label + ${i}`}
|
||||
name={formik.values.labelName || getString('labels.labelName')}
|
||||
label_color={formik.values.color}
|
||||
label_value={
|
||||
valueObj.value?.length
|
||||
? { name: valueObj.value, color: valueObj.color }
|
||||
: {
|
||||
name: getString('labels.labelValue'),
|
||||
color: valueObj.color || formik.values.color
|
||||
}
|
||||
}
|
||||
/>
|
||||
))
|
||||
: !formik.values.allowDynamicValues && (
|
||||
<Label
|
||||
name={formik.values.labelName || getString('labels.labelName')}
|
||||
label_color={formik.values.color}
|
||||
/>
|
||||
)}
|
||||
{formik.values.allowDynamicValues && (
|
||||
<Label
|
||||
name={formik.values.labelName || getString('labels.labelName')}
|
||||
label_color={formik.values.color}
|
||||
label_value={{ name: getString('labels.canbeAddedByUsers') }}
|
||||
/>
|
||||
)}
|
||||
</Layout.Vertical>
|
||||
{modalMode === ModalMode.UPDATE &&
|
||||
updateLabel?.value_count !== 0 &&
|
||||
(initValueListLoading || initValueListLoadingQuery) ? (
|
||||
<Spinner size={20} />
|
||||
) : (
|
||||
<Layout.Vertical spacing={'medium'}>
|
||||
{formik.values.labelValues?.length
|
||||
? formik.values.labelValues?.map((valueObj, i) => (
|
||||
<Label
|
||||
key={`label + ${i}`}
|
||||
name={formik.values.labelName || getString('labels.labelName')}
|
||||
label_color={formik.values.color}
|
||||
label_value={
|
||||
valueObj.value?.length
|
||||
? { name: valueObj.value, color: valueObj.color }
|
||||
: {
|
||||
name: getString('labels.labelValue'),
|
||||
color: valueObj.color || formik.values.color
|
||||
}
|
||||
}
|
||||
/>
|
||||
))
|
||||
: !formik.values.allowDynamicValues && (
|
||||
<Label
|
||||
name={formik.values.labelName || getString('labels.labelName')}
|
||||
label_color={formik.values.color}
|
||||
/>
|
||||
)}
|
||||
{formik.values.allowDynamicValues && (
|
||||
<Label
|
||||
name={formik.values.labelName || getString('labels.labelName')}
|
||||
label_color={formik.values.color}
|
||||
label_value={{ name: getString('labels.canbeAddedByUsers') }}
|
||||
/>
|
||||
)}
|
||||
</Layout.Vertical>
|
||||
)}
|
||||
</Layout.Vertical>
|
||||
</Layout.Horizontal>
|
||||
</FormikForm>
|
||||
|
@ -539,11 +573,12 @@ const useLabelModal = ({ refetchlabelsList }: LabelModalProps) => {
|
|||
)
|
||||
}, [
|
||||
updateLabel,
|
||||
repoLabelValues,
|
||||
spaceLabelValues,
|
||||
repoValueListLoading,
|
||||
spaceValueListLoading,
|
||||
initLabelValues,
|
||||
initLabelValuesQuery,
|
||||
initValueListLoading,
|
||||
initValueListLoadingQuery,
|
||||
refetchlabelsList,
|
||||
refetchInitValuesListQuery,
|
||||
modalMode
|
||||
])
|
||||
|
||||
|
|
|
@ -16,16 +16,7 @@
|
|||
|
||||
.main {
|
||||
background-color: var(--primary-bg) !important;
|
||||
.table {
|
||||
.row {
|
||||
height: 80px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
.title {
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.noData > div {
|
||||
height: calc(100vh - var(--page-header-height, 64px) - 120px) !important;
|
||||
}
|
||||
|
|
|
@ -19,10 +19,7 @@
|
|||
export declare const cancelButton: string
|
||||
export declare const main: string
|
||||
export declare const noData: string
|
||||
export declare const row: string
|
||||
export declare const scopeCheckbox: string
|
||||
export declare const table: string
|
||||
export declare const title: string
|
||||
export declare const toggle: string
|
||||
export declare const toggleDisable: string
|
||||
export declare const toggleEnable: string
|
||||
|
|
|
@ -18,9 +18,8 @@ import { Container, Layout, FlexExpander, ButtonVariation, Button, Checkbox } fr
|
|||
import { Render } from 'react-jsx-match'
|
||||
import { useStrings } from 'framework/strings'
|
||||
import { CodeIcon } from 'utils/GitUtils'
|
||||
import { useAppContext } from 'AppContext'
|
||||
import { SearchInputWithSpinner } from 'components/SearchInputWithSpinner/SearchInputWithSpinner'
|
||||
import { LabelsPageScope, permissionProps } from 'utils/Utils'
|
||||
import type { LabelsPageScope } from 'utils/Utils'
|
||||
import type { RepoRepositoryOutput } from 'services/code'
|
||||
import css from './LabelsHeader.module.scss'
|
||||
|
||||
|
@ -30,28 +29,10 @@ const LabelsHeader = ({
|
|||
showParentScopeFilter,
|
||||
inheritLabels,
|
||||
setInheritLabels,
|
||||
openLabelCreateModal,
|
||||
spaceRef,
|
||||
repoMetadata,
|
||||
currentPageScope
|
||||
openLabelCreateModal
|
||||
}: LabelsHeaderProps) => {
|
||||
const [searchTerm, setSearchTerm] = useState('')
|
||||
const { getString } = useStrings()
|
||||
const { hooks, standalone } = useAppContext()
|
||||
|
||||
const permPushResult = hooks?.usePermissionTranslate?.(
|
||||
{
|
||||
resource: {
|
||||
resourceType: 'CODE_REPOSITORY',
|
||||
resourceIdentifier:
|
||||
currentPageScope === LabelsPageScope.REPOSITORY && repoMetadata
|
||||
? repoMetadata.identifier
|
||||
: (spaceRef as string)
|
||||
},
|
||||
permissions: ['code_repo_edit']
|
||||
},
|
||||
[spaceRef]
|
||||
)
|
||||
|
||||
//ToDo: check space permissions as well in case of spaces
|
||||
|
||||
|
@ -63,7 +44,6 @@ const LabelsHeader = ({
|
|||
text={getString('labels.newLabel')}
|
||||
icon={CodeIcon.Add}
|
||||
onClick={openLabelCreateModal}
|
||||
{...permissionProps(permPushResult, standalone)}
|
||||
/>
|
||||
<Render when={showParentScopeFilter}>
|
||||
<Checkbox
|
||||
|
|
|
@ -29,60 +29,16 @@
|
|||
max-width: 55%;
|
||||
}
|
||||
|
||||
div[class*='TableV2--row'] {
|
||||
padding: 3px var(--spacing-medium);
|
||||
justify-content: center;
|
||||
min-height: 48px;
|
||||
}
|
||||
|
||||
div[class*='TableV2--rowSubComponent'] {
|
||||
border-top: 1px solid var(--grey-100);
|
||||
padding: 20px 4px 4px 5%;
|
||||
}
|
||||
}
|
||||
|
||||
.dividerContainer {
|
||||
opacity: 0.2;
|
||||
height: 1px;
|
||||
color: var(--grey-100);
|
||||
margin: 10px 0;
|
||||
width: 95%;
|
||||
}
|
||||
|
||||
.border {
|
||||
border-bottom: 1px solid var(--grey-100) !important;
|
||||
}
|
||||
|
||||
.hideDetailsContainer {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.appliedRulesTextContainer {
|
||||
border-radius: 4px;
|
||||
background: var(--grey-50) !important;
|
||||
font-size: 12px !important;
|
||||
font-weight: 500 !important;
|
||||
padding: var(--spacing-small) !important;
|
||||
margin-bottom: var(--spacing-xsmall) !important;
|
||||
}
|
||||
|
||||
.popover {
|
||||
z-index: 999;
|
||||
padding: var(--spacing-tiny) !important;
|
||||
}
|
||||
|
||||
.widthContainer {
|
||||
max-width: calc(100% - 100px);
|
||||
overflow-x: hidden;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.hideButtonIcon {
|
||||
:global {
|
||||
[class*='ConfirmationDialog--header'] {
|
||||
.bp3-icon {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
[class*='ConfirmationDialog--body'] {
|
||||
padding-left: 3px !important;
|
||||
}
|
||||
padding: 14px var(--spacing-xsmall) 14px 4.7%;
|
||||
margin-top: var(--spacing-tiny);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,16 +16,9 @@
|
|||
|
||||
/* eslint-disable */
|
||||
// This is an auto-generated file
|
||||
export declare const appliedRulesTextContainer: string
|
||||
export declare const border: string
|
||||
export declare const dividerContainer: string
|
||||
export declare const hideButtonIcon: string
|
||||
export declare const hideDetailsContainer: string
|
||||
export declare const labelCtn: string
|
||||
export declare const main: string
|
||||
export declare const optionItem: string
|
||||
export declare const popover: string
|
||||
export declare const row: string
|
||||
export declare const table: string
|
||||
export declare const toggleAccordion: string
|
||||
export declare const widthContainer: string
|
||||
|
|
|
@ -38,7 +38,6 @@ import { usePageIndex } from 'hooks/usePageIndex'
|
|||
import {
|
||||
getErrorMessage,
|
||||
LIST_FETCHING_LIMIT,
|
||||
permissionProps,
|
||||
type PageBrowserProps,
|
||||
ColorName,
|
||||
LabelTypes,
|
||||
|
@ -54,7 +53,7 @@ import { useConfirmAction } from 'hooks/useConfirmAction'
|
|||
import { OptionsMenuButton } from 'components/OptionsMenuButton/OptionsMenuButton'
|
||||
import { useAppContext } from 'AppContext'
|
||||
import { useUpdateQueryParams } from 'hooks/useUpdateQueryParams'
|
||||
import { LabelTitle, LabelValuesList } from 'components/Label/Label'
|
||||
import { LabelTitle, LabelValuesList, LabelValuesListQuery } from 'components/Label/Label'
|
||||
import { LoadingSpinner } from 'components/LoadingSpinner/LoadingSpinner'
|
||||
import { getConfig } from 'services/config'
|
||||
import LabelsHeader from './LabelsHeader/LabelsHeader'
|
||||
|
@ -63,7 +62,7 @@ import css from './LabelsListing.module.scss'
|
|||
|
||||
const LabelsListing = (props: LabelListingProps) => {
|
||||
const { activeTab, currentPageScope, repoMetadata, space } = props
|
||||
const { hooks, standalone } = useAppContext()
|
||||
const { standalone } = useAppContext()
|
||||
const { getString } = useStrings()
|
||||
const { showError, showSuccess } = useToaster()
|
||||
const history = useHistory()
|
||||
|
@ -133,15 +132,27 @@ const LabelsListing = (props: LabelListingProps) => {
|
|||
|
||||
const { openModal: openLabelCreateModal, openUpdateLabelModal } = useLabelModal({ refetchlabelsList })
|
||||
const renderRowSubComponent = React.useCallback(({ row }: { row: Row<LabelTypes> }) => {
|
||||
return (
|
||||
<LabelValuesList
|
||||
name={row.original?.key as string}
|
||||
scope={row.original?.scope as number}
|
||||
repoMetadata={repoMetadata}
|
||||
space={space}
|
||||
standalone={standalone}
|
||||
/>
|
||||
)
|
||||
if (standalone) {
|
||||
return (
|
||||
<LabelValuesList
|
||||
name={row.original?.key as string}
|
||||
scope={row.original?.scope as number}
|
||||
repoMetadata={repoMetadata}
|
||||
space={space}
|
||||
standalone={standalone}
|
||||
/>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<LabelValuesListQuery
|
||||
name={row.original?.key as string}
|
||||
scope={row.original?.scope as number}
|
||||
repoMetadata={repoMetadata}
|
||||
space={space}
|
||||
standalone={standalone}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}, [])
|
||||
|
||||
const ToggleAccordionCell: Renderer<{
|
||||
|
@ -215,7 +226,7 @@ const LabelsListing = (props: LabelListingProps) => {
|
|||
width: '40%',
|
||||
sort: 'true',
|
||||
Cell: ({ row }: CellProps<LabelTypes>) => {
|
||||
return <Text lineClamp={3}>{row.original?.description}</Text>
|
||||
return <Text lineClamp={1}>{row.original?.description}</Text>
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -235,6 +246,24 @@ const LabelsListing = (props: LabelListingProps) => {
|
|||
path: deleteLabelPath
|
||||
})
|
||||
|
||||
//ToDo : Remove the following block when Encoding is handled by BE for Harness
|
||||
const deleteLabelPathHarness =
|
||||
row.original?.scope === 0
|
||||
? `/repos/${repoMetadata?.identifier}/labels/${encodedLabelKey}`
|
||||
: `/labels/${encodedLabelKey}`
|
||||
|
||||
const { mutate: deleteLabelQueryCall } = useMutate({
|
||||
verb: 'DELETE',
|
||||
base: getConfig('code/api/v1'),
|
||||
path: deleteLabelPathHarness,
|
||||
queryParams: {
|
||||
accountIdentifier: scopeRef?.split('/')[0],
|
||||
orgIdentifier: scopeRef?.split('/')[1],
|
||||
projectIdentifier: scopeRef?.split('/')[2]
|
||||
}
|
||||
})
|
||||
|
||||
//ToDo: remove type check of standalone when Encoding is handled by BE for Harness
|
||||
const confirmLabelDelete = useConfirmAction({
|
||||
title: getString('labels.deleteLabel'),
|
||||
confirmText: getString('delete'),
|
||||
|
@ -242,23 +271,19 @@ const LabelsListing = (props: LabelListingProps) => {
|
|||
message: <String useRichText stringID="labels.deleteLabelConfirm" vars={{ name: row.original.key }} />,
|
||||
action: async e => {
|
||||
e.stopPropagation()
|
||||
deleteLabel({})
|
||||
.then(() => {
|
||||
showSuccess(
|
||||
<StringSubstitute
|
||||
str={getString('labels.deleteLabel')}
|
||||
vars={{
|
||||
tag: row.original.key
|
||||
}}
|
||||
/>,
|
||||
5000
|
||||
)
|
||||
refetchlabelsList()
|
||||
setPage(1)
|
||||
})
|
||||
.catch(error => {
|
||||
showError(getErrorMessage(error), 0, getString('labels.failedToDeleteLabel'))
|
||||
})
|
||||
const handleSuccess = (tag: string) => {
|
||||
showSuccess(<StringSubstitute str={getString('labels.deletedLabel')} vars={{ tag }} />, 5000)
|
||||
refetchlabelsList()
|
||||
setPage(1)
|
||||
}
|
||||
|
||||
const handleError = (error: any) => {
|
||||
showError(getErrorMessage(error), 0, getString('labels.failedToDeleteLabel'))
|
||||
}
|
||||
|
||||
const deleteAction = standalone ? deleteLabel({}) : deleteLabelQueryCall({})
|
||||
|
||||
deleteAction.then(() => handleSuccess(row.original.key ?? '')).catch(handleError)
|
||||
}
|
||||
})
|
||||
return (
|
||||
|
@ -296,18 +321,6 @@ const LabelsListing = (props: LabelListingProps) => {
|
|||
[history, getString, repoMetadata?.path, space, setPage, showError, showSuccess]
|
||||
)
|
||||
|
||||
const permPushResult = hooks?.usePermissionTranslate?.(
|
||||
{
|
||||
resource: {
|
||||
resourceType: 'CODE_REPOSITORY',
|
||||
resourceIdentifier:
|
||||
currentPageScope === LabelsPageScope.REPOSITORY ? (repoMetadata?.identifier as string) : (space as string)
|
||||
},
|
||||
permissions: ['code_repo_edit']
|
||||
},
|
||||
[space]
|
||||
)
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<LabelsHeader
|
||||
|
@ -346,7 +359,6 @@ const LabelsListing = (props: LabelListingProps) => {
|
|||
message={getString('labels.noLabelsFound')}
|
||||
buttonText={getString('labels.newLabel')}
|
||||
onButtonClick={() => openLabelCreateModal()}
|
||||
permissionProp={permissionProps(permPushResult, standalone)}
|
||||
/>
|
||||
</Container>
|
||||
)
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
border-radius: 8px;
|
||||
box-shadow: 0px 0.5px 2px 0px rgba(96, 97, 112, 0.16), 0px 0px 1px 0px rgba(40, 41, 61, 0.08);
|
||||
background: var(--grey-0);
|
||||
cursor: pointer;
|
||||
|
||||
&.expanded {
|
||||
.chevron {
|
||||
|
|
|
@ -81,6 +81,8 @@ export interface ConversationProps extends Pick<GitInfoProps, 'repoMetadata' | '
|
|||
standalone: boolean
|
||||
routingId: string
|
||||
pullReqCommits: TypesListCommitResponse | undefined
|
||||
refetchActivities: () => void
|
||||
refetchPullReq: () => void
|
||||
}
|
||||
|
||||
export const Conversation: React.FC<ConversationProps> = ({
|
||||
|
@ -93,7 +95,9 @@ export const Conversation: React.FC<ConversationProps> = ({
|
|||
prChecksDecisionResult,
|
||||
standalone,
|
||||
routingId,
|
||||
pullReqCommits
|
||||
pullReqCommits,
|
||||
refetchActivities,
|
||||
refetchPullReq
|
||||
}) => {
|
||||
const { getString } = useStrings()
|
||||
const { currentUser, routes, hooks } = useAppContext()
|
||||
|
@ -442,6 +446,7 @@ export const Conversation: React.FC<ConversationProps> = ({
|
|||
setActivityFilter={setActivityFilter}
|
||||
loadingReviewers={loadingReviewers}
|
||||
refetchCodeOwners={refetchCodeOwners}
|
||||
refetchPullReq={refetchPullReq}
|
||||
activities={activities}
|
||||
/>
|
||||
</Container>
|
||||
|
@ -508,6 +513,7 @@ export const Conversation: React.FC<ConversationProps> = ({
|
|||
refetchReviewers={refetchReviewers}
|
||||
labels={labels}
|
||||
refetchLabels={refetchLabels}
|
||||
refetchActivities={refetchActivities}
|
||||
/>
|
||||
</Layout.Horizontal>
|
||||
</Container>
|
||||
|
|
|
@ -35,7 +35,11 @@ import { useAppContext } from 'AppContext'
|
|||
import type { ConversationProps } from './Conversation'
|
||||
import css from './Conversation.module.scss'
|
||||
|
||||
interface DescriptionBoxProps extends Omit<ConversationProps, 'onCancelEditDescription' | 'pullReqCommits'> {
|
||||
interface DescriptionBoxProps
|
||||
extends Omit<
|
||||
ConversationProps,
|
||||
'onCancelEditDescription' | 'pullReqCommits' | 'refetchActivities' | 'refetchPullReq'
|
||||
> {
|
||||
onCancelEditDescription: () => void
|
||||
pullReqCommits: TypesListCommitResponse | undefined
|
||||
}
|
||||
|
|
|
@ -65,7 +65,8 @@ export const PullRequestActionsBox: React.FC<PullRequestActionsBoxProps> = ({
|
|||
allowedStrategy,
|
||||
pullReqCommits,
|
||||
PRStateLoading,
|
||||
setConflictingFiles
|
||||
setConflictingFiles,
|
||||
refetchPullReq
|
||||
}) => {
|
||||
const { getString } = useStrings()
|
||||
const { showError } = useToaster()
|
||||
|
@ -127,7 +128,8 @@ export const PullRequestActionsBox: React.FC<PullRequestActionsBoxProps> = ({
|
|||
setAllowedStrats,
|
||||
pullRequestSection,
|
||||
showError,
|
||||
setConflictingFiles
|
||||
setConflictingFiles,
|
||||
refetchPullReq
|
||||
) // eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [unchecked, pullReqMetadata?.source_sha])
|
||||
const [prMerged, setPrMerged] = useState(false)
|
||||
|
@ -146,7 +148,8 @@ export const PullRequestActionsBox: React.FC<PullRequestActionsBoxProps> = ({
|
|||
setAllowedStrats,
|
||||
pullRequestSection,
|
||||
showError,
|
||||
setConflictingFiles
|
||||
setConflictingFiles,
|
||||
refetchPullReq
|
||||
)
|
||||
}
|
||||
}, POLLING_INTERVAL) // Poll every 20 seconds
|
||||
|
@ -154,7 +157,7 @@ export const PullRequestActionsBox: React.FC<PullRequestActionsBoxProps> = ({
|
|||
return () => {
|
||||
clearInterval(intervalId)
|
||||
} // eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [onPRStateChanged, prMerged])
|
||||
}, [onPRStateChanged, prMerged, pullReqMetadata?.source_sha])
|
||||
const isDraft = pullReqMetadata.is_draft
|
||||
const mergeOptions: PRMergeOption[] = [
|
||||
{
|
||||
|
|
|
@ -51,6 +51,7 @@ interface PullRequestOverviewPanelProps {
|
|||
setActivityFilter: (val: SelectOption) => void
|
||||
loadingReviewers: boolean
|
||||
refetchCodeOwners: () => void
|
||||
refetchPullReq: () => void
|
||||
activities: TypesPullReqActivity[] | undefined
|
||||
pullReqCommits: TypesListCommitResponse | undefined
|
||||
}
|
||||
|
@ -67,7 +68,8 @@ const PullRequestOverviewPanel = (props: PullRequestOverviewPanelProps) => {
|
|||
loadingReviewers,
|
||||
refetchCodeOwners,
|
||||
activities,
|
||||
pullReqCommits
|
||||
pullReqCommits,
|
||||
refetchPullReq
|
||||
} = props
|
||||
const { getString } = useStrings()
|
||||
const { showError } = useToaster()
|
||||
|
@ -174,6 +176,7 @@ const PullRequestOverviewPanel = (props: PullRequestOverviewPanelProps) => {
|
|||
pullRequestSection,
|
||||
showError,
|
||||
setConflictingFiles,
|
||||
refetchPullReq,
|
||||
setRequiresCommentApproval,
|
||||
setAtLeastOneReviewerRule,
|
||||
setReqCodeOwnerApproval,
|
||||
|
@ -197,6 +200,7 @@ const PullRequestOverviewPanel = (props: PullRequestOverviewPanelProps) => {
|
|||
allowedStrategy={allowedStrats}
|
||||
pullReqCommits={pullReqCommits}
|
||||
PRStateLoading={PRStateLoading || loadingReviewers}
|
||||
refetchPullReq={refetchPullReq}
|
||||
/>
|
||||
{pullReqMetadata.state !== PullRequestState.CLOSED && (
|
||||
<PullRequestPanelSections
|
||||
|
|
|
@ -132,7 +132,7 @@ const MergeSection = (props: MergeSectionProps) => {
|
|||
</Layout.Vertical>
|
||||
)}
|
||||
</Layout.Horizontal>
|
||||
{!mergeable && (
|
||||
{!mergeable && !unchecked && (
|
||||
<Button
|
||||
padding={{ right: 'unset' }}
|
||||
className={cx(css.blueText, css.buttonPadding)}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
*/
|
||||
|
||||
import React, { useState } from 'react'
|
||||
import { PopoverInteractionKind } from '@blueprintjs/core'
|
||||
import { PopoverInteractionKind, Spinner } from '@blueprintjs/core'
|
||||
import { useGet, useMutate } from 'restful-react'
|
||||
import { omit } from 'lodash-es'
|
||||
import cx from 'classnames'
|
||||
|
@ -43,13 +43,15 @@ interface PullRequestSideBarProps {
|
|||
pullRequestMetadata: TypesPullReq
|
||||
refetchReviewers: () => void
|
||||
refetchLabels: () => void
|
||||
refetchActivities: () => void
|
||||
}
|
||||
|
||||
const PullRequestSideBar = (props: PullRequestSideBarProps) => {
|
||||
const { standalone, hooks } = useAppContext()
|
||||
const { CODE_PULLREQ_LABELS: isLabelEnabled } = hooks?.useFeatureFlags()
|
||||
const [labelQuery, setLabelQuery] = useState<string>('')
|
||||
const { reviewers, repoMetadata, pullRequestMetadata, refetchReviewers, labels, refetchLabels } = props
|
||||
const { reviewers, repoMetadata, pullRequestMetadata, refetchReviewers, labels, refetchLabels, refetchActivities } =
|
||||
props
|
||||
const { getString } = useStrings()
|
||||
const { showError, showSuccess } = useToaster()
|
||||
const generateReviewDecisionInfo = (
|
||||
|
@ -166,13 +168,10 @@ const PullRequestSideBar = (props: PullRequestSideBarProps) => {
|
|||
path: ({ id }) => `/api/v1/repos/${repoMetadata.path}/+/pullreq/${pullRequestMetadata?.number}/reviewers/${id}`
|
||||
})
|
||||
|
||||
const { mutate: removeLabel } = useMutate({
|
||||
const { mutate: removeLabel, loading: removingLabel } = useMutate({
|
||||
verb: 'DELETE',
|
||||
base: getConfig('code/api/v1'),
|
||||
path: ({ label_id }) =>
|
||||
`/repos/${encodeURIComponent(repoMetadata.path as string)}/pullreq/${
|
||||
pullRequestMetadata?.number
|
||||
}/labels/${encodeURIComponent(label_id)}`
|
||||
path: ({ label_id }) => `/repos/${repoMetadata.path}/+/pullreq/${pullRequestMetadata?.number}/labels/${label_id}`
|
||||
})
|
||||
|
||||
const {
|
||||
|
@ -420,6 +419,7 @@ const PullRequestSideBar = (props: PullRequestSideBarProps) => {
|
|||
query={labelQuery}
|
||||
setQuery={setLabelQuery}
|
||||
labelListLoading={labelListLoading}
|
||||
refetchActivities={refetchActivities}
|
||||
/>
|
||||
</Layout.Horizontal>
|
||||
<Container padding={{ top: 'medium', bottom: 'large' }}>
|
||||
|
@ -451,6 +451,7 @@ const PullRequestSideBar = (props: PullRequestSideBarProps) => {
|
|||
label: label.key
|
||||
}) as string
|
||||
)
|
||||
refetchActivities()
|
||||
})
|
||||
.catch(err => {
|
||||
showError(getErrorMessage(err))
|
||||
|
@ -464,6 +465,7 @@ const PullRequestSideBar = (props: PullRequestSideBarProps) => {
|
|||
{getString('labels.noLabels')}
|
||||
</Text>
|
||||
)}
|
||||
{removingLabel && <Spinner size={16} />}
|
||||
</Layout.Horizontal>
|
||||
</Container>
|
||||
</Layout.Vertical>
|
||||
|
|
|
@ -59,6 +59,7 @@ export default function PullRequest() {
|
|||
commitSHA,
|
||||
refetchActivities,
|
||||
refetchCommits,
|
||||
refetchPullReq,
|
||||
retryOnErrorFunc
|
||||
} = useGetPullRequestInfo()
|
||||
|
||||
|
@ -158,6 +159,8 @@ export default function PullRequest() {
|
|||
prStats={pullReqStats}
|
||||
showEditDescription={showEditDescription}
|
||||
onCancelEditDescription={() => setShowEditDescription(false)}
|
||||
refetchPullReq={refetchPullReq}
|
||||
refetchActivities={refetchActivities}
|
||||
/>
|
||||
)
|
||||
},
|
||||
|
|
|
@ -207,6 +207,7 @@ export function useGetPullRequestInfo() {
|
|||
commitSHA,
|
||||
refetchActivities,
|
||||
refetchCommits,
|
||||
refetchPullReq,
|
||||
retryOnErrorFunc
|
||||
}
|
||||
}
|
||||
|
|
|
@ -274,8 +274,7 @@ export default function PullRequests() {
|
|||
(isLabelEnabled || standalone) &&
|
||||
row.original &&
|
||||
row.original.labels &&
|
||||
row.original.labels.length !== 0 &&
|
||||
!prLoading
|
||||
row.original.labels.length !== 0
|
||||
}>
|
||||
{row.original?.labels?.map((label, index) => (
|
||||
<Label
|
||||
|
@ -406,19 +405,14 @@ export default function PullRequests() {
|
|||
<Layout.Horizontal
|
||||
flex={{ alignItems: 'center', justifyContent: 'flex-start' }}
|
||||
style={{ flexWrap: 'wrap', gap: '5px' }}>
|
||||
<Render when={!prLoading}>
|
||||
{isEmpty(data) ? (
|
||||
<Text color={Color.GREY_400}>{getString('labels.noResults')}</Text>
|
||||
) : (
|
||||
<Text color={Color.GREY_400}>
|
||||
{
|
||||
stringSubstitute(getString('labels.prCount'), {
|
||||
count: data?.length
|
||||
}) as string
|
||||
}
|
||||
</Text>
|
||||
)}
|
||||
</Render>
|
||||
<Text color={Color.GREY_400}>
|
||||
{isEmpty(data)
|
||||
? getString('labels.noResults')
|
||||
: (stringSubstitute(getString('labels.prCount'), {
|
||||
count: data?.length
|
||||
}) as string)}
|
||||
</Text>
|
||||
|
||||
{(isLabelEnabled || standalone) &&
|
||||
labelFilter &&
|
||||
labelFilter?.length !== 0 &&
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { useState, useEffect } from 'react'
|
||||
import React, { useState } from 'react'
|
||||
import {
|
||||
Container,
|
||||
Layout,
|
||||
|
@ -32,7 +32,7 @@ import cx from 'classnames'
|
|||
import { Color, FontVariation, Intent } from '@harnessio/design-system'
|
||||
import { Icon } from '@harnessio/icons'
|
||||
import { noop } from 'lodash-es'
|
||||
import { useMutate, useGet } from 'restful-react'
|
||||
import { useMutate } from 'restful-react'
|
||||
import { Render } from 'react-jsx-match'
|
||||
import { ACCESS_MODES, getErrorMessage, permissionProps, voidFn } from 'utils/Utils'
|
||||
import { useStrings } from 'framework/strings'
|
||||
|
@ -42,6 +42,7 @@ import { useGetSpaceParam } from 'hooks/useGetSpaceParam'
|
|||
import { RepoVisibility } from 'utils/GitUtils'
|
||||
import { BranchTagSelect } from 'components/BranchTagSelect/BranchTagSelect'
|
||||
import { useModalHook } from 'hooks/useModalHook'
|
||||
import { usePublicResourceConfig } from 'hooks/usePublicResourceConfig'
|
||||
import useDeleteRepoModal from './DeleteRepoModal/DeleteRepoModal'
|
||||
import useDefaultBranchModal from './DefaultBranchModal/DefaultBranchModal'
|
||||
import Private from '../../../icons/private.svg?url'
|
||||
|
@ -62,14 +63,13 @@ const GeneralSettingsContent = (props: GeneralSettingsProps) => {
|
|||
const [defaultBranch, setDefaultBranch] = useState(ACCESS_MODES.VIEW)
|
||||
const { openModal: openDefaultBranchModal } = useDefaultBranchModal({ currentGitRef, setDefaultBranch, refetch })
|
||||
const { showError, showSuccess } = useToaster()
|
||||
|
||||
const { standalone, hooks } = useAppContext()
|
||||
const space = useGetSpaceParam()
|
||||
const { standalone, hooks, isPublicAccessEnabledOnResources } = useAppContext()
|
||||
const { allowPublicResourceCreation } = usePublicResourceConfig()
|
||||
const { getString } = useStrings()
|
||||
const currRepoVisibility = repoMetadata?.is_public === true ? RepoVisibility.PUBLIC : RepoVisibility.PRIVATE
|
||||
|
||||
const [repoVis, setRepoVis] = useState<RepoVisibility>(currRepoVisibility)
|
||||
const [enablePublicRepo, setEnablePublicRepo] = useState(false)
|
||||
|
||||
const { mutate } = useMutate({
|
||||
verb: 'PATCH',
|
||||
path: `/api/v1/repos/${repoMetadata?.path}/+/`
|
||||
|
@ -100,19 +100,11 @@ const GeneralSettingsContent = (props: GeneralSettingsProps) => {
|
|||
},
|
||||
[space]
|
||||
)
|
||||
const { data: systemConfig } = useGet({ path: 'api/v1/system/config' })
|
||||
|
||||
useEffect(() => {
|
||||
if (systemConfig) {
|
||||
setEnablePublicRepo(systemConfig.public_resource_creation_enabled)
|
||||
}
|
||||
}, [systemConfig])
|
||||
|
||||
const ModalComponent: React.FC = () => {
|
||||
return (
|
||||
<Dialog
|
||||
className={css.dialogContainer}
|
||||
style={{ width: 585, maxHeight: '95vh', overflow: 'auto' }}
|
||||
title={<Text font={{ variation: FontVariation.H4 }}>{getString('changeRepoVis')}</Text>}
|
||||
isOpen
|
||||
onClose={hideModal}>
|
||||
|
@ -144,7 +136,6 @@ const GeneralSettingsContent = (props: GeneralSettingsProps) => {
|
|||
</Container>
|
||||
<Layout.Horizontal className={css.buttonContainer}>
|
||||
<Button
|
||||
margin={{ right: 'medium' }}
|
||||
type="submit"
|
||||
text={
|
||||
<StringSubstitute
|
||||
|
@ -333,7 +324,7 @@ const GeneralSettingsContent = (props: GeneralSettingsProps) => {
|
|||
</Container>
|
||||
</Layout.Horizontal>
|
||||
</Container>
|
||||
<Render when={enablePublicRepo && isPublicAccessEnabledOnResources}>
|
||||
<Render when={allowPublicResourceCreation}>
|
||||
<Container padding="large" margin={{ bottom: 'medium' }} className={css.generalContainer}>
|
||||
<Layout.Horizontal padding={{ bottom: 'medium' }}>
|
||||
<Container className={css.label}>
|
||||
|
|
|
@ -121,6 +121,9 @@
|
|||
}
|
||||
|
||||
.dialogContainer {
|
||||
width: 600px;
|
||||
max-height: 95vh;
|
||||
overflow: auto;
|
||||
:global(.bp3-dialog-header) {
|
||||
margin-bottom: var(--spacing-medium) !important;
|
||||
}
|
||||
|
@ -144,7 +147,7 @@
|
|||
.buttonContainer {
|
||||
width: 20%;
|
||||
padding-top: var(--spacing-xsmall) !important;
|
||||
gap: 10px;
|
||||
gap: 15px;
|
||||
margin-left: auto !important;
|
||||
}
|
||||
|
||||
|
|
|
@ -85,6 +85,12 @@ export const getUsingFetch = <
|
|||
if (res.status === 401) {
|
||||
return res.json().then(json => Promise.reject(json))
|
||||
}
|
||||
if (res.status === 400) {
|
||||
return res.text().then(text => Promise.reject(text))
|
||||
}
|
||||
if (res.status === 403) {
|
||||
return res.text().then(text => Promise.reject(text))
|
||||
}
|
||||
return res.json()
|
||||
}
|
||||
|
||||
|
@ -100,6 +106,14 @@ export const getUsingFetch = <
|
|||
return res.text().then(text => Promise.reject(text))
|
||||
}
|
||||
|
||||
if (res.status === 403) {
|
||||
return res.text().then(text => Promise.reject(text))
|
||||
}
|
||||
|
||||
if (res.status === 400) {
|
||||
return res.text().then(text => Promise.reject(text))
|
||||
}
|
||||
|
||||
return res.text()
|
||||
})
|
||||
}
|
||||
|
|
|
@ -468,6 +468,8 @@ export const getProviders = () =>
|
|||
export const codeOwnersNotFoundMessage = 'CODEOWNERS file not found'
|
||||
export const codeOwnersNotFoundMessage2 = `path "CODEOWNERS" not found`
|
||||
export const codeOwnersNotFoundMessage3 = `failed to find node 'CODEOWNERS' in 'main': failed to get tree node: failed to ls file: path "CODEOWNERS" not found`
|
||||
export const oldCommitRefetchRequired = 'A newer commit is available. Only the latest commit can be merged.'
|
||||
export const prMergedRefetchRequired = 'Pull request already merged'
|
||||
|
||||
export const dryMerge = (
|
||||
isMounted: React.MutableRefObject<boolean>,
|
||||
|
@ -504,6 +506,7 @@ export const dryMerge = (
|
|||
pullRequestSection: string | undefined,
|
||||
showError: (message: React.ReactNode, timeout?: number | undefined, key?: string | undefined) => void,
|
||||
setConflictingFiles: React.Dispatch<React.SetStateAction<string[] | undefined>>,
|
||||
refetchPullReq: () => void,
|
||||
setRequiresCommentApproval?: (value: React.SetStateAction<boolean>) => void,
|
||||
setAtLeastOneReviewerRule?: (value: React.SetStateAction<boolean>) => void,
|
||||
setReqCodeOwnerApproval?: (value: React.SetStateAction<boolean>) => void,
|
||||
|
@ -555,6 +558,11 @@ export const dryMerge = (
|
|||
setReqCodeOwnerLatestApproval?.(err.requires_code_owners_approval_latest)
|
||||
setMinReqLatestApproval?.(err.minimum_required_approvals_count_latest)
|
||||
setConflictingFiles?.(err.conflict_files)
|
||||
} else if (
|
||||
err.status === 400 &&
|
||||
(getErrorMessage(err) === oldCommitRefetchRequired || getErrorMessage(err) === prMergedRefetchRequired)
|
||||
) {
|
||||
refetchPullReq()
|
||||
} else if (
|
||||
getErrorMessage(err) === codeOwnersNotFoundMessage ||
|
||||
getErrorMessage(err) === codeOwnersNotFoundMessage2 ||
|
||||
|
|
|
@ -171,6 +171,7 @@ export interface PullRequestActionsBoxProps extends Pick<GitInfoProps, 'repoMeta
|
|||
PRStateLoading: boolean
|
||||
conflictingFiles: string[] | undefined
|
||||
setConflictingFiles: React.Dispatch<React.SetStateAction<string[] | undefined>>
|
||||
refetchPullReq: () => void
|
||||
}
|
||||
|
||||
export interface PRMergeOption extends SelectOption {
|
||||
|
|
Loading…
Reference in New Issue