mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-10-14 20:12:39 +08:00
fix(keys): sync status after resetting quota
This commit is contained in:
@@ -1823,14 +1823,18 @@ const setExpirationDays = (days: number) => {
|
||||
|
||||
// Reset quota used for an API key
|
||||
const resetQuotaUsed = async () => {
|
||||
if (!selectedKey.value) return
|
||||
const key = selectedKey.value
|
||||
if (!key) return
|
||||
showResetQuotaDialog.value = false
|
||||
try {
|
||||
await keysAPI.update(selectedKey.value.id, { reset_quota: true })
|
||||
const updatedKey = await keysAPI.update(key.id, { reset_quota: true })
|
||||
appStore.showSuccess(t('keys.quotaResetSuccess'))
|
||||
// Update local state
|
||||
if (selectedKey.value) {
|
||||
selectedKey.value.quota_used = 0
|
||||
key.quota_used = updatedKey.quota_used
|
||||
if (key.status !== updatedKey.status) {
|
||||
key.status = updatedKey.status
|
||||
if (selectedKey.value?.id === key.id) {
|
||||
formData.value.status = updatedKey.status === 'active' ? 'active' : 'inactive'
|
||||
}
|
||||
}
|
||||
} catch (error: any) {
|
||||
const errorMsg = error.response?.data?.detail || t('keys.failedToResetQuota')
|
||||
|
||||
@@ -7,6 +7,7 @@ import KeysView from '../KeysView.vue'
|
||||
|
||||
const {
|
||||
listKeys,
|
||||
updateKey,
|
||||
getPublicSettings,
|
||||
getDashboardApiKeysUsage,
|
||||
getAvailableGroups,
|
||||
@@ -18,6 +19,7 @@ const {
|
||||
nextStep,
|
||||
} = vi.hoisted(() => ({
|
||||
listKeys: vi.fn(),
|
||||
updateKey: vi.fn(),
|
||||
getPublicSettings: vi.fn(),
|
||||
getDashboardApiKeysUsage: vi.fn(),
|
||||
getAvailableGroups: vi.fn(),
|
||||
@@ -59,7 +61,7 @@ vi.mock('@/api', () => ({
|
||||
keysAPI: {
|
||||
list: listKeys,
|
||||
create: vi.fn(),
|
||||
update: vi.fn(),
|
||||
update: updateKey,
|
||||
delete: vi.fn(),
|
||||
toggleStatus: vi.fn(),
|
||||
},
|
||||
@@ -170,6 +172,7 @@ const DataTableStub = {
|
||||
<slot name="cell-id" :value="row.id" :row="row" />
|
||||
</div>
|
||||
<slot name="cell-name" :value="row.name" :row="row" />
|
||||
<slot name="cell-actions" :row="row" />
|
||||
<div data-test="current-concurrency">
|
||||
<slot name="cell-current_concurrency" :value="row.current_concurrency" :row="row" />
|
||||
</div>
|
||||
@@ -223,7 +226,10 @@ const mountView = async () => {
|
||||
TablePageLayout: TablePageLayoutStub,
|
||||
DataTable: DataTableStub,
|
||||
Pagination: PaginationStub,
|
||||
BaseDialog: true,
|
||||
BaseDialog: {
|
||||
props: ['show'],
|
||||
template: '<div v-if="show"><slot /><slot name="footer" /></div>',
|
||||
},
|
||||
ConfirmDialog: true,
|
||||
EmptyState: true,
|
||||
Select: SelectStub,
|
||||
@@ -261,6 +267,7 @@ describe('user KeysView column settings', () => {
|
||||
localStorage.clear()
|
||||
|
||||
listKeys.mockReset()
|
||||
updateKey.mockReset()
|
||||
getPublicSettings.mockReset()
|
||||
getDashboardApiKeysUsage.mockReset()
|
||||
getAvailableGroups.mockReset()
|
||||
@@ -285,6 +292,43 @@ describe('user KeysView column settings', () => {
|
||||
isCurrentStep.mockReturnValue(false)
|
||||
})
|
||||
|
||||
it.each([
|
||||
{ initialStatus: 'quota_exhausted', status: 'active', formStatus: 'active' },
|
||||
{ initialStatus: 'inactive', status: 'inactive', formStatus: 'inactive' },
|
||||
{ initialStatus: 'active', status: 'active', formStatus: 'inactive' },
|
||||
] as const)('syncs quota reset from $initialStatus to $status with form status $formStatus', async ({ initialStatus, status, formStatus }) => {
|
||||
const key: ApiKey = {
|
||||
...createApiKey(), group_id: 1, quota: 10, quota_used: 10,
|
||||
status: initialStatus,
|
||||
}
|
||||
listKeys.mockResolvedValueOnce({ items: [key], total: 1, page: 1, page_size: 20, pages: 1 })
|
||||
updateKey.mockResolvedValue({ ...key, status, quota_used: 0 })
|
||||
const wrapper = await mountView()
|
||||
await getButtonByText(wrapper, 'common.edit').trigger('click')
|
||||
await wrapper.get('[data-tour="key-form-name"]').setValue('Unsaved name')
|
||||
const statusSelect = wrapper.findAllComponents({ name: 'Select' })
|
||||
.find((select) => select.props('options').length === 2 &&
|
||||
select.props('options')[0].value === 'active')!
|
||||
statusSelect.vm.$emit('update:modelValue', 'inactive')
|
||||
await wrapper.get('button[title="keys.resetQuotaUsed"]').trigger('click')
|
||||
const confirmation = wrapper.findAllComponents({ name: 'ConfirmDialog' })
|
||||
.find((dialog) => dialog.props('title') === 'keys.resetQuotaTitle')!
|
||||
confirmation.vm.$emit('confirm')
|
||||
await flushPromises()
|
||||
|
||||
expect(updateKey).toHaveBeenNthCalledWith(1, key.id, { reset_quota: true })
|
||||
expect(wrapper.findComponent({ name: 'DataTable' }).props('data')[0])
|
||||
.toMatchObject({ status, quota_used: 0 })
|
||||
expect(statusSelect.props('modelValue')).toBe(formStatus)
|
||||
expect((wrapper.get('[data-tour="key-form-name"]').element as HTMLInputElement).value)
|
||||
.toBe('Unsaved name')
|
||||
|
||||
await wrapper.get('#key-form').trigger('submit')
|
||||
await flushPromises()
|
||||
expect(updateKey).toHaveBeenNthCalledWith(2, key.id, expect.objectContaining({ name: 'Unsaved name', status: formStatus }))
|
||||
wrapper.unmount()
|
||||
})
|
||||
|
||||
it('uses the default API key columns with low-frequency columns hidden', async () => {
|
||||
const wrapper = await mountView()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user