diff --git a/packages/perps-controller/CHANGELOG.md b/packages/perps-controller/CHANGELOG.md index a22b5c8bfe..8d1e37b1eb 100644 --- a/packages/perps-controller/CHANGELOG.md +++ b/packages/perps-controller/CHANGELOG.md @@ -9,6 +9,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- **BREAKING:** Add `ordersSideFilter`, `ordersSortField`, and `ordersSortDirection` to the flat `ProLayoutPreferences` object (defaults `'all'`, `'time'`, `'desc'`) so Pro Orders panel side-filter and sort preferences persist independently of Positions across markets and app restarts via the existing `getProLayoutPreferences()` / `setProLayoutPreferences(patch)` API; export `ProOrdersSideFilter`, `ProOrdersSortField`, and `ProOrdersSortDirection` ([#9862](https://github.com/MetaMask/core/pull/9862)) + - Consumers that construct a full `ProLayoutPreferences` object (instead of using `DEFAULT_PRO_LAYOUT_PREFERENCES`, the getter, or the patch setter) must include the new fields. Persisted state that predates them remains valid at runtime because the getter/selector merge over defaults. + - Orders side filter (`all` | `long` | `short`) is independent of `positionsSideFilter`. Orders sort fields are `orderValue` | `size` | `price` | `time`. - Add `PERPS_EVENT_PROPERTY.PERPS_MODE` (`perps_mode`) for Lite/Pro interface mode analytics (`'lite' | 'pro'`), distinct from existing `PERPS_EVENT_PROPERTY.MODE` (`mode`) which is search intent (`discovery` / `intent` / `browse`) ([#9819](https://github.com/MetaMask/core/pull/9819)) - **BREAKING:** Add `positionsSideFilter`, `positionsSortField`, and `positionsSortDirection` to the flat `ProLayoutPreferences` object (defaults `'all'`, `'positionValue'`, `'desc'`) so Pro Positions/Orders panel sort and side-filter preferences persist across markets and app restarts via the existing `getProLayoutPreferences()` / `setProLayoutPreferences(patch)` API; export `ProPositionsSideFilter`, `ProPositionsSortField`, and `ProPositionsSortDirection` ([#9838](https://github.com/MetaMask/core/pull/9838)) - Consumers that construct a full `ProLayoutPreferences` object (instead of using `DEFAULT_PRO_LAYOUT_PREFERENCES`, the getter, or the patch setter) must include the new fields. Persisted state that predates them remains valid at runtime because the getter/selector merge over defaults. diff --git a/packages/perps-controller/src/PerpsController.ts b/packages/perps-controller/src/PerpsController.ts index 84d0d20ca7..b097cc91ba 100644 --- a/packages/perps-controller/src/PerpsController.ts +++ b/packages/perps-controller/src/PerpsController.ts @@ -297,6 +297,9 @@ export { } from './constants/perpsConfig.js'; export type { ProLayoutPreferences, + ProOrdersSideFilter, + ProOrdersSortDirection, + ProOrdersSortField, ProPositionsSideFilter, ProPositionsSortDirection, ProPositionsSortField, diff --git a/packages/perps-controller/src/constants/perpsConfig.ts b/packages/perps-controller/src/constants/perpsConfig.ts index 05807168c0..34fafcbf82 100644 --- a/packages/perps-controller/src/constants/perpsConfig.ts +++ b/packages/perps-controller/src/constants/perpsConfig.ts @@ -487,9 +487,10 @@ export enum PerpsMode { } /** - * Side filter for the Pro Positions/Orders panel (long/short/all). + * Side filter for the Pro Positions list (long/short/all). * - * Shared across markets via `proLayoutPreferences.positionsSideFilter`. + * Independent of `ordersSideFilter`. Shared across markets via + * `proLayoutPreferences.positionsSideFilter`. */ export type ProPositionsSideFilter = 'all' | 'long' | 'short'; @@ -506,15 +507,32 @@ export type ProPositionsSortField = */ export type ProPositionsSortDirection = 'asc' | 'desc'; +/** + * Side filter for the Pro Orders list (long/short/all). + * + * Independent of `positionsSideFilter`. Shared across markets via + * `proLayoutPreferences.ordersSideFilter`. + */ +export type ProOrdersSideFilter = 'all' | 'long' | 'short'; + +/** + * Sort fields available on the Pro Orders list. + */ +export type ProOrdersSortField = 'orderValue' | 'size' | 'price' | 'time'; + +/** + * Sort direction for the Pro Orders list. + */ +export type ProOrdersSortDirection = 'asc' | 'desc'; + /** * Pro-mode layout preferences (network-independent). * * Flat object that persists across markets (unlike the per-market * `tradeConfigurations`). `chartExpanded` and the `*Position` fields are - * reserved for future container-position UI. `positionsSideFilter` / - * `positionsSortField` / `positionsSortDirection` back the Positions/Orders - * panel sort and side filter so they survive market navigation and app - * restarts. + * reserved for future container-position UI. Positions and Orders each have + * their own side filter and sort so they survive market navigation and app + * restarts independently. */ export type ProLayoutPreferences = { orderBookExpanded: boolean; @@ -524,6 +542,9 @@ export type ProLayoutPreferences = { positionsSideFilter: ProPositionsSideFilter; positionsSortField: ProPositionsSortField; positionsSortDirection: ProPositionsSortDirection; + ordersSideFilter: ProOrdersSideFilter; + ordersSortField: ProOrdersSortField; + ordersSortDirection: ProOrdersSortDirection; }; /** @@ -541,6 +562,9 @@ export const DEFAULT_PRO_LAYOUT_PREFERENCES: ProLayoutPreferences = { positionsSideFilter: 'all', positionsSortField: 'positionValue', positionsSortDirection: 'desc', + ordersSideFilter: 'all', + ordersSortField: 'time', + ordersSortDirection: 'desc', }; /** diff --git a/packages/perps-controller/src/index.ts b/packages/perps-controller/src/index.ts index 635231ec6b..b9cb86d190 100644 --- a/packages/perps-controller/src/index.ts +++ b/packages/perps-controller/src/index.ts @@ -44,6 +44,9 @@ export type { PerpsControllerActions, PerpsControllerEvents, ProLayoutPreferences, + ProOrdersSideFilter, + ProOrdersSortDirection, + ProOrdersSortField, ProPositionsSideFilter, ProPositionsSortDirection, ProPositionsSortField, diff --git a/packages/perps-controller/tests/src/PerpsController.configuration.test.ts b/packages/perps-controller/tests/src/PerpsController.configuration.test.ts index d5de543eb8..2d603e754c 100644 --- a/packages/perps-controller/tests/src/PerpsController.configuration.test.ts +++ b/packages/perps-controller/tests/src/PerpsController.configuration.test.ts @@ -694,7 +694,7 @@ describe('PerpsController', () => { }); describe('pro layout preferences', () => { - it('defaults to collapsed order book, collapsed chart, reserved positions, and positions sort/filter defaults', () => { + it('defaults to collapsed order book, collapsed chart, reserved positions, and positions/orders sort/filter defaults', () => { expect(controller.getProLayoutPreferences()).toEqual({ orderBookExpanded: false, chartExpanded: false, @@ -703,6 +703,9 @@ describe('PerpsController', () => { positionsSideFilter: 'all', positionsSortField: 'positionValue', positionsSortDirection: 'desc', + ordersSideFilter: 'all', + ordersSortField: 'time', + ordersSortDirection: 'desc', }); }); @@ -717,6 +720,9 @@ describe('PerpsController', () => { positionsSideFilter: 'all', positionsSortField: 'positionValue', positionsSortDirection: 'desc', + ordersSideFilter: 'all', + ordersSortField: 'time', + ordersSortDirection: 'desc', }); }); @@ -729,6 +735,11 @@ describe('PerpsController', () => { positionsSortField: 'unrealizedPnl', positionsSortDirection: 'asc', }); + controller.setProLayoutPreferences({ + ordersSideFilter: 'short', + ordersSortField: 'orderValue', + ordersSortDirection: 'asc', + }); expect(controller.getProLayoutPreferences()).toEqual({ orderBookExpanded: true, @@ -738,6 +749,9 @@ describe('PerpsController', () => { positionsSideFilter: 'long', positionsSortField: 'unrealizedPnl', positionsSortDirection: 'asc', + ordersSideFilter: 'short', + ordersSortField: 'orderValue', + ordersSortDirection: 'asc', }); }); @@ -758,6 +772,50 @@ describe('PerpsController', () => { positionsSideFilter: 'all', positionsSortField: 'unrealizedPnl', positionsSortDirection: 'asc', + ordersSideFilter: 'all', + ordersSortField: 'time', + ordersSortDirection: 'desc', + }); + }); + + it('updates orders sort field without clobbering orders sort direction or positions sort', () => { + controller.setProLayoutPreferences({ + ordersSortField: 'size', + ordersSortDirection: 'asc', + }); + controller.setProLayoutPreferences({ + ordersSortField: 'price', + }); + + expect(controller.getProLayoutPreferences()).toEqual({ + orderBookExpanded: false, + chartExpanded: false, + orderBookPosition: 'left', + orderFormPosition: 'right', + positionsSideFilter: 'all', + positionsSortField: 'positionValue', + positionsSortDirection: 'desc', + ordersSideFilter: 'all', + ordersSortField: 'price', + ordersSortDirection: 'asc', + }); + }); + + it('updates orders side filter without clobbering positions side filter', () => { + controller.setProLayoutPreferences({ positionsSideFilter: 'long' }); + controller.setProLayoutPreferences({ ordersSideFilter: 'short' }); + + expect(controller.getProLayoutPreferences()).toEqual({ + orderBookExpanded: false, + chartExpanded: false, + orderBookPosition: 'left', + orderFormPosition: 'right', + positionsSideFilter: 'long', + positionsSortField: 'positionValue', + positionsSortDirection: 'desc', + ordersSideFilter: 'short', + ordersSortField: 'time', + ordersSortDirection: 'desc', }); }); @@ -783,6 +841,9 @@ describe('PerpsController', () => { positionsSideFilter: 'all', positionsSortField: 'positionValue', positionsSortDirection: 'desc', + ordersSideFilter: 'all', + ordersSortField: 'time', + ordersSortDirection: 'desc', }); }); }); diff --git a/packages/perps-controller/tests/src/selectors.test.ts b/packages/perps-controller/tests/src/selectors.test.ts index 01983cd655..b1b309013c 100644 --- a/packages/perps-controller/tests/src/selectors.test.ts +++ b/packages/perps-controller/tests/src/selectors.test.ts @@ -639,6 +639,9 @@ describe('PerpsController selectors', () => { positionsSideFilter: 'all', positionsSortField: 'positionValue', positionsSortDirection: 'desc', + ordersSideFilter: 'all', + ordersSortField: 'time', + ordersSortDirection: 'desc', }; it('returns the pro-mode layout preferences', () => { @@ -650,6 +653,9 @@ describe('PerpsController selectors', () => { positionsSideFilter: 'long' as const, positionsSortField: 'unrealizedPnl' as const, positionsSortDirection: 'asc' as const, + ordersSideFilter: 'short' as const, + ordersSortField: 'orderValue' as const, + ordersSortDirection: 'asc' as const, }; const state = { proLayoutPreferences,