mirror of
https://github.com/sourcegraph/sourcegraph.git
synced 2026-02-06 19:21:50 +00:00
extract commit list (into TreeCommits) from TreePage (#45883)
TreePage was getting big. There is no behavior or UI change, this is just a refactor.
This commit is contained in:
parent
33f0bc372f
commit
39703ad1af
@ -17,19 +17,6 @@
|
||||
max-width: var(--media-xl);
|
||||
}
|
||||
|
||||
.git-commit-node {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
|
||||
&-message-subject {
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
:global(.btn) {
|
||||
opacity: 0.85;
|
||||
}
|
||||
}
|
||||
|
||||
.container {
|
||||
overflow-y: auto;
|
||||
height: 100%;
|
||||
|
||||
@ -200,7 +200,7 @@ export const TreePage: React.FunctionComponent<React.PropsWithChildren<Props>> =
|
||||
}
|
||||
|
||||
// To start using the feature flag bellow, you can go to /site-admin/feature-flags and
|
||||
// create a new featureFlag named 'new-repo-page' and set its value to true.
|
||||
// create a new featureFlag named 'new-repo-page' and set its to true.
|
||||
// https://docs.sourcegraph.com/dev/how-to/use_feature_flags#create-a-feature-flag
|
||||
const [isNewRepoPageEnabled] = useFeatureFlag('new-repo-page')
|
||||
|
||||
|
||||
@ -1,12 +1,9 @@
|
||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import React, { useMemo } from 'react'
|
||||
|
||||
import classNames from 'classnames'
|
||||
import formatISO from 'date-fns/formatISO'
|
||||
import subYears from 'date-fns/subYears'
|
||||
import * as H from 'history'
|
||||
|
||||
import { ContributableMenu } from '@sourcegraph/client-api'
|
||||
import { dataOrThrowErrors, gql } from '@sourcegraph/http-client'
|
||||
import { ActionItem } from '@sourcegraph/shared/src/actions/ActionItem'
|
||||
import { ActionsContainer } from '@sourcegraph/shared/src/actions/ActionsContainer'
|
||||
import { FileDecorationsByPath } from '@sourcegraph/shared/src/api/extension/extensionHostApi'
|
||||
@ -15,62 +12,16 @@ import { TreeFields } from '@sourcegraph/shared/src/graphql-operations'
|
||||
import { PlatformContextProps } from '@sourcegraph/shared/src/platform/context'
|
||||
import { TelemetryProps } from '@sourcegraph/shared/src/telemetry/telemetryService'
|
||||
import { ThemeProps } from '@sourcegraph/shared/src/theme'
|
||||
import { Button, Heading, Link, useObservable, ErrorAlert } from '@sourcegraph/wildcard'
|
||||
import { Button, Heading, useObservable } from '@sourcegraph/wildcard'
|
||||
|
||||
import { getFileDecorations } from '../../backend/features'
|
||||
import { useShowMorePagination } from '../../components/FilteredConnection/hooks/useShowMorePagination'
|
||||
import {
|
||||
ConnectionContainer,
|
||||
ConnectionList,
|
||||
ConnectionLoading,
|
||||
ConnectionSummary,
|
||||
ShowMoreButton,
|
||||
SummaryContainer,
|
||||
} from '../../components/FilteredConnection/ui'
|
||||
import {
|
||||
GitCommitFields,
|
||||
TreeCommitsResult,
|
||||
TreeCommitsVariables,
|
||||
TreePageRepositoryFields,
|
||||
} from '../../graphql-operations'
|
||||
import { GitCommitNode } from '../commits/GitCommitNode'
|
||||
import { gitCommitFragment } from '../commits/RepositoryCommitsPage'
|
||||
import { TreePageRepositoryFields } from '../../graphql-operations'
|
||||
|
||||
import { TreeCommits } from './commits/TreeCommits'
|
||||
import { TreeEntriesSection } from './TreeEntriesSection'
|
||||
|
||||
import styles from './TreePage.module.scss'
|
||||
|
||||
const TREE_COMMITS_PER_PAGE = 10
|
||||
|
||||
const TREE_COMMITS_QUERY = gql`
|
||||
query TreeCommits(
|
||||
$repo: ID!
|
||||
$revspec: String!
|
||||
$first: Int
|
||||
$filePath: String
|
||||
$after: String
|
||||
$afterCursor: String
|
||||
) {
|
||||
node(id: $repo) {
|
||||
__typename
|
||||
... on Repository {
|
||||
commit(rev: $revspec) {
|
||||
ancestors(first: $first, path: $filePath, after: $after, afterCursor: $afterCursor) {
|
||||
nodes {
|
||||
...GitCommitFields
|
||||
}
|
||||
pageInfo {
|
||||
hasNextPage
|
||||
endCursor
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
${gitCommitFragment}
|
||||
`
|
||||
|
||||
interface TreePageContentProps extends ExtensionsControllerProps, ThemeProps, TelemetryProps, PlatformContextProps {
|
||||
filePath: string
|
||||
tree: TreeFields
|
||||
@ -88,62 +39,6 @@ export const TreePageContent: React.FunctionComponent<React.PropsWithChildren<Tr
|
||||
revision,
|
||||
...props
|
||||
}) => {
|
||||
const [showOlderCommits, setShowOlderCommits] = useState(false)
|
||||
const after = useMemo(() => (showOlderCommits ? null : formatISO(subYears(Date.now(), 1))), [showOlderCommits])
|
||||
|
||||
const { connection, error, loading, hasNextPage, fetchMore, refetchAll } = useShowMorePagination<
|
||||
TreeCommitsResult,
|
||||
TreeCommitsVariables,
|
||||
GitCommitFields
|
||||
>({
|
||||
query: TREE_COMMITS_QUERY,
|
||||
variables: {
|
||||
repo: repo.id,
|
||||
revspec: revision || '',
|
||||
first: TREE_COMMITS_PER_PAGE,
|
||||
filePath,
|
||||
after,
|
||||
afterCursor: null,
|
||||
},
|
||||
getConnection: result => {
|
||||
const { node } = dataOrThrowErrors(result)
|
||||
|
||||
if (!node) {
|
||||
return { nodes: [] }
|
||||
}
|
||||
if (node.__typename !== 'Repository') {
|
||||
return { nodes: [] }
|
||||
}
|
||||
if (!node.commit?.ancestors) {
|
||||
return { nodes: [] }
|
||||
}
|
||||
|
||||
return node.commit.ancestors
|
||||
},
|
||||
options: {
|
||||
fetchPolicy: 'cache-first',
|
||||
useAlternateAfterCursor: true,
|
||||
},
|
||||
})
|
||||
|
||||
// We store the refetchAll callback in a ref since it will update when
|
||||
// variables or result length change and we need to call an up-to-date
|
||||
// version in the useEffect below to refetch the proper results.
|
||||
//
|
||||
// TODO: See if we can make refetchAll stable
|
||||
const refetchAllRef = useRef(refetchAll)
|
||||
useEffect(() => {
|
||||
refetchAllRef.current = refetchAll
|
||||
}, [refetchAll])
|
||||
|
||||
useEffect(() => {
|
||||
if (showOlderCommits && refetchAllRef.current) {
|
||||
// Updating the variables alone is not enough to force a loading
|
||||
// indicator to show, so we need to refetch the results.
|
||||
refetchAllRef.current()
|
||||
}
|
||||
}, [showOlderCommits])
|
||||
|
||||
const fileDecorationsByPath =
|
||||
useObservable<FileDecorationsByPath>(
|
||||
useMemo(
|
||||
@ -159,26 +54,8 @@ export const TreePageContent: React.FunctionComponent<React.PropsWithChildren<Tr
|
||||
)
|
||||
) ?? {}
|
||||
|
||||
const onShowOlderCommitsClicked = useCallback((event: React.MouseEvent): void => {
|
||||
event.preventDefault()
|
||||
setShowOlderCommits(true)
|
||||
}, [])
|
||||
|
||||
const showAllCommits = (
|
||||
<Button
|
||||
className="test-tree-page-show-all-commits"
|
||||
onClick={onShowOlderCommitsClicked}
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
>
|
||||
Show commits older than one year
|
||||
</Button>
|
||||
)
|
||||
|
||||
const { extensionsController } = props
|
||||
|
||||
const showLinkToCommitsPage = connection && hasNextPage && connection.nodes.length > TREE_COMMITS_PER_PAGE
|
||||
|
||||
return (
|
||||
<>
|
||||
<section className={classNames('test-tree-entries mb-3', styles.section)}>
|
||||
@ -220,49 +97,7 @@ export const TreePageContent: React.FunctionComponent<React.PropsWithChildren<Tr
|
||||
</ActionsContainer>
|
||||
) : null}
|
||||
|
||||
<ConnectionContainer className={styles.section}>
|
||||
<Heading as="h3" styleAs="h2">
|
||||
Changes
|
||||
</Heading>
|
||||
|
||||
{error && <ErrorAlert error={error} className="w-100 mb-0" />}
|
||||
<ConnectionList className="list-group list-group-flush w-100">
|
||||
{connection?.nodes.map(node => (
|
||||
<GitCommitNode
|
||||
key={node.id}
|
||||
className={classNames('list-group-item', styles.gitCommitNode)}
|
||||
messageSubjectClassName={styles.gitCommitNodeMessageSubject}
|
||||
compact={true}
|
||||
wrapperElement="li"
|
||||
node={node}
|
||||
/>
|
||||
))}
|
||||
</ConnectionList>
|
||||
{loading && <ConnectionLoading />}
|
||||
{connection && (
|
||||
<SummaryContainer centered={true}>
|
||||
<ConnectionSummary
|
||||
centered={true}
|
||||
first={TREE_COMMITS_PER_PAGE}
|
||||
connection={connection}
|
||||
noun={showOlderCommits ? 'commit' : 'commit in the past year'}
|
||||
pluralNoun={showOlderCommits ? 'commits' : 'commits in the past year'}
|
||||
hasNextPage={hasNextPage}
|
||||
emptyElement={null}
|
||||
/>
|
||||
{hasNextPage ? (
|
||||
showLinkToCommitsPage ? (
|
||||
<Link to={`${repo.url}/-/commits${filePath ? `/${filePath}` : ''}`}>
|
||||
Show all commits
|
||||
</Link>
|
||||
) : (
|
||||
<ShowMoreButton centered={true} onClick={fetchMore} />
|
||||
)
|
||||
) : null}
|
||||
{!hasNextPage && !showOlderCommits ? showAllCommits : null}
|
||||
</SummaryContainer>
|
||||
)}
|
||||
</ConnectionContainer>
|
||||
<TreeCommits repo={repo} commitID={commitID} filePath={filePath} className={styles.section} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
12
client/web/src/repo/tree/commits/TreeCommits.module.scss
Normal file
12
client/web/src/repo/tree/commits/TreeCommits.module.scss
Normal file
@ -0,0 +1,12 @@
|
||||
.git-commit-node {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
|
||||
&-message-subject {
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
:global(.btn) {
|
||||
opacity: 0.85;
|
||||
}
|
||||
}
|
||||
187
client/web/src/repo/tree/commits/TreeCommits.tsx
Normal file
187
client/web/src/repo/tree/commits/TreeCommits.tsx
Normal file
@ -0,0 +1,187 @@
|
||||
import React, { useCallback, useState, useEffect, useMemo, useRef } from 'react'
|
||||
|
||||
import classNames from 'classnames'
|
||||
import formatISO from 'date-fns/formatISO'
|
||||
import subYears from 'date-fns/subYears'
|
||||
|
||||
import { dataOrThrowErrors, gql } from '@sourcegraph/http-client'
|
||||
import { ErrorAlert, Button, Heading, Link } from '@sourcegraph/wildcard'
|
||||
|
||||
import { useShowMorePagination } from '../../../components/FilteredConnection/hooks/useShowMorePagination'
|
||||
import {
|
||||
ConnectionContainer,
|
||||
SummaryContainer,
|
||||
ConnectionList,
|
||||
ConnectionLoading,
|
||||
ShowMoreButton,
|
||||
ConnectionSummary,
|
||||
} from '../../../components/FilteredConnection/ui'
|
||||
import {
|
||||
GitCommitFields,
|
||||
TreeCommitsResult,
|
||||
TreeCommitsVariables,
|
||||
TreePageRepositoryFields,
|
||||
} from '../../../graphql-operations'
|
||||
import { GitCommitNode } from '../../commits/GitCommitNode'
|
||||
import { gitCommitFragment } from '../../commits/RepositoryCommitsPage'
|
||||
|
||||
import styles from './TreeCommits.module.scss'
|
||||
|
||||
interface Props {
|
||||
repo: TreePageRepositoryFields
|
||||
commitID: string
|
||||
filePath: string
|
||||
className?: string
|
||||
}
|
||||
|
||||
const DEFAULT_FIRST = 10
|
||||
|
||||
/**
|
||||
* A list of commits in a tree (or in the entire repository for the root tree).
|
||||
*/
|
||||
export const TreeCommits: React.FunctionComponent<Props> = ({ repo, commitID, filePath, className }) => {
|
||||
const [showOlderCommits, setShowOlderCommits] = useState(false)
|
||||
const after = useMemo(() => (showOlderCommits ? null : formatISO(subYears(Date.now(), 1))), [showOlderCommits])
|
||||
|
||||
const { connection, error, loading, hasNextPage, fetchMore, refetchAll } = useShowMorePagination<
|
||||
TreeCommitsResult,
|
||||
TreeCommitsVariables,
|
||||
GitCommitFields
|
||||
>({
|
||||
query: gql`
|
||||
query TreeCommits(
|
||||
$repo: ID!
|
||||
$revspec: String!
|
||||
$first: Int
|
||||
$filePath: String
|
||||
$after: String
|
||||
$afterCursor: String
|
||||
) {
|
||||
node(id: $repo) {
|
||||
__typename
|
||||
... on Repository {
|
||||
commit(rev: $revspec) {
|
||||
ancestors(first: $first, path: $filePath, after: $after, afterCursor: $afterCursor) {
|
||||
nodes {
|
||||
...GitCommitFields
|
||||
}
|
||||
pageInfo {
|
||||
hasNextPage
|
||||
endCursor
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
${gitCommitFragment}
|
||||
`,
|
||||
variables: {
|
||||
repo: repo.id,
|
||||
revspec: commitID,
|
||||
first: DEFAULT_FIRST,
|
||||
filePath,
|
||||
after,
|
||||
afterCursor: null,
|
||||
},
|
||||
getConnection: result => {
|
||||
const { node } = dataOrThrowErrors(result)
|
||||
|
||||
if (!node) {
|
||||
return { nodes: [] }
|
||||
}
|
||||
if (node.__typename !== 'Repository') {
|
||||
return { nodes: [] }
|
||||
}
|
||||
if (!node.commit?.ancestors) {
|
||||
return { nodes: [] }
|
||||
}
|
||||
|
||||
return node.commit.ancestors
|
||||
},
|
||||
options: {
|
||||
fetchPolicy: 'cache-first',
|
||||
useAlternateAfterCursor: true,
|
||||
},
|
||||
})
|
||||
|
||||
// We store the refetchAll callback in a ref since it will update when
|
||||
// variables or result length change and we need to call an up-to-date
|
||||
// version in the useEffect below to refetch the proper results.
|
||||
//
|
||||
// TODO: See if we can make refetchAll stable
|
||||
const refetchAllRef = useRef(refetchAll)
|
||||
useEffect(() => {
|
||||
refetchAllRef.current = refetchAll
|
||||
}, [refetchAll])
|
||||
|
||||
useEffect(() => {
|
||||
if (showOlderCommits && refetchAllRef.current) {
|
||||
// Updating the variables alone is not enough to force a loading
|
||||
// indicator to show, so we need to refetch the results.
|
||||
refetchAllRef.current()
|
||||
}
|
||||
}, [showOlderCommits])
|
||||
|
||||
const onShowOlderCommitsClicked = useCallback((event: React.MouseEvent): void => {
|
||||
event.preventDefault()
|
||||
setShowOlderCommits(true)
|
||||
}, [])
|
||||
|
||||
const showAllCommits = (
|
||||
<Button
|
||||
className="test-tree-page-show-all-commits"
|
||||
onClick={onShowOlderCommitsClicked}
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
>
|
||||
Show commits older than one year
|
||||
</Button>
|
||||
)
|
||||
|
||||
const showLinkToCommitsPage = connection && hasNextPage && connection.nodes.length > DEFAULT_FIRST
|
||||
|
||||
return (
|
||||
<ConnectionContainer className={className}>
|
||||
<Heading as="h3" styleAs="h2">
|
||||
Changes
|
||||
</Heading>
|
||||
|
||||
{error && <ErrorAlert error={error} className="w-100 mb-0" />}
|
||||
<ConnectionList className="list-group list-group-flush w-100">
|
||||
{connection?.nodes.map(node => (
|
||||
<GitCommitNode
|
||||
key={node.id}
|
||||
className={classNames('list-group-item', styles.gitCommitNode)}
|
||||
messageSubjectClassName={styles.gitCommitNodeMessageSubject}
|
||||
compact={true}
|
||||
wrapperElement="li"
|
||||
node={node}
|
||||
/>
|
||||
))}
|
||||
</ConnectionList>
|
||||
{loading && <ConnectionLoading />}
|
||||
{connection && (
|
||||
<SummaryContainer centered={true}>
|
||||
<ConnectionSummary
|
||||
centered={true}
|
||||
first={DEFAULT_FIRST}
|
||||
connection={connection}
|
||||
noun={showOlderCommits ? 'commit' : 'commit in the past year'}
|
||||
pluralNoun={showOlderCommits ? 'commits' : 'commits in the past year'}
|
||||
hasNextPage={hasNextPage}
|
||||
emptyElement={null}
|
||||
/>
|
||||
{hasNextPage ? (
|
||||
showLinkToCommitsPage ? (
|
||||
<Link to={`${repo.url}/-/commits${filePath ? `/${filePath}` : ''}`}>Show all commits</Link>
|
||||
) : (
|
||||
<ShowMoreButton centered={true} onClick={fetchMore} />
|
||||
)
|
||||
) : null}
|
||||
{!hasNextPage && !showOlderCommits ? showAllCommits : null}
|
||||
</SummaryContainer>
|
||||
)}
|
||||
</ConnectionContainer>
|
||||
)
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user