mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-09-24 16:05:44 +08:00
feat(keys): sort by current concurrency
This commit is contained in:
@@ -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) })
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user