Add empty state for Compare and PR views (#225)

This commit is contained in:
Tan Nhu 2023-01-17 17:12:53 -08:00 committed by GitHub
parent eed7b2c29b
commit 09e3c89657
12 changed files with 86 additions and 32 deletions

View File

@ -13,6 +13,7 @@ import { PipeSeparator } from 'components/PipeSeparator/PipeSeparator'
import type { DiffFileEntry } from 'utils/types' import type { DiffFileEntry } from 'utils/types'
// import { useRawDiff } from 'services/code' // import { useRawDiff } from 'services/code'
import { DIFF2HTML_CONFIG, ViewStyle } from 'components/DiffViewer/DiffViewerUtils' import { DIFF2HTML_CONFIG, ViewStyle } from 'components/DiffViewer/DiffViewerUtils'
import { NoResultCard } from 'components/NoResultCard/NoResultCard'
import type { TypesPullReq } from 'services/code' import type { TypesPullReq } from 'services/code'
import { PullRequestTabContentWrapper } from '../../pages/PullRequest/PullRequestTabContentWrapper' import { PullRequestTabContentWrapper } from '../../pages/PullRequest/PullRequestTabContentWrapper'
import { ChangesDropdown } from './ChangesDropdown' import { ChangesDropdown } from './ChangesDropdown'
@ -95,8 +96,6 @@ export const Changes: React.FC<ChangesProps> = ({
) )
return ( return (
// TODO: Move PullRequestTabContentWrapper out of this file
// as it's a reusable component and not just used for PR
<PullRequestTabContentWrapper loading={loading} error={error} onRetry={refetch} className={css.wrapper}> <PullRequestTabContentWrapper loading={loading} error={error} onRetry={refetch} className={css.wrapper}>
{diffs?.length ? ( {diffs?.length ? (
<> <>
@ -165,7 +164,14 @@ export const Changes: React.FC<ChangesProps> = ({
</Layout.Vertical> </Layout.Vertical>
</> </>
) : ( ) : (
<Container></Container> <Container>
<NoResultCard
showWhen={() => diffs?.length === 0}
forSearch={true}
title={getString('noChanges')}
emptySearchMessage={getString('noChangesPR')}
/>
</Container>
)} )}
</PullRequestTabContentWrapper> </PullRequestTabContentWrapper>
) )

View File

@ -6,6 +6,7 @@ import { useStrings } from 'framework/strings'
import { useAppContext } from 'AppContext' import { useAppContext } from 'AppContext'
import type { RepoCommit } from 'services/code' import type { RepoCommit } from 'services/code'
import { CommitActions } from 'components/CommitActions/CommitActions' import { CommitActions } from 'components/CommitActions/CommitActions'
import { NoResultCard } from 'components/NoResultCard/NoResultCard'
import { ThreadSection } from 'components/ThreadSection/ThreadSection' import { ThreadSection } from 'components/ThreadSection/ThreadSection'
import { formatDate } from 'utils/Utils' import { formatDate } from 'utils/Utils'
import { CodeIcon, GitInfoProps } from 'utils/GitUtils' import { CodeIcon, GitInfoProps } from 'utils/GitUtils'
@ -13,9 +14,11 @@ import css from './CommitsView.module.scss'
interface CommitsViewProps extends Pick<GitInfoProps, 'repoMetadata'> { interface CommitsViewProps extends Pick<GitInfoProps, 'repoMetadata'> {
commits: RepoCommit[] commits: RepoCommit[]
emptyTitle: string
emptyMessage: string
} }
export function CommitsView({ repoMetadata, commits }: CommitsViewProps) { export function CommitsView({ repoMetadata, commits, emptyTitle, emptyMessage }: CommitsViewProps) {
const { getString } = useStrings() const { getString } = useStrings()
const { routes } = useAppContext() const { routes } = useAppContext()
const columns: Column<RepoCommit>[] = useMemo( const columns: Column<RepoCommit>[] = useMemo(
@ -76,25 +79,32 @@ export function CommitsView({ repoMetadata, commits }: CommitsViewProps) {
return ( return (
<Container className={css.container}> <Container className={css.container}>
{Object.entries(commitsGroupedByDate).map(([date, commitsByDate]) => { {!!commits.length &&
return ( Object.entries(commitsGroupedByDate).map(([date, commitsByDate]) => {
<ThreadSection return (
key={date} <ThreadSection
title={ key={date}
<Text icon={CodeIcon.Commit} iconProps={{ size: 20 }} color={Color.GREY_500} className={css.label}> title={
{getString('commitsOn', { date })} <Text icon={CodeIcon.Commit} iconProps={{ size: 20 }} color={Color.GREY_500} className={css.label}>
</Text> {getString('commitsOn', { date })}
}> </Text>
<Table<RepoCommit> }>
className={css.table} <Table<RepoCommit>
hideHeaders className={css.table}
columns={columns} hideHeaders
data={orderBy(commitsByDate || [], ['author.when'], ['desc'])} columns={columns}
getRowClassName={() => css.row} data={orderBy(commitsByDate || [], ['author.when'], ['desc'])}
/> getRowClassName={() => css.row}
</ThreadSection> />
) </ThreadSection>
})} )
})}
<NoResultCard
showWhen={() => commits?.length === 0}
forSearch={true}
title={emptyTitle}
emptySearchMessage={emptyMessage}
/>
</Container> </Container>
) )
} }

View File

@ -1,5 +1,5 @@
.main { .main {
> div { > div {
height: calc(100vh - var(--page-header-height, 64px) - 120px) !important; height: calc(100vh - var(--page-header-height, 64px) - 180px) !important;
} }
} }

View File

@ -9,7 +9,9 @@ import css from './NoResultCard.module.scss'
interface NoResultCardProps { interface NoResultCardProps {
showWhen: () => boolean showWhen: () => boolean
forSearch: boolean forSearch: boolean
title?: string
message?: string message?: string
emptySearchMessage?: string
buttonText?: string buttonText?: string
buttonIcon?: IconName buttonIcon?: IconName
onButtonClick?: () => void onButtonClick?: () => void
@ -18,7 +20,9 @@ interface NoResultCardProps {
export const NoResultCard: React.FC<NoResultCardProps> = ({ export const NoResultCard: React.FC<NoResultCardProps> = ({
showWhen, showWhen,
forSearch, forSearch,
title,
message, message,
emptySearchMessage,
buttonText = '', buttonText = '',
buttonIcon = CodeIcon.Add, buttonIcon = CodeIcon.Add,
onButtonClick = noop onButtonClick = noop
@ -33,8 +37,10 @@ export const NoResultCard: React.FC<NoResultCardProps> = ({
<Container className={css.main}> <Container className={css.main}>
<NoDataCard <NoDataCard
image={emptyStateImage} image={emptyStateImage}
messageTitle={forSearch ? getString('noResultTitle') : undefined} messageTitle={forSearch ? title || getString('noResultTitle') : undefined}
message={forSearch ? getString('noResultMessage') : message || getString('noResultMessage')} message={
forSearch ? emptySearchMessage || getString('noResultMessage') : message || getString('noResultMessage')
}
button={ button={
forSearch ? undefined : ( forSearch ? undefined : (
<Button <Button

View File

@ -44,6 +44,8 @@ export interface StringsMap {
commits: string commits: string
commitsOn: string commitsOn: string
compare: string compare: string
compareEmptyDiffMessage: string
compareEmptyDiffTitle: string
comparingChanges: string comparingChanges: string
confirm: string confirm: string
confirmDeleteWebhook: string confirmDeleteWebhook: string
@ -117,6 +119,11 @@ export interface StringsMap {
newRepo: string newRepo: string
next: string next: string
noAccount: string noAccount: string
noChanges: string
noChangesPR: string
noCommits: string
noCommitsMessage: string
noCommitsPR: string
noResultMessage: string noResultMessage: string
noResultTitle: string noResultTitle: string
noWebHooks: string noWebHooks: string

View File

@ -267,3 +267,10 @@ repoEmptyMarkdown: |
You might need [to create an API token](CREATE_API_TOKEN_URL) in order to pull from or push into this repository. You might need [to create an API token](CREATE_API_TOKEN_URL) in order to pull from or push into this repository.
webhookEmpty: Here is no WebHooks. Try to webhookEmpty: Here is no WebHooks. Try to
compareEmptyDiffTitle: There isn't anything to compare
compareEmptyDiffMessage: Two branches are identical.
noCommits: There is no commits
noCommitsMessage: This repository does not have any commits yet.
noCommitsPR: This Pull Request does not have commit history.
noChanges: There is no changes
noChangesPR: This Pull Request does not have any changes.

View File

@ -95,7 +95,12 @@ export default function Compare() {
title: getString('commits'), title: getString('commits'),
panel: ( panel: (
<Container padding="xlarge"> <Container padding="xlarge">
{!!commits?.length && <CommitsView commits={commits} repoMetadata={repoMetadata} />} <CommitsView
commits={commits || []}
repoMetadata={repoMetadata}
emptyTitle={getString('compareEmptyDiffTitle')}
emptyMessage={getString('compareEmptyDiffMessage')}
/>
<ResourceListingPagination response={response} page={page} setPage={setPage} /> <ResourceListingPagination response={response} page={page} setPage={setPage} />
</Container> </Container>
) )

View File

@ -4,6 +4,7 @@ import type { RepoCommit } from 'services/code'
import type { GitInfoProps } from 'utils/GitUtils' import type { GitInfoProps } from 'utils/GitUtils'
import { voidFn, LIST_FETCHING_LIMIT } from 'utils/Utils' import { voidFn, LIST_FETCHING_LIMIT } from 'utils/Utils'
import { usePageIndex } from 'hooks/usePageIndex' import { usePageIndex } from 'hooks/usePageIndex'
import { useStrings } from 'framework/strings'
import { ResourceListingPagination } from 'components/ResourceListingPagination/ResourceListingPagination' import { ResourceListingPagination } from 'components/ResourceListingPagination/ResourceListingPagination'
import { CommitsView } from 'components/CommitsView/CommitsView' import { CommitsView } from 'components/CommitsView/CommitsView'
import { PullRequestTabContentWrapper } from '../PullRequestTabContentWrapper' import { PullRequestTabContentWrapper } from '../PullRequestTabContentWrapper'
@ -14,6 +15,7 @@ export const PullRequestCommits: React.FC<Pick<GitInfoProps, 'repoMetadata' | 'p
}) => { }) => {
const limit = LIST_FETCHING_LIMIT const limit = LIST_FETCHING_LIMIT
const [page, setPage] = usePageIndex() const [page, setPage] = usePageIndex()
const { getString } = useStrings()
const { const {
data: commits, data: commits,
error, error,
@ -33,7 +35,12 @@ export const PullRequestCommits: React.FC<Pick<GitInfoProps, 'repoMetadata' | 'p
return ( return (
<PullRequestTabContentWrapper loading={loading} error={error} onRetry={voidFn(refetch)}> <PullRequestTabContentWrapper loading={loading} error={error} onRetry={voidFn(refetch)}>
{!!commits?.length && <CommitsView commits={commits} repoMetadata={repoMetadata} />} <CommitsView
commits={commits || []}
repoMetadata={repoMetadata}
emptyTitle={getString('noCommits')}
emptyMessage={getString('noCommitsPR')}
/>
<ResourceListingPagination response={response} page={page} setPage={setPage} /> <ResourceListingPagination response={response} page={page} setPage={setPage} />
</PullRequestTabContentWrapper> </PullRequestTabContentWrapper>

View File

@ -26,7 +26,7 @@ import { SearchInputWithSpinner } from 'components/SearchInputWithSpinner/Search
import { useAppContext } from 'AppContext' import { useAppContext } from 'AppContext'
import { NoResultCard } from 'components/NoResultCard/NoResultCard' import { NoResultCard } from 'components/NoResultCard/NoResultCard'
import { ResourceListingPagination } from 'components/ResourceListingPagination/ResourceListingPagination' import { ResourceListingPagination } from 'components/ResourceListingPagination/ResourceListingPagination'
import emptyStateImage from './empty-state.svg' import noRepoImage from './no-repo.svg'
import css from './RepositoriesListing.module.scss' import css from './RepositoriesListing.module.scss'
export default function RepositoriesListing() { export default function RepositoriesListing() {
@ -131,7 +131,7 @@ export default function RepositoriesListing() {
retryOnError={voidFn(refetch)} retryOnError={voidFn(refetch)}
noData={{ noData={{
when: () => repositories?.length === 0 && searchTerm === undefined, when: () => repositories?.length === 0 && searchTerm === undefined,
image: emptyStateImage, image: noRepoImage,
message: getString('repos.noDataMessage'), message: getString('repos.noDataMessage'),
button: NewRepoButton button: NewRepoButton
}}> }}>
@ -141,6 +141,7 @@ export default function RepositoriesListing() {
<FlexExpander /> <FlexExpander />
<SearchInputWithSpinner loading={loading} query={searchTerm} setQuery={setSearchTerm} /> <SearchInputWithSpinner loading={loading} query={searchTerm} setQuery={setSearchTerm} />
</Layout.Horizontal> </Layout.Horizontal>
<Container margin={{ top: 'medium' }}> <Container margin={{ top: 'medium' }}>
{!!repositories?.length && ( {!!repositories?.length && (
<Table<TypesRepository> <Table<TypesRepository>

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 55 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 33 KiB

View File

@ -70,7 +70,12 @@ export default function RepositoryCommits() {
</Layout.Horizontal> </Layout.Horizontal>
</Container> </Container>
<CommitsView commits={commits} repoMetadata={repoMetadata} /> <CommitsView
commits={commits}
repoMetadata={repoMetadata}
emptyTitle={getString('noCommits')}
emptyMessage={getString('noCommitsMessage')}
/>
<ResourceListingPagination response={response} page={page} setPage={setPage} /> <ResourceListingPagination response={response} page={page} setPage={setPage} />
</Container> </Container>