t0ng7u 583da45296 refactor(ui): Improve usage log filter responsiveness and mobile UX
Refactor the usage log filter toolbar into a shared reusable component for common, drawing, and task logs. Optimize desktop filters with a responsive grid, move secondary filters into a mobile drawer, standardize filter typography, remove redundant filter icons, and add the missing i18n translations for the new drawer description.
2026-05-25 05:35:44 +08:00

153 lines
4.6 KiB
TypeScript
Vendored

/*
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 <https://www.gnu.org/licenses/>.
For commercial licensing, please contact support@quantumnous.com
*/
import { useState, useCallback } from 'react'
import {
flexRender,
getCoreRowModel,
getPaginationRowModel,
useReactTable,
type PaginationState,
} from '@tanstack/react-table'
import { useTranslation } from 'react-i18next'
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from '@/components/ui/table'
import { TableSkeleton, TableEmpty } from '@/components/data-table'
import { DataTablePagination } from '@/components/data-table/pagination'
import { DEFAULT_PRICING_PAGE_SIZE, DEFAULT_TOKEN_UNIT } from '../constants'
import type { PricingModel, TokenUnit } from '../types'
import { usePricingColumns } from './pricing-columns'
export interface PricingTableProps {
models: PricingModel[]
isLoading?: boolean
priceRate?: number
usdExchangeRate?: number
tokenUnit?: TokenUnit
showRechargePrice?: boolean
onModelClick?: (modelName: string) => void
}
export function PricingTable(props: PricingTableProps) {
const { t } = useTranslation()
const {
models,
isLoading = false,
priceRate = 1,
usdExchangeRate = 1,
tokenUnit = DEFAULT_TOKEN_UNIT,
showRechargePrice = false,
onModelClick,
} = props
const [pagination, setPagination] = useState<PaginationState>({
pageIndex: 0,
pageSize: DEFAULT_PRICING_PAGE_SIZE,
})
const columns = usePricingColumns({
tokenUnit,
priceRate,
usdExchangeRate,
showRechargePrice,
})
const table = useReactTable({
data: models,
columns,
pageCount: Math.ceil(models.length / pagination.pageSize),
state: { pagination },
onPaginationChange: setPagination,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
manualPagination: false,
})
const handleRowClick = useCallback(
(model: PricingModel) => {
onModelClick?.(model.model_name)
},
[onModelClick]
)
return (
<div className='space-y-4'>
<div className='overflow-hidden rounded-lg border'>
<Table>
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id}>
{headerGroup.headers.map((header) => (
<TableHead
key={header.id}
style={{ width: header.getSize() }}
className='text-muted-foreground font-medium'
>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext()
)}
</TableHead>
))}
</TableRow>
))}
</TableHeader>
<TableBody>
{isLoading ? (
<TableSkeleton table={table} keyPrefix='pricing-skeleton' />
) : table.getRowModel().rows.length === 0 ? (
<TableEmpty
colSpan={columns.length}
title={t('No Models Found')}
description={t('No models match your current filters.')}
/>
) : (
table.getRowModel().rows.map((row) => (
<TableRow
key={row.id}
onClick={() => handleRowClick(row.original)}
className='hover:bg-muted/30 cursor-pointer transition-colors'
>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id}>
{flexRender(
cell.column.columnDef.cell,
cell.getContext()
)}
</TableCell>
))}
</TableRow>
))
)}
</TableBody>
</Table>
</div>
{!isLoading && models.length > 0 && <DataTablePagination table={table} />}
</div>
)
}