mirror of
https://github.com/sourcegraph/sourcegraph.git
synced 2026-02-06 20:51:43 +00:00
Make repo settings pages available for uncloned repos (#57609)
The repo settings pages contain a bunch of useful information for repos even when they aren't cloned yet - like log outputs, corruption logs, and ways to exclude the repo from cloning. Thus, it should be visible before the repo is cloned successfully. This also consolidates mirroring and options into one menu, like discussed.
This commit is contained in:
parent
8acc71a840
commit
29fbcfb868
@ -1380,13 +1380,13 @@ ts_project(
|
||||
"src/repo/settings/RepoSettingsArea.tsx",
|
||||
"src/repo/settings/RepoSettingsIndexPage.tsx",
|
||||
"src/repo/settings/RepoSettingsMirrorPage.tsx",
|
||||
"src/repo/settings/RepoSettingsOptionsPage.tsx",
|
||||
"src/repo/settings/RepoSettingsOptions.tsx",
|
||||
"src/repo/settings/RepoSettingsSidebar.tsx",
|
||||
"src/repo/settings/backend.ts",
|
||||
"src/repo/settings/components/ActionContainer.tsx",
|
||||
"src/repo/settings/components/ExternalServiceEntry.tsx",
|
||||
"src/repo/settings/components/RedirectionAlert.tsx",
|
||||
"src/repo/settings/routes.ts",
|
||||
"src/repo/settings/routes.tsx",
|
||||
"src/repo/settings/sidebaritems.ts",
|
||||
"src/repo/stats/RepositoryStatsArea.tsx",
|
||||
"src/repo/stats/RepositoryStatsContributorsPage.tsx",
|
||||
|
||||
@ -91,9 +91,9 @@ export const RepoSettingsPermissionsPage: FC<RepoSettingsPermissionsPageProps> =
|
||||
|
||||
return (
|
||||
<>
|
||||
<PageTitle title="Permissions" />
|
||||
<PageTitle title="Repo Permissions" />
|
||||
<PageHeader
|
||||
path={[{ text: 'Permissions' }]}
|
||||
path={[{ text: 'Repo Permissions' }]}
|
||||
headingElement="h2"
|
||||
className="mb-3"
|
||||
description={
|
||||
|
||||
@ -19,7 +19,7 @@ export const enterpriseRepoSettingsSidebarGroups: RepoSettingsSideBarGroups =
|
||||
{
|
||||
to: '/permissions',
|
||||
exact: true,
|
||||
label: 'Permissions',
|
||||
label: 'Repo Permissions',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@ -25,7 +25,7 @@ import type { SettingsCascadeProps } from '@sourcegraph/shared/src/settings/sett
|
||||
import type { TelemetryProps } from '@sourcegraph/shared/src/telemetry/telemetryService'
|
||||
import { lazyComponent } from '@sourcegraph/shared/src/util/lazyComponent'
|
||||
import { makeRepoURI } from '@sourcegraph/shared/src/util/url'
|
||||
import { Panel, useObservable } from '@sourcegraph/wildcard'
|
||||
import { LoadingSpinner, Panel, useObservable } from '@sourcegraph/wildcard'
|
||||
|
||||
import type { AuthenticatedUser } from '../auth'
|
||||
import type { BatchChangesProps } from '../batches'
|
||||
@ -48,7 +48,7 @@ import type { RouteV6Descriptor } from '../util/contributions'
|
||||
import { parseBrowserRepoURL } from '../util/url'
|
||||
|
||||
import { GoToCodeHostAction } from './actions/GoToCodeHostAction'
|
||||
import { fetchFileExternalLinks, type ResolvedRevision, resolveRepoRevision } from './backend'
|
||||
import { fetchFileExternalLinks, type ResolvedRevision, resolveRepoRevision, Repo } from './backend'
|
||||
import { AskCodyButton } from './cody/AskCodyButton'
|
||||
import { RepoContainerError } from './RepoContainerError'
|
||||
import { RepoHeader, type RepoHeaderActionButton, type RepoHeaderContributionsLifecycleProps } from './RepoHeader'
|
||||
@ -142,35 +142,11 @@ export interface HoverThresholdProps {
|
||||
* Renders a horizontal bar and content for a repository page.
|
||||
*/
|
||||
export const RepoContainer: FC<RepoContainerProps> = props => {
|
||||
const { extensionsController, repoContainerRoutes, authenticatedUser, selectedSearchContextSpec } = props
|
||||
const { authenticatedUser } = props
|
||||
|
||||
const location = useLocation()
|
||||
|
||||
const { repoName, revision, rawRevision, filePath, commitRange, position, range } = parseBrowserRepoURL(
|
||||
location.pathname + location.search + location.hash
|
||||
)
|
||||
|
||||
const {
|
||||
isSidebarOpen: isCodySidebarOpen,
|
||||
setIsSidebarOpen: setIsCodySidebarOpen,
|
||||
scope,
|
||||
setEditorScope,
|
||||
logTranscriptEvent,
|
||||
} = useCodySidebar()
|
||||
|
||||
const { sidebarSize, setSidebarSize: setCodySidebarSize } = useSidebarSize()
|
||||
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
const codySidebarSize = useMemo(() => sidebarSize, [isCodySidebarOpen])
|
||||
/* eslint-enable react-hooks/exhaustive-deps */
|
||||
|
||||
useEffect(() => {
|
||||
const activeEditor = scope.editor.getActiveTextEditor()
|
||||
|
||||
if (activeEditor?.repoName !== repoName) {
|
||||
setEditorScope(new RepoContainerEditor(repoName))
|
||||
}
|
||||
}, [scope.editor, repoName, setEditorScope])
|
||||
const { repoName, revision, rawRevision } = parseBrowserRepoURL(location.pathname + location.search + location.hash)
|
||||
|
||||
const resolvedRevisionOrError = useObservable(
|
||||
useMemo(
|
||||
@ -207,8 +183,6 @@ export const RepoContainer: FC<RepoContainerProps> = props => {
|
||||
)
|
||||
)
|
||||
|
||||
const focusCodyShortcut = useKeyboardShortcut('focusCody')
|
||||
|
||||
/**
|
||||
* A long time ago, we fetched `repo` in a separate GraphQL query.
|
||||
* This GraphQL query was merged into the `resolveRevision` query to
|
||||
@ -218,9 +192,6 @@ export const RepoContainer: FC<RepoContainerProps> = props => {
|
||||
*/
|
||||
const repoOrError = isErrorLike(resolvedRevisionOrError) ? resolvedRevisionOrError : resolvedRevisionOrError?.repo
|
||||
|
||||
// The external links to show in the repository header, if any.
|
||||
const [externalLinks, setExternalLinks] = useState<ExternalLinkFields[] | undefined>()
|
||||
|
||||
// The lifecycle props for repo header contributions.
|
||||
const [repoHeaderContributionsLifecycleProps, setRepoHeaderContributionsLifecycleProps] =
|
||||
useState<RepoHeaderContributionsLifecycleProps>()
|
||||
@ -244,6 +215,115 @@ export const RepoContainer: FC<RepoContainerProps> = props => {
|
||||
}, [resolvedRevisionOrError, repoOrError, repoName])
|
||||
)
|
||||
|
||||
// must exactly match how the revision was encoded in the URL
|
||||
const repoNameAndRevision = `${repoName}${typeof rawRevision === 'string' ? `@${rawRevision}` : ''}`
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={classNames('w-100 d-flex flex-row')}>
|
||||
<div className={classNames('w-100 d-flex flex-column', styles.repoContainer)}>
|
||||
<RepoHeader
|
||||
actionButtons={props.repoHeaderActionButtons}
|
||||
breadcrumbs={props.breadcrumbs}
|
||||
repoName={repoName}
|
||||
revision={revision}
|
||||
onLifecyclePropsChange={setRepoHeaderContributionsLifecycleProps}
|
||||
settingsCascade={props.settingsCascade}
|
||||
authenticatedUser={authenticatedUser}
|
||||
platformContext={props.platformContext}
|
||||
telemetryService={props.telemetryService}
|
||||
/>
|
||||
|
||||
<Suspense fallback={<LoadingSpinner />}>
|
||||
<Routes>
|
||||
{props.authenticatedUser?.siteAdmin && (
|
||||
<Route
|
||||
path={repoNameAndRevision + repoSettingsAreaPath}
|
||||
errorElement={<RouteError />}
|
||||
// Always render the `RepoSettingsArea` even for empty repo to allow side-admins access it.
|
||||
element={
|
||||
<RepoSettingsArea
|
||||
repoName={repoName}
|
||||
authenticatedUser={props.authenticatedUser}
|
||||
repoSettingsAreaRoutes={props.repoSettingsAreaRoutes}
|
||||
repoSettingsSidebarGroups={props.repoSettingsSidebarGroups}
|
||||
setBreadcrumb={childBreadcrumbSetters.setBreadcrumb}
|
||||
useBreadcrumb={childBreadcrumbSetters.useBreadcrumb}
|
||||
telemetryService={props.telemetryService}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
<Route
|
||||
path="*"
|
||||
errorElement={<RouteError />}
|
||||
element={
|
||||
<RepoUserContainer
|
||||
{...props}
|
||||
childBreadcrumbSetters={childBreadcrumbSetters}
|
||||
repoOrError={repoOrError}
|
||||
resolvedRevisionOrError={resolvedRevisionOrError}
|
||||
repoHeaderContributionsLifecycleProps={repoHeaderContributionsLifecycleProps}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</Routes>
|
||||
</Suspense>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
interface RepoUserContainerProps extends RepoContainerProps {
|
||||
repoHeaderContributionsLifecycleProps?: RepoHeaderContributionsLifecycleProps
|
||||
resolvedRevisionOrError: (ResolvedRevision & Repo) | ErrorLike | undefined
|
||||
repoOrError: ErrorLike | RepositoryFields | undefined
|
||||
childBreadcrumbSetters: BreadcrumbSetters
|
||||
}
|
||||
|
||||
const RepoUserContainer: FC<RepoUserContainerProps> = ({
|
||||
resolvedRevisionOrError,
|
||||
repoOrError,
|
||||
childBreadcrumbSetters,
|
||||
repoHeaderContributionsLifecycleProps,
|
||||
...props
|
||||
}) => {
|
||||
const { extensionsController, repoContainerRoutes, authenticatedUser, selectedSearchContextSpec } = props
|
||||
|
||||
const location = useLocation()
|
||||
|
||||
const { repoName, revision, rawRevision, filePath, commitRange, position, range } = parseBrowserRepoURL(
|
||||
location.pathname + location.search + location.hash
|
||||
)
|
||||
|
||||
const {
|
||||
isSidebarOpen: isCodySidebarOpen,
|
||||
setIsSidebarOpen: setIsCodySidebarOpen,
|
||||
scope,
|
||||
setEditorScope,
|
||||
logTranscriptEvent,
|
||||
} = useCodySidebar()
|
||||
|
||||
const { sidebarSize, setSidebarSize: setCodySidebarSize } = useSidebarSize()
|
||||
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
const codySidebarSize = useMemo(() => sidebarSize, [isCodySidebarOpen])
|
||||
/* eslint-enable react-hooks/exhaustive-deps */
|
||||
|
||||
useEffect(() => {
|
||||
const activeEditor = scope.editor.getActiveTextEditor()
|
||||
|
||||
if (activeEditor?.repoName !== repoName) {
|
||||
setEditorScope(new RepoContainerEditor(repoName))
|
||||
}
|
||||
}, [scope.editor, repoName, setEditorScope])
|
||||
|
||||
const focusCodyShortcut = useKeyboardShortcut('focusCody')
|
||||
|
||||
// The external links to show in the repository header, if any.
|
||||
const [externalLinks, setExternalLinks] = useState<ExternalLinkFields[] | undefined>()
|
||||
|
||||
// Update the workspace roots service to reflect the current repo / resolved revision
|
||||
useEffect(() => {
|
||||
const workspaceRootUri =
|
||||
@ -363,151 +443,128 @@ export const RepoContainer: FC<RepoContainerProps> = props => {
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
<div className={classNames('w-100 d-flex flex-row')}>
|
||||
<div className={classNames('w-100 d-flex flex-column', styles.repoContainer)}>
|
||||
<RepoHeader
|
||||
actionButtons={props.repoHeaderActionButtons}
|
||||
breadcrumbs={props.breadcrumbs}
|
||||
|
||||
<RepoHeaderContributionPortal
|
||||
position="right"
|
||||
priority={1}
|
||||
id="cody"
|
||||
{...repoHeaderContributionsLifecycleProps}
|
||||
>
|
||||
{() =>
|
||||
!isCodySidebarOpen ? (
|
||||
<AskCodyButton
|
||||
onClick={() => {
|
||||
logTranscriptEvent(EventName.CODY_SIDEBAR_CHAT_OPENED, { repo, path: filePath })
|
||||
setIsCodySidebarOpen(true)
|
||||
}}
|
||||
/>
|
||||
) : null
|
||||
}
|
||||
</RepoHeaderContributionPortal>
|
||||
|
||||
<RepoHeaderContributionPortal
|
||||
position="right"
|
||||
priority={2}
|
||||
id="go-to-code-host"
|
||||
{...repoHeaderContributionsLifecycleProps}
|
||||
>
|
||||
{({ actionType }) => (
|
||||
<GoToCodeHostAction
|
||||
repo={repo}
|
||||
repoName={repoName}
|
||||
revision={revision}
|
||||
onLifecyclePropsChange={setRepoHeaderContributionsLifecycleProps}
|
||||
settingsCascade={props.settingsCascade}
|
||||
authenticatedUser={authenticatedUser}
|
||||
platformContext={props.platformContext}
|
||||
telemetryService={props.telemetryService}
|
||||
// We need a revision to generate code host URLs, if revision isn't available, we use the default branch or HEAD.
|
||||
revision={rawRevision || repo?.defaultBranch?.displayName || 'HEAD'}
|
||||
filePath={filePath}
|
||||
commitRange={commitRange}
|
||||
range={range}
|
||||
position={position}
|
||||
perforceCodeHostUrlToSwarmUrlMap={perforceCodeHostUrlToSwarmUrlMap}
|
||||
fetchFileExternalLinks={fetchFileExternalLinks}
|
||||
actionType={actionType}
|
||||
source="repoHeader"
|
||||
key="go-to-code-host"
|
||||
externalLinks={externalLinks}
|
||||
/>
|
||||
)}
|
||||
</RepoHeaderContributionPortal>
|
||||
|
||||
<RepoHeaderContributionPortal
|
||||
position="right"
|
||||
priority={1}
|
||||
id="cody"
|
||||
{...repoHeaderContributionsLifecycleProps}
|
||||
>
|
||||
{() =>
|
||||
!isCodySidebarOpen ? (
|
||||
<AskCodyButton
|
||||
onClick={() => {
|
||||
logTranscriptEvent(EventName.CODY_SIDEBAR_CHAT_OPENED, { repo, path: filePath })
|
||||
setIsCodySidebarOpen(true)
|
||||
}}
|
||||
/>
|
||||
) : null
|
||||
}
|
||||
</RepoHeaderContributionPortal>
|
||||
|
||||
<RepoHeaderContributionPortal
|
||||
position="right"
|
||||
priority={2}
|
||||
id="go-to-code-host"
|
||||
{...repoHeaderContributionsLifecycleProps}
|
||||
>
|
||||
{({ actionType }) => (
|
||||
<GoToCodeHostAction
|
||||
repo={repo}
|
||||
{isBrainDotVisible && (
|
||||
<RepoHeaderContributionPortal
|
||||
position="right"
|
||||
priority={110}
|
||||
id="code-intelligence-status"
|
||||
{...repoHeaderContributionsLifecycleProps}
|
||||
>
|
||||
{({ actionType }) =>
|
||||
props.brainDot && actionType === 'nav' ? (
|
||||
<props.brainDot
|
||||
key="code-intelligence-status"
|
||||
repoName={repoName}
|
||||
// We need a revision to generate code host URLs, if revision isn't available, we use the default branch or HEAD.
|
||||
revision={rawRevision || repo?.defaultBranch?.displayName || 'HEAD'}
|
||||
filePath={filePath}
|
||||
commitRange={commitRange}
|
||||
range={range}
|
||||
position={position}
|
||||
perforceCodeHostUrlToSwarmUrlMap={perforceCodeHostUrlToSwarmUrlMap}
|
||||
fetchFileExternalLinks={fetchFileExternalLinks}
|
||||
actionType={actionType}
|
||||
source="repoHeader"
|
||||
key="go-to-code-host"
|
||||
externalLinks={externalLinks}
|
||||
path={filePath}
|
||||
commit={resolvedRevision?.commitID ?? ''}
|
||||
/>
|
||||
)}
|
||||
</RepoHeaderContributionPortal>
|
||||
) : null
|
||||
}
|
||||
</RepoHeaderContributionPortal>
|
||||
)}
|
||||
|
||||
{isBrainDotVisible && (
|
||||
<RepoHeaderContributionPortal
|
||||
position="right"
|
||||
priority={110}
|
||||
id="code-intelligence-status"
|
||||
{...repoHeaderContributionsLifecycleProps}
|
||||
>
|
||||
{({ actionType }) =>
|
||||
props.brainDot && actionType === 'nav' ? (
|
||||
<props.brainDot
|
||||
key="code-intelligence-status"
|
||||
repoName={repoName}
|
||||
path={filePath}
|
||||
commit={resolvedRevision?.commitID ?? ''}
|
||||
/>
|
||||
<Suspense fallback={<LoadingSpinner />}>
|
||||
<Routes>
|
||||
{repoContainerRoutes.map(({ path, render, condition = () => true }) => (
|
||||
<Route
|
||||
key="hardcoded-key" // see https://github.com/ReactTraining/react-router/issues/4578#issuecomment-334489490
|
||||
path={repoNameAndRevision + path}
|
||||
errorElement={<RouteError />}
|
||||
element={
|
||||
/**
|
||||
* `repoContainerRoutes` depend on `repo`. We render these routes only when
|
||||
* the `repo` value is resolved. If repo resolves to error due to empty repository
|
||||
* then we return Empty Repository.
|
||||
*/
|
||||
repo && condition({ ...repoContainerContext, repo }) ? (
|
||||
render({ ...repoContainerContext, repo })
|
||||
) : isEmptyRepo ? (
|
||||
<EmptyRepo />
|
||||
) : null
|
||||
}
|
||||
</RepoHeaderContributionPortal>
|
||||
)}
|
||||
|
||||
<Suspense fallback={null}>
|
||||
<Routes>
|
||||
{repoContainerRoutes.map(({ path, render, condition = () => true }) => (
|
||||
<Route
|
||||
key="hardcoded-key" // see https://github.com/ReactTraining/react-router/issues/4578#issuecomment-334489490
|
||||
path={repoNameAndRevision + path}
|
||||
errorElement={<RouteError />}
|
||||
element={
|
||||
/**
|
||||
* `repoContainerRoutes` depend on `repo`. We render these routes only when
|
||||
* the `repo` value is resolved. If repo resolves to error due to empty repository
|
||||
* then we return Empty Repository.
|
||||
*/
|
||||
repo && condition({ ...repoContainerContext, repo }) ? (
|
||||
render({ ...repoContainerContext, repo })
|
||||
) : isEmptyRepo ? (
|
||||
<EmptyRepo />
|
||||
) : null
|
||||
}
|
||||
/>
|
||||
))}
|
||||
{props.authenticatedUser?.siteAdmin && (
|
||||
<Route
|
||||
path={repoNameAndRevision + repoSettingsAreaPath}
|
||||
errorElement={<RouteError />}
|
||||
// Always render the `RepoSettingsArea` even for empty repo to allow side-admins access it.
|
||||
element={<RepoSettingsArea {...repoRevisionContainerContext} repoName={repoName} />}
|
||||
/>
|
||||
)}
|
||||
<Route
|
||||
key="hardcoded-key" // see https://github.com/ReactTraining/react-router/issues/4578#issuecomment-334489490
|
||||
path={repoNameAndRevision + '/*'}
|
||||
errorElement={<RouteError />}
|
||||
element={
|
||||
isEmptyRepo ? (
|
||||
<EmptyRepo />
|
||||
) : (
|
||||
<RepoRevisionContainer
|
||||
{...repoRevisionContainerContext}
|
||||
{...childBreadcrumbSetters}
|
||||
routes={props.repoRevisionContainerRoutes}
|
||||
/>
|
||||
)
|
||||
}
|
||||
/>
|
||||
</Routes>
|
||||
</Suspense>
|
||||
</div>
|
||||
|
||||
{isCodySidebarOpen && (
|
||||
<Panel
|
||||
className="cody-sidebar-panel"
|
||||
position="right"
|
||||
ariaLabel="Cody sidebar"
|
||||
maxSize={CODY_SIDEBAR_SIZES.max}
|
||||
minSize={CODY_SIDEBAR_SIZES.min}
|
||||
defaultSize={codySidebarSize || CODY_SIDEBAR_SIZES.default}
|
||||
storageKey="size-cache-cody-sidebar"
|
||||
onResize={setCodySidebarSize}
|
||||
>
|
||||
<CodySidebar
|
||||
onClose={() => setIsCodySidebarOpen(false)}
|
||||
authenticatedUser={props.authenticatedUser}
|
||||
/>
|
||||
</Panel>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
<Route
|
||||
key="hardcoded-key" // see https://github.com/ReactTraining/react-router/issues/4578#issuecomment-334489490
|
||||
path={repoNameAndRevision + '/*'}
|
||||
errorElement={<RouteError />}
|
||||
element={
|
||||
isEmptyRepo ? (
|
||||
<EmptyRepo />
|
||||
) : (
|
||||
<RepoRevisionContainer
|
||||
{...repoRevisionContainerContext}
|
||||
{...childBreadcrumbSetters}
|
||||
routes={props.repoRevisionContainerRoutes}
|
||||
/>
|
||||
)
|
||||
}
|
||||
/>
|
||||
</Routes>
|
||||
</Suspense>
|
||||
|
||||
{isCodySidebarOpen && (
|
||||
<Panel
|
||||
className="cody-sidebar-panel"
|
||||
position="right"
|
||||
ariaLabel="Cody sidebar"
|
||||
maxSize={CODY_SIDEBAR_SIZES.max}
|
||||
minSize={CODY_SIDEBAR_SIZES.min}
|
||||
defaultSize={codySidebarSize || CODY_SIDEBAR_SIZES.default}
|
||||
storageKey="size-cache-cody-sidebar"
|
||||
onResize={setCodySidebarSize}
|
||||
>
|
||||
<CodySidebar
|
||||
onClose={() => setIsCodySidebarOpen(false)}
|
||||
authenticatedUser={props.authenticatedUser}
|
||||
/>
|
||||
</Panel>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@ -10,7 +10,7 @@ import {
|
||||
} from '@sourcegraph/shared/src/backend/errors'
|
||||
import { RepoQuestionIcon } from '@sourcegraph/shared/src/components/icons'
|
||||
import { displayRepoName } from '@sourcegraph/shared/src/components/RepoLink'
|
||||
import { Code, ErrorMessage } from '@sourcegraph/wildcard'
|
||||
import { Code, ErrorMessage, Link, Text } from '@sourcegraph/wildcard'
|
||||
|
||||
import { HeroPage } from '../components/HeroPage'
|
||||
|
||||
@ -41,15 +41,38 @@ export const RepoContainerError: React.FunctionComponent<React.PropsWithChildren
|
||||
icon={SourceRepositoryIcon}
|
||||
title={displayRepoName(repoName)}
|
||||
className="repository-cloning-in-progress-page"
|
||||
subtitle="Cloning in progress"
|
||||
detail={<Code>{(repoFetchError as CloneInProgressError).progress}</Code>}
|
||||
subtitle={<Text>Cloning in progress</Text>}
|
||||
detail={
|
||||
<>
|
||||
<Code>{(repoFetchError as CloneInProgressError).progress}</Code>
|
||||
{viewerCanAdminister && (
|
||||
<Text className="mt-4">
|
||||
<Link to={`${repoName}/-/settings`}>Go to settings</Link> to view details
|
||||
</Text>
|
||||
)}
|
||||
</>
|
||||
}
|
||||
body={<DirectImportRepoAlert className="mt-3" />}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
if (isRevisionNotFoundErrorLike(repoFetchError)) {
|
||||
return <HeroPage icon={RepoQuestionIcon} title="Empty repository" />
|
||||
return (
|
||||
<HeroPage
|
||||
icon={RepoQuestionIcon}
|
||||
title="Empty repository"
|
||||
detail={
|
||||
<>
|
||||
{viewerCanAdminister && (
|
||||
<Text>
|
||||
<Link to={`${repoName}/-/settings`}>Go to settings</Link>
|
||||
</Text>
|
||||
)}
|
||||
</>
|
||||
}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
return <HeroPage icon={AlertCircleIcon} title="Error" subtitle={<ErrorMessage error={repoFetchError} />} />
|
||||
|
||||
@ -265,7 +265,7 @@ export class RepoSettingsIndexPage extends React.PureComponent<Props, State> {
|
||||
<>
|
||||
<PageTitle title="Index settings" />
|
||||
<PageHeader
|
||||
path={[{ text: 'Indexing' }]}
|
||||
path={[{ text: 'Search Indexing' }]}
|
||||
headingElement="h2"
|
||||
className="mb-3"
|
||||
description={
|
||||
|
||||
@ -46,6 +46,7 @@ import { DirectImportRepoAlert } from '../DirectImportRepoAlert'
|
||||
|
||||
import { FETCH_SETTINGS_AREA_REPOSITORY_GQL } from './backend'
|
||||
import { ActionContainer, BaseActionContainer } from './components/ActionContainer'
|
||||
import { RepoSettingsOptions } from './RepoSettingsOptions'
|
||||
|
||||
import styles from './RepoSettingsMirrorPage.module.scss'
|
||||
|
||||
@ -83,7 +84,7 @@ const UpdateMirrorRepositoryActionContainer: FC<UpdateMirrorRepositoryActionCont
|
||||
</span>
|
||||
)
|
||||
buttonDisabled = true
|
||||
info = <DirectImportRepoAlert className={styles.alert} />
|
||||
info = <DirectImportRepoAlert className={classNames(styles.alert, 'mb-0')} />
|
||||
} else if (props.repo.mirrorInfo.cloned) {
|
||||
const updateSchedule = props.repo.mirrorInfo.updateSchedule
|
||||
title = (
|
||||
@ -244,35 +245,33 @@ const CorruptionLogsContainer: FC<CorruptionLogProps> = props => {
|
||||
title="Repository corruption"
|
||||
titleAs="h3"
|
||||
description={<span>Recent corruption events that have been detected on this repository.</span>}
|
||||
className="mb-0"
|
||||
details={
|
||||
<div className="flex-1">
|
||||
{health}
|
||||
<Collapse isOpen={isOpened} onOpenChange={setIsOpened}>
|
||||
<CollapseHeader
|
||||
as={Button}
|
||||
outline={true}
|
||||
focusLocked={true}
|
||||
variant="secondary"
|
||||
className="w-100 my-2"
|
||||
disabled={!hasLogs}
|
||||
>
|
||||
{hasLogs ? (
|
||||
<>
|
||||
Show corruption history
|
||||
<Icon
|
||||
aria-hidden={true}
|
||||
svgPath={isOpened ? mdiChevronUp : mdiChevronDown}
|
||||
className="mr-1"
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
'No corruption history'
|
||||
)}
|
||||
</CollapseHeader>
|
||||
<CollapsePanel>
|
||||
<ul className="list-group">{logEvents}</ul>
|
||||
</CollapsePanel>
|
||||
</Collapse>
|
||||
{!hasLogs && <Text className="mt-3 text-muted text-center mb-0">No corruption history</Text>}
|
||||
{hasLogs && (
|
||||
<Collapse isOpen={isOpened} onOpenChange={setIsOpened}>
|
||||
<CollapseHeader
|
||||
as={Button}
|
||||
outline={true}
|
||||
focusLocked={true}
|
||||
variant="secondary"
|
||||
className="w-100 my-2"
|
||||
disabled={!hasLogs}
|
||||
>
|
||||
Show corruption history
|
||||
<Icon
|
||||
aria-hidden={true}
|
||||
svgPath={isOpened ? mdiChevronUp : mdiChevronDown}
|
||||
className="mr-1"
|
||||
/>
|
||||
</CollapseHeader>
|
||||
<CollapsePanel>
|
||||
<ul className="list-group">{logEvents}</ul>
|
||||
</CollapsePanel>
|
||||
</Collapse>
|
||||
)}
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
@ -312,6 +311,7 @@ export const RepoSettingsMirrorPage: FC<RepoSettingsMirrorPageProps> = props =>
|
||||
<>
|
||||
<PageTitle title="Mirror settings" />
|
||||
<PageHeader path={[{ text: 'Mirroring and cloning' }]} headingElement="h2" className="mb-3" />
|
||||
<RepoSettingsOptions repo={repo} />
|
||||
<Container className="repo-settings-mirror-page">
|
||||
{error && <ErrorAlert error={error} />}
|
||||
|
||||
@ -319,15 +319,16 @@ export const RepoSettingsMirrorPage: FC<RepoSettingsMirrorPageProps> = props =>
|
||||
<Label>
|
||||
{' '}
|
||||
Remote repository URL{' '}
|
||||
<small className="text-info">
|
||||
<Icon aria-hidden={true} svgPath={mdiLock} /> Only visible to site admins
|
||||
<small className="text-muted">
|
||||
<Icon aria-hidden={true} svgPath={mdiLock} className="text-warning" /> Only visible to site
|
||||
admins
|
||||
</small>
|
||||
</Label>
|
||||
<Input value={repo.mirrorInfo.remoteURL || '(unknown)'} readOnly={true} className="mb-0" />
|
||||
{repo.viewerCanAdminister && (
|
||||
<small className="form-text text-muted">
|
||||
Configure repository mirroring in{' '}
|
||||
<Link to="/site-admin/external-services">external services</Link>.
|
||||
<Link to="/site-admin/external-services">code host connections</Link>.
|
||||
</small>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@ -3,10 +3,9 @@ import { type FC, useCallback, useEffect, useState } from 'react'
|
||||
import { noop } from 'lodash'
|
||||
|
||||
import { useMutation, useQuery } from '@sourcegraph/http-client'
|
||||
import { Button, Container, ErrorAlert, H2, LoadingSpinner, PageHeader, renderError, Text } from '@sourcegraph/wildcard'
|
||||
import { Button, Container, ErrorAlert, H3, LoadingSpinner, renderError, Text } from '@sourcegraph/wildcard'
|
||||
|
||||
import { CopyableText } from '../../components/CopyableText'
|
||||
import { PageTitle } from '../../components/PageTitle'
|
||||
import type {
|
||||
ExcludeRepoFromExternalServicesResult,
|
||||
ExcludeRepoFromExternalServicesVariables,
|
||||
@ -23,16 +22,13 @@ import { EXCLUDE_REPO_FROM_EXTERNAL_SERVICES, FETCH_SETTINGS_AREA_REPOSITORY_GQL
|
||||
import { ExternalServiceEntry } from './components/ExternalServiceEntry'
|
||||
import { RedirectionAlert } from './components/RedirectionAlert'
|
||||
|
||||
import styles from './RepoSettingsOptionsPage.module.scss'
|
||||
import styles from './RepoSettingsOptions.module.scss'
|
||||
|
||||
interface Props {
|
||||
repo: SettingsAreaRepositoryFields
|
||||
}
|
||||
|
||||
/**
|
||||
* The repository settings options page.
|
||||
*/
|
||||
export const RepoSettingsOptionsPage: FC<Props> = ({ repo }) => {
|
||||
export const RepoSettingsOptions: FC<Props> = ({ repo }) => {
|
||||
useEffect(() => {
|
||||
eventLogger.logViewEvent('RepoSettings')
|
||||
})
|
||||
@ -71,12 +67,10 @@ export const RepoSettingsOptionsPage: FC<Props> = ({ repo }) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<PageTitle title="Repository settings" />
|
||||
<PageHeader path={[{ text: 'Settings' }]} headingElement="h2" className="mb-3" />
|
||||
<Container className="repo-settings-options-page">
|
||||
<H2 className="mb-3">Repository name</H2>
|
||||
<Container className="mb-3 repo-settings-options-page">
|
||||
<H3>Repository name</H3>
|
||||
<CopyableText className="mb-3" text={repo.name} size={repo.name.length} />
|
||||
<H2 className="mb-3">Code host connections</H2>
|
||||
<H3>Code host connections</H3>
|
||||
{loading && <LoadingSpinner />}
|
||||
{error && <ErrorAlert error={error} />}
|
||||
{services && services.length > 0 && (
|
||||
@ -1,5 +1,7 @@
|
||||
import { lazyComponent } from '@sourcegraph/shared/src/util/lazyComponent'
|
||||
|
||||
import { RedirectRoute } from '../../components/RedirectRoute'
|
||||
|
||||
import type { RepoSettingsAreaRoute } from './RepoSettingsArea'
|
||||
|
||||
export const repoSettingsAreaPath = '/-/settings/*'
|
||||
@ -7,7 +9,7 @@ export const repoSettingsAreaPath = '/-/settings/*'
|
||||
export const repoSettingsAreaRoutes: readonly RepoSettingsAreaRoute[] = [
|
||||
{
|
||||
path: '',
|
||||
render: lazyComponent(() => import('./RepoSettingsOptionsPage'), 'RepoSettingsOptionsPage'),
|
||||
render: lazyComponent(() => import('./RepoSettingsMirrorPage'), 'RepoSettingsMirrorPage'),
|
||||
},
|
||||
{
|
||||
path: '/index',
|
||||
@ -15,6 +17,9 @@ export const repoSettingsAreaRoutes: readonly RepoSettingsAreaRoute[] = [
|
||||
},
|
||||
{
|
||||
path: '/mirror',
|
||||
render: lazyComponent(() => import('./RepoSettingsMirrorPage'), 'RepoSettingsMirrorPage'),
|
||||
// The /mirror page used to be separate but we combined this one and the
|
||||
// '' route above, so we redirect here in case people still link to this
|
||||
// page.
|
||||
render: () => <RedirectRoute getRedirectURL={() => '..'} />,
|
||||
},
|
||||
]
|
||||
@ -8,17 +8,12 @@ export const settingsGroup = {
|
||||
{
|
||||
to: '',
|
||||
exact: true,
|
||||
label: 'Options',
|
||||
label: 'Mirroring',
|
||||
},
|
||||
{
|
||||
to: '/index',
|
||||
exact: true,
|
||||
label: 'Indexing',
|
||||
},
|
||||
{
|
||||
to: '/mirror',
|
||||
exact: true,
|
||||
label: 'Mirroring',
|
||||
label: 'Search Indexing',
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user