Skip to content

Commit 3477b99

Browse files
anurag2787arkid15rkasya
authored
Fix #1792 Added a tooltip to show the entire number on hover (#1855)
* Added a tooltip to show the entire number on hover * Run make check * add generated package-lock.json files from make check-test * Remove unnecessary package-lock.json files * handled invalid or undefined values * Update code * Update tests --------- Co-authored-by: Arkadii Yakovets <arkadii.yakovets@owasp.org> Co-authored-by: Kate Golovanova <kate@kgthreads.com> Co-authored-by: Arkadii Yakovets <2201626+arkid15r@users.noreply.github.com>
1 parent f1a26a6 commit 3477b99

File tree

4 files changed

+56
-22
lines changed

4 files changed

+56
-22
lines changed

frontend/__tests__/unit/components/InfoItem.test.tsx

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { faUser } from '@fortawesome/free-solid-svg-icons'
22
import { render, screen } from '@testing-library/react'
33
import millify from 'millify'
4+
import React from 'react'
45
import { pluralize } from 'utils/pluralize'
56
import InfoItem from 'components/InfoItem'
67

@@ -9,6 +10,14 @@ jest.mock('utils/pluralize', () => ({
910
pluralize: jest.fn(),
1011
}))
1112

13+
jest.mock('@heroui/tooltip', () => ({
14+
Tooltip: ({ children, content }: { children: React.ReactNode; content: string }) => (
15+
<span data-testid="tooltip" title={content}>
16+
{children}
17+
</span>
18+
),
19+
}))
20+
1221
const mockMillify = millify as jest.Mock
1322
const mockPluralize = pluralize as jest.Mock
1423

@@ -39,8 +48,13 @@ describe('InfoItem', () => {
3948
})
4049

4150
it('respects precision prop when formatting value', () => {
51+
mockMillify.mockReturnValue('15.4k')
52+
mockPluralize.mockReturnValue('15430 views')
53+
4254
render(<InfoItem icon={faUser} unit="view" value={15430} precision={3} />)
55+
4356
expect(mockMillify).toHaveBeenCalledWith(15430, { precision: 3 })
57+
expect(screen.getByText('15.4k')).toBeInTheDocument()
4458
})
4559

