mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-10-31 00:24:38 +00:00
Merge pull request #6283 from okbexx/feat/usage-compaction-kind
feat(usage): track native compaction requests
This commit is contained in:
@@ -127,6 +127,12 @@
|
||||
<Select v-model="filters.request_type" :options="requestTypeOptions" @change="emitChange" />
|
||||
</div>
|
||||
|
||||
<!-- Native compaction is independent of the transport request type. -->
|
||||
<div v-if="mode !== 'errors'" class="w-full sm:w-auto sm:min-w-[180px]">
|
||||
<label class="input-label">{{ t('usage.compactionFilter') }}</label>
|
||||
<Select v-model="filters.native_compaction_v2" :options="compactionOptions" @change="emitChange" />
|
||||
</div>
|
||||
|
||||
<!-- Billing Type Filter (usage only) -->
|
||||
<div v-if="mode !== 'errors'" class="w-full sm:w-auto sm:min-w-[200px]">
|
||||
<label class="input-label">{{ t('admin.usage.billingType') }}</label>
|
||||
@@ -274,6 +280,11 @@ const requestTypeOptions = ref<SelectOption[]>([
|
||||
{ value: 'cyber', label: t('usage.cyber') }
|
||||
])
|
||||
|
||||
const compactionOptions = ref<SelectOption[]>([
|
||||
{ value: null, label: t('usage.allCompactionTypes') },
|
||||
{ value: true, label: t('usage.compactionOnly') }
|
||||
])
|
||||
|
||||
const billingTypeOptions = ref<SelectOption[]>([
|
||||
{ value: null, label: t('admin.usage.allBillingTypes') },
|
||||
{ value: 0, label: t('admin.usage.billingTypeBalance') },
|
||||
|
||||
@@ -125,9 +125,18 @@
|
||||
</template>
|
||||
|
||||
<template #cell-stream="{ row }">
|
||||
<span class="inline-flex items-center rounded px-2 py-0.5 text-xs font-medium" :class="getRequestTypeBadgeClass(row)">
|
||||
{{ getRequestTypeLabel(row) }}
|
||||
</span>
|
||||
<div class="flex flex-wrap items-center gap-1">
|
||||
<span data-testid="request-type-badge" class="inline-flex items-center rounded px-2 py-0.5 text-xs font-medium" :class="getRequestTypeBadgeClass(row)">
|
||||
{{ getRequestTypeLabel(row) }}
|
||||
</span>
|
||||
<span
|
||||
v-if="row.native_compaction_v2"
|
||||
data-testid="native-compaction-badge"
|
||||
class="inline-flex items-center rounded bg-teal-100 px-2 py-0.5 text-xs font-medium text-teal-800 dark:bg-teal-900 dark:text-teal-200"
|
||||
>
|
||||
{{ t('usage.nativeCompactionV2') }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #cell-billing_mode="{ row }">
|
||||
|
||||
@@ -19,6 +19,9 @@ const messages: Record<string, string> = {
|
||||
'usage.ws': 'WS',
|
||||
'usage.stream': 'Stream',
|
||||
'usage.sync': 'Sync',
|
||||
'usage.compactionFilter': 'Request Kind',
|
||||
'usage.allCompactionTypes': 'All Requests',
|
||||
'usage.compactionOnly': 'Compaction Only',
|
||||
'admin.usage.billingType': 'Billing Type',
|
||||
'admin.usage.allBillingTypes': 'All Billing Types',
|
||||
'admin.usage.billingTypeBalance': 'Balance',
|
||||
@@ -77,6 +80,7 @@ const defaultFilters = () => ({
|
||||
account_id: undefined,
|
||||
model: null,
|
||||
request_type: null,
|
||||
native_compaction_v2: null,
|
||||
billing_type: null,
|
||||
billing_mode: null,
|
||||
upstream_model_mismatch: null,
|
||||
@@ -259,3 +263,45 @@ describe('UsageFilters — model options come from prop (no dup request)', () =>
|
||||
expect(opts.map((o) => o.value)).toEqual([null, 'claude-3', 'gpt-4o'])
|
||||
})
|
||||
})
|
||||
|
||||
describe('UsageFilters — native compaction filter', () => {
|
||||
it('offers only All/Compaction and emits the independent boolean filter', async () => {
|
||||
const SelectStub = {
|
||||
name: 'Select',
|
||||
props: ['modelValue', 'options'],
|
||||
emits: ['update:modelValue', 'change'],
|
||||
template: '<div />',
|
||||
}
|
||||
const filters = defaultFilters()
|
||||
const wrapper = mount(UsageFilters, {
|
||||
props: {
|
||||
modelValue: filters,
|
||||
exporting: false,
|
||||
startDate: '2026-05-01',
|
||||
endDate: '2026-05-28',
|
||||
showActions: false,
|
||||
modelOptions: [],
|
||||
},
|
||||
global: { stubs: { Select: SelectStub, Teleport: true } },
|
||||
})
|
||||
|
||||
const compactionSelect = wrapper.findAllComponents(SelectStub).find((select: any) =>
|
||||
(select.props('options') as Array<{ value: unknown }>).some((option) => option.value === true)
|
||||
)
|
||||
expect(compactionSelect).toBeDefined()
|
||||
expect(compactionSelect!.props('options')).toEqual([
|
||||
{ value: null, label: 'All Requests' },
|
||||
{ value: true, label: 'Compaction Only' },
|
||||
])
|
||||
expect(compactionSelect!.props('options')).not.toEqual(
|
||||
expect.arrayContaining([expect.objectContaining({ value: false })])
|
||||
)
|
||||
|
||||
compactionSelect!.vm.$emit('update:modelValue', true)
|
||||
compactionSelect!.vm.$emit('change')
|
||||
await wrapper.vm.$nextTick()
|
||||
|
||||
expect(filters.native_compaction_v2).toBe(true)
|
||||
expect(wrapper.emitted('change')).toBeTruthy()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -54,6 +54,9 @@ const messages: Record<string, string> = {
|
||||
'usage.imageSizeUnknown': 'unknown',
|
||||
'usage.imageUnitPrice': 'Per-image price',
|
||||
'usage.imageTotalPrice': 'Image total price',
|
||||
'usage.stream': 'Stream',
|
||||
'usage.sync': 'Sync',
|
||||
'usage.nativeCompactionV2': 'Compaction',
|
||||
'admin.usage.billingModeToken': 'Token',
|
||||
'admin.usage.billingModePerRequest': 'Per request',
|
||||
'admin.usage.billingModeImage': 'Image',
|
||||
@@ -169,6 +172,56 @@ describe('admin UsageTable tooltip', () => {
|
||||
expect(wrapper.get('[data-testid="long-context-billing-marker"]').text()).toBe('x2')
|
||||
})
|
||||
|
||||
it('keeps the request type badge and adds a separate badge only for native compaction rows', () => {
|
||||
const DataTableStreamStub = {
|
||||
props: ['data'],
|
||||
template: `
|
||||
<div>
|
||||
<div v-for="row in data" :key="row.request_id">
|
||||
<slot name="cell-stream" :row="row" />
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
}
|
||||
const wrapper = mount(UsageTable, {
|
||||
props: {
|
||||
data: [
|
||||
{
|
||||
...baseImageRow,
|
||||
request_id: 'req-compaction-stream',
|
||||
request_type: 'stream',
|
||||
stream: true,
|
||||
native_compaction_v2: true,
|
||||
},
|
||||
{
|
||||
...baseImageRow,
|
||||
request_id: 'req-historical-sync',
|
||||
request_type: 'sync',
|
||||
stream: false,
|
||||
native_compaction_v2: false,
|
||||
},
|
||||
],
|
||||
loading: false,
|
||||
columns: [],
|
||||
},
|
||||
global: {
|
||||
stubs: {
|
||||
DataTable: DataTableStreamStub,
|
||||
EmptyState: true,
|
||||
Icon: true,
|
||||
Teleport: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const requestBadges = wrapper.findAll('[data-testid="request-type-badge"]')
|
||||
expect(requestBadges).toHaveLength(2)
|
||||
expect(requestBadges[0].text()).toBe('Stream')
|
||||
expect(requestBadges[1].text()).toBe('Sync')
|
||||
expect(wrapper.findAll('[data-testid="native-compaction-badge"]')).toHaveLength(1)
|
||||
expect(wrapper.get('[data-testid="native-compaction-badge"]').text()).toBe('Compaction')
|
||||
})
|
||||
|
||||
it('shows service tier and billing breakdown in cost tooltip', async () => {
|
||||
const row = {
|
||||
request_id: 'req-admin-1',
|
||||
|
||||
Reference in New Issue
Block a user