Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
dc6aea0
refactor(web): centralize data table implementation
QuentinHsu Jun 9, 2026
04c0ae7
refactor(web): trim data table public API
QuentinHsu Jun 9, 2026
0863ddc
refactor(web): unify table rendering components
QuentinHsu Jun 9, 2026
a1f7256
perf(web): keep list tables fixed within page content
QuentinHsu Jun 9, 2026
8fb8cac
perf(web): refine table pagination controls
QuentinHsu Jun 9, 2026
5306e64
perf(web): stabilize model pricing table columns
QuentinHsu Jun 9, 2026
895fae6
refactor(web): simplify data table rendering internals
QuentinHsu Jun 9, 2026
e6f910e
perf(pricing): reduce dynamic pricing table render work
QuentinHsu Jun 10, 2026
9190895
refactor(web): streamline pricing table rendering
QuentinHsu Jun 10, 2026
767020d
refactor(web): merge pricing table imports
QuentinHsu Jun 10, 2026
e861caf
refactor(web): merge upstream ratio table imports
QuentinHsu Jun 10, 2026
d380ed8
refactor(web): merge channel selector table imports
QuentinHsu Jun 10, 2026
9274edc
refactor(web): simplify tiered pricing select items
QuentinHsu Jun 10, 2026
2f6edab
refactor(web): reuse model ratio row state
QuentinHsu Jun 10, 2026
f78a797
refactor(web): rely on table view row defaults
QuentinHsu Jun 10, 2026
d26f277
refactor(web): reuse pagination state values
QuentinHsu Jun 10, 2026
d64e09b
refactor(web): hoist pagination size select items
QuentinHsu Jun 10, 2026
4835abf
refactor(web): clarify static table body rows
QuentinHsu Jun 10, 2026
6df10dc
refactor(web): extract table page pagination rendering
QuentinHsu Jun 10, 2026
5034471
fix(web): remove direct hast type dependency
QuentinHsu Jun 10, 2026
2d978cc
refactor(web): trim data table hook return API
QuentinHsu Jun 10, 2026
f8f7716
refactor(web): keep static table empty row private
QuentinHsu Jun 10, 2026
33d87e6
refactor(web): hide data table view props from barrel
QuentinHsu Jun 10, 2026
990ec72
refactor(web): remove stale long text lint override
QuentinHsu Jun 10, 2026
d73f6b4
fix(web): keep pinned table columns opaque
QuentinHsu Jun 10, 2026
9b1fc29
refactor(data-table): organize shared table components
QuentinHsu Jun 10, 2026
7efe325
fix(web): stabilize split table column sizing
QuentinHsu Jun 10, 2026
0cec454
fix(web): set stable table utility column widths
QuentinHsu Jun 10, 2026
823418b
fix(web): align model metadata icon cells
QuentinHsu Jun 10, 2026
445a87c
fix(status-badge): hide status dot by default
QuentinHsu Jun 10, 2026
9691ca0
fix(web): prevent user invite info overlap
QuentinHsu Jun 10, 2026
40d0d6a
perf(data-table): cache pinned column class resolution
QuentinHsu Jun 10, 2026
6799f27
refactor(data-table): tighten static table modes
QuentinHsu Jun 10, 2026
d58ddf2
fix(data-table): make pinned edit column opaque
QuentinHsu Jun 10, 2026
c57009f
fix(data-table): prevent narrow column overlap
QuentinHsu Jun 10, 2026
0a8fcb4
fix(table): align table cell content with headers
QuentinHsu Jun 10, 2026
ac694fb
fix(table): prevent admin list column overflow
QuentinHsu Jun 10, 2026
b5d13a6
fix(provider-badge): unify provider icon spacing
QuentinHsu Jun 10, 2026
8a44183
Merge branch 'main' into perf/ui-table
QuentinHsu Jun 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions web/default/src/components/ai-elements/code-block.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import {
useEffect,
useState,
} from 'react'
import type { Element } from 'hast'
import { CheckIcon, CopyIcon } from 'lucide-react'
import {
type BundledLanguage,
Expand All @@ -53,7 +52,7 @@ const CodeBlockContext = createContext<CodeBlockContextType>({

const lineNumberTransformer: ShikiTransformer = {
name: 'line-numbers',
line(node: Element, line: number) {
line(node, line) {
node.children.unshift({
type: 'element',
tagName: 'span',
Expand Down
17 changes: 17 additions & 0 deletions web/default/src/components/data-table/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Data Table Components

This package keeps a stable public API through `index.ts`; feature code should
continue importing from `@/components/data-table`.

- `core/`: TanStack table rendering primitives, headers, rows, pagination,
loading, empty states, and pinned-column behavior.
- `layout/`: responsive page-level composition that combines toolbar, desktop
table, mobile list, bulk actions, and pagination placement.
- `toolbar/`: filter/search/view-option controls and selection action toolbar.
- `static/`: lightweight table rendering for local/static arrays that do not
need TanStack state.
- `hooks/`: table state and filter hooks.

Keep feature-specific columns, actions, and dialogs inside their feature
folders. Shared table code belongs here only when it is reusable across more
than one feature.
73 changes: 73 additions & 0 deletions web/default/src/components/data-table/core/column-pinning.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
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 { cn } from '@/lib/utils'
import type { DataTableColumnClassName, DataTablePinnedColumn } from './types'

export function getResolvedColumnClassName(
getColumnClassName?: DataTableColumnClassName,
pinnedColumns?: DataTablePinnedColumn[]
): DataTableColumnClassName {
return getResolvedColumnClassNameFromMap(
getColumnClassName,
getPinnedColumnMap(pinnedColumns)
)
}

export function getResolvedColumnClassNameFromMap(
getColumnClassName?: DataTableColumnClassName,
pinnedColumnById?: Map<string, DataTablePinnedColumn>
): DataTableColumnClassName {
return (columnId, kind) => {
const customClassName = getColumnClassName?.(columnId, kind)
const pinnedColumn = pinnedColumnById?.get(columnId)

if (!pinnedColumn) return customClassName

return cn(customClassName, getPinnedColumnClassName(pinnedColumn, kind))
}
}

export function getPinnedColumnMap(pinnedColumns?: DataTablePinnedColumn[]) {
if (!pinnedColumns?.length) return undefined

return new Map(pinnedColumns.map((column) => [column.columnId, column]))
}

function getPinnedColumnClassName(
pinnedColumn: DataTablePinnedColumn,
kind: 'header' | 'cell'
) {
const edgeClassName =
pinnedColumn.side === 'left'
? 'shadow-[8px_0_10px_-10px_hsl(var(--foreground))]'
: 'shadow-[-8px_0_10px_-10px_hsl(var(--foreground))]'

return cn(
'sticky whitespace-nowrap',
pinnedColumn.side === 'left' ? 'left-0' : 'right-0',
edgeClassName,
kind === 'header'
? 'bg-background z-30'
: 'bg-background z-10 group-hover:bg-muted group-data-[state=selected]:bg-muted',
pinnedColumn.className,
kind === 'header'
? pinnedColumn.headerClassName
: pinnedColumn.cellClassName
)
}
33 changes: 33 additions & 0 deletions web/default/src/components/data-table/core/data-table-colgroup.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
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 type { Table as TanstackTable } from '@tanstack/react-table'

export function DataTableColgroup<TData>({
table,
}: {
table: TanstackTable<TData>
}) {
return (
<colgroup>
{table.getVisibleLeafColumns().map((column) => (
<col key={column.id} style={{ width: column.getSize() }} />
))}
</colgroup>
)
}
61 changes: 61 additions & 0 deletions web/default/src/components/data-table/core/data-table-header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
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 { flexRender, type Table as TanstackTable } from '@tanstack/react-table'
import { TableHead, TableHeader, TableRow } from '@/components/ui/table'
import type { DataTableColumnClassName } from './types'

type DataTableHeaderProps<TData> = {
table: TanstackTable<TData>
applyHeaderSize?: boolean
className?: string
rowClassName?: string
getColumnClassName?: DataTableColumnClassName
}

export function DataTableHeader<TData>({
table,
applyHeaderSize,
className,
rowClassName,
getColumnClassName,
}: DataTableHeaderProps<TData>) {
return (
<TableHeader className={className}>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id} className={rowClassName}>
{headerGroup.headers.map((header) => (
<TableHead
key={header.id}
colSpan={header.colSpan}
className={getColumnClassName?.(header.column.id, 'header')}
style={applyHeaderSize ? { width: header.getSize() } : undefined}
>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext()
)}
</TableHead>
))}
</TableRow>
))}
</TableHeader>
)
}
52 changes: 52 additions & 0 deletions web/default/src/components/data-table/core/data-table-row.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
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 type * as React from 'react'
import { flexRender, type Row } from '@tanstack/react-table'
import { TableCell, TableRow } from '@/components/ui/table'
import type { DataTableColumnClassName } from './types'

type DataTableRowProps<TData> = {
row: Row<TData>
className?: string
getColumnClassName?: DataTableColumnClassName
} & Omit<React.ComponentProps<typeof TableRow>, 'children'>

export function DataTableRow<TData>({
row,
className,
getColumnClassName,
...rowProps
}: DataTableRowProps<TData>) {
return (
<TableRow
data-state={row.getIsSelected() ? 'selected' : undefined}
className={className}
{...rowProps}
>
{row.getVisibleCells().map((cell) => (
<TableCell
key={cell.id}
className={getColumnClassName?.(cell.column.id, 'cell')}
>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableCell>
))}
</TableRow>
)
}
Loading