-
Notifications
You must be signed in to change notification settings - Fork 6
feat: add total used traffic above the chart #3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -109,12 +109,13 @@ function CustomTrafficTooltip({ active, payload }: TooltipProps<number, string>) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export function TrafficChart({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| data, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| isLoading = false, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| error, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export function TrafficChart({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| data, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| isLoading = false, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| error, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| timeRange = "7d", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onTimeRangeChange | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onTimeRangeChange | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }: TrafficChartProps) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { t, i18n } = useTranslation() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -133,6 +134,21 @@ export function TrafficChart({ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, [data]) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const hasChartPoints = filteredData.length > 0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Calculate total traffic for the period | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const totalPeriodTraffic = React.useMemo(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!data || data.length === 0) return 0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return data.reduce((sum, point) => sum + point.total_traffic, 0) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, [data]) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Format bytes to human-readable | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const formatBytes = (bytes: number) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (bytes === 0) return '0 B' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const k = 1024 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const sizes = ['B', 'KB', 'MB', 'GB', 'TB'] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const i = Math.floor(Math.log(bytes) / Math.log(k)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return `${(bytes / Math.pow(k, i)).toFixed(2)} ${sizes[i]}` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const timeRangeOptions = [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { value: '12h', label: t('timeRange.12h') || '12h' }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { value: '24h', label: t('timeRange.24h') || '24h' }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -141,10 +157,25 @@ export function TrafficChart({ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { value: '90d', label: t('timeRange.90d') || '90d' }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const isRTL = i18n.language === 'fa' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Card className="overflow-hidden"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <CardHeader className="flex flex-col gap-4 space-y-0 border-b pb-4"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <CardTitle className="text-base sm:text-lg">{t('usage.title')}</CardTitle> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <CardHeader className="flex flex-1 flex-col gap-4 space-y-0 border-b pb-4"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div className={`flex w-full items-center flex-row justify-between gap-2 `}> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <CardTitle className="text-base sm:text-lg w-1/2"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {t('usage.title')} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </CardTitle> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div className="w-1/2"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {hasChartPoints && ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div className="flex flex-1"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <span className={`text-lg flex-1 ${isRTL ? "text-left": "text-right"} sm:text-xl font-bold text-foreground f`}> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {formatBytes(totalPeriodTraffic)} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </span> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| )} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+164
to
+178
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix the typo and improve RTL layout handling. Several issues in the header layout:
Apply this diff to fix the typo and improve the layout: - <CardHeader className="flex flex-1 flex-col gap-4 space-y-0 border-b pb-4">
- <div className={`flex w-full items-center flex-row justify-between gap-2 `}>
+ <CardHeader className="flex flex-col gap-4 space-y-0 border-b pb-4">
+ <div className="flex w-full items-center justify-between gap-2" dir={isRTL ? 'rtl' : 'ltr'}>
<CardTitle className="text-base sm:text-lg w-1/2">
{t('usage.title')}
</CardTitle>
- <div className="w-1/2">
- {hasChartPoints && (
- <div className="flex flex-1">
- <span className={`text-lg flex-1 ${isRTL ? "text-left": "text-right"} sm:text-xl font-bold text-foreground f`}>
- {formatBytes(totalPeriodTraffic)}
- </span>
- </div>
- )}
- </div>
+ {hasChartPoints && (
+ <div className="w-1/2 text-right sm:text-xl">
+ <span className="text-lg sm:text-xl font-bold text-foreground">
+ {formatBytes(totalPeriodTraffic)}
+ </span>
+ </div>
+ )}
</div>Note: Removed redundant 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div className="flex flex-wrap gap-2"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {timeRangeOptions.map((option) => ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <button | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
Extract the duplicate
formatBytesfunction.The same
formatBytesfunction is defined twice: here (lines 143-150) and inCustomTrafficTooltip(lines 58-64). Extract it to module scope or a shared utility to eliminate duplication.Apply this diff to extract the function to module scope:
And remove the duplicate inside
TrafficChart:const totalPeriodTraffic = React.useMemo(() => { if (!data || data.length === 0) return 0 return data.reduce((sum, point) => sum + point.total_traffic, 0) }, [data]) - // Format bytes to human-readable - const formatBytes = (bytes: number) => { - if (bytes === 0) return '0 B' - const k = 1024 - const sizes = ['B', 'KB', 'MB', 'GB', 'TB'] - const i = Math.floor(Math.log(bytes) / Math.log(k)) - return `${(bytes / Math.pow(k, i)).toFixed(2)} ${sizes[i]}` - } - const timeRangeOptions = [🤖 Prompt for AI Agents