perf(model-pricing): optimize upstream price sync table

- batch select and unselect operations into single state updates to reduce lag with large model lists.
- align current price and upstream preset rows by rendering the same ordered field set.
- switch the table to a fixed header, internal body scrolling, and fixed pagination layout with compact upstream header counts.
- hide synthesized preset internal IDs and count only effective selectable resolutions.
This commit is contained in:
QuentinHsu
2026-07-10 23:37:11 +08:00
parent 4e570389dd
commit 489c045842
6 changed files with 558 additions and 210 deletions
@@ -83,7 +83,9 @@ function SettingsPageFrame(props: SettingsPageFrameProps) {
/>
</SectionPageLayout.Actions>
<SectionPageLayout.Content>
<div className='flex w-full flex-col gap-4'>{props.children}</div>
<div className='flex h-full min-h-0 w-full flex-col gap-4'>
{props.children}
</div>
</SectionPageLayout.Content>
</SectionPageLayout>
</SettingsPageProvider>
@@ -58,18 +58,24 @@ function formatJsonValidationError(
)
}
const parts = [
error.line && error.column
? t('JSON is invalid at line {{line}}, column {{column}}.', {
let locationMessage: string
if (error.line && error.column) {
locationMessage = t(
'JSON is invalid at line {{line}}, column {{column}}.',
{
line: error.line,
column: error.column,
})
: error.position !== undefined
? t('JSON is invalid at position {{position}}.', {
}
)
} else if (error.position !== undefined) {
locationMessage = t('JSON is invalid at position {{position}}.', {
position: error.position,
})
: t('JSON is invalid. Please check the syntax.'),
]
} else {
locationMessage = t('JSON is invalid. Please check the syntax.')
}
const parts = [locationMessage]
if (error.missingCommaLine) {
parts.push(
@@ -459,14 +465,14 @@ export function RatioSettingsCard({
{renderTabContent(defaultTab)}
</SettingsSection>
) : (
<Tabs defaultValue={defaultTab} className='space-y-6'>
<Tabs defaultValue={defaultTab} className='h-full min-h-0 gap-6'>
<SettingsPageTitleStatusPortal>
{renderTabSwitcher()}
</SettingsPageTitleStatusPortal>
<SettingsSection title={t(titleKey)}>
<SettingsSection title={t(titleKey)} className='min-h-0 flex-1'>
{visibleTabs.map((tab) => (
<TabsContent key={tab} value={tab}>
<TabsContent key={tab} value={tab} className='min-h-0'>
{renderTabContent(tab)}
</TabsContent>
))}
@@ -16,12 +16,12 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
For commercial licensing, please contact support@quantumnous.com
*/
import { type ColumnDef } from '@tanstack/react-table'
import type { ColumnDef } from '@tanstack/react-table'
import { AlertTriangle } from 'lucide-react'
import { useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import { BadgeCell } from '@/components/data-table'
import { DataTableColumnHeader } from '@/components/data-table'
import { StatusBadge } from '@/components/status-badge'
import { Checkbox } from '@/components/ui/checkbox'
import {
@@ -33,16 +33,23 @@ import {
import type { RatioType } from '../types'
import {
getOrderedRatioTypes,
getAlignedRatioTypes,
getPreferredSyncField,
getSyncFieldLabel,
isSelectableUpstreamValue,
isSelectedResolutionValue,
type ModelRow,
type ResolutionsMap,
} from './upstream-ratio-sync-helpers'
import type { UpstreamBulkSelectState } from './upstream-ratio-sync-table'
const syncFieldListClassName = 'flex max-w-full min-w-0 flex-col gap-1.5'
const syncFieldRowClassName =
'bg-muted/30 flex h-8 w-fit max-w-full min-w-0 items-center gap-2 rounded-md px-2'
const syncFieldLabelClassName = 'min-w-[4.5rem] shrink-0'
export function useUpstreamRatioSyncColumns(
upstreamNames: string[],
bulkSelectStateByUpstream: Record<string, UpstreamBulkSelectState>,
resolutions: ResolutionsMap,
ratioTypeFilter: string,
isDisabled: boolean,
@@ -53,8 +60,8 @@ export function useUpstreamRatioSyncColumns(
sourceName: string
) => void,
onUnselectValue: (model: string, ratioType: RatioType) => void,
onBulkSelect: (upstreamName: string, rows: ModelRow[]) => void,
onBulkUnselect: (upstreamName: string, rows: ModelRow[]) => void
onBulkSelect: (upstreamName: string) => void,
onBulkUnselect: (upstreamName: string) => void
): ColumnDef<ModelRow>[] {
const { t } = useTranslation()
@@ -62,7 +69,11 @@ export function useUpstreamRatioSyncColumns(
const baseColumns: ColumnDef<ModelRow>[] = [
{
accessorKey: 'model',
header: t('Model'),
header: ({ column }) => (
<DataTableColumnHeader column={column} title={t('Model')} />
),
size: 220,
minSize: 180,
cell: ({ row }) => {
const model = row.original.model
return (
@@ -90,23 +101,29 @@ export function useUpstreamRatioSyncColumns(
},
{
id: 'current',
header: t('Current Price'),
header: ({ column }) => (
<DataTableColumnHeader column={column} title={t('Current Price')} />
),
size: 260,
minSize: 220,
cell: ({ row }) => {
const fields = getOrderedRatioTypes(
const fields = getAlignedRatioTypes(
row.original.ratioTypes,
upstreamNames,
ratioTypeFilter
)
return (
<div className='flex max-w-full min-w-0 flex-col gap-2'>
<div className={syncFieldListClassName}>
{fields.map((ratioType) => {
const current = row.original.ratioTypes[ratioType]?.current
return (
<BadgeCell key={ratioType} className='ml-0 flex-wrap gap-2'>
<div key={ratioType} className={syncFieldRowClassName}>
<StatusBadge
label={getSyncFieldLabel(ratioType, t)}
autoColor={ratioType}
size='sm'
copyable={false}
className={syncFieldLabelClassName}
/>
{current === null || current === undefined ? (
<StatusBadge
@@ -124,10 +141,10 @@ export function useUpstreamRatioSyncColumns(
label={String(current)}
variant='info'
size='sm'
className='max-w-[200px] truncate'
className='max-w-[160px] truncate font-mono'
/>
}
></TooltipTrigger>
/>
<TooltipContent>
<p className='max-w-xs text-xs break-all'>
{String(current)}
@@ -136,7 +153,7 @@ export function useUpstreamRatioSyncColumns(
</Tooltip>
</TooltipProvider>
)}
</BadgeCell>
</div>
)
})}
</div>
@@ -148,41 +165,19 @@ export function useUpstreamRatioSyncColumns(
const upstreamColumns: ColumnDef<ModelRow>[] = upstreamNames.map(
(upstreamName) => ({
id: `upstream_${upstreamName}`,
header: ({ table }) => {
const rows = table.getFilteredRowModel().rows.map((r) => r.original)
let selectableCount = 0
let selectedCount = 0
rows.forEach((row) => {
getOrderedRatioTypes(row.ratioTypes, ratioTypeFilter).forEach(
(ratioType) => {
const upstreamVal =
row.ratioTypes[ratioType]?.upstreams?.[upstreamName]
const preferredField = getPreferredSyncField(
row.ratioTypes,
ratioType,
upstreamName
)
if (
preferredField === ratioType &&
isSelectableUpstreamValue(upstreamVal)
) {
selectableCount++
if (resolutions[row.model]?.[ratioType] === upstreamVal) {
selectedCount++
}
}
}
)
})
size: 280,
minSize: 240,
header: () => {
const bulkSelectState = bulkSelectStateByUpstream[upstreamName]
const displayName = bulkSelectState?.displayName ?? upstreamName
const selectableCount = bulkSelectState?.selectableCount ?? 0
const selectedCount = bulkSelectState?.selectedCount ?? 0
const allSelected =
selectableCount > 0 && selectedCount === selectableCount
const someSelected =
selectedCount > 0 && selectedCount < selectableCount
return (
<div className='flex items-center gap-2'>
<div className='flex h-9 min-w-0 items-center gap-1.5'>
{selectableCount > 0 && (
<Checkbox
checked={allSelected}
@@ -190,56 +185,68 @@ export function useUpstreamRatioSyncColumns(
disabled={isDisabled}
onCheckedChange={(checked) => {
if (checked) {
onBulkSelect(upstreamName, rows)
onBulkSelect(upstreamName)
} else {
onBulkUnselect(upstreamName, rows)
onBulkUnselect(upstreamName)
}
}}
aria-label={t('Select all (filtered)')}
className='shrink-0'
/>
)}
<span className='font-medium'>{upstreamName}</span>
<div className='flex min-w-0 flex-1 items-center gap-1.5'>
<span className='min-w-0 truncate font-medium'>
{displayName}
</span>
{selectableCount > 0 && (
<span className='bg-muted text-muted-foreground shrink-0 rounded px-1.5 py-0.5 text-[11px] leading-none font-normal tabular-nums'>
{selectedCount}/{selectableCount}
</span>
)}
</div>
</div>
)
},
cell: ({ row }) => {
const fields = getOrderedRatioTypes(
const fields = getAlignedRatioTypes(
row.original.ratioTypes,
upstreamNames,
ratioTypeFilter
).filter(
(ratioType) =>
)
return (
<div className={syncFieldListClassName}>
{fields.map((ratioType) => {
const diff = row.original.ratioTypes[ratioType]
const upstreamVal = diff?.upstreams?.[upstreamName]
const isConfident = diff?.confidence?.[upstreamName] !== false
const isVisibleForSource =
getPreferredSyncField(
row.original.ratioTypes,
ratioType,
upstreamName
) === ratioType
)
return (
<div className='flex max-w-full min-w-0 flex-col gap-2'>
{fields.map((ratioType) => {
const diff = row.original.ratioTypes[ratioType]
const upstreamVal = diff?.upstreams?.[upstreamName]
const isConfident = diff?.confidence?.[upstreamName] !== false
return (
<div
key={ratioType}
className='flex min-w-0 items-start gap-2'
>
<div key={ratioType} className={syncFieldRowClassName}>
<StatusBadge
label={getSyncFieldLabel(ratioType, t)}
autoColor={ratioType}
size='sm'
copyable={false}
className='shrink-0'
className={syncFieldLabelClassName}
/>
<div className='min-w-0 flex-1'>
{renderUpstreamValue({
upstreamVal,
isAvailable: isVisibleForSource,
isConfident,
isSelected:
resolutions[row.original.model]?.[ratioType] ===
upstreamVal,
isSelected: isSelectedResolutionValue(
resolutions,
row.original.model,
ratioType,
upstreamVal
),
isDisabled,
t,
onSelect: () =>
@@ -265,6 +272,7 @@ export function useUpstreamRatioSyncColumns(
return [...baseColumns, ...upstreamColumns]
}, [
upstreamNames,
bulkSelectStateByUpstream,
resolutions,
ratioTypeFilter,
isDisabled,
@@ -278,6 +286,7 @@ export function useUpstreamRatioSyncColumns(
type RenderUpstreamValueArgs = {
upstreamVal: number | string | 'same' | null | undefined
isAvailable: boolean
isConfident: boolean
isSelected: boolean
isDisabled: boolean
@@ -287,7 +296,14 @@ type RenderUpstreamValueArgs = {
}
function renderUpstreamValue(args: RenderUpstreamValueArgs) {
const { upstreamVal, isConfident, isSelected, isDisabled, t } = args
const { upstreamVal, isAvailable, isConfident, isSelected, isDisabled, t } =
args
if (!isAvailable) {
return (
<StatusBadge label='—' variant='neutral' size='sm' copyable={false} />
)
}
if (upstreamVal === null || upstreamVal === undefined) {
return (
@@ -314,7 +330,7 @@ function renderUpstreamValue(args: RenderUpstreamValueArgs) {
const text = String(upstreamVal)
return (
<div className='flex min-w-0 items-center gap-2'>
<div className='flex h-full min-w-0 items-center gap-2'>
<Checkbox
checked={isSelected}
disabled={isDisabled}
@@ -325,6 +341,7 @@ function renderUpstreamValue(args: RenderUpstreamValueArgs) {
args.onUnselect()
}
}}
className='size-4'
/>
<TooltipProvider>
<Tooltip>
@@ -17,7 +17,13 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
For commercial licensing, please contact support@quantumnous.com
*/
import type { RatioType } from '../types'
import { RATIO_TYPE_OPTIONS } from './constants'
import {
MODELS_DEV_PRESET_ID,
MODELS_DEV_PRESET_NAME,
OFFICIAL_CHANNEL_ID,
OFFICIAL_CHANNEL_NAME,
RATIO_TYPE_OPTIONS,
} from './constants'
export type RatioDifferenceEntry = {
current: number | string | null
@@ -34,6 +40,24 @@ export type ModelRow = {
export type ResolutionsMap = Record<string, Record<string, number | string>>
export type ResolutionSelection = {
model: string
ratioType: RatioType
value: number | string
sourceName: string
}
export type ResolvedResolutionSelection = ResolutionSelection & {
ratioType: RatioType
}
export type ResolutionRemoval = {
model: string
ratioType: RatioType
}
export type ResolutionRemovalPlan = Map<string, Set<RatioType>>
export const RATIO_SYNC_FIELDS: RatioType[] = [
'model_ratio',
'completion_ratio',
@@ -95,8 +119,291 @@ export function getPreferredSyncField(
return ratioType
}
export function getVisibleRatioTypesForSource(
ratioTypes: Partial<Record<RatioType, RatioDifferenceEntry>>,
sourceName: string,
filter?: string
): RatioType[] {
return getOrderedRatioTypes(ratioTypes, filter).filter(
(ratioType) =>
getPreferredSyncField(ratioTypes, ratioType, sourceName) === ratioType
)
}
export function getAlignedRatioTypes(
ratioTypes: Partial<Record<RatioType, RatioDifferenceEntry>>,
sourceNames: string[],
filter?: string
): RatioType[] {
const ordered = getOrderedRatioTypes(ratioTypes, filter)
if (sourceNames.length === 0) return ordered
const visible = new Set<RatioType>()
sourceNames.forEach((sourceName) => {
getVisibleRatioTypesForSource(ratioTypes, sourceName, filter).forEach(
(ratioType) => visible.add(ratioType)
)
})
return ordered.filter((ratioType) => visible.has(ratioType))
}
export function getBillingCategory(
ratioType: string
): 'price' | 'ratio' | 'tiered' {
if (ratioType === 'model_price') return 'price'
if (ratioType === 'billing_mode' || ratioType === 'billing_expr') {
return 'tiered'
}
return 'ratio'
}
export function isSelectableUpstreamValue(
value: number | string | 'same' | null | undefined
): boolean {
return value !== null && value !== undefined && value !== 'same'
}
export function getUpstreamDisplayName(sourceName: string): string {
const synthesizedPresets = [
{ name: OFFICIAL_CHANNEL_NAME, id: OFFICIAL_CHANNEL_ID },
{ name: MODELS_DEV_PRESET_NAME, id: MODELS_DEV_PRESET_ID },
]
for (const preset of synthesizedPresets) {
if (sourceName === `${preset.name}(${preset.id})`) {
return preset.name
}
}
return sourceName
}
export function isSelectedResolutionValue(
resolutions: ResolutionsMap,
model: string,
ratioType: RatioType,
upstreamValue: number | string | 'same' | null | undefined
): boolean {
if (!isSelectableUpstreamValue(upstreamValue)) return false
const selectedValue = resolutions[model]?.[ratioType]
if (selectedValue === undefined) return false
if (NUMERIC_SYNC_FIELDS.has(ratioType)) {
const selectedNumber = Number(selectedValue)
const upstreamNumber = Number(upstreamValue)
return (
Number.isFinite(selectedNumber) &&
Number.isFinite(upstreamNumber) &&
selectedNumber === upstreamNumber
)
}
return selectedValue === upstreamValue
}
export function deleteResolutionField(
resolutions: ResolutionsMap,
model: string,
ratioType: RatioType
): ResolutionsMap {
return applyResolutionRemovals(resolutions, [{ model, ratioType }])
}
function getDraftModelResolution(
drafts: Map<string, Record<string, number | string>>,
resolutions: ResolutionsMap,
model: string
): Record<string, number | string> {
const existingDraft = drafts.get(model)
if (existingDraft) return existingDraft
const draft = resolutions[model] ? { ...resolutions[model] } : {}
drafts.set(model, draft)
return draft
}
function applyResolutionSelectionToDraft(
drafts: Map<string, Record<string, number | string>>,
resolutions: ResolutionsMap,
differences: Record<string, Partial<Record<RatioType, RatioDifferenceEntry>>>,
selection: ResolutionSelection
) {
const modelDiffs = differences[selection.model]
const preferredType = getPreferredSyncField(
modelDiffs || {},
selection.ratioType,
selection.sourceName
)
const preferredValue =
preferredType === selection.ratioType
? selection.value
: (modelDiffs?.[preferredType]?.upstreams?.[selection.sourceName] ??
selection.value)
const finalType = preferredType
const finalValue = preferredValue as number | string
const category = getBillingCategory(finalType)
const newModelRes = getDraftModelResolution(
drafts,
resolutions,
selection.model
)
Object.keys(newModelRes).forEach((rt) => {
if (
category !== 'tiered' &&
getBillingCategory(rt) !== 'tiered' &&
getBillingCategory(rt) !== category
) {
delete newModelRes[rt]
}
})
newModelRes[finalType] = finalValue
if (category === 'tiered' && modelDiffs) {
const modeVal = modelDiffs.billing_mode?.upstreams?.[selection.sourceName]
const exprVal = modelDiffs.billing_expr?.upstreams?.[selection.sourceName]
if (modeVal !== undefined && modeVal !== null && modeVal !== 'same') {
newModelRes['billing_mode'] = modeVal
} else if (finalType === 'billing_expr') {
newModelRes['billing_mode'] = 'tiered_expr'
}
if (exprVal !== undefined && exprVal !== null && exprVal !== 'same') {
newModelRes['billing_expr'] = exprVal
}
}
}
export function resolveResolutionSelection(
differences: Record<string, Partial<Record<RatioType, RatioDifferenceEntry>>>,
selection: ResolutionSelection
): ResolvedResolutionSelection {
const modelDiffs = differences[selection.model]
const preferredType = getPreferredSyncField(
modelDiffs || {},
selection.ratioType,
selection.sourceName
)
const preferredValue =
preferredType === selection.ratioType
? selection.value
: (modelDiffs?.[preferredType]?.upstreams?.[selection.sourceName] ??
selection.value)
return {
...selection,
ratioType: preferredType,
value: preferredValue as number | string,
}
}
export function getEffectiveResolutionSelections(
differences: Record<string, Partial<Record<RatioType, RatioDifferenceEntry>>>,
selections: ResolutionSelection[]
): ResolvedResolutionSelection[] {
const effectiveByKey = new Map<string, ResolvedResolutionSelection>()
selections.forEach((selection) => {
const resolved = resolveResolutionSelection(differences, selection)
const category = getBillingCategory(resolved.ratioType)
if (category !== 'tiered') {
for (const [key, existing] of effectiveByKey) {
if (
existing.model === resolved.model &&
getBillingCategory(existing.ratioType) !== 'tiered' &&
getBillingCategory(existing.ratioType) !== category
) {
effectiveByKey.delete(key)
}
}
}
effectiveByKey.set(`${resolved.model}\u0000${resolved.ratioType}`, resolved)
})
return [...effectiveByKey.values()]
}
export function applyResolutionSelections(
resolutions: ResolutionsMap,
differences: Record<string, Partial<Record<RatioType, RatioDifferenceEntry>>>,
selections: ResolutionSelection[]
): ResolutionsMap {
if (selections.length === 0) return resolutions
const next = { ...resolutions }
const drafts = new Map<string, Record<string, number | string>>()
selections.forEach((selection) => {
applyResolutionSelectionToDraft(drafts, resolutions, differences, selection)
})
drafts.forEach((draft, model) => {
if (Object.keys(draft).length === 0) {
delete next[model]
} else {
next[model] = draft
}
})
return next
}
export function applyResolutionSelection(
resolutions: ResolutionsMap,
differences: Record<string, Partial<Record<RatioType, RatioDifferenceEntry>>>,
selection: ResolutionSelection
): ResolutionsMap {
return applyResolutionSelections(resolutions, differences, [selection])
}
export function applyResolutionRemovals(
resolutions: ResolutionsMap,
removals: ResolutionRemoval[]
): ResolutionsMap {
if (removals.length === 0) return resolutions
const plan: ResolutionRemovalPlan = new Map()
removals.forEach((removal) => {
const ratioTypes = plan.get(removal.model)
if (ratioTypes) {
ratioTypes.add(removal.ratioType)
} else {
plan.set(removal.model, new Set([removal.ratioType]))
}
})
return applyResolutionRemovalPlan(resolutions, plan)
}
export function applyResolutionRemovalPlan(
resolutions: ResolutionsMap,
plan: ResolutionRemovalPlan
): ResolutionsMap {
if (plan.size === 0) return resolutions
const next = { ...resolutions }
plan.forEach((ratioTypes, model) => {
const current = resolutions[model]
if (!current) return
const draft = { ...current }
ratioTypes.forEach((ratioType) => {
delete draft[ratioType]
if (ratioType === 'billing_expr') delete draft['billing_mode']
if (ratioType === 'billing_mode') delete draft['billing_expr']
})
if (Object.keys(draft).length === 0) {
delete next[model]
} else {
next[model] = draft
}
})
return next
}
@@ -39,11 +39,16 @@ import type { DifferencesMap, RatioType } from '../types'
import { RATIO_TYPE_OPTIONS } from './constants'
import { useUpstreamRatioSyncColumns } from './upstream-ratio-sync-columns'
import {
getAlignedRatioTypes,
getEffectiveResolutionSelections,
getOrderedRatioTypes,
getPreferredSyncField,
getUpstreamDisplayName,
isSelectedResolutionValue,
isSelectableUpstreamValue,
RATIO_SYNC_FIELDS,
type ModelRow,
type ResolutionRemovalPlan,
type ResolutionSelection,
type ResolutionsMap,
} from './upstream-ratio-sync-helpers'
@@ -58,7 +63,17 @@ type UpstreamRatioSyncTableProps = {
value: number | string,
sourceName: string
) => void
onSelectValues: (selections: ResolutionSelection[]) => void
onUnselectValue: (model: string, ratioType: RatioType) => void
onUnselectValues: (plan: ResolutionRemovalPlan) => void
}
export type UpstreamBulkSelectState = {
displayName: string
selections: ResolutionSelection[]
removalPlan: ResolutionRemovalPlan
selectableCount: number
selectedCount: number
}
export function UpstreamRatioSyncTable({
@@ -67,7 +82,9 @@ export function UpstreamRatioSyncTable({
isDisabled,
isSyncing,
onSelectValue,
onSelectValues,
onUnselectValue,
onUnselectValues,
}: UpstreamRatioSyncTableProps) {
const { t } = useTranslation()
const [search, setSearch] = useState('')
@@ -112,57 +129,88 @@ export function UpstreamRatioSyncTable({
}
)
})
return Array.from(set)
return [...set]
}, [filteredData, ratioTypeFilter])
const handleBulkSelect = useCallback(
(upstream: string, rows: ModelRow[]) => {
rows.forEach((row) => {
getOrderedRatioTypes(row.ratioTypes, ratioTypeFilter).forEach(
(ratioType) => {
const upstreamVal = row.ratioTypes[ratioType]?.upstreams?.[upstream]
const preferredField = getPreferredSyncField(
const bulkSelectStateByUpstream = useMemo<
Record<string, UpstreamBulkSelectState>
>(() => {
return upstreamNames.reduce<Record<string, UpstreamBulkSelectState>>(
(states, upstreamName) => {
const selections: ResolutionSelection[] = []
const removalPlan: ResolutionRemovalPlan = new Map()
filteredData.forEach((row) => {
getAlignedRatioTypes(
row.ratioTypes,
[upstreamName],
ratioTypeFilter
).forEach((ratioType) => {
const upstreamVal =
row.ratioTypes[ratioType]?.upstreams?.[upstreamName]
if (isSelectableUpstreamValue(upstreamVal)) {
selections.push({
model: row.model,
ratioType,
upstream
)
if (
preferredField === ratioType &&
isSelectableUpstreamValue(upstreamVal)
) {
onSelectValue(
row.model,
ratioType,
upstreamVal as number | string,
upstream
)
}
}
)
value: upstreamVal as number | string,
sourceName: upstreamName,
})
const removalRatioTypes = removalPlan.get(row.model)
if (removalRatioTypes) {
removalRatioTypes.add(ratioType)
} else {
removalPlan.set(row.model, new Set([ratioType]))
}
}
})
})
const effectiveSelections = getEffectiveResolutionSelections(
differences,
selections
)
const selectedCount = effectiveSelections.filter((selection) =>
isSelectedResolutionValue(
resolutions,
selection.model,
selection.ratioType,
selection.value
)
).length
states[upstreamName] = {
displayName: getUpstreamDisplayName(upstreamName),
selections: effectiveSelections,
removalPlan,
selectableCount: effectiveSelections.length,
selectedCount,
}
return states
},
[ratioTypeFilter, onSelectValue]
{}
)
}, [differences, filteredData, ratioTypeFilter, resolutions, upstreamNames])
const handleBulkSelect = useCallback(
(upstream: string) => {
const selections = bulkSelectStateByUpstream[upstream]?.selections ?? []
onSelectValues(selections)
},
[bulkSelectStateByUpstream, onSelectValues]
)
const handleBulkUnselect = useCallback(
(upstream: string, rows: ModelRow[]) => {
rows.forEach((row) => {
getOrderedRatioTypes(row.ratioTypes, ratioTypeFilter).forEach(
(ratioType) => {
if (
row.ratioTypes[ratioType]?.upstreams?.[upstream] !== undefined
) {
onUnselectValue(row.model, ratioType)
}
}
)
})
(upstream: string) => {
const removalPlan =
bulkSelectStateByUpstream[upstream]?.removalPlan ?? new Map()
onUnselectValues(removalPlan)
},
[ratioTypeFilter, onUnselectValue]
[bulkSelectStateByUpstream, onUnselectValues]
)
const columns = useUpstreamRatioSyncColumns(
upstreamNames,
bulkSelectStateByUpstream,
resolutions,
ratioTypeFilter,
isDisabled,
@@ -209,8 +257,8 @@ export function UpstreamRatioSyncTable({
}
return (
<div className='space-y-4'>
<div className='flex flex-col gap-2 sm:flex-row sm:items-center'>
<div className='flex h-full min-h-[520px] flex-col gap-4'>
<div className='flex shrink-0 flex-col gap-2 sm:flex-row sm:items-center'>
<div className='relative flex-1'>
<Search className='text-muted-foreground absolute top-1/2 left-2 h-4 w-4 -translate-y-1/2' />
<Input
@@ -251,15 +299,23 @@ export function UpstreamRatioSyncTable({
<DataTableView
table={table}
containerClassName='rounded-md'
tableContainerClassName='overflow-x-auto'
getColumnClassName={() => 'align-top'}
containerClassName='min-h-0 flex-1 rounded-md'
tableContainerClassName='h-full min-h-0'
tableHeaderClassName='[background-color:var(--table-header)]'
splitHeaderScrollClassName='h-full'
bodyContainerClassName='[scrollbar-gutter:stable]'
splitHeader
getColumnClassName={(_, part) =>
part === 'header' ? 'h-11 align-middle' : 'align-top'
}
getRowClassName={() => 'align-top'}
emptyContent={t('No results found')}
emptyCellClassName='h-24 text-center'
/>
<div className='shrink-0'>
<DataTablePagination table={table} />
</div>
</div>
)
}
@@ -52,7 +52,12 @@ import {
import {
NUMERIC_SYNC_FIELDS,
RATIO_SYNC_FIELDS,
getPreferredSyncField,
applyResolutionRemovalPlan,
applyResolutionSelection,
applyResolutionSelections,
deleteResolutionField,
type ResolutionRemovalPlan,
type ResolutionSelection,
type ResolutionsMap,
} from './upstream-ratio-sync-helpers'
import { UpstreamRatioSyncTable } from './upstream-ratio-sync-table'
@@ -90,13 +95,6 @@ function getDefaultEndpointForChannel(channel: UpstreamChannel): string {
return DEFAULT_ENDPOINT
}
function getBillingCategory(ratioType: string): 'price' | 'ratio' | 'tiered' {
if (ratioType === 'model_price') return 'price'
if (ratioType === 'billing_mode' || ratioType === 'billing_expr')
return 'tiered'
return 'ratio'
}
function optionKeyBySyncField(ratioType: string): string {
const explicit: Record<string, string> = {
billing_mode: 'billing_setting.billing_mode',
@@ -117,25 +115,6 @@ function parseJsonRecord<T>(raw: string | undefined | null): Record<string, T> {
}
}
function deleteResolutionField(
res: ResolutionsMap,
model: string,
ratioType: string
): ResolutionsMap {
if (!res[model]) return res
const newModelRes = { ...res[model] }
delete newModelRes[ratioType]
if (ratioType === 'billing_expr') delete newModelRes['billing_mode']
if (ratioType === 'billing_mode') delete newModelRes['billing_expr']
const next = { ...res }
if (Object.keys(newModelRes).length === 0) {
delete next[model]
} else {
next[model] = newModelRes
}
return next
}
// ---------------------------------------------------------------------------
// Component
// ---------------------------------------------------------------------------
@@ -276,53 +255,24 @@ export function UpstreamRatioSync({ modelRatios }: UpstreamRatioSyncProps) {
value: number | string,
sourceName: string
) => {
const modelDiffs = differences[model]
// Prefer billing_expr over individual ratio fields when available
const preferredType = sourceName
? getPreferredSyncField(modelDiffs || {}, ratioType, sourceName)
: ratioType
const preferredValue =
preferredType === ratioType
? value
: (modelDiffs?.[preferredType]?.upstreams?.[sourceName] ?? value)
const finalType = preferredType
const finalValue = preferredValue as number | string
const category = getBillingCategory(finalType)
setResolutions((prev) => {
const newModelRes = { ...(prev[model] || {}) }
// Clear conflicting categories
Object.keys(newModelRes).forEach((rt) => {
if (
category !== 'tiered' &&
getBillingCategory(rt) !== 'tiered' &&
getBillingCategory(rt) !== category
) {
delete newModelRes[rt]
}
setResolutions((prev) =>
applyResolutionSelection(prev, differences, {
model,
ratioType,
value,
sourceName,
})
)
},
[differences]
)
newModelRes[finalType] = finalValue
// When selecting a tiered field, auto-populate paired fields from the same source
if (category === 'tiered' && sourceName && modelDiffs) {
const modeVal = modelDiffs.billing_mode?.upstreams?.[sourceName]
const exprVal = modelDiffs.billing_expr?.upstreams?.[sourceName]
if (modeVal !== undefined && modeVal !== null && modeVal !== 'same') {
newModelRes['billing_mode'] = modeVal
} else if (finalType === 'billing_expr') {
newModelRes['billing_mode'] = 'tiered_expr'
}
if (exprVal !== undefined && exprVal !== null && exprVal !== 'same') {
newModelRes['billing_expr'] = exprVal
}
}
return { ...prev, [model]: newModelRes }
})
const handleSelectValues = useCallback(
(selections: ResolutionSelection[]) => {
if (selections.length === 0) return
setResolutions((prev) =>
applyResolutionSelections(prev, differences, selections)
)
},
[differences]
)
@@ -334,6 +284,11 @@ export function UpstreamRatioSync({ modelRatios }: UpstreamRatioSyncProps) {
[]
)
const handleUnselectValues = useCallback((plan: ResolutionRemovalPlan) => {
if (plan.size === 0) return
setResolutions((prev) => applyResolutionRemovalPlan(prev, plan))
}, [])
const parsedRatios = useMemo(() => {
return {
ModelRatio: parseJsonRecord<number>(modelRatios.ModelRatio),
@@ -370,8 +325,9 @@ export function UpstreamRatioSync({ modelRatios }: UpstreamRatioSyncProps) {
currentRatios.ImageRatio[model] !== undefined ||
currentRatios.AudioRatio[model] !== undefined ||
currentRatios.AudioCompletionRatio[model] !== undefined
)
) {
return 'ratio'
}
return null
}
@@ -519,8 +475,8 @@ export function UpstreamRatioSync({ modelRatios }: UpstreamRatioSyncProps) {
const isLoading = fetchMutation.isPending || isSyncPending || confirmLoading
return (
<div className='space-y-4'>
<div className='flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between'>
<div className='flex h-full min-h-0 flex-col gap-4'>
<div className='flex shrink-0 flex-col gap-2 sm:flex-row sm:items-center sm:justify-between'>
<div className='flex flex-col gap-2 sm:flex-row'>
<Button onClick={handleOpenChannelDialog} disabled={isLoading}>
<RefreshCcw className='mr-2 h-4 w-4' />
@@ -540,14 +496,18 @@ export function UpstreamRatioSync({ modelRatios }: UpstreamRatioSyncProps) {
</div>
</div>
<div className='min-h-0 flex-1'>
<UpstreamRatioSyncTable
differences={differences}
resolutions={resolutions}
isDisabled={isLoading}
isSyncing={fetchMutation.isPending}
onSelectValue={handleSelectValue}
onSelectValues={handleSelectValues}
onUnselectValue={handleUnselectValue}
onUnselectValues={handleUnselectValues}
/>
</div>
<ChannelSelectorDialog
open={channelDialogOpen}