feat(trading): split orders into tabs

This commit is contained in:
Bartłomiej Głownia
2023-04-26 09:51:07 +02:00
parent cf1f10e324
commit 44f17fd028
7 changed files with 106 additions and 100 deletions
@@ -0,0 +1,16 @@
import { MarketState } from '@vegaprotocol/types';
describe('market oracle', { tags: '@smoke' }, () => {
it('current fees displayed', () => {
cy.mockTradingPage(
MarketState.STATE_ACTIVE,
undefined,
undefined,
'COMPROMISED'
);
cy.visit('/#/markets/market-0');
cy.wait('@Markets');
cy.wait('@MarketInfo');
cy.getByTestId('oracle-status').should('contain.text', 'COMPROMISED');
});
});
@@ -1,7 +1,7 @@
import { DealTicketContainer } from '@vegaprotocol/deal-ticket';
import { MarketInfoAccordionContainer } from '@vegaprotocol/market-info';
import { OrderbookContainer } from '@vegaprotocol/market-depth';
import { OrderListContainer } from '@vegaprotocol/orders';
import { OrderListContainer, Filter } from '@vegaprotocol/orders';
import { FillsContainer } from '@vegaprotocol/fills';
import { PositionsContainer } from '@vegaprotocol/positions';
import { TradesContainer } from '@vegaprotocol/trades';
@@ -153,7 +153,40 @@ const MarketBottomPanel = memo(
<TradingViews.Positions onMarketClick={onMarketClick} />
</VegaWalletContainer>
</Tab>
<Tab id="orders" name={t('Orders')}>
<Tab id="open-orders" name={t('Open')}>
<VegaWalletContainer>
<TradingViews.Orders
marketId={marketId}
filter={Filter.Open}
onMarketClick={onMarketClick}
onOrderTypeClick={onOrderTypeClick}
enforceBottomPlaceholder
/>
</VegaWalletContainer>
</Tab>
<Tab id="closed-orders" name={t('Closed')}>
<VegaWalletContainer>
<TradingViews.Orders
marketId={marketId}
filter={Filter.Closed}
onMarketClick={onMarketClick}
onOrderTypeClick={onOrderTypeClick}
enforceBottomPlaceholder
/>
</VegaWalletContainer>
</Tab>
<Tab id="rejected-orders" name={t('Rejected')}>
<VegaWalletContainer>
<TradingViews.Orders
marketId={marketId}
filter={Filter.Rejected}
onMarketClick={onMarketClick}
onOrderTypeClick={onOrderTypeClick}
enforceBottomPlaceholder
/>
</VegaWalletContainer>
</Tab>
<Tab id="orders" name={t('All')}>
<VegaWalletContainer>
<TradingViews.Orders
marketId={marketId}
@@ -28,6 +28,11 @@ export type Order = Omit<OrderFieldsFragment, 'market'> & {
};
export type OrderEdge = Edge<Order>;
const liveOnlyOrderStatuses = [
OrderStatus.STATUS_ACTIVE,
OrderStatus.STATUS_PARKED,
];
const orderMatchFilters = (
order: OrderUpdateFieldsFragment,
variables: OrdersQueryVariables
@@ -41,6 +46,12 @@ const orderMatchFilters = (
) {
return false;
}
if (
variables?.filter?.liveOnly &&
!(order.status && liveOnlyOrderStatuses.includes(order.status))
) {
return false;
}
if (
variables?.filter?.types &&
!(order.type && variables.filter.types.includes(order.type))
@@ -204,7 +215,7 @@ export const activeOrdersProvider = makeDerivedDataProvider<
ordersProvider(callback, client, {
partyId: variables.partyId,
filter: {
status: [OrderStatus.STATUS_ACTIVE, OrderStatus.STATUS_PARKED],
liveOnly: true,
},
}),
],
@@ -2,17 +2,20 @@ import { t } from '@vegaprotocol/i18n';
import { Splash } from '@vegaprotocol/ui-toolkit';
import { useVegaWallet } from '@vegaprotocol/wallet';
import { OrderListManager } from './order-list-manager';
import type { Filter } from './order-list-manager/use-order-list-data';
export const OrderListContainer = ({
marketId,
onMarketClick,
onOrderTypeClick,
enforceBottomPlaceholder,
filter,
}: {
marketId?: string;
onMarketClick?: (marketId: string, metaKey?: boolean) => void;
onOrderTypeClick?: (marketId: string, metaKey?: boolean) => void;
enforceBottomPlaceholder?: boolean;
filter?: Filter;
}) => {
const { pubKey, isReadOnly } = useVegaWallet();
@@ -24,6 +27,7 @@ export const OrderListContainer = ({
<OrderListManager
partyId={pubKey}
marketId={marketId}
filter={filter}
onMarketClick={onMarketClick}
onOrderTypeClick={onOrderTypeClick}
isReadOnly={isReadOnly}
@@ -1,7 +1,6 @@
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
import { t } from '@vegaprotocol/i18n';
import { useCallback, useEffect, useRef, useState } from 'react';
import type { FilterChangedEvent, SortChangedEvent } from 'ag-grid-community';
import { Button } from '@vegaprotocol/ui-toolkit';
import type { AgGridReact } from 'ag-grid-react';
import type { GridReadyEvent } from 'ag-grid-community';
@@ -9,14 +8,13 @@ import type { GridReadyEvent } from 'ag-grid-community';
import { OrderListTable } from '../order-list/order-list';
import { useOrderListData } from './use-order-list-data';
import { useHasAmendableOrder } from '../../order-hooks/use-has-amendable-order';
import type { Filter, Sort } from './use-order-list-data';
import type { Filter } from './use-order-list-data';
import { FilterStatus } from './use-order-list-data';
import { useBottomPlaceholder } from '@vegaprotocol/react-helpers';
import { OrderStatus } from '@vegaprotocol/types';
import {
normalizeOrderAmendment,
useVegaTransactionStore,
} from '@vegaprotocol/wallet';
import isEqual from 'lodash/isEqual';
import type { OrderTxUpdateFieldsFragment } from '@vegaprotocol/wallet';
import { OrderEditDialog } from '../order-list/order-edit-dialog';
import type { Order, OrderEdge } from '../order-data-provider';
@@ -28,6 +26,7 @@ export interface OrderListManagerProps {
onOrderTypeClick?: (marketId: string, metaKey?: boolean) => void;
isReadOnly: boolean;
enforceBottomPlaceholder?: boolean;
filter?: Filter;
}
const CancelAllOrdersButton = ({ onClick }: { onClick: () => void }) => (
@@ -43,12 +42,6 @@ const CancelAllOrdersButton = ({ onClick }: { onClick: () => void }) => (
</div>
);
const initialFilter: Filter = {
status: {
value: [OrderStatus.STATUS_ACTIVE, OrderStatus.STATUS_PARKED],
},
};
export const OrderListManager = ({
partyId,
marketId,
@@ -56,20 +49,16 @@ export const OrderListManager = ({
onOrderTypeClick,
isReadOnly,
enforceBottomPlaceholder,
filter,
}: OrderListManagerProps) => {
const gridRef = useRef<AgGridReact | null>(null);
const [dataCount, setDataCount] = useState(0);
const scrolledToTop = useRef(false);
const [sort, setSort] = useState<Sort[] | undefined>();
const [filter, setFilter] = useState<Filter | undefined>(initialFilter);
const filterRef = useRef(initialFilter);
const [editOrder, setEditOrder] = useState<Order | null>(null);
const create = useVegaTransactionStore((state) => state.create);
const hasAmendableOrder = useHasAmendableOrder(marketId);
const { data, error, loading, reload } = useOrderListData({
partyId,
sort,
filter,
gridRef,
scrolledToTop,
@@ -84,42 +73,6 @@ export const OrderListManager = ({
disabled: !enforceBottomPlaceholder && !isReadOnly && !hasAmendableOrder,
});
const onFilterChanged = useCallback(
(event: FilterChangedEvent) => {
const updatedFilter = event.api.getFilterModel();
if (isEqual(updatedFilter, filterRef.current)) {
return;
}
filterRef.current = updatedFilter;
if (Object.keys(updatedFilter).length) {
setFilter(updatedFilter);
} else {
setFilter(undefined);
}
setDataCount(gridRef.current?.api?.getModel().getRowCount() ?? 0);
bottomPlaceholderOnFilterChanged?.();
},
[setFilter, bottomPlaceholderOnFilterChanged]
);
const onSortChange = useCallback(
(event: SortChangedEvent) => {
const sort = event.columnApi
.getColumnState()
.sort((a, b) => (a.sortIndex || 0) - (b.sortIndex || 0))
.reduce((acc, col) => {
if (col.sort) {
const { colId, sort } = col;
acc.push({ colId, sort });
}
return acc;
}, [] as { colId: string; sort: string }[]);
setSort(sort.length > 0 ? sort : undefined);
bottomPlaceholderOnSortChanged?.();
},
[setSort, bottomPlaceholderOnSortChanged]
);
const cancel = useCallback(
(order: Order) => {
if (!order.market) return;
@@ -133,9 +86,18 @@ export const OrderListManager = ({
[create]
);
const onGridReady = useCallback(({ api }: GridReadyEvent) => {
api.setFilterModel(initialFilter);
}, []);
const onGridReady = useCallback(
({ api }: GridReadyEvent) => {
if (filter) {
api.setFilterModel({
status: {
value: FilterStatus[filter],
},
});
}
},
[filter]
);
useEffect(() => {
setDataCount(gridRef.current?.api?.getModel().getRowCount() ?? 0);
@@ -162,8 +124,6 @@ export const OrderListManager = ({
rowData={extractedData}
ref={gridRef}
onGridReady={onGridReady}
onFilterChanged={onFilterChanged}
onSortChanged={onSortChange}
cancel={cancel}
setEditOrder={setEditOrder}
onMarketClick={onMarketClick}
@@ -3,6 +3,7 @@ import type { RefObject } from 'react';
import type { AgGridReact } from 'ag-grid-react';
import { makeInfiniteScrollGetRows } from '@vegaprotocol/utils';
import { useDataProvider, updateGridData } from '@vegaprotocol/react-helpers';
import { OrderStatus } from '@vegaprotocol/types';
import { ordersWithMarketProvider } from '../order-data-provider/order-data-provider';
import type {
OrderEdge,
@@ -12,38 +13,33 @@ import type {
OrdersQueryVariables,
OrdersUpdateSubscriptionVariables,
} from '../order-data-provider/__generated__/Orders';
import type * as Types from '@vegaprotocol/types';
export interface Sort {
colId: string;
sort: string;
}
export interface Filter {
updatedAt?: {
value: Types.DateRange;
};
type?: {
value: Types.OrderType[];
};
status?: {
value: Types.OrderStatus[];
};
timeInForce?: {
value: Types.OrderTimeInForce[];
};
export enum Filter {
'Open' = 1,
'Closed',
'Rejected',
}
const FilterStatus = {
[Filter.Open]: [OrderStatus.STATUS_ACTIVE, OrderStatus.STATUS_PARKED],
[Filter.Closed]: [
OrderStatus.STATUS_CANCELLED,
OrderStatus.STATUS_EXPIRED,
OrderStatus.STATUS_FILLED,
OrderStatus.STATUS_PARTIALLY_FILLED,
OrderStatus.STATUS_STOPPED,
],
[Filter.Rejected]: [OrderStatus.STATUS_REJECTED],
};
interface Props {
partyId: string;
marketId?: string;
filter?: Filter;
sort?: Sort[];
gridRef: RefObject<AgGridReact>;
scrolledToTop: RefObject<boolean>;
}
export const useOrderListData = ({
partyId,
marketId,
sort,
filter,
gridRef,
scrolledToTop,
@@ -72,25 +68,10 @@ export const useOrderListData = ({
const allVars: OrdersQueryVariables & OrdersUpdateSubscriptionVariables = {
partyId,
};
if (
filter?.updatedAt?.value ||
filter?.status?.value.length ||
filter?.timeInForce?.value.length ||
filter?.type?.value.length
) {
allVars.filter = {};
if (filter?.updatedAt?.value) {
allVars.filter.dateRange = filter?.updatedAt?.value;
}
if (filter?.status?.value.length) {
allVars.filter.status = filter?.status?.value;
}
if (filter?.timeInForce?.value.length) {
allVars.filter.timeInForce = filter?.timeInForce?.value;
}
if (filter?.type?.value.length) {
allVars.filter.types = filter?.type?.value;
}
if (filter === Filter.Open) {
allVars.filter = {
liveOnly: true,
};
}
return allVars;
}, [partyId, filter]);
+1
View File
@@ -2279,6 +2279,7 @@ export type OrderFilter = {
/** Date range to retrieve orders from/to. Start and end time should be expressed as an integer value of nano-seconds past the Unix epoch */
dateRange?: InputMaybe<DateRange>;
excludeLiquidity?: InputMaybe<Scalars['Boolean']>;
liveOnly?: InputMaybe<Scalars['Boolean']>;
status?: InputMaybe<Array<OrderStatus>>;
timeInForce?: InputMaybe<Array<OrderTimeInForce>>;
types?: InputMaybe<Array<OrderType>>;