chore: remove superpowers docs
This commit is contained in:
@@ -1,359 +0,0 @@
|
|||||||
# Account Bulk Edit Scope And Compact Implementation Plan
|
|
||||||
|
|
||||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
|
||||||
|
|
||||||
**Goal:** Add filter-result bulk edit to admin accounts, unify the table-level bulk-edit entry, and align OpenAI bulk-edit controls with the existing compact-related single-account settings.
|
|
||||||
|
|
||||||
**Architecture:** Extend the existing `/admin/accounts/bulk-update` flow to accept either explicit account IDs or a server-resolved filter target. Reuse the current account-list filter contract for scope resolution, then update the accounts view and bulk-edit modal so the UI can launch either selected-account edits or current-filter-result edits from one compact dropdown. Keep the existing bulk-edit form, but expand its target contract and OpenAI-specific field coverage.
|
|
||||||
|
|
||||||
**Tech Stack:** Vue 3, TypeScript, Vitest, Gin, Go service/repository layer, existing admin accounts API.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Task 1: Add backend test coverage for filter-target bulk update
|
|
||||||
|
|
||||||
**Files:**
|
|
||||||
- Modify: `backend/internal/handler/admin/account_handler_mixed_channel_test.go`
|
|
||||||
- Modify: `backend/internal/service/admin_service_bulk_update_test.go`
|
|
||||||
- Test: `backend/internal/handler/admin/account_handler_mixed_channel_test.go`
|
|
||||||
- Test: `backend/internal/service/admin_service_bulk_update_test.go`
|
|
||||||
|
|
||||||
- [ ] **Step 1: Write the failing handler test for filter-target request acceptance**
|
|
||||||
|
|
||||||
```go
|
|
||||||
func TestBulkUpdateAcceptsFilterTargetRequest(t *testing.T) {
|
|
||||||
// add a request body that omits account_ids and submits filters instead
|
|
||||||
// assert the route does not reject the request as malformed once service stubs are wired
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
- [ ] **Step 2: Run test to verify it fails**
|
|
||||||
|
|
||||||
Run: `GOCACHE=/tmp/go-build GOMODCACHE=/tmp/go-mod go test ./backend/internal/handler/admin -run TestBulkUpdateAcceptsFilterTargetRequest -count=1`
|
|
||||||
Expected: FAIL because `BulkUpdateAccountsRequest` does not yet support `filters`.
|
|
||||||
|
|
||||||
- [ ] **Step 3: Write the failing service test for resolving IDs from filters**
|
|
||||||
|
|
||||||
```go
|
|
||||||
func TestAdminServiceBulkUpdateAccounts_ResolvesIDsFromFilters(t *testing.T) {
|
|
||||||
// construct BulkUpdateAccountsInput with Filters and no AccountIDs
|
|
||||||
// stub repository list/search path to return matching IDs
|
|
||||||
// assert BulkUpdate is called with all matching account IDs
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
- [ ] **Step 4: Run test to verify it fails**
|
|
||||||
|
|
||||||
Run: `GOCACHE=/tmp/go-build GOMODCACHE=/tmp/go-mod go test ./backend/internal/service -run TestAdminServiceBulkUpdateAccounts_ResolvesIDsFromFilters -count=1`
|
|
||||||
Expected: FAIL because `BulkUpdateAccountsInput` and service logic only use explicit `AccountIDs`.
|
|
||||||
|
|
||||||
- [ ] **Step 5: Commit**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git add backend/internal/handler/admin/account_handler_mixed_channel_test.go backend/internal/service/admin_service_bulk_update_test.go
|
|
||||||
git commit -m "test: cover filter-target account bulk update"
|
|
||||||
```
|
|
||||||
|
|
||||||
### Task 2: Implement backend filter-target bulk update
|
|
||||||
|
|
||||||
**Files:**
|
|
||||||
- Modify: `backend/internal/handler/admin/account_handler.go`
|
|
||||||
- Modify: `backend/internal/service/admin_service.go`
|
|
||||||
- Modify: `backend/internal/repository/account_repo.go`
|
|
||||||
- Modify: `backend/internal/service/account_service.go`
|
|
||||||
- Test: `backend/internal/handler/admin/account_handler_mixed_channel_test.go`
|
|
||||||
- Test: `backend/internal/service/admin_service_bulk_update_test.go`
|
|
||||||
|
|
||||||
- [ ] **Step 1: Implement request structs and validation for filter targets**
|
|
||||||
|
|
||||||
```go
|
|
||||||
type BulkUpdateAccountFilters struct {
|
|
||||||
Platform string `json:"platform"`
|
|
||||||
Type string `json:"type"`
|
|
||||||
Status string `json:"status"`
|
|
||||||
Group string `json:"group"`
|
|
||||||
Search string `json:"search"`
|
|
||||||
PrivacyMode string `json:"privacy_mode"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type BulkUpdateAccountsRequest struct {
|
|
||||||
AccountIDs []int64 `json:"account_ids"`
|
|
||||||
Filters *BulkUpdateAccountFilters `json:"filters"`
|
|
||||||
// existing fields remain unchanged
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
- [ ] **Step 2: Resolve filter targets in the service layer with one canonical path**
|
|
||||||
|
|
||||||
```go
|
|
||||||
type BulkUpdateAccountsInput struct {
|
|
||||||
AccountIDs []int64
|
|
||||||
Filters *BulkUpdateAccountFilters
|
|
||||||
// existing fields remain unchanged
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(input.AccountIDs) == 0 && input.Filters != nil {
|
|
||||||
ids, err := s.resolveBulkUpdateTargetIDs(ctx, input.Filters)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
input.AccountIDs = ids
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
- [ ] **Step 3: Reuse existing account-search/repository logic to resolve all matching IDs**
|
|
||||||
|
|
||||||
```go
|
|
||||||
func (s *AdminService) resolveBulkUpdateTargetIDs(ctx context.Context, filters *BulkUpdateAccountFilters) ([]int64, error) {
|
|
||||||
// call the existing repository list/search path with the submitted filters
|
|
||||||
// page through all matching rows or use a dedicated ID-only query helper
|
|
||||||
// return unique IDs in stable order
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
- [ ] **Step 4: Run targeted backend tests**
|
|
||||||
|
|
||||||
Run: `GOCACHE=/tmp/go-build GOMODCACHE=/tmp/go-mod go test ./backend/internal/handler/admin ./backend/internal/service -run 'TestBulkUpdateAcceptsFilterTargetRequest|TestAdminServiceBulkUpdateAccounts_ResolvesIDsFromFilters' -count=1`
|
|
||||||
Expected: PASS
|
|
||||||
|
|
||||||
- [ ] **Step 5: Commit**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git add backend/internal/handler/admin/account_handler.go backend/internal/service/admin_service.go backend/internal/repository/account_repo.go backend/internal/service/account_service.go backend/internal/handler/admin/account_handler_mixed_channel_test.go backend/internal/service/admin_service_bulk_update_test.go
|
|
||||||
git commit -m "feat: support filter-target account bulk update"
|
|
||||||
```
|
|
||||||
|
|
||||||
### Task 3: Add frontend API and modal tests for target scope
|
|
||||||
|
|
||||||
**Files:**
|
|
||||||
- Modify: `frontend/src/components/account/__tests__/BulkEditAccountModal.spec.ts`
|
|
||||||
- Create: `frontend/src/views/admin/__tests__/AccountsView.bulkEdit.spec.ts`
|
|
||||||
- Modify: `frontend/src/api/admin/accounts.ts`
|
|
||||||
- Test: `frontend/src/components/account/__tests__/BulkEditAccountModal.spec.ts`
|
|
||||||
- Test: `frontend/src/views/admin/__tests__/AccountsView.bulkEdit.spec.ts`
|
|
||||||
|
|
||||||
- [ ] **Step 1: Write the failing modal test for filter-target payload submission**
|
|
||||||
|
|
||||||
```ts
|
|
||||||
it('submits bulk edit using current filters when target mode is filtered-results', async () => {
|
|
||||||
// mount BulkEditAccountModal with targetMode='filtered'
|
|
||||||
// submit a minimal change
|
|
||||||
// expect adminAPI.accounts.bulkUpdate to receive { filters: ... } rather than account_ids
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
- [ ] **Step 2: Run test to verify it fails**
|
|
||||||
|
|
||||||
Run: `pnpm -C frontend test:run src/components/account/__tests__/BulkEditAccountModal.spec.ts -t "filtered-results"`
|
|
||||||
Expected: FAIL because the modal only accepts `accountIds`.
|
|
||||||
|
|
||||||
- [ ] **Step 3: Write the failing accounts-view test for dropdown launch actions**
|
|
||||||
|
|
||||||
```ts
|
|
||||||
it('opens bulk edit for current filtered results from the table action dropdown', async () => {
|
|
||||||
// mount AccountsView with filters set
|
|
||||||
// click Bulk edit > current filtered results
|
|
||||||
// assert modal props contain filter target metadata
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
- [ ] **Step 4: Run test to verify it fails**
|
|
||||||
|
|
||||||
Run: `pnpm -C frontend test:run src/views/admin/__tests__/AccountsView.bulkEdit.spec.ts`
|
|
||||||
Expected: FAIL because the dropdown action and target scope state do not exist yet.
|
|
||||||
|
|
||||||
- [ ] **Step 5: Commit**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git add frontend/src/components/account/__tests__/BulkEditAccountModal.spec.ts frontend/src/views/admin/__tests__/AccountsView.bulkEdit.spec.ts frontend/src/api/admin/accounts.ts
|
|
||||||
git commit -m "test: cover account bulk edit target scopes"
|
|
||||||
```
|
|
||||||
|
|
||||||
### Task 4: Implement unified frontend bulk-edit target scope flow
|
|
||||||
|
|
||||||
**Files:**
|
|
||||||
- Modify: `frontend/src/views/admin/AccountsView.vue`
|
|
||||||
- Modify: `frontend/src/components/admin/account/AccountBulkActionsBar.vue`
|
|
||||||
- Modify: `frontend/src/components/account/BulkEditAccountModal.vue`
|
|
||||||
- Modify: `frontend/src/api/admin/accounts.ts`
|
|
||||||
- Modify: `frontend/src/i18n/locales/zh.ts`
|
|
||||||
- Modify: `frontend/src/i18n/locales/en.ts`
|
|
||||||
- Test: `frontend/src/components/account/__tests__/BulkEditAccountModal.spec.ts`
|
|
||||||
- Test: `frontend/src/views/admin/__tests__/AccountsView.bulkEdit.spec.ts`
|
|
||||||
|
|
||||||
- [ ] **Step 1: Add a typed frontend target contract for bulk edit**
|
|
||||||
|
|
||||||
```ts
|
|
||||||
export type AccountBulkEditTarget =
|
|
||||||
| { mode: 'selected'; accountIds: number[]; selectedPlatforms: AccountPlatform[]; selectedTypes: AccountType[] }
|
|
||||||
| { mode: 'filtered'; filters: AccountListFilters; previewCount: number; selectedPlatforms: AccountPlatform[]; selectedTypes: AccountType[] }
|
|
||||||
```
|
|
||||||
|
|
||||||
- [ ] **Step 2: Replace the single selected-row edit button with one dropdown**
|
|
||||||
|
|
||||||
```vue
|
|
||||||
<BulkEditDropdown
|
|
||||||
:has-selection="selectedIds.length > 0"
|
|
||||||
@edit-selected="openBulkEditSelected"
|
|
||||||
@edit-filtered="openBulkEditFiltered"
|
|
||||||
/>
|
|
||||||
```
|
|
||||||
|
|
||||||
- [ ] **Step 3: Snapshot current filters and preview count when launching filtered mode**
|
|
||||||
|
|
||||||
```ts
|
|
||||||
const openBulkEditFiltered = async () => {
|
|
||||||
const filters = toBulkEditFilterSnapshot(params)
|
|
||||||
const preview = await adminAPI.accounts.list(1, 1, filters)
|
|
||||||
bulkEditTarget.value = {
|
|
||||||
mode: 'filtered',
|
|
||||||
filters,
|
|
||||||
previewCount: preview.pagination.total,
|
|
||||||
selectedPlatforms: collectPlatforms(preview.data),
|
|
||||||
selectedTypes: collectTypes(preview.data)
|
|
||||||
}
|
|
||||||
showBulkEdit.value = true
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
- [ ] **Step 4: Update modal submission to call `bulkUpdate` with either `account_ids` or `filters`**
|
|
||||||
|
|
||||||
```ts
|
|
||||||
if (props.target.mode === 'selected') {
|
|
||||||
await adminAPI.accounts.bulkUpdate({ account_ids: props.target.accountIds, ...updates })
|
|
||||||
} else {
|
|
||||||
await adminAPI.accounts.bulkUpdate({ filters: props.target.filters, ...updates })
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
- [ ] **Step 5: Run targeted frontend tests**
|
|
||||||
|
|
||||||
Run: `pnpm -C frontend test:run src/components/account/__tests__/BulkEditAccountModal.spec.ts src/views/admin/__tests__/AccountsView.bulkEdit.spec.ts`
|
|
||||||
Expected: PASS
|
|
||||||
|
|
||||||
- [ ] **Step 6: Commit**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git add frontend/src/views/admin/AccountsView.vue frontend/src/components/admin/account/AccountBulkActionsBar.vue frontend/src/components/account/BulkEditAccountModal.vue frontend/src/api/admin/accounts.ts frontend/src/i18n/locales/zh.ts frontend/src/i18n/locales/en.ts frontend/src/components/account/__tests__/BulkEditAccountModal.spec.ts frontend/src/views/admin/__tests__/AccountsView.bulkEdit.spec.ts
|
|
||||||
git commit -m "feat: add filtered-result account bulk edit"
|
|
||||||
```
|
|
||||||
|
|
||||||
### Task 5: Add failing tests for missing OpenAI bulk-edit fields
|
|
||||||
|
|
||||||
**Files:**
|
|
||||||
- Modify: `frontend/src/components/account/__tests__/BulkEditAccountModal.spec.ts`
|
|
||||||
- Test: `frontend/src/components/account/__tests__/BulkEditAccountModal.spec.ts`
|
|
||||||
|
|
||||||
- [ ] **Step 1: Write the failing OAuth test for `codex_cli_only`**
|
|
||||||
|
|
||||||
```ts
|
|
||||||
it('OpenAI OAuth bulk edit can submit codex_cli_only', async () => {
|
|
||||||
// enable the toggle and submit
|
|
||||||
// expect extra.codex_cli_only to be sent
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
- [ ] **Step 2: Run test to verify it fails**
|
|
||||||
|
|
||||||
Run: `pnpm -C frontend test:run src/components/account/__tests__/BulkEditAccountModal.spec.ts -t "codex_cli_only"`
|
|
||||||
Expected: FAIL because the modal has no such control or payload mapping.
|
|
||||||
|
|
||||||
- [ ] **Step 3: Write the failing API key test for API key WS mode**
|
|
||||||
|
|
||||||
```ts
|
|
||||||
it('OpenAI API key bulk edit submits API key WS mode fields', async () => {
|
|
||||||
// enable the API key WS mode selector and submit
|
|
||||||
// expect openai_apikey_responses_websockets_v2_mode and enabled flag
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
- [ ] **Step 4: Run test to verify it fails**
|
|
||||||
|
|
||||||
Run: `pnpm -C frontend test:run src/components/account/__tests__/BulkEditAccountModal.spec.ts -t "API key WS mode"`
|
|
||||||
Expected: FAIL because the modal only submits OAuth WS mode.
|
|
||||||
|
|
||||||
- [ ] **Step 5: Commit**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git add frontend/src/components/account/__tests__/BulkEditAccountModal.spec.ts
|
|
||||||
git commit -m "test: cover missing OpenAI bulk edit fields"
|
|
||||||
```
|
|
||||||
|
|
||||||
### Task 6: Implement missing OpenAI bulk-edit controls and payload wiring
|
|
||||||
|
|
||||||
**Files:**
|
|
||||||
- Modify: `frontend/src/components/account/BulkEditAccountModal.vue`
|
|
||||||
- Modify: `frontend/src/i18n/locales/zh.ts`
|
|
||||||
- Modify: `frontend/src/i18n/locales/en.ts`
|
|
||||||
- Test: `frontend/src/components/account/__tests__/BulkEditAccountModal.spec.ts`
|
|
||||||
|
|
||||||
- [ ] **Step 1: Add UI controls for OAuth `codex_cli_only` and API key WS mode**
|
|
||||||
|
|
||||||
```vue
|
|
||||||
<div v-if="allOpenAIOAuth">
|
|
||||||
<!-- existing OAuth WS mode -->
|
|
||||||
<!-- add codex_cli_only toggle -->
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-if="allOpenAIAPIKey">
|
|
||||||
<!-- add API key WS mode selector -->
|
|
||||||
</div>
|
|
||||||
```
|
|
||||||
|
|
||||||
- [ ] **Step 2: Mirror single-account payload semantics in the bulk-edit submit builder**
|
|
||||||
|
|
||||||
```ts
|
|
||||||
if (enableCodexCLIOnly.value) {
|
|
||||||
const extra = ensureExtra()
|
|
||||||
extra.codex_cli_only = codexCLIOnlyEnabled.value
|
|
||||||
}
|
|
||||||
|
|
||||||
if (enableOpenAIAPIKeyWSMode.value) {
|
|
||||||
const extra = ensureExtra()
|
|
||||||
extra.openai_apikey_responses_websockets_v2_mode = openaiAPIKeyResponsesWebSocketV2Mode.value
|
|
||||||
extra.openai_apikey_responses_websockets_v2_enabled = isOpenAIWSModeEnabled(openaiAPIKeyResponsesWebSocketV2Mode.value)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
- [ ] **Step 3: Run focused modal tests**
|
|
||||||
|
|
||||||
Run: `pnpm -C frontend test:run src/components/account/__tests__/BulkEditAccountModal.spec.ts`
|
|
||||||
Expected: PASS
|
|
||||||
|
|
||||||
- [ ] **Step 4: Commit**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git add frontend/src/components/account/BulkEditAccountModal.vue frontend/src/i18n/locales/zh.ts frontend/src/i18n/locales/en.ts frontend/src/components/account/__tests__/BulkEditAccountModal.spec.ts
|
|
||||||
git commit -m "feat: align OpenAI bulk edit compact settings"
|
|
||||||
```
|
|
||||||
|
|
||||||
### Task 7: Final regression verification
|
|
||||||
|
|
||||||
**Files:**
|
|
||||||
- Modify: none expected
|
|
||||||
- Test: `frontend/src/components/account/__tests__/BulkEditAccountModal.spec.ts`
|
|
||||||
- Test: `frontend/src/views/admin/__tests__/AccountsView.bulkEdit.spec.ts`
|
|
||||||
- Test: `backend/internal/handler/admin/account_handler_mixed_channel_test.go`
|
|
||||||
- Test: `backend/internal/service/admin_service_bulk_update_test.go`
|
|
||||||
|
|
||||||
- [ ] **Step 1: Run frontend typecheck**
|
|
||||||
|
|
||||||
Run: `pnpm -C frontend typecheck`
|
|
||||||
Expected: PASS
|
|
||||||
|
|
||||||
- [ ] **Step 2: Run focused frontend test suite**
|
|
||||||
|
|
||||||
Run: `pnpm -C frontend test:run src/components/account/__tests__/BulkEditAccountModal.spec.ts src/views/admin/__tests__/AccountsView.bulkEdit.spec.ts`
|
|
||||||
Expected: PASS
|
|
||||||
|
|
||||||
- [ ] **Step 3: Run focused backend test suite**
|
|
||||||
|
|
||||||
Run: `GOCACHE=/tmp/go-build GOMODCACHE=/tmp/go-mod go test ./backend/internal/handler/admin ./backend/internal/service -run 'BulkUpdate|bulk update' -count=1`
|
|
||||||
Expected: PASS
|
|
||||||
|
|
||||||
- [ ] **Step 4: Commit final integration fixes if needed**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git add frontend/src/components/account/BulkEditAccountModal.vue frontend/src/views/admin/AccountsView.vue frontend/src/components/admin/account/AccountBulkActionsBar.vue frontend/src/api/admin/accounts.ts frontend/src/i18n/locales/zh.ts frontend/src/i18n/locales/en.ts backend/internal/handler/admin/account_handler.go backend/internal/service/admin_service.go backend/internal/repository/account_repo.go backend/internal/service/account_service.go frontend/src/components/account/__tests__/BulkEditAccountModal.spec.ts frontend/src/views/admin/__tests__/AccountsView.bulkEdit.spec.ts backend/internal/handler/admin/account_handler_mixed_channel_test.go backend/internal/service/admin_service_bulk_update_test.go
|
|
||||||
git commit -m "feat: finish account bulk edit scope and compact support"
|
|
||||||
```
|
|
||||||
@@ -1,233 +0,0 @@
|
|||||||
# Account Bulk Edit Scope And Compact Design
|
|
||||||
|
|
||||||
## Summary
|
|
||||||
|
|
||||||
This change expands admin account bulk edit in two directions:
|
|
||||||
|
|
||||||
1. Add a second bulk-edit target scope based on the current filter result set, so operators do not need to manually select every account.
|
|
||||||
2. Align OpenAI bulk-edit fields with single-account create/edit for the compact-related settings that are already supported elsewhere.
|
|
||||||
|
|
||||||
The design keeps the existing selected-row workflow intact and adds a unified bulk-edit entry with two explicit actions:
|
|
||||||
|
|
||||||
- `Bulk edit selected accounts`
|
|
||||||
- `Bulk edit current filtered results`
|
|
||||||
|
|
||||||
`Current filtered results` reuses the existing account-list filters. That means:
|
|
||||||
|
|
||||||
- with no filters, it targets the whole account inventory
|
|
||||||
- with a group filter, it targets all accounts in that group
|
|
||||||
- with combined filters, it targets all matching accounts
|
|
||||||
|
|
||||||
## Goals
|
|
||||||
|
|
||||||
- Preserve the current selected-account bulk edit flow.
|
|
||||||
- Let operators bulk edit the full current filtered result set without manual row selection.
|
|
||||||
- Show the user the exact target scope before applying changes.
|
|
||||||
- Reuse the current list filter semantics instead of inventing a separate "all accounts" or "by group" API.
|
|
||||||
- Add the missing OpenAI bulk-edit fields:
|
|
||||||
- OAuth `codex_cli_only`
|
|
||||||
- API key `openai_apikey_responses_websockets_v2_mode`
|
|
||||||
|
|
||||||
## Non-Goals
|
|
||||||
|
|
||||||
- No new standalone "edit all accounts" route that ignores filters.
|
|
||||||
- No new dedicated "edit group" route separate from list filters.
|
|
||||||
- No change to the backend merge semantics for other bulk-edit fields.
|
|
||||||
- No attempt in this change to refactor all account form components into a shared schema system.
|
|
||||||
|
|
||||||
## Current State
|
|
||||||
|
|
||||||
### Bulk edit entry
|
|
||||||
|
|
||||||
The account list currently exposes bulk edit only through selected-row actions. `AccountsView.vue` passes `selIds`, `selPlatforms`, and `selTypes` into `BulkEditAccountModal.vue`.
|
|
||||||
|
|
||||||
### Filter state
|
|
||||||
|
|
||||||
The account page already keeps a central `params` object for current filters and reloads the table from that state. Group filtering already exists in `AccountTableFilters.vue`.
|
|
||||||
|
|
||||||
### Bulk edit payload
|
|
||||||
|
|
||||||
`BulkEditAccountModal.vue` builds a bulk update request around explicit account IDs.
|
|
||||||
|
|
||||||
### OpenAI field gap
|
|
||||||
|
|
||||||
Single-account create/edit already supports:
|
|
||||||
|
|
||||||
- `openai_passthrough`
|
|
||||||
- OAuth WS mode
|
|
||||||
- API key WS mode
|
|
||||||
- OAuth `codex_cli_only`
|
|
||||||
|
|
||||||
Bulk edit currently supports:
|
|
||||||
|
|
||||||
- `openai_passthrough`
|
|
||||||
- OAuth WS mode only
|
|
||||||
|
|
||||||
That leaves a real capability gap for operators managing large OpenAI account sets.
|
|
||||||
|
|
||||||
## User Experience
|
|
||||||
|
|
||||||
### Entry point
|
|
||||||
|
|
||||||
Use one compact `Bulk edit` dropdown button in the table-level bulk actions area above the grid.
|
|
||||||
|
|
||||||
The dropdown contains:
|
|
||||||
|
|
||||||
- `Bulk edit selected accounts`
|
|
||||||
- `Bulk edit current filtered results`
|
|
||||||
|
|
||||||
Behavior:
|
|
||||||
|
|
||||||
- If there is no row selection, the `selected accounts` action is disabled.
|
|
||||||
- `Current filtered results` is always available.
|
|
||||||
- The existing separate immediate `Edit` action in the selected-row bar is replaced by this unified dropdown to avoid duplicate buttons that mean different scopes.
|
|
||||||
|
|
||||||
### Modal scope messaging
|
|
||||||
|
|
||||||
The bulk edit modal gets a required scope descriptor prop.
|
|
||||||
|
|
||||||
For `selected accounts`:
|
|
||||||
|
|
||||||
- show the existing count-based info banner
|
|
||||||
- keep using explicit selected account metadata for platform/type compatibility checks
|
|
||||||
|
|
||||||
For `current filtered results`:
|
|
||||||
|
|
||||||
- show a banner stating that edits apply to the current filtered result set
|
|
||||||
- show the matched account count from a preview query
|
|
||||||
- show a short summary of active filters when practical, especially group/search/platform/type/status filters
|
|
||||||
|
|
||||||
### Safety
|
|
||||||
|
|
||||||
For filtered-result mode:
|
|
||||||
|
|
||||||
- disable submit if the preview count is `0`
|
|
||||||
- refresh the target count when the modal opens
|
|
||||||
- keep the final success toast count aligned with the backend result
|
|
||||||
|
|
||||||
The modal should not silently fall back from filtered mode to selected mode.
|
|
||||||
|
|
||||||
## Backend/API Design
|
|
||||||
|
|
||||||
### Request model
|
|
||||||
|
|
||||||
Extend bulk update to support two target modes:
|
|
||||||
|
|
||||||
- explicit IDs
|
|
||||||
- filter-based query
|
|
||||||
|
|
||||||
The request shape should keep backward compatibility for the selected-ID path while allowing a filter target. The backend handler can accept a payload that contains either:
|
|
||||||
|
|
||||||
- `account_ids`
|
|
||||||
- or `filters`
|
|
||||||
|
|
||||||
but not neither.
|
|
||||||
|
|
||||||
The `filters` payload should reuse the existing account-list query semantics already used by `/admin/accounts` and `/admin/accounts/data`, including:
|
|
||||||
|
|
||||||
- `search`
|
|
||||||
- `platform`
|
|
||||||
- `type`
|
|
||||||
- `status`
|
|
||||||
- `privacy_mode`
|
|
||||||
- `group`
|
|
||||||
- existing sort fields may be ignored for mutation targeting if not needed
|
|
||||||
|
|
||||||
### Preview count
|
|
||||||
|
|
||||||
The frontend needs an accurate target count before submit in filtered-result mode. The simplest compatible approach is:
|
|
||||||
|
|
||||||
- call the existing account list endpoint with the current filters and a minimal page size strategy sufficient to obtain total count
|
|
||||||
|
|
||||||
If the current API makes that awkward, add a narrow preview/count helper for bulk edit target resolution. Prefer reusing the existing listing contract first.
|
|
||||||
|
|
||||||
### Target resolution
|
|
||||||
|
|
||||||
For filtered-result mode, the backend must resolve matching account IDs server-side from the submitted filters rather than trusting only currently loaded page data. This is required so filtered-result mode can act on the full result set across pagination.
|
|
||||||
|
|
||||||
### Compatibility metadata
|
|
||||||
|
|
||||||
The frontend still needs platform/type compatibility to determine which fields to show. For filtered-result mode, derive this from the preview result set returned from the same query used to show count. If the preview spans mixed incompatible account types, show the same warnings/conditional UI that selected mode already uses.
|
|
||||||
|
|
||||||
## Frontend Design
|
|
||||||
|
|
||||||
### Accounts view
|
|
||||||
|
|
||||||
`AccountsView.vue` will:
|
|
||||||
|
|
||||||
- replace the direct selected-only bulk edit trigger with a dropdown action model
|
|
||||||
- keep a reactive description of the pending bulk edit scope
|
|
||||||
- pass either selected IDs or current filter params into the modal
|
|
||||||
|
|
||||||
The "current filtered results" action uses the live `params` object snapshot at open time, not a mutable live subscription while the modal is already open.
|
|
||||||
|
|
||||||
### Bulk edit modal
|
|
||||||
|
|
||||||
`BulkEditAccountModal.vue` will accept a richer target contract, for example:
|
|
||||||
|
|
||||||
- target mode
|
|
||||||
- selected IDs or filter snapshot
|
|
||||||
- preview count
|
|
||||||
- preview platform/type coverage if needed
|
|
||||||
|
|
||||||
The modal remains one form; only the scope banner and submission target differ.
|
|
||||||
|
|
||||||
### OpenAI field alignment
|
|
||||||
|
|
||||||
Add the missing OpenAI controls to bulk edit:
|
|
||||||
|
|
||||||
- OAuth `codex_cli_only`
|
|
||||||
- API key WS mode selector
|
|
||||||
|
|
||||||
Rules:
|
|
||||||
|
|
||||||
- OAuth accounts show OAuth WS mode and `codex_cli_only`
|
|
||||||
- API key accounts show API key WS mode
|
|
||||||
- mixed OpenAI OAuth/API key selections continue to show only fields that are safe for the entire target set
|
|
||||||
|
|
||||||
The payload builder must write:
|
|
||||||
|
|
||||||
- `extra.codex_cli_only`
|
|
||||||
- `extra.openai_apikey_responses_websockets_v2_mode`
|
|
||||||
- `extra.openai_apikey_responses_websockets_v2_enabled`
|
|
||||||
|
|
||||||
with the same enable/disable semantics already used by single-account forms.
|
|
||||||
|
|
||||||
## Testing Strategy
|
|
||||||
|
|
||||||
### Frontend tests
|
|
||||||
|
|
||||||
Add or extend tests for:
|
|
||||||
|
|
||||||
- bulk edit dropdown actions in the accounts view
|
|
||||||
- selected-account mode still calling bulk update by IDs
|
|
||||||
- filtered-result mode calling bulk update with filter target
|
|
||||||
- filtered-result mode showing preview count and blocking submit on zero matches
|
|
||||||
- OAuth bulk edit supporting `codex_cli_only`
|
|
||||||
- API key bulk edit supporting API key WS mode
|
|
||||||
- no regression for existing passthrough and OAuth WS mode tests
|
|
||||||
|
|
||||||
### Backend tests
|
|
||||||
|
|
||||||
Add or extend tests for:
|
|
||||||
|
|
||||||
- bulk update request validation for IDs vs filters
|
|
||||||
- filtered-result mode resolving all matching accounts across pagination semantics
|
|
||||||
- mixed-channel risk checks still running for filter-target updates if applicable
|
|
||||||
- backward compatibility for the existing selected-ID request path
|
|
||||||
|
|
||||||
## Risks
|
|
||||||
|
|
||||||
- Filter semantics can drift if bulk edit reimplements list-filter parsing differently from the listing endpoints.
|
|
||||||
- Filtered-result mode can surprise users if the active scope is not shown clearly enough.
|
|
||||||
- Large filtered updates may affect many rows; success/error messaging must stay explicit.
|
|
||||||
|
|
||||||
## Recommendation
|
|
||||||
|
|
||||||
Implement this as a targeted extension of the existing bulk edit flow:
|
|
||||||
|
|
||||||
- unify the entry point in the table action area
|
|
||||||
- add filter-target bulk update support
|
|
||||||
- align the missing OpenAI compact-related fields
|
|
||||||
|
|
||||||
This keeps the mental model simple and solves the large-account-management pain without introducing a second parallel batch-edit system.
|
|
||||||
Reference in New Issue
Block a user