From f396991b6a074746cc7ed890853070404ecbfeb3 Mon Sep 17 00:00:00 2001 From: Wang Lvyuan <74089601+LvyuanW@users.noreply.github.com> Date: Tue, 31 Mar 2026 11:21:32 +0800 Subject: [PATCH] fix: add paused account filter --- backend/internal/repository/account_repo.go | 2 ++ .../repository/account_repo_integration_test.go | 17 +++++++++++++++++ .../admin/account/AccountTableFilters.vue | 2 +- .../__tests__/AccountTableFilters.spec.ts | 3 +++ frontend/src/views/admin/AccountsView.vue | 4 +++- 5 files changed, 26 insertions(+), 2 deletions(-) diff --git a/backend/internal/repository/account_repo.go b/backend/internal/repository/account_repo.go index d45e8a1297..8e3449afa2 100644 --- a/backend/internal/repository/account_repo.go +++ b/backend/internal/repository/account_repo.go @@ -468,6 +468,8 @@ func (r *accountRepository) ListWithFilters(ctx context.Context, params paginati } if status != "" { switch status { + case "paused": + q = q.Where(dbaccount.SchedulableEQ(false)) case "rate_limited": q = q.Where(dbaccount.RateLimitResetAtGT(time.Now())) case "temp_unschedulable": diff --git a/backend/internal/repository/account_repo_integration_test.go b/backend/internal/repository/account_repo_integration_test.go index 8da30c92a8..93799ca70a 100644 --- a/backend/internal/repository/account_repo_integration_test.go +++ b/backend/internal/repository/account_repo_integration_test.go @@ -255,6 +255,23 @@ func (s *AccountRepoSuite) TestListWithFilters() { s.Require().Equal(service.StatusDisabled, accounts[0].Status) }, }, + { + name: "filter_by_paused", + setup: func(client *dbent.Client) { + active := mustCreateAccount(s.T(), client, &service.Account{Name: "active-schedulable"}) + paused := mustCreateAccount(s.T(), client, &service.Account{Name: "paused-account"}) + err := client.Account.UpdateOneID(paused.ID).SetSchedulable(false).Exec(context.Background()) + s.Require().NoError(err) + err = client.Account.UpdateOneID(active.ID).SetSchedulable(true).Exec(context.Background()) + s.Require().NoError(err) + }, + status: "paused", + wantCount: 1, + validate: func(accounts []service.Account) { + s.Require().Equal("paused-account", accounts[0].Name) + s.Require().False(accounts[0].Schedulable) + }, + }, { name: "filter_by_search", setup: func(client *dbent.Client) { diff --git a/frontend/src/components/admin/account/AccountTableFilters.vue b/frontend/src/components/admin/account/AccountTableFilters.vue index 43e703ec1e..678b785567 100644 --- a/frontend/src/components/admin/account/AccountTableFilters.vue +++ b/frontend/src/components/admin/account/AccountTableFilters.vue @@ -27,7 +27,7 @@ const updatePrivacyMode = (value: string | number | boolean | null) => { emit('u const updateGroup = (value: string | number | boolean | null) => { emit('update:filters', { ...props.filters, group: value }) } const pOpts = computed(() => [{ value: '', label: t('admin.accounts.allPlatforms') }, { value: 'anthropic', label: 'Anthropic' }, { value: 'openai', label: 'OpenAI' }, { value: 'gemini', label: 'Gemini' }, { value: 'antigravity', label: 'Antigravity' }, { value: 'sora', label: 'Sora' }]) const tOpts = computed(() => [{ value: '', label: t('admin.accounts.allTypes') }, { value: 'oauth', label: t('admin.accounts.oauthType') }, { value: 'setup-token', label: t('admin.accounts.setupToken') }, { value: 'apikey', label: t('admin.accounts.apiKey') }, { value: 'bedrock', label: 'AWS Bedrock' }]) -const sOpts = computed(() => [{ value: '', label: t('admin.accounts.allStatus') }, { value: 'active', label: t('admin.accounts.status.active') }, { value: 'inactive', label: t('admin.accounts.status.inactive') }, { value: 'error', label: t('admin.accounts.status.error') }, { value: 'rate_limited', label: t('admin.accounts.status.rateLimited') }, { value: 'temp_unschedulable', label: t('admin.accounts.status.tempUnschedulable') }]) +const sOpts = computed(() => [{ value: '', label: t('admin.accounts.allStatus') }, { value: 'active', label: t('admin.accounts.status.active') }, { value: 'inactive', label: t('admin.accounts.status.inactive') }, { value: 'paused', label: t('admin.accounts.status.paused') }, { value: 'error', label: t('admin.accounts.status.error') }, { value: 'rate_limited', label: t('admin.accounts.status.rateLimited') }, { value: 'temp_unschedulable', label: t('admin.accounts.status.tempUnschedulable') }]) const privacyOpts = computed(() => [ { value: '', label: t('admin.accounts.allPrivacyModes') }, { value: '__unset__', label: t('admin.accounts.privacyUnset') }, diff --git a/frontend/src/components/admin/account/__tests__/AccountTableFilters.spec.ts b/frontend/src/components/admin/account/__tests__/AccountTableFilters.spec.ts index 5a0044e5f2..f982075d84 100644 --- a/frontend/src/components/admin/account/__tests__/AccountTableFilters.spec.ts +++ b/frontend/src/components/admin/account/__tests__/AccountTableFilters.spec.ts @@ -44,6 +44,9 @@ describe('AccountTableFilters', () => { const selects = wrapper.findAll('.select-stub') expect(selects).toHaveLength(5) + const statusOptions = JSON.parse(selects[2].attributes('data-options')) + expect(statusOptions).toContainEqual({ value: 'paused', label: 'admin.accounts.status.paused' }) + const privacyOptions = JSON.parse(selects[3].attributes('data-options')) expect(privacyOptions).toEqual([ { value: '', label: 'admin.accounts.allPrivacyModes' }, diff --git a/frontend/src/views/admin/AccountsView.vue b/frontend/src/views/admin/AccountsView.vue index 35e0fcec48..b3fefb2e03 100644 --- a/frontend/src/views/admin/AccountsView.vue +++ b/frontend/src/views/admin/AccountsView.vue @@ -1107,7 +1107,9 @@ const accountMatchesCurrentFilters = (account: Account) => { if (params.platform && account.platform !== params.platform) return false if (params.type && account.type !== params.type) return false if (params.status) { - if (params.status === 'rate_limited') { + if (params.status === 'paused') { + if (account.schedulable) return false + } else if (params.status === 'rate_limited') { if (!account.rate_limit_reset_at) return false const resetAt = new Date(account.rate_limit_reset_at).getTime() if (!Number.isFinite(resetAt) || resetAt <= Date.now()) return false