From 9a2d66031677d3f5ab8e3f57006f0d7ff6c94b61 Mon Sep 17 00:00:00 2001 From: QuentinHsu Date: Tue, 14 Jul 2026 20:15:27 +0800 Subject: [PATCH] fix(users): prevent large quota values from overflowing (#6134) - widen the quota column and add consistent spacing between remaining and total values. - extract quota rendering into a dedicated component and truncate oversized text within the cell. - preserve full-value tooltips, progress indicators, and the zero-quota state. --- .../users/components/user-quota-cell.tsx | 98 +++++++++++++++++++ .../users/components/users-columns.tsx | 65 +----------- 2 files changed, 102 insertions(+), 61 deletions(-) create mode 100644 web/default/src/features/users/components/user-quota-cell.tsx diff --git a/web/default/src/features/users/components/user-quota-cell.tsx b/web/default/src/features/users/components/user-quota-cell.tsx new file mode 100644 index 00000000..0d024cf9 --- /dev/null +++ b/web/default/src/features/users/components/user-quota-cell.tsx @@ -0,0 +1,98 @@ +/* +Copyright (C) 2023-2026 QuantumNous + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . + +For commercial licensing, please contact support@quantumnous.com +*/ +import { useTranslation } from 'react-i18next' + +import { StatusBadge } from '@/components/status-badge' +import { Progress } from '@/components/ui/progress' +import { + Tooltip, + TooltipContent, + TooltipTrigger, +} from '@/components/ui/tooltip' +import { formatQuota } from '@/lib/format' +import { cn } from '@/lib/utils' + +type UserQuotaCellProps = { + used: number + remaining: number +} + +function getQuotaProgressColor(percentage: number): string { + if (percentage <= 10) return '[&_[data-slot=progress-indicator]]:bg-rose-500' + if (percentage <= 30) return '[&_[data-slot=progress-indicator]]:bg-amber-500' + return '[&_[data-slot=progress-indicator]]:bg-emerald-500' +} + +export function UserQuotaCell(props: UserQuotaCellProps) { + const { t } = useTranslation() + const total = props.used + props.remaining + const percentage = total > 0 ? (props.remaining / total) * 100 : 0 + const formattedRemaining = formatQuota(props.remaining) + const formattedTotal = formatQuota(total) + + if (total === 0) { + return ( + + ) + } + + return ( + + + } + > +
+ + {formattedRemaining} + + + {formattedTotal} + +
+ +
+ +
+
+ {t('Used:')} {formatQuota(props.used)} +
+
+ {t('Remaining:')} {formattedRemaining} +
+
+ {t('Total:')} {formattedTotal} +
+
+ {t('Percentage:')} {percentage.toFixed(1)}% +
+
+
+
+ ) +} diff --git a/web/default/src/features/users/components/users-columns.tsx b/web/default/src/features/users/components/users-columns.tsx index 964132e5..2fadc772 100644 --- a/web/default/src/features/users/components/users-columns.tsx +++ b/web/default/src/features/users/components/users-columns.tsx @@ -25,14 +25,12 @@ import { LongText } from '@/components/long-text' import { StatusBadge } from '@/components/status-badge' import { TableId } from '@/components/table-id' import { Checkbox } from '@/components/ui/checkbox' -import { Progress } from '@/components/ui/progress' import { Tooltip, TooltipContent, TooltipTrigger, } from '@/components/ui/tooltip' import { formatQuota, formatTimestamp } from '@/lib/format' -import { cn } from '@/lib/utils' import { USER_STATUS, @@ -42,12 +40,7 @@ import { } from '../constants' import type { User } from '../types' import { DataTableRowActions } from './data-table-row-actions' - -function getQuotaProgressColor(percentage: number): string { - if (percentage <= 10) return '[&_[data-slot=progress-indicator]]:bg-rose-500' - if (percentage <= 30) return '[&_[data-slot=progress-indicator]]:bg-amber-500' - return '[&_[data-slot=progress-indicator]]:bg-emerald-500' -} +import { UserQuotaCell } from './user-quota-cell' export function useUsersColumns(): ColumnDef[] { const { t } = useTranslation() @@ -173,60 +166,10 @@ export function useUsersColumns(): ColumnDef[] { header: t('Quota'), cell: ({ row }) => { const user = row.original - const used = user.used_quota - const remaining = user.quota - const total = used + remaining - const percentage = total > 0 ? (remaining / total) * 100 : 0 - - if (total === 0) { - return ( - - ) - } - - return ( - - } - > -
- - {formatQuota(remaining)} - - - {formatQuota(total)} - -
- -
- -
-
- {t('Used:')} {formatQuota(used)} -
-
- {t('Remaining:')} {formatQuota(remaining)} -
-
- {t('Total:')} {formatQuota(total)} -
-
- {t('Percentage:')} {percentage.toFixed(1)}% -
-
-
-
- ) + return }, - size: 170, + size: 300, + minSize: 260, meta: { mobileOrder: 40 }, }, {