feat(keys): sort by current concurrency

This commit is contained in:
Bestony@Homelab
2026-07-08 15:51:22 +08:00
parent 6f43986c37
commit 5debe1db33
6 changed files with 358 additions and 22 deletions
+1 -1
View File
@@ -1168,7 +1168,7 @@ const allColumns = computed<Column[]>(() => [
{ key: 'name', label: t('common.name'), sortable: true },
{ key: 'key', label: t('keys.apiKey'), sortable: false },
{ key: 'group', label: t('keys.group'), sortable: false },
{ key: 'current_concurrency', label: t('keys.currentConcurrency'), sortable: false },
{ key: 'current_concurrency', label: t('keys.currentConcurrency'), sortable: true },
{ key: 'usage', label: t('keys.usage'), sortable: false },
{ key: 'rate_limit', label: t('keys.rateLimitColumn'), sortable: false },
{ key: 'expires_at', label: t('keys.expiresAt'), sortable: true },
@@ -149,11 +149,16 @@ const TablePageLayoutStub = {
}
const DataTableStub = {
name: 'DataTable',
props: ['columns', 'data'],
emits: ['sort'],
template: `
<div>
<div data-test="columns">{{ columns.map((col) => col.key).join(',') }}</div>
<div data-test="columns-meta">{{ JSON.stringify(columns.map((col) => ({ key: col.key, sortable: !!col.sortable }))) }}</div>
<button data-test="sort-current-concurrency" @click="$emit('sort', 'current_concurrency', 'asc')">
Sort Current Concurrency
</button>
<div v-for="row in data" :key="row.id">
<slot name="cell-name" :value="row.name" :row="row" />
<div data-test="current-concurrency">
@@ -166,17 +171,30 @@ const DataTableStub = {
}
const SelectStub = {
name: 'Select',
props: ['modelValue', 'options'],
emits: ['update:modelValue'],
template: '<select :value="modelValue" @change="$emit(\'update:modelValue\', $event.target.value)"></select>',
}
const SearchInputStub = {
name: 'SearchInput',
props: ['modelValue'],
emits: ['update:modelValue', 'search'],
template: '<input :value="modelValue" @input="$emit(\'update:modelValue\', $event.target.value)" />',
}
const PaginationStub = {
name: 'Pagination',
props: ['page', 'total', 'pageSize'],
emits: ['update:page', 'update:pageSize'],
template: `
<div>
<button data-test="page-size-50" @click="$emit('update:pageSize', 50)">50</button>
</div>
`,
}
const IconStub = {
props: ['name'],
template: '<span data-test="icon">{{ name }}</span>',
@@ -189,7 +207,7 @@ const mountView = async () => {
AppLayout: AppLayoutStub,
TablePageLayout: TablePageLayoutStub,
DataTable: DataTableStub,
Pagination: true,
Pagination: PaginationStub,
BaseDialog: true,
ConfirmDialog: true,
EmptyState: true,
@@ -212,6 +230,9 @@ const mountView = async () => {
const visibleColumnKeys = (wrapper: VueWrapper) =>
wrapper.get('[data-test="columns"]').text().split(',').filter(Boolean)
const visibleColumnMeta = (wrapper: VueWrapper): Array<{ key: string; sortable: boolean }> =>
JSON.parse(wrapper.get('[data-test="columns-meta"]').text())
const getButtonByText = (wrapper: VueWrapper, text: string) => {
const button = wrapper.findAll('button').find((item) => item.text().includes(text))
if (!button) {
@@ -317,4 +338,49 @@ describe('user KeysView column settings', () => {
expect(wrapper.get('[data-test="current-concurrency"]').text()).toBe('3')
})
it('marks current concurrency as sortable', async () => {
const wrapper = await mountView()
const currentConcurrencyColumn = visibleColumnMeta(wrapper).find(
(column) => column.key === 'current_concurrency'
)
expect(currentConcurrencyColumn?.sortable).toBe(true)
})
it('keeps filters and selected page size when sorting by current concurrency', async () => {
getAvailableGroups.mockResolvedValue([{ id: 42, name: 'OpenAI' }])
const wrapper = await mountView()
await wrapper.get('[data-test="page-size-50"]').trigger('click')
await flushPromises()
await wrapper.findComponent({ name: 'SearchInput' }).vm.$emit('update:modelValue', 'target')
await wrapper.findComponent({ name: 'SearchInput' }).vm.$emit('search')
await flushPromises()
const selects = wrapper.findAllComponents({ name: 'Select' })
await selects[0].vm.$emit('update:modelValue', 42)
await flushPromises()
await selects[1].vm.$emit('update:modelValue', 'active')
await flushPromises()
listKeys.mockClear()
await wrapper.get('[data-test="sort-current-concurrency"]').trigger('click')
await flushPromises()
expect(listKeys).toHaveBeenLastCalledWith(
1,
50,
{
search: 'target',
status: 'active',
group_id: 42,
sort_by: 'current_concurrency',
sort_order: 'asc',
},
expect.objectContaining({ signal: expect.any(AbortSignal) })
)
})
})