) {
*:has(>[data-slot=status-badge]:first-child):first-child]:-ml-1.5 [&>[data-slot=status-badge]:first-child]:-ml-1.5',
+ 'p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0',
className
)}
{...props}
diff --git a/web/default/src/features/channels/components/channels-columns.tsx b/web/default/src/features/channels/components/channels-columns.tsx
index 331f1867..cf8d3cef 100644
--- a/web/default/src/features/channels/components/channels-columns.tsx
+++ b/web/default/src/features/channels/components/channels-columns.tsx
@@ -45,10 +45,10 @@ import {
TooltipTrigger,
} from '@/components/ui/tooltip'
import { ConfirmDialog } from '@/components/confirm-dialog'
-import { DataTableColumnHeader } from '@/components/data-table'
+import { BadgeListCell } from '@/components/data-table'
import { GroupBadge } from '@/components/group-badge'
import { ProviderBadge } from '@/components/provider-badge'
-import { StatusBadge, StatusBadgeList } from '@/components/status-badge'
+import { StatusBadge } from '@/components/status-badge'
import { TableId } from '@/components/table-id'
import { TruncatedText } from '@/components/truncated-text'
import { getCodexUsage } from '../api'
@@ -98,22 +98,6 @@ function parseIonetMeta(otherInfo: string | null | undefined): null | {
return null
}
-/**
- * Render limited items with "and X more" indicator
- */
-function renderLimitedItems(
- items: React.ReactNode[],
- maxDisplay: number = 2
-): React.ReactNode {
- return (
- item}
- />
- )
-}
-
/**
* Upstream update tags (+N / -N) shown on channel name for model-fetchable channels
*/
@@ -314,6 +298,7 @@ function BalanceCell({ channel }: { channel: Channel }) {
size='sm'
copyable={false}
showDot={false}
+ className='-ml-1.5'
/>
)
}
@@ -349,7 +334,7 @@ function BalanceCell({ channel }: { channel: Channel }) {
return (
-
+
[] {
// ID column
{
accessorKey: 'id',
- meta: { label: t('ID'), mobileHidden: true },
- header: ({ column }) => (
-
- ),
+ header: t('ID'),
+ meta: { mobileHidden: true },
cell: ({ row }) => {
const id = row.getValue('id') as number
return
@@ -490,10 +473,8 @@ export function useChannelsColumns(): ColumnDef[] {
// Name column
{
accessorKey: 'name',
- meta: { label: t('Name'), mobileTitle: true },
- header: ({ column }) => (
-
- ),
+ header: t('Name'),
+ meta: { mobileTitle: true },
cell: ({ row }) => {
const isTagRow = isTagAggregateRow(row.original)
const name = row.getValue('name') as string
@@ -603,7 +584,6 @@ export function useChannelsColumns(): ColumnDef[] {
// Type column
{
accessorKey: 'type',
- meta: { label: t('Type') },
header: t('Type'),
cell: ({ row }) => {
const isTagRow = isTagAggregateRow(row.original)
@@ -615,6 +595,7 @@ export function useChannelsColumns(): ColumnDef[] {
variant='blue'
size='sm'
copyable={false}
+ className='-ml-1.5'
/>
)
}
@@ -718,8 +699,8 @@ export function useChannelsColumns(): ColumnDef[] {
// Status column
{
accessorKey: 'status',
- meta: { label: t('Status'), mobileBadge: true },
header: t('Status'),
+ meta: { mobileBadge: true },
cell: ({ row }) => {
const isTagRow = isTagAggregateRow(row.original)
const status = row.getValue('status') as number
@@ -737,6 +718,7 @@ export function useChannelsColumns(): ColumnDef[] {
variant='success'
size='sm'
copyable={false}
+ className='-ml-1.5'
/>
)
} else {
@@ -746,6 +728,7 @@ export function useChannelsColumns(): ColumnDef[] {
variant='neutral'
size='sm'
copyable={false}
+ className='-ml-1.5'
/>
)
}
@@ -823,6 +806,7 @@ export function useChannelsColumns(): ColumnDef[] {
variant={config.variant}
size='sm'
copyable={false}
+ className='-ml-1.5'
/>
)
},
@@ -840,42 +824,23 @@ export function useChannelsColumns(): ColumnDef[] {
// Models column
{
accessorKey: 'models',
- meta: { label: t('Models'), mobileHidden: true },
header: t('Models'),
+ meta: { mobileHidden: true },
cell: ({ row }) => {
const models = row.getValue('models') as string
const modelArray = parseModelsList(models)
-
- if (modelArray.length === 0) {
- return -
- }
-
- const modelBadges = modelArray.map((model, idx) => (
-
- ))
-
return (
-
-
- }>
- {renderLimitedItems(modelBadges, 2)}
-
- {modelArray.length > 2 && (
-
- {modelBadges}
-
- )}
-
-
+
(
+
+ ))}
+ />
)
},
size: 200,
@@ -885,32 +850,17 @@ export function useChannelsColumns(): ColumnDef[] {
// Group column
{
accessorKey: 'group',
- meta: { label: t('Groups'), mobileHidden: true },
header: t('Groups'),
+ meta: { mobileHidden: true },
cell: ({ row }) => {
const group = row.getValue('group') as string
const groupArray = parseGroupsList(group)
-
- const groupBadges = groupArray.map((g) => (
-
- ))
-
return (
-
-
- }>
- {renderLimitedItems(groupBadges, 2)}
-
- {groupArray.length > 2 && (
-
- {groupBadges}
-
- )}
-
-
+ (
+
+ ))}
+ />
)
},
filterFn: (row, id, value) => {
@@ -926,14 +876,14 @@ export function useChannelsColumns(): ColumnDef[] {
// Tag column
{
accessorKey: 'tag',
- meta: { label: t('Tag'), mobileHidden: true },
header: t('Tag'),
+ meta: { mobileHidden: true },
cell: ({ row }) => {
const tag = row.getValue('tag') as string | null
if (!tag)
return -
- return
+ return
},
size: 120,
enableSorting: false,
@@ -942,10 +892,8 @@ export function useChannelsColumns(): ColumnDef[] {
// Priority column
{
accessorKey: 'priority',
- meta: { label: t('Priority'), mobileHidden: true },
- header: ({ column }) => (
-
- ),
+ header: t('Priority'),
+ meta: { mobileHidden: true },
cell: ({ row }) => ,
size: 100,
},
@@ -953,8 +901,8 @@ export function useChannelsColumns(): ColumnDef[] {
// Weight column
{
accessorKey: 'weight',
- meta: { label: t('Weight'), mobileHidden: true },
header: t('Weight'),
+ meta: { mobileHidden: true },
cell: ({ row }) => ,
size: 90,
enableSorting: false,
@@ -963,10 +911,7 @@ export function useChannelsColumns(): ColumnDef[] {
// Balance column (Used/Remaining)
{
accessorKey: 'balance',
- meta: { label: t('Used / Remaining') },
- header: ({ column }) => (
-
- ),
+ header: t('Used / Remaining'),
cell: ({ row }) => ,
size: 180,
},
@@ -974,10 +919,8 @@ export function useChannelsColumns(): ColumnDef[] {
// Response Time column
{
accessorKey: 'response_time',
- meta: { label: t('Response'), mobileHidden: true },
- header: ({ column }) => (
-
- ),
+ header: t('Response'),
+ meta: { mobileHidden: true },
cell: ({ row }) => {
const responseTime = row.getValue('response_time') as number
const config = getResponseTimeConfig(responseTime)
@@ -988,6 +931,7 @@ export function useChannelsColumns(): ColumnDef[] {
variant={config.variant}
size='sm'
copyable={false}
+ className='-ml-1.5'
/>
)
},
@@ -997,10 +941,8 @@ export function useChannelsColumns(): ColumnDef[] {
// Test Time column
{
accessorKey: 'test_time',
- meta: { label: t('Last Tested'), mobileHidden: true },
- header: ({ column }) => (
-
- ),
+ header: t('Last Tested'),
+ meta: { mobileHidden: true },
cell: ({ row }) => {
const testTime = row.getValue('test_time') as number
@@ -1037,6 +979,7 @@ export function useChannelsColumns(): ColumnDef[] {
// Actions column
{
id: 'actions',
+ header: () => t('Actions'),
cell: ({ row }) => {
// Check if this is a tag row (has children)
const isTagRow = isTagAggregateRow(row.original)
@@ -1055,6 +998,7 @@ export function useChannelsColumns(): ColumnDef[] {
size: 132,
enableSorting: false,
enableHiding: false,
+ meta: { pinned: 'right' as const },
},
]
}
diff --git a/web/default/src/features/channels/components/data-table-row-actions.tsx b/web/default/src/features/channels/components/data-table-row-actions.tsx
index 92394245..0d93bf11 100644
--- a/web/default/src/features/channels/components/data-table-row-actions.tsx
+++ b/web/default/src/features/channels/components/data-table-row-actions.tsx
@@ -140,7 +140,7 @@ export function DataTableRowActions({ row }: DataTableRowActionsProps) {
}
return (
-
+
[] {
enableSorting: false,
enableHiding: false,
size: 40,
- meta: { label: t('Select') },
},
{
accessorKey: 'name',
- header: ({ column }) => (
-
- ),
+ header: t('Name'),
cell: ({ row }) => (
{row.getValue('name')}
),
size: 180,
- meta: { label: t('Name'), mobileTitle: true },
+ meta: { mobileTitle: true },
},
{
accessorKey: 'status',
- header: ({ column }) => (
-
- ),
+ header: t('Status'),
cell: ({ row }) => {
const statusConfig = API_KEY_STATUSES[row.getValue('status') as number]
if (!statusConfig) return null
@@ -121,12 +115,13 @@ export function useApiKeysColumns(): ColumnDef[] {
label={t(statusConfig.label)}
variant={statusConfig.variant}
copyable={false}
+ className='-ml-1.5'
/>
)
},
filterFn: (row, id, value) => value.includes(String(row.getValue(id))),
size: 120,
- meta: { label: t('Status'), mobileBadge: true },
+ meta: { mobileBadge: true },
},
{
id: 'key',
@@ -135,14 +130,11 @@ export function useApiKeysColumns(): ColumnDef[] {
cell: ({ row }) => ,
enableSorting: false,
size: 260,
- meta: { label: t('API Key') },
},
{
id: 'quota',
accessorKey: 'remain_quota',
- header: ({ column }) => (
-
- ),
+ header: t('Quota'),
cell: ({ row }) => {
const apiKey = row.original
if (apiKey.unlimited_quota) {
@@ -151,6 +143,7 @@ export function useApiKeysColumns(): ColumnDef[] {
label={t('Unlimited')}
variant='neutral'
copyable={false}
+ className='-ml-1.5'
/>
)
}
@@ -194,13 +187,10 @@ export function useApiKeysColumns(): ColumnDef[] {
)
},
size: 170,
- meta: { label: t('Quota') },
},
{
accessorKey: 'group',
- header: ({ column }) => (
-
- ),
+ header: t('Group'),
cell: ({ row }) => {
const apiKey = row.original
const group = row.getValue('group') as string
@@ -236,48 +226,40 @@ export function useApiKeysColumns(): ColumnDef[] {
return
},
size: 160,
- meta: { label: t('Group'), mobileHidden: true },
+ meta: { mobileHidden: true },
},
{
id: 'model_limits',
accessorKey: 'model_limits',
- header: ({ column }) => (
-
- ),
+ header: t('Models'),
cell: ({ row }) => ,
enableSorting: false,
size: 160,
- meta: { label: t('Models'), mobileHidden: true },
+ meta: { mobileHidden: true },
},
{
id: 'allow_ips',
accessorKey: 'allow_ips',
- header: ({ column }) => (
-
- ),
+ header: t('IP Restriction'),
cell: ({ row }) => ,
enableSorting: false,
size: 160,
- meta: { label: t('IP Restriction'), mobileHidden: true },
+ meta: { mobileHidden: true },
},
{
accessorKey: 'created_time',
- header: ({ column }) => (
-
- ),
+ header: t('Created'),
cell: ({ row }) => (
{formatTimestampToDate(row.getValue('created_time'))}
),
size: 180,
- meta: { label: t('Created'), mobileHidden: true },
+ meta: { mobileHidden: true },
},
{
accessorKey: 'accessed_time',
- header: ({ column }) => (
-
- ),
+ header: t('Last Used'),
cell: ({ row }) => {
const accessedTime = row.getValue('accessed_time') as number
if (!accessedTime) {
@@ -290,13 +272,11 @@ export function useApiKeysColumns(): ColumnDef[] {
)
},
size: 180,
- meta: { label: t('Last Used'), mobileHidden: true },
+ meta: { mobileHidden: true },
},
{
accessorKey: 'expired_time',
- header: ({ column }) => (
-
- ),
+ header: t('Expires'),
cell: ({ row }) => {
const expiredTime = row.getValue('expired_time') as number
if (expiredTime === -1) {
@@ -305,6 +285,7 @@ export function useApiKeysColumns(): ColumnDef[] {
label={t('Never')}
variant='neutral'
copyable={false}
+ className='-ml-1.5'
/>
)
}
@@ -321,12 +302,13 @@ export function useApiKeysColumns(): ColumnDef[] {
)
},
size: 180,
- meta: { label: t('Expires'), mobileHidden: true },
+ meta: { mobileHidden: true },
},
{
id: 'actions',
+ header: () => t('Actions'),
cell: ({ row }) => ,
- meta: { label: t('Actions') },
+ meta: { pinned: 'right' as const },
size: 88,
},
]
diff --git a/web/default/src/features/keys/components/data-table-row-actions.tsx b/web/default/src/features/keys/components/data-table-row-actions.tsx
index 81855abc..d155f156 100644
--- a/web/default/src/features/keys/components/data-table-row-actions.tsx
+++ b/web/default/src/features/keys/components/data-table-row-actions.tsx
@@ -190,7 +190,7 @@ export function DataTableRowActions({
}
return (
-
+
+
+
+
)
}
diff --git a/web/default/src/features/models/components/deployments-columns.tsx b/web/default/src/features/models/components/deployments-columns.tsx
index 32d5eff0..541fefb5 100644
--- a/web/default/src/features/models/components/deployments-columns.tsx
+++ b/web/default/src/features/models/components/deployments-columns.tsx
@@ -21,7 +21,6 @@ import { Eye, Info, Pencil, Settings2, Timer, Trash2 } from 'lucide-react'
import { useTranslation } from 'react-i18next'
import { formatTimestampToDate } from '@/lib/format'
import { Button } from '@/components/ui/button'
-import { DataTableColumnHeader } from '@/components/data-table'
import { StatusBadge } from '@/components/status-badge'
import { TableId } from '@/components/table-id'
import { getDeploymentStatusConfig } from '../constants'
@@ -45,10 +44,8 @@ export function useDeploymentsColumns(opts: {
return [
{
accessorKey: 'id',
- meta: { label: t('ID'), mobileHidden: true },
- header: ({ column }) => (
-
- ),
+ header: t('ID'),
+ meta: { mobileHidden: true },
cell: ({ row }) => {
const id = row.original.id
return
@@ -59,10 +56,8 @@ export function useDeploymentsColumns(opts: {
id: 'name',
accessorFn: (row) =>
row.container_name || row.deployment_name || row.name || '',
- meta: { label: t('Name'), mobileTitle: true },
- header: ({ column }) => (
-
- ),
+ header: t('Name'),
+ meta: { mobileTitle: true },
cell: ({ getValue }) => {
const name = String(getValue() || '-') || '-'
return (
@@ -71,7 +66,7 @@ export function useDeploymentsColumns(opts: {
variant='neutral'
copyText={name}
size='sm'
- className='font-mono'
+ className='-ml-1.5 font-mono'
/>
)
},
@@ -79,8 +74,8 @@ export function useDeploymentsColumns(opts: {
},
{
accessorKey: 'status',
- meta: { label: t('Status'), mobileBadge: true },
header: t('Status'),
+ meta: { mobileBadge: true },
cell: ({ row }) => {
const raw = row.original.status
const key = normalizeDeploymentStatus(raw)
@@ -95,6 +90,7 @@ export function useDeploymentsColumns(opts: {
variant={config.variant}
size='sm'
copyable={false}
+ className='-ml-1.5'
/>
)
},
@@ -114,7 +110,6 @@ export function useDeploymentsColumns(opts: {
},
{
accessorKey: 'provider',
- meta: { label: t('Provider') },
header: t('Provider'),
cell: ({ row }) => {
const provider = row.original.provider
@@ -126,6 +121,7 @@ export function useDeploymentsColumns(opts: {
autoColor={String(provider)}
size='sm'
copyable={false}
+ className='-ml-1.5'
/>
)
},
@@ -134,7 +130,6 @@ export function useDeploymentsColumns(opts: {
},
{
accessorKey: 'time_remaining',
- meta: { label: t('Time remaining') },
header: t('Time remaining'),
cell: ({ row }) => {
const status = normalizeDeploymentStatus(row.original.status)
@@ -185,8 +180,8 @@ export function useDeploymentsColumns(opts: {
},
{
id: 'hardware',
- meta: { label: t('Hardware'), mobileHidden: true },
header: t('Hardware'),
+ meta: { mobileHidden: true },
accessorFn: (row) =>
row.hardware_info || row.hardware_name || row.brand_name || '',
cell: ({ row }) => {
@@ -220,10 +215,8 @@ export function useDeploymentsColumns(opts: {
},
{
accessorKey: 'created_at',
- meta: { label: t('Created'), mobileHidden: true },
- header: ({ column }) => (
-
- ),
+ header: t('Created'),
+ meta: { mobileHidden: true },
cell: ({ row }) => {
const ts =
typeof row.original.created_at === 'number'
@@ -241,6 +234,7 @@ export function useDeploymentsColumns(opts: {
},
{
id: 'actions',
+ header: () => t('Actions'),
enableHiding: false,
enableSorting: false,
cell: ({ row }) => {
@@ -252,7 +246,7 @@ export function useDeploymentsColumns(opts: {
''
return (
-
+
item}
- />
- )
-}
-
/**
* Generate models columns configuration
*/
@@ -107,10 +91,8 @@ export function useModelsColumns(vendors: Vendor[] = []): ColumnDef[] {
// ID column
{
accessorKey: 'id',
- meta: { label: t('ID'), mobileHidden: true },
- header: ({ column }) => (
-
- ),
+ header: t('ID'),
+ meta: { mobileHidden: true },
cell: ({ row }) => {
const id = row.getValue('id') as number
return
@@ -121,8 +103,8 @@ export function useModelsColumns(vendors: Vendor[] = []): ColumnDef[] {
// Icon column
{
accessorKey: 'icon',
- meta: { label: t('Icon'), mobileHidden: true },
header: t('Icon'),
+ meta: { mobileHidden: true },
cell: ({ row }) => {
const model = row.original
const iconKey =
@@ -145,10 +127,8 @@ export function useModelsColumns(vendors: Vendor[] = []): ColumnDef[] {
// Model Name column
{
accessorKey: 'model_name',
- meta: { label: t('Model Name'), mobileTitle: true },
- header: ({ column }) => (
-
- ),
+ header: t('Model Name'),
+ meta: { mobileTitle: true },
cell: ({ row }) => {
const name = row.getValue('model_name') as string
return (
@@ -157,7 +137,7 @@ export function useModelsColumns(vendors: Vendor[] = []): ColumnDef[] {
variant='neutral'
copyText={name}
size='sm'
- className='font-mono'
+ className='-ml-1.5 font-mono'
/>
)
},
@@ -167,10 +147,7 @@ export function useModelsColumns(vendors: Vendor[] = []): ColumnDef[] {
// Name Rule column
{
accessorKey: 'name_rule',
- meta: { label: t('Match Type') },
- header: ({ column }) => (
-
- ),
+ header: t('Match Type'),
cell: ({ row }) => {
const rule = row.getValue('name_rule') as 0 | 1 | 2 | 3
const model = row.original
@@ -193,6 +170,7 @@ export function useModelsColumns(vendors: Vendor[] = []): ColumnDef[] {
| 'info'
}
size='sm'
+ className='-ml-1.5'
/>
)
@@ -209,7 +187,7 @@ export function useModelsColumns(vendors: Vendor[] = []): ColumnDef[] {
return (
- }>{badge}
+ }>{badge}
[] {
// Status column
{
accessorKey: 'status',
- meta: { label: t('Status'), mobileBadge: true },
header: t('Status'),
+ meta: { mobileBadge: true },
cell: ({ row }) => {
const status = row.getValue('status') as number
const config =
@@ -243,6 +221,7 @@ export function useModelsColumns(vendors: Vendor[] = []): ColumnDef[] {
variant={config.variant}
size='sm'
copyable={false}
+ className='-ml-1.5'
/>
)
},
@@ -260,7 +239,6 @@ export function useModelsColumns(vendors: Vendor[] = []): ColumnDef[] {
// Vendor column
{
accessorKey: 'vendor_id',
- meta: { label: t('Vendor') },
header: t('Vendor'),
cell: ({ row }) => {
const vendorId = row.getValue('vendor_id') as number
@@ -283,8 +261,8 @@ export function useModelsColumns(vendors: Vendor[] = []): ColumnDef[] {
// Description column
{
accessorKey: 'description',
- meta: { label: t('Description'), mobileHidden: true },
header: t('Description'),
+ meta: { mobileHidden: true },
cell: ({ row }) => {
const description = row.getValue('description') as string
const modelName = row.getValue('model_name') as string
@@ -300,36 +278,17 @@ export function useModelsColumns(vendors: Vendor[] = []): ColumnDef[] {
// Tags column
{
accessorKey: 'tags',
- meta: { label: t('Tags'), mobileHidden: true },
header: t('Tags'),
+ meta: { mobileHidden: true },
cell: ({ row }) => {
const tags = row.getValue('tags') as string
const tagArray = parseModelTags(tags)
-
- if (tagArray.length === 0) {
- return -
- }
-
- const tagBadges = tagArray.map((tag, idx) => (
-
- ))
-
return (
-
-
- }>
- {renderLimitedItems(tagBadges, 2)}
-
- {tagArray.length > 2 && (
-
- {tagBadges}
-
- )}
-
-
+ (
+
+ ))}
+ />
)
},
size: 150,
@@ -339,36 +298,17 @@ export function useModelsColumns(vendors: Vendor[] = []): ColumnDef[] {
// Endpoints column
{
accessorKey: 'endpoints',
- meta: { label: t('Endpoints'), mobileHidden: true },
header: t('Endpoints'),
+ meta: { mobileHidden: true },
cell: ({ row }) => {
const endpoints = row.getValue('endpoints') as string
const endpointArray = formatEndpointsDisplay(endpoints)
-
- if (endpointArray.length === 0) {
- return -
- }
-
- const endpointBadges = endpointArray.map((ep, idx) => (
-
- ))
-
return (
-
-
- }>
- {renderLimitedItems(endpointBadges, 2)}
-
- {endpointArray.length > 2 && (
-
- {endpointBadges}
-
- )}
-
-
+ (
+
+ ))}
+ />
)
},
size: 150,
@@ -378,8 +318,8 @@ export function useModelsColumns(vendors: Vendor[] = []): ColumnDef[] {
// Bound Channels column
{
accessorKey: 'bound_channels',
- meta: { label: t('Bound Channels'), mobileHidden: true },
header: t('Bound Channels'),
+ meta: { mobileHidden: true },
cell: ({ row }) => {
const channels = row.getValue('bound_channels') as Array<{
id: number
@@ -387,36 +327,17 @@ export function useModelsColumns(vendors: Vendor[] = []): ColumnDef[] {
type?: number
status?: number
}>
-
- if (!channels || channels.length === 0) {
- return -
- }
-
- const channelBadges = channels.map((c, idx) => (
-
- ))
-
return (
-
-
- }>
- {renderLimitedItems(channelBadges, 2)}
-
- {channels.length > 2 && (
-
- {channelBadges}
-
- )}
-
-
+ (
+
+ ))}
+ />
)
},
size: 150,
@@ -426,37 +347,16 @@ export function useModelsColumns(vendors: Vendor[] = []): ColumnDef[] {
// Enable Groups column
{
accessorKey: 'enable_groups',
- meta: { label: t('Enable Groups'), mobileHidden: true },
- header: ({ column }) => (
-
- ),
+ header: t('Enable Groups'),
+ meta: { mobileHidden: true },
cell: ({ row }) => {
const groups = row.getValue('enable_groups') as string[]
-
- if (!groups || groups.length === 0) {
- return -
- }
-
- const groupBadges = groups.map((g) => (
-
- ))
-
return (
-
-
- }>
- {renderLimitedItems(groupBadges, 2)}
-
- {groups.length > 2 && (
-
- {groupBadges}
-
- )}
-
-
+ (
+
+ ))}
+ />
)
},
size: 150,
@@ -466,50 +366,31 @@ export function useModelsColumns(vendors: Vendor[] = []): ColumnDef[] {
// Quota Types column
{
accessorKey: 'quota_types',
- meta: { label: t('Quota Types'), mobileHidden: true },
header: t('Quota Types'),
+ meta: { mobileHidden: true },
cell: ({ row }) => {
const quotaTypes = row.getValue('quota_types') as number[]
-
- if (!quotaTypes || quotaTypes.length === 0) {
- return -
- }
-
- const quotaBadges = quotaTypes.map((qt, idx) => {
- const config = QUOTA_TYPE_CONFIG[qt]
- return (
-
- )
- })
-
return (
-
-
- }>
- {renderLimitedItems(quotaBadges, 2)}
-
- {quotaTypes.length > 2 && (
-
- {quotaBadges}
-
- )}
-
-
+ {
+ const config = QUOTA_TYPE_CONFIG[qt]
+ return (
+
+ )
+ })}
+ />
)
},
size: 150,
@@ -519,8 +400,8 @@ export function useModelsColumns(vendors: Vendor[] = []): ColumnDef[] {
// Sync Official column
{
accessorKey: 'sync_official',
- meta: { label: t('Official Sync'), mobileHidden: true },
header: t('Official Sync'),
+ meta: { mobileHidden: true },
cell: ({ row }) => {
const syncOfficial = row.getValue('sync_official') as number
return (
@@ -529,6 +410,7 @@ export function useModelsColumns(vendors: Vendor[] = []): ColumnDef[] {
variant={syncOfficial === 1 ? 'success' : 'warning'}
size='sm'
copyable={false}
+ className='-ml-1.5'
/>
)
},
@@ -546,10 +428,8 @@ export function useModelsColumns(vendors: Vendor[] = []): ColumnDef[] {
// Created Time column
{
accessorKey: 'created_time',
- meta: { label: t('Created'), mobileHidden: true },
- header: ({ column }) => (
-
- ),
+ header: t('Created'),
+ meta: { mobileHidden: true },
cell: ({ row }) => {
const timestamp = row.getValue('created_time') as number
return (
@@ -564,10 +444,8 @@ export function useModelsColumns(vendors: Vendor[] = []): ColumnDef[] {
// Updated Time column
{
accessorKey: 'updated_time',
- meta: { label: t('Updated'), mobileHidden: true },
- header: ({ column }) => (
-
- ),
+ header: t('Updated'),
+ meta: { mobileHidden: true },
cell: ({ row }) => {
const timestamp = row.getValue('updated_time') as number
return (
@@ -582,12 +460,14 @@ export function useModelsColumns(vendors: Vendor[] = []): ColumnDef[] {
// Actions column
{
id: 'actions',
+ header: () => t('Actions'),
cell: ({ row }) => {
return
},
size: 100,
enableSorting: false,
enableHiding: false,
+ meta: { pinned: 'right' as const },
},
]
}
diff --git a/web/default/src/features/pricing/components/pricing-columns.tsx b/web/default/src/features/pricing/components/pricing-columns.tsx
index 2f1bc3d2..d64d3bcc 100644
--- a/web/default/src/features/pricing/components/pricing-columns.tsx
+++ b/web/default/src/features/pricing/components/pricing-columns.tsx
@@ -19,15 +19,9 @@ For commercial licensing, please contact support@quantumnous.com
import { type ColumnDef } from '@tanstack/react-table'
import { useTranslation } from 'react-i18next'
import { getLobeIcon } from '@/lib/lobe-icon'
-import {
- Tooltip,
- TooltipContent,
- TooltipProvider,
- TooltipTrigger,
-} from '@/components/ui/tooltip'
-import { DataTableColumnHeader } from '@/components/data-table'
+import { DataTableColumnHeader, BadgeListCell } from '@/components/data-table'
import { GroupBadge } from '@/components/group-badge'
-import { StatusBadge, StatusBadgeList } from '@/components/status-badge'
+import { StatusBadge } from '@/components/status-badge'
import { DEFAULT_TOKEN_UNIT, QUOTA_TYPE_VALUES } from '../constants'
import {
getDynamicDisplayGroupRatio,
@@ -53,36 +47,6 @@ export interface PricingColumnsOptions {
showRechargePrice?: boolean
}
-function renderLimitedTags(
- items: string[],
- maxDisplay: number = 3
-): React.ReactNode {
- return (
- item}
- renderItem={(item) => (
-
- )}
- />
- )
-}
-
-function renderLimitedGroupBadges(
- groups: string[],
- maxDisplay: number = 2
-): React.ReactNode {
- return (
- group}
- renderItem={(group) => }
- />
- )
-}
-
export function usePricingColumns(
options: PricingColumnsOptions = {}
): ColumnDef[] {
@@ -124,7 +88,6 @@ export function usePricingColumns(
// Type column
{
accessorKey: 'quota_type',
- meta: { label: t('Type') },
header: t('Type'),
cell: ({ row }) => {
const isTokenBased = row.original.quota_type === QUOTA_TYPE_VALUES.TOKEN
@@ -133,6 +96,7 @@ export function usePricingColumns(
label={isTokenBased ? t('Token') : t('Request')}
variant={isTokenBased ? 'info' : 'neutral'}
copyable={false}
+ className='-ml-1.5'
/>
)
},
@@ -269,7 +233,6 @@ export function usePricingColumns(
// Cached price column (Vercel AI Gateway style)
{
id: 'cached_price',
- meta: { label: t('Cached') },
header: t('Cached'),
cell: ({ row }) => {
const model = row.original
@@ -344,7 +307,6 @@ export function usePricingColumns(
// Vendor column
{
accessorKey: 'vendor_name',
- meta: { label: t('Vendor') },
header: t('Vendor'),
cell: ({ row }) => {
const model = row.original
@@ -373,27 +335,21 @@ export function usePricingColumns(
// Tags column
{
accessorKey: 'tags',
- meta: { label: t('Tags') },
header: t('Tags'),
cell: ({ row }) => {
const tags = parseTags(row.original.tags)
- if (tags.length === 0) {
- return —
- }
-
return (
-
-
- }>
- {renderLimitedTags(tags, 2)}
-
- {tags.length > 2 && (
-
- {tags.join(', ')}
-
- )}
-
-
+ (
+
+ ))}
+ />
)
},
size: 140,
@@ -403,27 +359,21 @@ export function usePricingColumns(
// Endpoints column
{
accessorKey: 'supported_endpoint_types',
- meta: { label: t('Endpoints') },
header: t('Endpoints'),
cell: ({ row }) => {
const endpoints = row.original.supported_endpoint_types || []
- if (endpoints.length === 0) {
- return —
- }
-
return (
-
-
- }>
- {renderLimitedTags(endpoints, 2)}
-
- {endpoints.length > 2 && (
-
- {endpoints.join(', ')}
-
- )}
-
-
+ (
+
+ ))}
+ />
)
},
size: 130,
@@ -433,31 +383,16 @@ export function usePricingColumns(
// Enable Groups column
{
accessorKey: 'enable_groups',
- meta: { label: t('Groups') },
header: t('Groups'),
cell: ({ row }) => {
const groups = row.original.enable_groups || []
- if (groups.length === 0) {
- return —
- }
-
return (
-
-
- }>
- {renderLimitedGroupBadges(groups, 2)}
-
- {groups.length > 2 && (
-
-
- {groups.map((group) => (
-
- ))}
-
-
- )}
-
-
+ (
+
+ ))}
+ tooltipClassName='max-w-[280px] p-2'
+ />
)
},
size: 130,
diff --git a/web/default/src/features/redemption-codes/components/data-table-row-actions.tsx b/web/default/src/features/redemption-codes/components/data-table-row-actions.tsx
index e9b1ef51..447ad6e7 100644
--- a/web/default/src/features/redemption-codes/components/data-table-row-actions.tsx
+++ b/web/default/src/features/redemption-codes/components/data-table-row-actions.tsx
@@ -77,7 +77,8 @@ export function DataTableRowActions({
const canToggle = !isUsed && !isExpired
return (
-
+
+
({
+
)
}
diff --git a/web/default/src/features/redemption-codes/components/redemptions-columns.tsx b/web/default/src/features/redemption-codes/components/redemptions-columns.tsx
index 2370d44d..6512fb73 100644
--- a/web/default/src/features/redemption-codes/components/redemptions-columns.tsx
+++ b/web/default/src/features/redemption-codes/components/redemptions-columns.tsx
@@ -25,7 +25,6 @@ import {
TooltipContent,
TooltipTrigger,
} from '@/components/ui/tooltip'
-import { DataTableColumnHeader } from '@/components/data-table'
import { MaskedValueDisplay } from '@/components/masked-value-display'
import { StatusBadge } from '@/components/status-badge'
import { TableId } from '@/components/table-id'
@@ -39,7 +38,6 @@ export function useRedemptionsColumns(): ColumnDef[] {
return [
{
id: 'select',
- meta: { label: t('Select') },
header: ({ table }) => (
[] {
},
{
accessorKey: 'id',
- meta: { label: t('ID'), mobileHidden: true },
- header: ({ column }) => (
-
- ),
+ header: t('ID'),
+ meta: { mobileHidden: true },
cell: ({ row }) => {
return (
@@ -76,10 +72,8 @@ export function useRedemptionsColumns(): ColumnDef[] {
},
{
accessorKey: 'name',
- meta: { label: t('Name'), mobileTitle: true },
- header: ({ column }) => (
-
- ),
+ header: t('Name'),
+ meta: { mobileTitle: true },
cell: ({ row }) => {
return (
@@ -91,10 +85,8 @@ export function useRedemptionsColumns(): ColumnDef
[] {
},
{
accessorKey: 'status',
- meta: { label: t('Status'), mobileBadge: true },
- header: ({ column }) => (
-
- ),
+ header: t('Status'),
+ meta: { mobileBadge: true },
cell: ({ row }) => {
const redemption = row.original
const statusValue = row.getValue('status') as number
@@ -106,6 +98,7 @@ export function useRedemptionsColumns(): ColumnDef[] {
label={t('Expired')}
variant='warning'
copyable={false}
+ className='-ml-1.5'
/>
)
}
@@ -121,6 +114,7 @@ export function useRedemptionsColumns(): ColumnDef[] {
label={t(statusConfig.labelKey)}
variant={statusConfig.variant}
copyable={false}
+ className='-ml-1.5'
/>
)
},
@@ -143,10 +137,7 @@ export function useRedemptionsColumns(): ColumnDef[] {
{
id: 'code',
accessorKey: 'key',
- meta: { label: t('Code') },
- header: ({ column }) => (
-
- ),
+ header: t('Code'),
cell: function CodeCell({ row }) {
const redemption = row.original
const key = redemption.key
@@ -167,10 +158,7 @@ export function useRedemptionsColumns(): ColumnDef[] {
},
{
accessorKey: 'quota',
- meta: { label: t('Quota') },
- header: ({ column }) => (
-
- ),
+ header: t('Quota'),
cell: ({ row }) => {
const quota = row.getValue('quota') as number
return (
@@ -178,6 +166,7 @@ export function useRedemptionsColumns(): ColumnDef[] {
label={formatQuota(quota)}
variant='neutral'
copyable={false}
+ className='-ml-1.5'
/>
)
},
@@ -185,10 +174,8 @@ export function useRedemptionsColumns(): ColumnDef[] {
},
{
accessorKey: 'created_time',
- meta: { label: t('Created'), mobileHidden: true },
- header: ({ column }) => (
-
- ),
+ header: t('Created'),
+ meta: { mobileHidden: true },
cell: ({ row }) => {
return (
@@ -200,10 +187,8 @@ export function useRedemptionsColumns(): ColumnDef
[] {
},
{
accessorKey: 'expired_time',
- meta: { label: t('Expires'), mobileHidden: true },
- header: ({ column }) => (
-
- ),
+ header: t('Expires'),
+ meta: { mobileHidden: true },
cell: ({ row }) => {
const expiredTime = row.getValue('expired_time') as number
if (expiredTime === 0) {
@@ -212,6 +197,7 @@ export function useRedemptionsColumns(): ColumnDef[] {
label={t('Never')}
variant='neutral'
copyable={false}
+ className='-ml-1.5'
/>
)
}
@@ -228,10 +214,8 @@ export function useRedemptionsColumns(): ColumnDef[] {
},
{
accessorKey: 'used_user_id',
- meta: { label: t('Redeemed By'), mobileHidden: true },
- header: ({ column }) => (
-
- ),
+ header: t('Redeemed By'),
+ meta: { mobileHidden: true },
cell: ({ row }) => {
const userId = row.getValue('used_user_id') as number
const redemption = row.original
@@ -272,7 +256,9 @@ export function useRedemptionsColumns(): ColumnDef[] {
},
{
id: 'actions',
+ header: () => t('Actions'),
cell: ({ row }) => ,
+ meta: { pinned: 'right' as const },
size: 88,
},
]
diff --git a/web/default/src/features/subscriptions/components/data-table-row-actions.tsx b/web/default/src/features/subscriptions/components/data-table-row-actions.tsx
index ed5b5476..61e72ce8 100644
--- a/web/default/src/features/subscriptions/components/data-table-row-actions.tsx
+++ b/web/default/src/features/subscriptions/components/data-table-row-actions.tsx
@@ -38,7 +38,8 @@ export function DataTableRowActions({ row }: DataTableRowActionsProps) {
const { setOpen, setCurrentRow, complianceConfirmed } = useSubscriptions()
return (
-
+
+
}
>
@@ -76,5 +77,6 @@ export function DataTableRowActions({ row }: DataTableRowActionsProps) {
+
)
}
diff --git a/web/default/src/features/subscriptions/components/subscriptions-columns.tsx b/web/default/src/features/subscriptions/components/subscriptions-columns.tsx
index a0e0c8a7..4c4d6497 100644
--- a/web/default/src/features/subscriptions/components/subscriptions-columns.tsx
+++ b/web/default/src/features/subscriptions/components/subscriptions-columns.tsx
@@ -20,7 +20,6 @@ import { useMemo } from 'react'
import { type ColumnDef } from '@tanstack/react-table'
import { useTranslation } from 'react-i18next'
import { formatQuota } from '@/lib/format'
-import { DataTableColumnHeader } from '@/components/data-table'
import { GroupBadge } from '@/components/group-badge'
import { StatusBadge } from '@/components/status-badge'
import { TableId } from '@/components/table-id'
@@ -36,20 +35,16 @@ export function useSubscriptionsColumns(): ColumnDef[] {
{
accessorFn: (row) => row.plan.id,
id: 'id',
- meta: { label: t('ID'), mobileHidden: true },
- header: ({ column }) => (
-
- ),
+ header: t('ID'),
+ meta: { mobileHidden: true },
cell: ({ row }) => ,
size: 60,
},
{
accessorFn: (row) => row.plan.title,
id: 'title',
- meta: { label: t('Plan'), mobileTitle: true },
- header: ({ column }) => (
-
- ),
+ header: t('Plan'),
+ meta: { mobileTitle: true },
cell: ({ row }) => {
const plan = row.original.plan
return (
@@ -68,10 +63,7 @@ export function useSubscriptionsColumns(): ColumnDef[] {
{
accessorFn: (row) => row.plan.price_amount,
id: 'price',
- meta: { label: t('Price') },
- header: ({ column }) => (
-
- ),
+ header: t('Price'),
cell: ({ row }) => (
${Number(row.original.plan.price_amount || 0).toFixed(2)}
@@ -81,10 +73,7 @@ export function useSubscriptionsColumns(): ColumnDef[] {
},
{
id: 'duration',
- meta: { label: t('Validity') },
- header: ({ column }) => (
-
- ),
+ header: t('Validity'),
cell: ({ row }) => (
{formatDuration(row.original.plan, t)}
@@ -94,10 +83,8 @@ export function useSubscriptionsColumns(): ColumnDef[] {
},
{
id: 'reset',
- meta: { label: t('Quota Reset'), mobileHidden: true },
- header: ({ column }) => (
-
- ),
+ header: t('Quota Reset'),
+ meta: { mobileHidden: true },
cell: ({ row }) => (
{formatResetPeriod(row.original.plan, t)}
@@ -108,10 +95,8 @@ export function useSubscriptionsColumns(): ColumnDef[] {
{
accessorFn: (row) => row.plan.sort_order,
id: 'sort_order',
- meta: { label: t('Priority'), mobileHidden: true },
- header: ({ column }) => (
-
- ),
+ header: t('Priority'),
+ meta: { mobileHidden: true },
cell: ({ row }) => (
{row.original.plan.sort_order}
@@ -122,32 +107,30 @@ export function useSubscriptionsColumns(): ColumnDef[] {
{
accessorFn: (row) => row.plan.enabled,
id: 'enabled',
- meta: { label: t('Status'), mobileBadge: true },
- header: ({ column }) => (
-
- ),
+ header: t('Status'),
+ meta: { mobileBadge: true },
cell: ({ row }) =>
row.original.plan.enabled ? (
) : (
),
size: 80,
},
{
id: 'payment',
- meta: { label: t('Payment Channel'), mobileHidden: true },
- header: ({ column }) => (
-
- ),
+ header: t('Payment Channel'),
+ meta: { mobileHidden: true },
cell: ({ row }) => {
const plan = row.original.plan
return (
@@ -176,10 +159,8 @@ export function useSubscriptionsColumns(): ColumnDef[] {
},
{
id: 'total_amount',
- meta: { label: t('Received amount'), mobileHidden: true },
- header: ({ column }) => (
-
- ),
+ header: t('Received amount'),
+ meta: { mobileHidden: true },
cell: ({ row }) => {
const total = Number(row.original.plan.total_amount || 0)
return (
@@ -192,10 +173,8 @@ export function useSubscriptionsColumns(): ColumnDef[] {
},
{
id: 'upgrade_group',
- meta: { label: t('Upgrade Group'), mobileHidden: true },
- header: ({ column }) => (
-
- ),
+ header: t('Upgrade Group'),
+ meta: { mobileHidden: true },
cell: ({ row }) => {
const group = row.original.plan.upgrade_group
if (!group) {
@@ -209,7 +188,9 @@ export function useSubscriptionsColumns(): ColumnDef[] {
},
{
id: 'actions',
+ header: () => t('Actions'),
cell: ({ row }) => ,
+ meta: { pinned: 'right' as const },
size: 80,
},
],
diff --git a/web/default/src/features/system-settings/models/model-ratio-table-columns.tsx b/web/default/src/features/system-settings/models/model-ratio-table-columns.tsx
index 0c8389fe..7e89f223 100644
--- a/web/default/src/features/system-settings/models/model-ratio-table-columns.tsx
+++ b/web/default/src/features/system-settings/models/model-ratio-table-columns.tsx
@@ -72,7 +72,6 @@ export function buildModelRatioColumns({
enableSorting: false,
enableHiding: false,
size: 40,
- meta: { label: t('Select') },
},
{
accessorKey: 'name',
@@ -113,7 +112,7 @@ export function buildModelRatioColumns({
variant={getModeVariant(row.original.billingMode)}
copyable={false}
showDot={false}
- className='px-0'
+ className='-ml-1.5 px-0'
/>
),
filterFn: (row, id, value) =>
diff --git a/web/default/src/features/usage-logs/components/columns/common-logs-columns.tsx b/web/default/src/features/usage-logs/components/columns/common-logs-columns.tsx
index 396afa75..ea6871bf 100644
--- a/web/default/src/features/usage-logs/components/columns/common-logs-columns.tsx
+++ b/web/default/src/features/usage-logs/components/columns/common-logs-columns.tsx
@@ -35,7 +35,6 @@ import {
TooltipProvider,
TooltipTrigger,
} from '@/components/ui/tooltip'
-import { DataTableColumnHeader } from '@/components/data-table'
import { StatusBadge, type StatusBadgeProps } from '@/components/status-badge'
import { LOG_TYPE_ALL_VALUE } from '../../constants'
import type { UsageLog } from '../../data/schema'
@@ -265,9 +264,7 @@ export function useCommonLogsColumns(isAdmin: boolean): ColumnDef[] {
const columns: ColumnDef[] = [
{
accessorKey: 'created_at',
- header: ({ column }) => (
-
- ),
+ header: t('Time'),
cell: ({ row }) => {
const log = row.original
const timestamp = row.getValue('created_at') as number
@@ -295,7 +292,6 @@ export function useCommonLogsColumns(isAdmin: boolean): ColumnDef[] {
},
enableHiding: false,
size: 180,
- meta: { label: t('Time') },
},
]
@@ -303,10 +299,8 @@ export function useCommonLogsColumns(isAdmin: boolean): ColumnDef[] {
columns.push(
{
id: 'channel',
+ header: t('Channel'),
accessorFn: (row) => row.channel,
- header: ({ column }) => (
-
- ),
cell: function ChannelCell({ row }) {
const { sensitiveVisible, setAffinityTarget, setAffinityDialogOpen } =
useUsageLogsContext()
@@ -404,14 +398,11 @@ export function useCommonLogsColumns(isAdmin: boolean): ColumnDef[] {
)
},
- meta: { label: t('Channel') },
},
{
id: 'user',
+ header: t('User'),
accessorFn: (row) => row.username,
- header: ({ column }) => (
-
- ),
cell: function UserCell({ row }) {
const { sensitiveVisible, setSelectedUserId, setUserInfoDialogOpen } =
useUsageLogsContext()
@@ -461,16 +452,13 @@ export function useCommonLogsColumns(isAdmin: boolean): ColumnDef[] {
)
},
- meta: { label: t('User') },
}
)
}
columns.push({
accessorKey: 'token_name',
- header: ({ column }) => (
-
- ),
+ header: t('Token'),
cell: function TokenNameCell({ row }) {
const { sensitiveVisible } = useUsageLogsContext()
const log = row.original
@@ -520,16 +508,12 @@ export function useCommonLogsColumns(isAdmin: boolean): ColumnDef[] {
)
},
- meta: { label: t('Token') },
size: 160,
})
-
columns.push(
{
accessorKey: 'model_name',
- header: ({ column }) => (
-
- ),
+ header: t('Model'),
cell: function ModelCell({ row }) {
const log = row.original
if (!isDisplayableLogType(log.type)) return null
@@ -545,14 +529,11 @@ export function useCommonLogsColumns(isAdmin: boolean): ColumnDef[] {
)
},
- meta: { label: t('Model'), mobileTitle: true },
+ meta: { mobileTitle: true },
},
-
{
accessorKey: 'use_time',
- header: ({ column }) => (
-
- ),
+ header: t('Timing'),
cell: ({ row }) => {
const log = row.original
if (!isTimingLogType(log.type)) return null
@@ -656,14 +637,11 @@ export function useCommonLogsColumns(isAdmin: boolean): ColumnDef[] {
)
},
- meta: { label: t('Timing') },
},
{
accessorKey: 'prompt_tokens',
- header: ({ column }) => (
-
- ),
+ header: 'Tokens',
cell: ({ row }) => {
const log = row.original
if (!isDisplayableLogType(log.type)) return null
@@ -707,14 +685,11 @@ export function useCommonLogsColumns(isAdmin: boolean): ColumnDef
[] {
)
},
- meta: { label: 'Tokens' },
},
{
accessorKey: 'quota',
- header: ({ column }) => (
-
- ),
+ header: t('Cost'),
cell: ({ row }) => {
const log = row.original
if (!isDisplayableLogType(log.type)) return null
@@ -762,7 +737,6 @@ export function useCommonLogsColumns(isAdmin: boolean): ColumnDef[] {
)
},
- meta: { label: t('Cost') },
},
{
@@ -820,7 +794,6 @@ export function useCommonLogsColumns(isAdmin: boolean): ColumnDef
[] {
>
)
},
- meta: { label: t('Details') },
size: 180,
maxSize: 200,
}
diff --git a/web/default/src/features/usage-logs/components/columns/drawing-logs-columns.tsx b/web/default/src/features/usage-logs/components/columns/drawing-logs-columns.tsx
index 41b46aa6..83fb73ed 100644
--- a/web/default/src/features/usage-logs/components/columns/drawing-logs-columns.tsx
+++ b/web/default/src/features/usage-logs/components/columns/drawing-logs-columns.tsx
@@ -38,7 +38,6 @@ import {
} from 'lucide-react'
import { useTranslation } from 'react-i18next'
import { formatTimestampToDate } from '@/lib/format'
-import { DataTableColumnHeader } from '@/components/data-table'
import { StatusBadge } from '@/components/status-badge'
import { MJ_TASK_TYPES } from '../../constants'
import {
@@ -87,9 +86,7 @@ export function useDrawingLogsColumns(
const columns: ColumnDef[] = [
{
accessorKey: 'submit_time',
- header: ({ column }) => (
-
- ),
+ header: t('Submit Time'),
cell: ({ row }) => {
const log = row.original
const submitTime = row.getValue('submit_time') as number
@@ -109,7 +106,6 @@ export function useDrawingLogsColumns(
)
},
size: 180,
- meta: { label: t('Submit Time') },
},
]
@@ -121,9 +117,7 @@ export function useDrawingLogsColumns(
columns.push({
accessorKey: 'action',
- header: ({ column }) => (
-
- ),
+ header: t('Type'),
cell: ({ row }) => {
const action = row.getValue('action') as string
return (
@@ -133,17 +127,15 @@ export function useDrawingLogsColumns(
icon={getDrawingTypeIcon(action)}
size='sm'
copyable={false}
+ className='-ml-1.5'
/>
)
},
- meta: { label: t('Type') },
})
columns.push({
accessorKey: 'mj_id',
- header: ({ column }) => (
-
- ),
+ header: t('Task ID'),
cell: ({ row }) => {
const mjId = row.getValue('mj_id') as string
@@ -162,7 +154,7 @@ export function useDrawingLogsColumns(
)
},
- meta: { label: t('Task ID'), mobileTitle: true },
+ meta: { mobileTitle: true },
})
columns.push(
@@ -176,9 +168,7 @@ export function useDrawingLogsColumns(
if (isAdmin) {
columns.push({
accessorKey: 'code',
- header: ({ column }) => (
-
- ),
+ header: t('Submit Result'),
cell: ({ row }) => {
const code = row.getValue('code') as number
@@ -188,10 +178,10 @@ export function useDrawingLogsColumns(
variant={mjSubmitResultMapper.getVariant(String(code))}
size='sm'
copyable={false}
+ className='-ml-1.5'
/>
)
},
- meta: { label: t('Submit Result') },
})
}
@@ -199,9 +189,7 @@ export function useDrawingLogsColumns(
createProgressColumn({ headerLabel: t('Progress') }),
{
accessorKey: 'image_url',
- header: ({ column }) => (
-
- ),
+ header: t('Image'),
cell: function ImageCell({ row }) {
const log = row.original
const imageUrl = row.getValue('image_url') as string
@@ -232,13 +220,10 @@ export function useDrawingLogsColumns(
>
)
},
- meta: { label: t('Image') },
},
{
accessorKey: 'prompt',
- header: ({ column }) => (
-
- ),
+ header: t('Prompt'),
cell: function PromptCell({ row }) {
const log = row.original
const prompt = row.getValue('prompt') as string
@@ -269,7 +254,6 @@ export function useDrawingLogsColumns(
>
)
},
- meta: { label: t('Prompt') },
size: 200,
maxSize: 220,
},
diff --git a/web/default/src/features/usage-logs/components/columns/task-logs-columns.tsx b/web/default/src/features/usage-logs/components/columns/task-logs-columns.tsx
index 61825161..9f37b6ee 100644
--- a/web/default/src/features/usage-logs/components/columns/task-logs-columns.tsx
+++ b/web/default/src/features/usage-logs/components/columns/task-logs-columns.tsx
@@ -25,7 +25,6 @@ import { getUserAvatarFallback, getUserAvatarStyle } from '@/lib/avatar'
import { formatTimestampToDate } from '@/lib/format'
import { cn } from '@/lib/utils'
import { Avatar, AvatarFallback } from '@/components/ui/avatar'
-import { DataTableColumnHeader } from '@/components/data-table'
import { StatusBadge } from '@/components/status-badge'
import { TASK_ACTIONS, TASK_STATUS } from '../../constants'
import { taskActionMapper, taskStatusMapper } from '../../lib/mappers'
@@ -94,9 +93,7 @@ export function useTaskLogsColumns(isAdmin: boolean): ColumnDef[] {
const columns: ColumnDef[] = [
{
accessorKey: 'submit_time',
- header: ({ column }) => (
-
- ),
+ header: t('Submit Time'),
cell: ({ row }) => {
const log = row.original
const submitTime = row.getValue('submit_time') as number
@@ -117,17 +114,14 @@ export function useTaskLogsColumns(isAdmin: boolean): ColumnDef[] {
)
},
size: 180,
- meta: { label: t('Submit Time') },
},
]
if (isAdmin) {
columns.push(createChannelColumn({ headerLabel: t('Channel') }), {
id: 'user',
+ header: t('User'),
accessorFn: (row) => row.username || row.user_id,
- header: ({ column }) => (
-
- ),
cell: function UserCell({ row }) {
const { sensitiveVisible, setSelectedUserId, setUserInfoDialogOpen } =
useUsageLogsContext()
@@ -163,16 +157,13 @@ export function useTaskLogsColumns(isAdmin: boolean): ColumnDef[] {
)
},
- meta: { label: t('User') },
})
}
columns.push(
{
accessorKey: 'task_id',
- header: ({ column }) => (
-
- ),
+ header: t('Task ID'),
cell: ({ row }) => {
const log = row.original
const taskId = row.getValue('task_id') as string
@@ -193,7 +184,7 @@ export function useTaskLogsColumns(isAdmin: boolean): ColumnDef[] {
)
},
- meta: { label: t('Task ID'), mobileTitle: true },
+ meta: { mobileTitle: true },
},
createDurationColumn
({
submitTimeKey: 'submit_time',
@@ -204,9 +195,7 @@ export function useTaskLogsColumns(isAdmin: boolean): ColumnDef[] {
}),
{
accessorKey: 'status',
- header: ({ column }) => (
-
- ),
+ header: t('Status'),
cell: ({ row }) => {
const status = row.getValue('status') as string
return (
@@ -215,17 +204,15 @@ export function useTaskLogsColumns(isAdmin: boolean): ColumnDef[] {
variant={taskStatusMapper.getVariant(status)}
size='sm'
copyable={false}
+ className='-ml-1.5'
/>
)
},
- meta: { label: t('Status') },
},
createProgressColumn({ headerLabel: t('Progress') }),
{
accessorKey: 'fail_reason',
- header: ({ column }) => (
-
- ),
+ header: t('Details'),
cell: function DetailsCell({ row }) {
const log = row.original
const failReason = row.getValue('fail_reason') as string
@@ -295,7 +282,6 @@ export function useTaskLogsColumns(isAdmin: boolean): ColumnDef[] {
>
)
},
- meta: { label: t('Details') },
size: 200,
maxSize: 220,
}
diff --git a/web/default/src/features/users/components/data-table-row-actions.tsx b/web/default/src/features/users/components/data-table-row-actions.tsx
index ca632bec..9a078ca8 100644
--- a/web/default/src/features/users/components/data-table-row-actions.tsx
+++ b/web/default/src/features/users/components/data-table-row-actions.tsx
@@ -136,7 +136,7 @@ export function DataTableRowActions({ row }: DataTableRowActionsProps) {
}
return (
- <>
+
- >
+
)
}
diff --git a/web/default/src/features/users/components/users-columns.tsx b/web/default/src/features/users/components/users-columns.tsx
index aed7bd2e..1cc3953d 100644
--- a/web/default/src/features/users/components/users-columns.tsx
+++ b/web/default/src/features/users/components/users-columns.tsx
@@ -27,7 +27,6 @@ import {
TooltipContent,
TooltipTrigger,
} from '@/components/ui/tooltip'
-import { DataTableColumnHeader } from '@/components/data-table'
import { GroupBadge } from '@/components/group-badge'
import { LongText } from '@/components/long-text'
import { StatusBadge } from '@/components/status-badge'
@@ -67,26 +66,21 @@ export function useUsersColumns(): ColumnDef[] {
enableSorting: false,
enableHiding: false,
size: 40,
- meta: { label: t('Select') },
},
{
accessorKey: 'id',
- header: ({ column }) => (
-
- ),
+ header: t('ID'),
cell: ({ row }) => {
return (
)
},
size: 80,
- meta: { label: t('ID'), mobileHidden: true },
+ meta: { mobileHidden: true },
},
{
accessorKey: 'username',
- header: ({ column }) => (
-
- ),
+ header: t('Username'),
cell: ({ row }) => {
const username = row.getValue('username') as string
const displayName = row.original.display_name
@@ -121,13 +115,11 @@ export function useUsersColumns(): ColumnDef[] {
},
enableHiding: false,
size: 220,
- meta: { label: t('Username'), mobileTitle: true },
+ meta: { mobileTitle: true },
},
{
accessorKey: 'status',
- header: ({ column }) => (
-
- ),
+ header: t('Status'),
cell: ({ row }) => {
const user = row.original
const requestCount = user.request_count
@@ -142,7 +134,7 @@ export function useUsersColumns(): ColumnDef[] {
return (
- }>
+ }>
[] {
},
enableSorting: false,
size: 120,
- meta: { label: t('Status'), mobileBadge: true },
+ meta: { mobileBadge: true },
},
{
id: 'quota',
accessorKey: 'quota',
- header: ({ column }) => (
-
- ),
+ header: t('Quota'),
cell: ({ row }) => {
const user = row.original
const used = user.used_quota
@@ -183,6 +173,7 @@ export function useUsersColumns(): ColumnDef[] {
label={t('No Quota')}
variant='neutral'
copyable={false}
+ className='-ml-1.5'
/>
)
}
@@ -225,13 +216,10 @@ export function useUsersColumns(): ColumnDef[] {
)
},
size: 170,
- meta: { label: t('Quota') },
},
{
accessorKey: 'group',
- header: ({ column }) => (
-
- ),
+ header: t('Group'),
cell: ({ row }) => {
const group = row.getValue('group') as string
return
@@ -242,13 +230,10 @@ export function useUsersColumns(): ColumnDef[] {
return group.includes(searchValue)
},
size: 140,
- meta: { label: t('Group') },
},
{
accessorKey: 'role',
- header: ({ column }) => (
-
- ),
+ header: t('Role'),
cell: ({ row }) => {
const roleValue = row.getValue('role') as number
const roleConfig = USER_ROLES[roleValue as keyof typeof USER_ROLES]
@@ -271,13 +256,10 @@ export function useUsersColumns(): ColumnDef[] {
},
enableSorting: false,
size: 120,
- meta: { label: t('Role') },
},
{
id: 'invite_info',
- header: ({ column }) => (
-
- ),
+ header: t('Invite Info'),
cell: ({ row }) => {
const user = row.original
const affCount = user.aff_count || 0
@@ -347,13 +329,11 @@ export function useUsersColumns(): ColumnDef[] {
},
size: 240,
enableSorting: false,
- meta: { label: t('Invite Info'), mobileHidden: true },
+ meta: { mobileHidden: true },
},
{
accessorKey: 'created_at',
- header: ({ column }) => (
-
- ),
+ header: t('Created At'),
cell: ({ row }) => {
const ts = row.getValue('created_at') as number | undefined
return (
@@ -363,13 +343,11 @@ export function useUsersColumns(): ColumnDef[] {
)
},
size: 180,
- meta: { label: t('Created At'), mobileHidden: true },
+ meta: { mobileHidden: true },
},
{
accessorKey: 'last_login_at',
- header: ({ column }) => (
-
- ),
+ header: t('Last Login'),
cell: ({ row }) => {
const ts = row.getValue('last_login_at') as number | undefined
return (
@@ -379,12 +357,13 @@ export function useUsersColumns(): ColumnDef[] {
)
},
size: 180,
- meta: { label: t('Last Login'), mobileHidden: true },
+ meta: { mobileHidden: true },
},
{
id: 'actions',
+ header: () => t('Actions'),
cell: ({ row }) => ,
- meta: { label: t('Actions') },
+ meta: { pinned: 'right' as const },
},
]
}
diff --git a/web/default/src/tanstack-table.d.ts b/web/default/src/tanstack-table.d.ts
index ba7d6c2a..e9b3cdf8 100644
--- a/web/default/src/tanstack-table.d.ts
+++ b/web/default/src/tanstack-table.d.ts
@@ -19,15 +19,14 @@ For commercial licensing, please contact support@quantumnous.com
import '@tanstack/react-table'
declare module '@tanstack/react-table' {
- // Extended column metadata for enhanced table functionality
interface ColumnMeta<_TData, _TValue> {
- // Human-readable label for the column
label?: string
- // Optional description shown in tooltips or help text
description?: string
- // Whether this column can be sorted (overrides default behavior)
- sortable?: boolean
- // Custom CSS classes to apply to the column cells
className?: string
+ pinned?: 'left' | 'right'
+ // Mobile card list layout hints (used by MobileCardList)
+ mobileTitle?: boolean // card title area (left, larger text)
+ mobileBadge?: boolean // status badge alongside title (right)
+ mobileHidden?: boolean // hide this column on mobile entirely
}
}