You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add an outcome-distribution donut to the Position History section that doubles as the outcome filter. Above the threshold of ≥ 10 settled trades (outcome ≠ OPEN), the donut replaces the existing outcome filter pills. Each slice (EXPIRED / ASSIGNED / CALLED / CLOSED) both shows its share and acts as the filter toggle — clicking a slice invokes the existing setHistOutcome setter.
Includes a new pure helper outcomeDistribution(trades, assetFilter) → [{outcome, count, premium}] that prepares the donut's data and is unit-tested in isolation. Donut respects the active asset-filter chips above the hero. Donut does NOT respect the From/To date pickers in the history section header.
Below 10 settled trades, the existing pills render as today.
Acceptance criteria
New pure helper outcomeDistribution(trades, assetFilter) lives in its own numbered file under src/js/, dual-exported (browser global + Node module.exports)
Helper excludes OPEN trades and orders results EXPIRED / ASSIGNED / CALLED / CLOSED
Helper subtracts closeCost from premium for CLOSED outcomes (cash-flow lens convention)
At ≥ 10 settled trades: donut renders in place of the outcome pills
Hover tooltip on a slice shows <OUTCOME> — N trades, $X total premium
Clicking a slice toggles that outcome's filter via setHistOutcome and re-renders the table
Clicking the active slice clears the filter (idempotent toggle)
Active slice is opaque + outlined; inactive slices are dimmed
Donut respects the active asset-filter chips
Donut does NOT respect the From/To date pickers
Donut uses CSS variables only (no hardcoded colours)
Unit tests in test/unit/outcome-distribution.test.js cover: empty trades, OPEN-only, one trade per outcome, multiple trades per outcome, asset filter applied, CLOSED outcome closeCost handling
Integration tests in test/integration/donut-filter.test.js cover: donut renders above threshold (pills hidden), pills render below threshold (donut hidden), slice click filters table, second click on active slice clears filter, asset-filter chip changes the donut data
Parent
PRD #34
What to build
Add an outcome-distribution donut to the Position History section that doubles as the outcome filter. Above the threshold of ≥ 10 settled trades (outcome ≠ OPEN), the donut replaces the existing outcome filter pills. Each slice (EXPIRED / ASSIGNED / CALLED / CLOSED) both shows its share and acts as the filter toggle — clicking a slice invokes the existing
setHistOutcomesetter.Includes a new pure helper
outcomeDistribution(trades, assetFilter) → [{outcome, count, premium}]that prepares the donut's data and is unit-tested in isolation. Donut respects the active asset-filter chips above the hero. Donut does NOT respect the From/To date pickers in the history section header.Below 10 settled trades, the existing pills render as today.
Acceptance criteria
outcomeDistribution(trades, assetFilter)lives in its own numbered file undersrc/js/, dual-exported (browser global + Nodemodule.exports)closeCostfrom premium for CLOSED outcomes (cash-flow lens convention)<OUTCOME> — N trades, $X total premiumsetHistOutcomeand re-renders the tabletest/unit/outcome-distribution.test.jscover: empty trades, OPEN-only, one trade per outcome, multiple trades per outcome, asset filter applied, CLOSED outcomecloseCosthandlingtest/integration/donut-filter.test.jscover: donut renders above threshold (pills hidden), pills render below threshold (donut hidden), slice click filters table, second click on active slice clears filter, asset-filter chip changes the donut datapython3 build.py --checkpassesnpm testpassesBlocked by
None - can start immediately