feat: sync deployed v1.0.0-rc.38-custom.42

Sync production source including routing, billing, Astra detection and public uptime. Update custom build instructions and license packaging.
This commit is contained in:
cneicy committed 2026-09-26 04:49:11 +08:00
1 parent aa6c3f50f4
commit ceddfd3d6b
828 files changed
+122253 -13702

No files matched your search

+1
View File
@@ -23,6 +23,7 @@ export { BadgeListCell } from './core/badge-list-cell'
export { TruncatedCell } from './core/truncated-cell'
export { DataTableViewOptions } from './toolbar/view-options'
export { DataTableToolbar } from './toolbar/toolbar'
export { DataTableMobileFilterPanel } from './toolbar/mobile-filter-panel'
export { DataTableBulkActions } from './toolbar/bulk-actions'
export {
StaticDataTable,
@@ -0,0 +1,161 @@
/*
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 {
getCoreRowModel,
useReactTable,
type ColumnFiltersState,
} from '@tanstack/react-table'
import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { useState } from 'react'
import { afterEach, expect, it, vi } from 'vitest'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { DataTableToolbar } from '../toolbar'
const rows = [{ name: 'Channel', model: 'model', status: 'enabled' }]
const filters = [
{
columnId: 'status',
title: 'Status',
options: [{ value: 'enabled', label: 'Enabled' }],
},
]
function Fixture(props: { collapsibleOnMobile?: boolean }) {
const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([
{ id: 'status', value: ['enabled'] },
])
const table = useReactTable({
data: rows,
columns: [
{ accessorKey: 'name' },
{ accessorKey: 'model' },
{ accessorKey: 'status' },
],
getCoreRowModel: getCoreRowModel(),
state: { columnFilters },
onColumnFiltersChange: setColumnFilters,
})
return (
<DataTableToolbar
table={table}
collapsibleOnMobile={props.collapsibleOnMobile}
searchPlaceholder='Search channels'
searchDebounceMs={50}
filters={filters}
additionalSearch={
<Input
aria-label='Model'
value={String(table.getColumn('model')?.getFilterValue() ?? '')}
onChange={(event) =>
table.getColumn('model')?.setFilterValue(event.target.value)
}
/>
}
preActions={<Button>Refresh</Button>}
viewToggle={<Button>Card view</Button>}
/>
)
}
function setMobileViewport(mobile: boolean) {
const original = window.matchMedia
vi.spyOn(window, 'matchMedia').mockImplementation((query) => ({
...original(query),
matches: mobile && query === '(max-width: 640px)',
}))
}
afterEach(() => {
vi.restoreAllMocks()
})
it('hides the mobile filter group while keeping reset and quick actions accessible', async () => {
setMobileViewport(true)
const user = userEvent.setup()
render(<Fixture collapsibleOnMobile />)
const collapse = screen.getByRole('button', { name: 'Collapse' })
expect(collapse).toHaveAttribute('aria-expanded', 'true')
expect(screen.getByPlaceholderText('Search channels')).toBeVisible()
expect(screen.getByRole('textbox', { name: 'Model' })).toBeVisible()
expect(screen.getByRole('button', { name: /^Status/ })).toBeVisible()
collapse.focus()
await user.keyboard('{Enter}')
expect(screen.getByRole('button', { name: 'Expand' })).toHaveAttribute(
'aria-expanded',
'false'
)
expect(screen.queryByRole('textbox')).not.toBeInTheDocument()
expect(
screen.queryByRole('button', { name: /^Status/ })
).not.toBeInTheDocument()
for (const name of ['Reset', 'Refresh', 'Card view', 'View']) {
expect(screen.getByRole('button', { name })).toBeVisible()
expect(screen.getByRole('button', { name })).toBeEnabled()
}
})
it('retains mobile search and filter values after expanding and resets them while collapsed', async () => {
setMobileViewport(true)
const user = userEvent.setup()
render(<Fixture collapsibleOnMobile />)
await user.type(screen.getByPlaceholderText('Search channels'), 'production')
await user.type(screen.getByRole('textbox', { name: 'Model' }), 'gpt')
await user.click(screen.getByRole('button', { name: 'Collapse' }))
await user.click(screen.getByRole('button', { name: 'Expand' }))
expect(screen.getByPlaceholderText('Search channels')).toHaveValue(
'production'
)
expect(screen.getByRole('textbox', { name: 'Model' })).toHaveValue('gpt')
expect(screen.getByRole('button', { name: /^Status/ })).toHaveTextContent(
'Enabled'
)
await user.click(screen.getByRole('button', { name: 'Collapse' }))
await user.click(screen.getByRole('button', { name: 'Reset' }))
await user.click(screen.getByRole('button', { name: 'Expand' }))
expect(screen.getByPlaceholderText('Search channels')).toHaveValue('')
expect(screen.getByRole('textbox', { name: 'Model' })).toHaveValue('')
expect(screen.getByRole('button', { name: 'Status' })).toBeVisible()
expect(
screen.queryByRole('button', { name: 'Reset' })
).not.toBeInTheDocument()
})
it.each([
{ mobile: false, collapsibleOnMobile: true, condition: 'on desktop' },
{ mobile: true, collapsibleOnMobile: undefined, condition: 'without opt-in' },
])('keeps filters visible without a panel toggle $condition', (testCase) => {
setMobileViewport(testCase.mobile)
render(<Fixture collapsibleOnMobile={testCase.collapsibleOnMobile} />)
expect(screen.getByPlaceholderText('Search channels')).toBeVisible()
expect(screen.getByRole('textbox', { name: 'Model' })).toBeVisible()
expect(screen.getByRole('button', { name: /^Status/ })).toBeVisible()
expect(
screen.queryByRole('button', { name: /^(Collapse|Expand)$/ })
).not.toBeInTheDocument()
})
@@ -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 <https://www.gnu.org/licenses/>.
For commercial licensing, please contact support@quantumnous.com
*/
import { ChevronDown } from 'lucide-react'
import { useState, type ReactNode } from 'react'
import { useTranslation } from 'react-i18next'
import { Button } from '@/components/ui/button'
import {
Collapsible,
CollapsibleContent,
CollapsibleTrigger,
} from '@/components/ui/collapsible'
import { cn } from '@/lib/utils'
type DataTableMobileFilterPanelProps = {
children: ReactNode
actions: ReactNode
compact?: boolean
className?: string
}
export function DataTableMobileFilterPanel(
props: DataTableMobileFilterPanelProps
) {
const { t } = useTranslation()
const [open, setOpen] = useState(true)
return (
<Collapsible
open={open}
onOpenChange={setOpen}
className={cn(
'bg-card/50 flex min-w-0 flex-col rounded-lg border p-2.5',
open && (props.compact ? 'gap-2.5' : 'gap-2'),
props.className
)}
>
<CollapsibleContent>{props.children}</CollapsibleContent>
<div
className={cn(
props.compact
? 'grid min-w-0 grid-cols-[auto_minmax(0,1fr)] items-start gap-2'
: 'flex items-center justify-end gap-1.5'
)}
>
<CollapsibleTrigger
aria-label={open ? t('Collapse') : t('Expand')}
render={
<Button
variant='ghost'
size='icon'
className={cn(
'text-muted-foreground hover:text-foreground',
props.compact ? 'size-9' : 'mr-auto size-7'
)}
/>
}
>
<ChevronDown
aria-hidden='true'
className={cn(
'transition-transform duration-200',
props.compact ? 'size-4' : 'size-3.5',
open && 'rotate-180'
)}
/>
</CollapsibleTrigger>
<div
role='group'
aria-label={t('Actions')}
className={cn(
'flex items-center justify-end gap-1.5',
props.compact &&
'min-w-0 flex-wrap [&>button]:h-auto [&>button]:min-h-9 [&>button]:max-w-full [&>button]:[overflow-wrap:anywhere] [&>button]:whitespace-normal'
)}
>
{props.actions}
</div>
</div>
</Collapsible>
)
}
@@ -24,10 +24,11 @@ import { useTranslation } from 'react-i18next'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { useDebounce } from '@/hooks'
import { useDebounce, useMediaQuery } from '@/hooks'
import { cn } from '@/lib/utils'
import { DataTableFacetedFilter } from './faceted-filter'
import { DataTableMobileFilterPanel } from './mobile-filter-panel'
import { DataTableViewOptions } from './view-options'
type FilterDef = {
@@ -78,6 +79,10 @@ export type DataTableToolbarProps<TData> = {
* search input and filter chips.
*/
additionalSearch?: ReactNode
/**
* Collapse the complete filter panel on mobile while keeping actions visible.
*/
collapsibleOnMobile?: boolean
/**
* Whether non-table filters (e.g. `additionalSearch` or `expandable`
* inputs) are currently active. Controls Reset button visibility
@@ -155,6 +160,7 @@ export function DataTableToolbar<TData>(props: DataTableToolbarProps<TData>) {
const { t } = useTranslation()
const [expanded, setExpanded] = useState(false)
const [isSearchComposing, setIsSearchComposing] = useState(false)
const isMobile = useMediaQuery('(max-width: 640px)')
const filters = props.filters ?? []
const hasExpandable = props.expandable != null
@@ -341,6 +347,33 @@ export function DataTableToolbar<TData>(props: DataTableToolbarProps<TData>) {
const hasLeftActions = props.leftActions != null
if (isMobile && props.collapsibleOnMobile) {
return (
<DataTableMobileFilterPanel
compact
className={props.className}
actions={
<>
{props.leftActions}
{props.preActions}
{resetButton}
{searchButton}
{viewToggleNode}
{viewOptionsNode}
</>
}
>
<div className='flex min-w-0 flex-wrap items-center gap-2'>
{props.customSearch !== undefined ? props.customSearch : searchInput}
{props.additionalSearch}
{filterChips}
{expanded && hasExpandable && props.expandable}
{expandToggle}
</div>
</DataTableMobileFilterPanel>
)
}
if (hasLeftActions) {
return (
<div className={cn('flex flex-col gap-2', props.className)}>