diff --git a/docs/superpowers/plans/2026-04-23-market-selection-export.md b/docs/superpowers/plans/2026-04-23-market-selection-export.md new file mode 100644 index 0000000..70e8fe4 --- /dev/null +++ b/docs/superpowers/plans/2026-04-23-market-selection-export.md @@ -0,0 +1,181 @@ +# Market Selection Export 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 cross-page creator selection checkboxes so CSV export and batch submission operate on selected creators within the chosen export range, with fallback to the full export range when no selected creators are present in that range. + +**Architecture:** Extend the market table DOM sync layer with a leading checkbox column and a current-page header select-all control, then keep selection state in the content controller as a `Set`. Reuse the existing export-range pipeline by filtering resolved `MarketRecord[]` after range collection and before CSV generation or batch payload creation. + +**Tech Stack:** TypeScript, Chrome MV3 content script, existing DOM sync helpers, Vitest, jsdom + +--- + +## File Map + +- Modify: `src/content/market/dom-sync.ts` + - Add checkbox column rendering, row checkbox references, header checkbox references, and checkbox state sync helpers. +- Modify: `src/content/market/types.ts` + - Add minimal selection-related DOM typing if needed. +- Modify: `src/content/market/index.ts` + - Store selected creator ids, respond to row and header checkbox changes, and filter export / batch records with fallback logic. +- Test: `tests/market-dom-sync.test.ts` + - Cover injected checkbox header and row controls for both synthetic and div-grid layouts. +- Test: `tests/market-content-entry.test.ts` + - Cover per-row selection, current-page select-all, cross-page persistence, export filtering, fallback behavior, and batch submission filtering. + +### Task 1: Checkbox Column DOM + +**Files:** +- Modify: `src/content/market/dom-sync.ts` +- Modify: `src/content/market/types.ts` +- Test: `tests/market-dom-sync.test.ts` + +- [ ] **Step 1: Write the failing DOM tests** + +Add tests for: +- synthetic tables inject a leading checkbox header cell and one checkbox cell per row +- div-grid tables inject a leading checkbox column and current-page header checkbox +- returned table DOM exposes row checkbox elements and the header checkbox + +- [ ] **Step 2: Run tests to verify they fail** + +Run: `npm test -- tests/market-dom-sync.test.ts` +Expected: FAIL because the checkbox column and DOM references do not exist yet. + +- [ ] **Step 3: Write minimal DOM implementation** + +Implement in `src/content/market/dom-sync.ts`: +- a leading selection column key +- row checkbox creation for synthetic rows +- row checkbox column creation for div-grid rows +- header checkbox creation for both layouts +- `MarketRowDom` and `MarketTableDom` additions for checkbox references + +Keep the new column visually narrow and place it before the author column. + +- [ ] **Step 4: Run tests to verify they pass** + +Run: `npm test -- tests/market-dom-sync.test.ts` +Expected: PASS + +- [ ] **Step 5: Commit** + +```bash +git add src/content/market/dom-sync.ts src/content/market/types.ts tests/market-dom-sync.test.ts +git commit -m "feat: add market row selection column" +``` + +### Task 2: Controller Selection State + +**Files:** +- Modify: `src/content/market/index.ts` +- Test: `tests/market-content-entry.test.ts` + +- [ ] **Step 1: Write the failing controller tests** + +Add tests for: +- clicking a row checkbox stores that creator selection +- selection survives a page change and re-render +- header checkbox selects all visible creators on the current page +- header checkbox clears all visible creators on the current page +- header checkbox becomes indeterminate when only part of the current page is selected + +- [ ] **Step 2: Run tests to verify they fail** + +Run: `npm test -- tests/market-content-entry.test.ts -t "selection"` +Expected: FAIL because the controller does not yet track selection or bind checkbox events. + +- [ ] **Step 3: Write minimal controller implementation** + +Implement in `src/content/market/index.ts`: +- `selectedAuthorIds: Set` +- event listeners for row checkboxes and the header checkbox +- current-page checkbox state sync during `applyCurrentView()` +- current-page select-all behavior scoped only to visible rows from the current DOM table + +Do not persist selection in `resultStore`. Keep it controller-local and keyed by `authorId`. + +- [ ] **Step 4: Run tests to verify they pass** + +Run: `npm test -- tests/market-content-entry.test.ts -t "selection"` +Expected: PASS + +- [ ] **Step 5: Commit** + +```bash +git add src/content/market/index.ts tests/market-content-entry.test.ts +git commit -m "feat: track selected market creators" +``` + +### Task 3: Export and Batch Filtering + +**Files:** +- Modify: `src/content/market/index.ts` +- Test: `tests/market-content-entry.test.ts` + +- [ ] **Step 1: Write the failing filtering tests** + +Add tests for: +- export uses only selected creators when the resolved export range contains selected creators +- export falls back to the full resolved export range when none of the selected creators are inside that resolved range +- batch submit uses the same selected-with-fallback record set +- cross-page selections only apply when those selected creators are inside the chosen export range + +- [ ] **Step 2: Run tests to verify they fail** + +Run: `npm test -- tests/market-content-entry.test.ts -t "selected"` +Expected: FAIL because export and batch submit still use the full resolved range. + +- [ ] **Step 3: Write minimal filtering implementation** + +Implement in `src/content/market/index.ts`: +- a helper that filters resolved `MarketRecord[]` by `selectedAuthorIds` +- fallback to the original resolved records when the filtered subset is empty +- use this helper in both: + - CSV export before `buildCsv(records)` + - batch submit before `createBatchPayload(...)` + +Keep the CSV exporter and batch payload builder unchanged. Only change the records passed into them. + +- [ ] **Step 4: Run tests to verify they pass** + +Run: `npm test -- tests/market-content-entry.test.ts -t "selected"` +Expected: PASS + +- [ ] **Step 5: Run focused verification** + +Run: +- `npm test -- tests/market-dom-sync.test.ts` +- `npm test -- tests/market-content-entry.test.ts` +- `npm run build` + +Expected: +- market DOM sync tests pass +- market content controller tests pass +- build exits 0 + +- [ ] **Step 6: Commit** + +```bash +git add src/content/market/index.ts tests/market-content-entry.test.ts +git commit -m "feat: filter market export by selected creators" +``` + +## Notes for Implementation + +- Scope the header checkbox to the current visible page only. +- Recompute header checkbox state after every DOM re-sync and after every selection change. +- Apply selection after export-range resolution, not before. This preserves current range semantics. +- When no selected creators exist inside the resolved export range, keep current behavior and export / submit the whole resolved range. +- Do not modify CSV headers or batch payload shape. + +## Final Verification + +- [ ] `npm test -- tests/market-dom-sync.test.ts tests/market-content-entry.test.ts` +- [ ] `npm test -- tests/backend-metrics-client.test.ts tests/batch-submit-client.test.ts tests/background-index.test.ts tests/batch-payload.test.ts` +- [ ] `npm run build` +- [ ] Manual browser check: + - select a few creators on page 1 and page 3 + - export `当前页` from page 1 and confirm only selected page 1 creators export + - export `前5页` and confirm selected creators across pages are included + - clear current page via header checkbox and confirm other-page selections remain