Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/components/ContributionHeatmap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
TEXT_OPACITY,
scrollbarSx,
} from '../theme';
import { pluralize } from '../utils/format';

interface ContributionData {
date: string;
Expand Down Expand Up @@ -146,7 +147,7 @@ const ContributionHeatmap: React.FC<ContributionHeatmapProps> = ({
onClick={() => onDayClick?.(activity.date)}
style={{ cursor: 'pointer' }}
role="button"
aria-label={`View ${activity.count} contribution${activity.count !== 1 ? 's' : ''} on ${activity.date}`}
aria-label={`View ${pluralize(activity.count, 'contribution')} on ${activity.date}`}
>
{highlighted}
</g>
Expand All @@ -155,7 +156,7 @@ const ContributionHeatmap: React.FC<ContributionHeatmapProps> = ({
);
return (
<Tooltip
title={`${activity.count} contribution${activity.count !== 1 ? 's' : ''} on ${new Date(activity.date).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })}${clickable ? ' — click to view PRs' : ''}`}
title={`${pluralize(activity.count, 'contribution')} on ${new Date(activity.date).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })}${clickable ? ' — click to view PRs' : ''}`}
arrow
placement="top"
enterDelay={0}
Expand Down
3 changes: 2 additions & 1 deletion src/components/miners/MinerPrScoreDetail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
OpenInNew as OpenInNewIcon,
} from '@mui/icons-material';
import { linkResetSx, useLinkBehavior } from '../common/linkBehavior';
import { pluralize } from '../../utils/format';
import { usePullRequestDetails, type CommitLog } from '../../api';
import { STATUS_COLORS, tooltipSlotProps } from '../../theme';
import { parseNumber } from '../../utils/ExplorerUtils';
Expand Down Expand Up @@ -201,7 +202,7 @@ const MinerPrScoreDetail: React.FC<MinerPrScoreDetailProps> = ({
{[
baseScore > 0 && `base ${baseScore.toFixed(2)}`,
`+${pr.additions} / -${pr.deletions}`,
`${pr.commitCount} commit${pr.commitCount !== 1 ? 's' : ''}`,
pluralize(pr.commitCount, 'commit'),
pr.tokenScore != null &&
`tokens ${parseNumber(pr.tokenScore).toFixed(2)}`,
pr.totalNodesScored != null &&
Expand Down
5 changes: 3 additions & 2 deletions src/pages/RepositoriesPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { useAllPrs, useAllMiners, useReposAndWeights } from '../api';
import { type CommitLog } from '../api/models/Dashboard';
import { getRepositoryOwnerAvatarSrc } from '../utils/avatar';
import { buildRepoDiscoveryRollupFromMiners } from '../utils/ExplorerUtils';
import { pluralize } from '../utils/format';
import { isMergedPr } from '../utils/prStatus';

const FONTS = { mono: '"JetBrains Mono", monospace' } as const;
Expand Down Expand Up @@ -509,8 +510,8 @@ const RepositoriesPage: React.FC = () => {
whiteSpace: 'nowrap',
}}
>
{repo.collateral.toFixed(1)} ({repo.openPRs} PR
{repo.openPRs !== 1 ? 's' : ''})
{repo.collateral.toFixed(1)} (
{pluralize(repo.openPRs, 'PR')})
</Typography>
}
/>
Expand Down
3 changes: 2 additions & 1 deletion src/pages/RepositoryDetailsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import React, {
} from 'react';
import { useSearchParams, useNavigate } from 'react-router-dom';
import { getRepositoryOwnerAvatarSrc } from '../utils/avatar';
import { pluralize } from '../utils/format';
import {
Alert,
Box,
Expand Down Expand Up @@ -272,7 +273,7 @@ const RepositoryDetailsPage: React.FC = () => {
lineHeight: 1.4,
}}
>
{openBounties} {openBounties === 1 ? 'bounty' : 'bounties'}
{pluralize(openBounties, 'bounty', 'bounties')}
</Box>
) : null}
</Box>
Expand Down
4 changes: 2 additions & 2 deletions src/pages/dashboard/views/FeaturedWorkRepoCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import GitHubIcon from '@mui/icons-material/GitHub';
import { Avatar, Box, Stack, Tooltip, Typography } from '@mui/material';
import { type Theme } from '@mui/material/styles';
import { getGithubAvatarSrc } from '../../../utils';
import { pluralize } from '../../../utils/format';
import { type FeaturedWorkRepo, type FeaturedWorkPr } from '../dashboardData';
import FeaturedWorkPrRow from './FeaturedWorkPrRow';
import {
Expand All @@ -25,8 +26,7 @@ interface FeaturedWorkRepoCardProps {
const extractOwner = (repository: string): string =>
repository.split('/')[0] || '';

const formatPrCount = (count: number): string =>
`${count} PR${count !== 1 ? 's' : ''}`;
const formatPrCount = (count: number): string => pluralize(count, 'PR');

const formatTotalScore = (score: number): string => score.toFixed(1);

Expand Down
3 changes: 2 additions & 1 deletion src/pages/search/SearchPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Alert, Box, Stack, Tab, Tabs, Typography } from '@mui/material';
import { useLocation, useSearchParams } from 'react-router-dom';
import { BackButton, SEO } from '../../components';
import { GlobalSearchBar, Page } from '../../components/layout';
import { pluralize } from '../../utils/format';
import IssuesTab from './IssuesTab';
import MinerTab from './MinerTab';
import PullRequestsTab from './PullRequestsTab';
Expand Down Expand Up @@ -209,7 +210,7 @@ const SearchPage: React.FC = () => {
<Typography variant="body2" color="text.secondary">
{isAnySectionLoading && totalResults === 0
? `Loading search results for "${query}"...`
: `${activeResultCount} result${activeResultCount === 1 ? '' : 's'} in ${activeTabLabel} for "${query}"`}
: `${pluralize(activeResultCount, 'result')} in ${activeTabLabel} for "${query}"`}
</Typography>

<Box
Expand Down
11 changes: 11 additions & 0 deletions src/utils/format.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,3 +104,14 @@ export const credibilityColor = (cred: number): string => {

export const getLowerText = (value: string | null | undefined): string =>
(value ?? '').toLowerCase();

/**
* `1 issue` / `2 issues`. Pass an explicit `plural` for irregular forms,
* e.g. `pluralize(n, 'repository', 'repositories')`.
*/
export const pluralize = (
count: number,
singular: string,
plural?: string,
): string =>
count === 1 ? `${count} ${singular}` : `${count} ${plural ?? `${singular}s`}`;
5 changes: 3 additions & 2 deletions src/utils/repoConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
* to the default below.
*/
import type { RepositoryConfig } from '../api/models/Dashboard';
import { pluralize } from './format';

type RepoConfigFormat =
| 'integer'
Expand Down Expand Up @@ -347,9 +348,9 @@ export function formatRepoConfigValue(
case 'multiplier':
return `${value}×`;
case 'days':
return `${value} ${value === 1 ? 'day' : 'days'}`;
return pluralize(value, 'day');
case 'hours':
return `${value} ${value === 1 ? 'hr' : 'hrs'}`;
return pluralize(value, 'hr');
case 'integer':
case 'score':
case 'decimal':
Expand Down
Loading