4660
it('handles value = 0 properly', () => {
@@ -59,28 +73,47 @@ describe('InfoItem', () => {
5973

6074
render(<InfoItem icon={faUser} unit="like" value={5} />)
6175

62-
const container = screen.getByText('5').closest('div')
63-
expect(container).toHaveClass('flex items-center justify-between')
76+
const container = screen.getByText('5 likes').closest('div')
77+
expect(container).toHaveClass('flex', 'items-center', 'justify-between')
6478

65-
const label = screen.getByText(/like/i).closest('span')
66-
expect(label).toHaveClass('flex items-center')
79+
const nameSpan = screen.getByText('5 likes').closest('span')
80+
expect(nameSpan).toHaveClass('flex', 'items-center')
6781

6882
const icon = screen.getByRole('img', { hidden: true })
69-
expect(icon).toHaveClass('mr-2 h-4 w-4')
83+
expect(icon).toHaveClass('mr-2', 'h-4', 'w-4')
84+
85+
const valueSpan = screen.getByText('5').closest('span')
86+
expect(valueSpan).toHaveClass('font-medium')
7087
})
7188

7289
it('uses default precision = 1 when not provided', () => {
90+
mockMillify.mockReturnValue('1k')
91+
mockPluralize.mockReturnValue('1010 stars')
92+
7393
render(<InfoItem icon={faUser} unit="star" value={1010} />)
94+
7495
expect(mockMillify).toHaveBeenCalledWith(1010, { precision: 1 })
7596
})
7697

77-
it('renders both text and number correctly', () => {
98+
it('creates tooltip with correct content', () => {
7899
mockMillify.mockReturnValue('7.5k')
79-
mockPluralize.mockReturnValue('7.5 stars')
100+
mockPluralize.mockReturnValue('7.5k stars')
80101

81102
render(<InfoItem icon={faUser} unit="star" value={7500} />)
82103

104+
const tooltip = screen.getByTestId('tooltip')
105+
expect(tooltip).toHaveAttribute('title', '7,500 7.5k stars')
83106
expect(screen.getByText('7.5k')).toBeInTheDocument()
84-
expect(screen.getByText('7.5 stars')).toBeInTheDocument()
107+
})
108+
109+
it('handles zero value with proper tooltip content', () => {
110+
mockMillify.mockReturnValue('0')
111+
mockPluralize.mockReturnValue('0 items')
112+
113+
render(<InfoItem icon={faUser} unit="item" value={0} />)
114+
115+
const tooltip = screen.getByTestId('tooltip')
116+
expect(tooltip).toHaveAttribute('title', 'No 0 items')
117+
expect(screen.getByText('0')).toBeInTheDocument()
85118
})
86119
})

frontend/src/components/InfoBlock.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { IconProp } from '@fortawesome/fontawesome-svg-core'
22
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
3+
import { Tooltip } from '@heroui/tooltip'
34
import millify from 'millify'
45
import { pluralize } from 'utils/pluralize'
56

@@ -20,18 +21,19 @@ const InfoBlock = ({
2021
unit?: string
2122
value: number
2223
}) => {
23-
const name = pluralizedName
24-
? pluralize(value, unit || '', pluralizedName)
25-
: pluralize(value, unit || '')
24+
const name = pluralizedName ? pluralize(value, unit, pluralizedName) : pluralize(value, unit)
2625
const formattedValue = value ? `${millify(value, { precision })} ${name}` : `No ${name}`
26+
const tooltipValue = value ? `${value.toLocaleString()} ${name}` : `No ${name}`
2727

2828
return (
2929
<div className={`flex ${className}`}>
3030
<FontAwesomeIcon icon={icon} className="mr-3 mt-1 w-5" />
3131
<div>
3232
<div className="text-sm md:text-base">
3333
{label && <div className="text-sm font-medium">{label}</div>}
34-
{formattedValue}
34+
<Tooltip content={tooltipValue} delay={100} closeDelay={100} showArrow placement="top">
35+
{formattedValue}
36+
</Tooltip>
3537
</div>
3638
</div>
3739
</div>

frontend/src/components/InfoItem.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { IconDefinition } from '@fortawesome/free-solid-svg-icons'
22
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
3+
import { Tooltip } from '@heroui/tooltip'
34
import millify from 'millify'
45
import { pluralize } from 'utils/pluralize'
56

@@ -18,14 +19,17 @@ const InfoItem = ({
1819
}) => {
1920
const name = pluralizedName ? pluralize(value, unit, pluralizedName) : pluralize(value, unit)
2021
const formattedValue = millify(value, { precision })
22+
const tooltipValue = value ? `${value.toLocaleString()} ${name}` : `No ${name}`
2123

2224
return (
2325
<div className="flex items-center justify-between">
2426
<span className="flex items-center">
2527
<FontAwesomeIcon icon={icon} className="mr-2 h-4 w-4" />
2628
{name}
2729
</span>
28-
<span className="font-medium">{formattedValue}</span>
30+
<Tooltip content={tooltipValue} delay={100} closeDelay={100} showArrow placement="top">
31+
<span className="font-medium">{formattedValue}</span>
32+
</Tooltip>
2933
</div>
3034
)
3135
}

frontend/src/components/RepositoriesCard.tsx

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -64,23 +64,18 @@ const RepositoryItem = ({ details }: { details: RepositoryCardProps }) => {
6464
</button>
6565

6666
<div className="space-y-2 text-sm">
67-
<InfoItem icon={faStar} pluralizedName="Stars" unit="Stars" value={details.starsCount} />
68-
<InfoItem
69-
icon={faCodeFork}
70-
pluralizedName="Forks"
71-
unit="Forks"
72-
value={details.forksCount}
73-
/>
67+
<InfoItem icon={faStar} pluralizedName="Stars" unit="Star" value={details.starsCount} />
68+
<InfoItem icon={faCodeFork} pluralizedName="Forks" unit="Fork" value={details.forksCount} />
7469
<InfoItem
7570
icon={faUsers}
7671
pluralizedName="Contributors"
77-
unit="Contributors"
72+
unit="Contributor"
7873
value={details.contributorsCount}
7974
/>
8075
<InfoItem
8176
icon={faExclamationCircle}
8277
pluralizedName="Issues"
83-
unit="Issues"
78+
unit="Issue"
8479
value={details.openIssuesCount}
8580
/>
8681
</div>

0 commit comments

Comments
 (0)