feat(trading): pane settings view (#5509)
Co-authored-by: Dariusz Majcherczyk <dariusz.majcherczyk@gmail.com> Co-authored-by: Matthew Russell <mattrussell36@gmail.com>
This commit is contained in:
parent
d47d894147
commit
4adaeea40a
@ -24,7 +24,7 @@ export const AssetsTable = ({ data }: AssetsTableProps) => {
|
||||
const navigate = useNavigate();
|
||||
const ref = useRef<AgGridReact>(null);
|
||||
const showColumnsOnDesktop = () => {
|
||||
ref.current?.columnApi.setColumnsVisible(
|
||||
ref.current?.api.setColumnsVisible(
|
||||
['id', 'type', 'status'],
|
||||
window.innerWidth > BREAKPOINT_MD
|
||||
);
|
||||
|
@ -29,7 +29,7 @@ export const MarketsTable = ({ data }: MarketsTableProps) => {
|
||||
const gridRef = useRef<AgGridReact>(null);
|
||||
useLayoutEffect(() => {
|
||||
const showColumnsOnDesktop = () => {
|
||||
gridRef.current?.columnApi.setColumnsVisible(
|
||||
gridRef.current?.api.setColumnsVisible(
|
||||
['id', 'state', 'asset'],
|
||||
window.innerWidth > BREAKPOINT_MD
|
||||
);
|
||||
|
@ -44,11 +44,11 @@ export const ProposalsTable = ({ data }: ProposalsTableProps) => {
|
||||
const gridRef = useRef<AgGridReact>(null);
|
||||
useLayoutEffect(() => {
|
||||
const showColumnsOnDesktop = () => {
|
||||
gridRef.current?.columnApi.setColumnsVisible(
|
||||
gridRef.current?.api.setColumnsVisible(
|
||||
['voting', 'cDate', 'eDate', 'type'],
|
||||
window.innerWidth > BREAKPOINT_MD
|
||||
);
|
||||
gridRef.current?.columnApi.setColumnWidth(
|
||||
gridRef.current?.api.setColumnWidth(
|
||||
'actions',
|
||||
window.innerWidth > BREAKPOINT_MD ? 221 : 80
|
||||
);
|
||||
|
@ -90,7 +90,11 @@ const MainGrid = memo(
|
||||
{market &&
|
||||
market.tradableInstrument.instrument.product.__typename ===
|
||||
'Perpetual' ? (
|
||||
<Tab id="funding-payments" name={t('Funding payments')}>
|
||||
<Tab
|
||||
id="funding-payments"
|
||||
name={t('Funding payments')}
|
||||
settings={<TradingViews.fundingPayments.settings />}
|
||||
>
|
||||
<ErrorBoundary feature="funding-payments">
|
||||
<TradingViews.fundingPayments.component
|
||||
marketId={marketId}
|
||||
@ -112,7 +116,11 @@ const MainGrid = memo(
|
||||
<TradingViews.orderbook.component marketId={marketId} />
|
||||
</ErrorBoundary>
|
||||
</Tab>
|
||||
<Tab id="trades" name={t('Trades')}>
|
||||
<Tab
|
||||
id="trades"
|
||||
name={t('Trades')}
|
||||
settings={<TradingViews.trades.settings />}
|
||||
>
|
||||
<ErrorBoundary feature="trades">
|
||||
<TradingViews.trades.component marketId={marketId} />
|
||||
</ErrorBoundary>
|
||||
@ -133,6 +141,7 @@ const MainGrid = memo(
|
||||
id="positions"
|
||||
name={t('Positions')}
|
||||
menu={<TradingViews.positions.menu />}
|
||||
settings={<TradingViews.positions.settings />}
|
||||
>
|
||||
<ErrorBoundary feature="positions">
|
||||
<TradingViews.positions.component />
|
||||
@ -142,17 +151,26 @@ const MainGrid = memo(
|
||||
id="open-orders"
|
||||
name={t('Open')}
|
||||
menu={<TradingViews.activeOrders.menu />}
|
||||
settings={<TradingViews.activeOrders.settings />}
|
||||
>
|
||||
<ErrorBoundary feature="activeOrders">
|
||||
<TradingViews.activeOrders.component />
|
||||
</ErrorBoundary>
|
||||
</Tab>
|
||||
<Tab id="closed-orders" name={t('Closed')}>
|
||||
<Tab
|
||||
id="closed-orders"
|
||||
name={t('Closed')}
|
||||
settings={<TradingViews.closedOrders.settings />}
|
||||
>
|
||||
<ErrorBoundary feature="closedOrders">
|
||||
<TradingViews.closedOrders.component />
|
||||
</ErrorBoundary>
|
||||
</Tab>
|
||||
<Tab id="rejected-orders" name={t('Rejected')}>
|
||||
<Tab
|
||||
id="rejected-orders"
|
||||
name={t('Rejected')}
|
||||
settings={<TradingViews.rejectedOrders.settings />}
|
||||
>
|
||||
<ErrorBoundary feature="rejectedOrders">
|
||||
<TradingViews.rejectedOrders.component />
|
||||
</ErrorBoundary>
|
||||
@ -161,25 +179,35 @@ const MainGrid = memo(
|
||||
id="orders"
|
||||
name={t('All')}
|
||||
menu={<TradingViews.orders.menu />}
|
||||
settings={<TradingViews.orders.settings />}
|
||||
>
|
||||
<ErrorBoundary feature="orders">
|
||||
<TradingViews.orders.component />
|
||||
</ErrorBoundary>
|
||||
</Tab>
|
||||
{featureFlags.STOP_ORDERS ? (
|
||||
<Tab id="stop-orders" name={t('Stop orders')}>
|
||||
<Tab
|
||||
id="stop-orders"
|
||||
name={t('Stop orders')}
|
||||
settings={<TradingViews.stopOrders.settings />}
|
||||
>
|
||||
<ErrorBoundary feature="stop-orders">
|
||||
<TradingViews.stopOrders.component />
|
||||
</ErrorBoundary>
|
||||
</Tab>
|
||||
) : null}
|
||||
<Tab id="fills" name={t('Fills')}>
|
||||
<Tab
|
||||
id="fills"
|
||||
name={t('Fills')}
|
||||
settings={<TradingViews.fills.settings />}
|
||||
>
|
||||
<TradingViews.fills.component />
|
||||
</Tab>
|
||||
<Tab
|
||||
id="accounts"
|
||||
name={t('Collateral')}
|
||||
menu={<TradingViews.collateral.menu />}
|
||||
settings={<TradingViews.collateral.settings />}
|
||||
>
|
||||
<ErrorBoundary feature="collateral">
|
||||
<TradingViews.collateral.component
|
||||
|
@ -4,7 +4,12 @@ import { OracleBanner } from '@vegaprotocol/markets';
|
||||
import { useState } from 'react';
|
||||
import AutoSizer from 'react-virtualized-auto-sizer';
|
||||
import classNames from 'classnames';
|
||||
import { Splash } from '@vegaprotocol/ui-toolkit';
|
||||
import {
|
||||
Popover,
|
||||
Splash,
|
||||
VegaIcon,
|
||||
VegaIconNames,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { useT } from '../../lib/use-t';
|
||||
import {
|
||||
MarketSuccessorBanner,
|
||||
@ -24,6 +29,7 @@ interface TradePanelsProps {
|
||||
export const TradePanels = ({ market, pinnedAsset }: TradePanelsProps) => {
|
||||
const featureFlags = useFeatureFlags((state) => state.flags);
|
||||
const [view, setView] = useState<TradingView>('chart');
|
||||
const viewCfg = TradingViews[view];
|
||||
|
||||
const renderView = () => {
|
||||
const Component = TradingViews[view].component;
|
||||
@ -44,19 +50,27 @@ export const TradePanels = ({ market, pinnedAsset }: TradePanelsProps) => {
|
||||
};
|
||||
|
||||
const renderMenu = () => {
|
||||
const viewCfg = TradingViews[view];
|
||||
|
||||
if ('menu' in viewCfg) {
|
||||
const Menu = viewCfg.menu;
|
||||
|
||||
if ('menu' in viewCfg || 'settings' in viewCfg) {
|
||||
return (
|
||||
<div className="flex items-center justify-end gap-1 p-1 bg-vega-clight-800 dark:bg-vega-cdark-800 border-b border-default">
|
||||
<Menu />
|
||||
{'menu' in viewCfg ? <viewCfg.menu /> : null}
|
||||
{'settings' in viewCfg ? (
|
||||
<Popover
|
||||
align="end"
|
||||
trigger={
|
||||
<span className="ml-1 flex items-center justify-center h-6 w-6">
|
||||
<VegaIcon name={VegaIconNames.COG} size={16} />
|
||||
</span>
|
||||
}
|
||||
>
|
||||
<div className="p-4 flex justify-end">
|
||||
<viewCfg.settings />
|
||||
</div>
|
||||
</Popover>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
return (
|
||||
@ -72,7 +86,7 @@ export const TradePanels = ({ market, pinnedAsset }: TradePanelsProps) => {
|
||||
<OracleBanner marketId={market?.id || ''} />
|
||||
</div>
|
||||
<div>{renderMenu()}</div>
|
||||
<div className="h-full">
|
||||
<div className="h-full relative">
|
||||
<AutoSizer>
|
||||
{({ width, height }) => (
|
||||
<div style={{ width, height }} className="overflow-auto">
|
||||
@ -110,7 +124,9 @@ export const TradePanels = ({ market, pinnedAsset }: TradePanelsProps) => {
|
||||
key={key}
|
||||
view={key}
|
||||
isActive={isActive}
|
||||
onClick={() => setView(key)}
|
||||
onClick={() => {
|
||||
setView(key);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
@ -1,15 +1,36 @@
|
||||
import { DepthChartContainer } from '@vegaprotocol/market-depth';
|
||||
import { Filter, OpenOrdersMenu } from '@vegaprotocol/orders';
|
||||
import { TradesContainer } from '../../components/trades-container';
|
||||
import {
|
||||
TradesContainer,
|
||||
TradesSettings,
|
||||
} from '../../components/trades-container';
|
||||
import { OrderbookContainer } from '../../components/orderbook-container';
|
||||
import { FillsContainer } from '../../components/fills-container';
|
||||
import { PositionsContainer } from '../../components/positions-container';
|
||||
import { AccountsContainer } from '../../components/accounts-container';
|
||||
import {
|
||||
FillsContainer,
|
||||
FillsSettings,
|
||||
} from '../../components/fills-container';
|
||||
import {
|
||||
PositionsContainer,
|
||||
PositionsSettings,
|
||||
} from '../../components/positions-container';
|
||||
import {
|
||||
AccountsContainer,
|
||||
AccountsSettings,
|
||||
} from '../../components/accounts-container';
|
||||
import { LiquidityContainer } from '../../components/liquidity-container';
|
||||
import { FundingContainer } from '../../components/funding-container';
|
||||
import { FundingPaymentsContainer } from '../../components/funding-payments-container';
|
||||
import { OrdersContainer } from '../../components/orders-container';
|
||||
import { StopOrdersContainer } from '../../components/stop-orders-container';
|
||||
import {
|
||||
FundingPaymentsContainer,
|
||||
FundingPaymentsSettings,
|
||||
} from '../../components/funding-payments-container';
|
||||
import {
|
||||
OrdersContainer,
|
||||
OrdersSettings,
|
||||
} from '../../components/orders-container';
|
||||
import {
|
||||
StopOrdersContainer,
|
||||
StopOrdersSettings,
|
||||
} from '../../components/stop-orders-container';
|
||||
import { AccountsMenu } from '../../components/accounts-menu';
|
||||
import { PositionsMenu } from '../../components/positions-menu';
|
||||
import { ChartContainer, ChartMenu } from '../../components/chart-container';
|
||||
@ -32,37 +53,46 @@ export const TradingViews = {
|
||||
},
|
||||
fundingPayments: {
|
||||
component: FundingPaymentsContainer,
|
||||
settings: FundingPaymentsSettings,
|
||||
},
|
||||
orderbook: {
|
||||
component: OrderbookContainer,
|
||||
},
|
||||
trades: {
|
||||
component: TradesContainer,
|
||||
settings: TradesSettings,
|
||||
},
|
||||
positions: {
|
||||
component: PositionsContainer,
|
||||
menu: PositionsMenu,
|
||||
settings: PositionsSettings,
|
||||
},
|
||||
activeOrders: {
|
||||
component: () => <OrdersContainer filter={Filter.Open} />,
|
||||
menu: OpenOrdersMenu,
|
||||
settings: () => <OrdersSettings filter={Filter.Open} />,
|
||||
},
|
||||
closedOrders: {
|
||||
component: () => <OrdersContainer filter={Filter.Closed} />,
|
||||
settings: () => <OrdersSettings filter={Filter.Closed} />,
|
||||
},
|
||||
rejectedOrders: {
|
||||
component: () => <OrdersContainer filter={Filter.Rejected} />,
|
||||
settings: () => <OrdersSettings filter={Filter.Rejected} />,
|
||||
},
|
||||
orders: {
|
||||
component: OrdersContainer,
|
||||
menu: OpenOrdersMenu,
|
||||
settings: OrdersSettings,
|
||||
},
|
||||
stopOrders: {
|
||||
component: StopOrdersContainer,
|
||||
settings: StopOrdersSettings,
|
||||
},
|
||||
collateral: {
|
||||
component: AccountsContainer,
|
||||
menu: AccountsMenu,
|
||||
settings: AccountsSettings,
|
||||
},
|
||||
fills: { component: FillsContainer },
|
||||
fills: { component: FillsContainer, settings: FillsSettings },
|
||||
} as const;
|
||||
|
@ -42,7 +42,7 @@ export const createDataGridSlice: StateCreator<DataGridSlice> = (set) => ({
|
||||
},
|
||||
});
|
||||
|
||||
const useMarketsStore = create<DataGridSlice>()(
|
||||
export const useMarketsStore = create<DataGridSlice>()(
|
||||
persist(createDataGridSlice, {
|
||||
name: 'vega_market_list_store',
|
||||
})
|
||||
|
@ -16,6 +16,7 @@ import {
|
||||
} from '@vegaprotocol/environment';
|
||||
import { useT } from '../../lib/use-t';
|
||||
import { ErrorBoundary } from '../../components/error-boundary';
|
||||
import { MarketsSettings } from './markets-settings';
|
||||
|
||||
export const MarketsPage = () => {
|
||||
const t = useT();
|
||||
@ -34,7 +35,11 @@ export const MarketsPage = () => {
|
||||
<div className="h-full pt-0.5 pb-3 px-1.5">
|
||||
<div className="h-full my-1 border rounded-sm border-default">
|
||||
<Tabs storageKey="console-markets">
|
||||
<Tab id="open-markets" name={t('Open markets')}>
|
||||
<Tab
|
||||
id="open-markets"
|
||||
name={t('Open markets')}
|
||||
settings={<MarketsSettings />}
|
||||
>
|
||||
<ErrorBoundary feature="markets-open">
|
||||
<OpenMarkets />
|
||||
</ErrorBoundary>
|
||||
@ -42,6 +47,7 @@ export const MarketsPage = () => {
|
||||
<Tab
|
||||
id="proposed-markets"
|
||||
name={t('Proposed markets')}
|
||||
settings={<MarketsSettings />}
|
||||
menu={
|
||||
<TradingAnchorButton
|
||||
size="extra-small"
|
||||
@ -56,7 +62,11 @@ export const MarketsPage = () => {
|
||||
<Proposed />
|
||||
</ErrorBoundary>
|
||||
</Tab>
|
||||
<Tab id="closed-markets" name={t('Closed markets')}>
|
||||
<Tab
|
||||
id="closed-markets"
|
||||
name={t('Closed markets')}
|
||||
settings={<MarketsSettings />}
|
||||
>
|
||||
<ErrorBoundary feature="markets-closed">
|
||||
<Closed />
|
||||
</ErrorBoundary>
|
||||
|
8
apps/trading/client-pages/markets/markets-settings.tsx
Normal file
8
apps/trading/client-pages/markets/markets-settings.tsx
Normal file
@ -0,0 +1,8 @@
|
||||
import { GridSettings } from '../../components/grid-settings/grid-settings';
|
||||
import { useMarketsStore } from './market-list-table';
|
||||
|
||||
export const MarketsSettings = () => (
|
||||
<GridSettings
|
||||
updateGridStore={useMarketsStore((store) => store.updateGridStore)}
|
||||
/>
|
||||
);
|
@ -5,14 +5,29 @@ import { titlefy } from '@vegaprotocol/utils';
|
||||
import { useIncompleteWithdrawals } from '@vegaprotocol/withdraws';
|
||||
import { Tab, LocalStoragePersistTabs as Tabs } from '@vegaprotocol/ui-toolkit';
|
||||
import { usePageTitleStore } from '../../stores';
|
||||
import { AccountsContainer } from '../../components/accounts-container';
|
||||
import {
|
||||
AccountsContainer,
|
||||
AccountsSettings,
|
||||
} from '../../components/accounts-container';
|
||||
import { DepositsContainer } from '../../components/deposits-container';
|
||||
import { FillsContainer } from '../../components/fills-container';
|
||||
import { FundingPaymentsContainer } from '../../components/funding-payments-container';
|
||||
import { PositionsContainer } from '../../components/positions-container';
|
||||
import {
|
||||
FillsContainer,
|
||||
FillsSettings,
|
||||
} from '../../components/fills-container';
|
||||
import {
|
||||
FundingPaymentsContainer,
|
||||
FundingPaymentsSettings,
|
||||
} from '../../components/funding-payments-container';
|
||||
import {
|
||||
PositionsContainer,
|
||||
PositionsSettings,
|
||||
} from '../../components/positions-container';
|
||||
import { PositionsMenu } from '../../components/positions-menu';
|
||||
import { WithdrawalsContainer } from '../../components/withdrawals-container';
|
||||
import { OrdersContainer } from '../../components/orders-container';
|
||||
import {
|
||||
OrdersContainer,
|
||||
OrdersSettings,
|
||||
} from '../../components/orders-container';
|
||||
import { LedgerContainer } from '../../components/ledger-container';
|
||||
import {
|
||||
ResizableGrid,
|
||||
@ -76,22 +91,27 @@ export const Portfolio = () => {
|
||||
id="positions"
|
||||
name={t('Positions')}
|
||||
menu={<PositionsMenu />}
|
||||
settings={<PositionsSettings />}
|
||||
>
|
||||
<ErrorBoundary feature="portfolio-positions">
|
||||
<PositionsContainer allKeys />
|
||||
</ErrorBoundary>
|
||||
</Tab>
|
||||
<Tab id="orders" name={t('Orders')}>
|
||||
<Tab id="orders" name={t('Orders')} settings={<OrdersSettings />}>
|
||||
<ErrorBoundary feature="portfolio-orders">
|
||||
<OrdersContainer />
|
||||
</ErrorBoundary>
|
||||
</Tab>
|
||||
<Tab id="fills" name={t('Fills')}>
|
||||
<Tab id="fills" name={t('Fills')} settings={<FillsSettings />}>
|
||||
<ErrorBoundary feature="portfolio-fills">
|
||||
<FillsContainer />
|
||||
</ErrorBoundary>
|
||||
</Tab>
|
||||
<Tab id="funding-payments" name={t('Funding payments')}>
|
||||
<Tab
|
||||
id="funding-payments"
|
||||
name={t('Funding payments')}
|
||||
settings={<FundingPaymentsSettings />}
|
||||
>
|
||||
<ErrorBoundary feature="portfolio-funding-payments">
|
||||
<FundingPaymentsContainer />
|
||||
</ErrorBoundary>
|
||||
@ -114,6 +134,7 @@ export const Portfolio = () => {
|
||||
<Tab
|
||||
id="collateral"
|
||||
name={t('Collateral')}
|
||||
settings={<AccountsSettings />}
|
||||
menu={<AccountsMenu />}
|
||||
>
|
||||
<ErrorBoundary feature="portfolio-accounts">
|
||||
|
@ -73,7 +73,7 @@ export const AccountsContainer = ({
|
||||
);
|
||||
};
|
||||
|
||||
const useAccountStore = create<DataGridSlice>()(
|
||||
export const useAccountStore = create<DataGridSlice>()(
|
||||
persist(createDataGridSlice, {
|
||||
name: 'vega_accounts_store',
|
||||
})
|
||||
|
@ -0,0 +1,8 @@
|
||||
import { GridSettings } from '../grid-settings/grid-settings';
|
||||
import { useAccountStore } from './accounts-container';
|
||||
|
||||
export const AccountsSettings = () => (
|
||||
<GridSettings
|
||||
updateGridStore={useAccountStore((store) => store.updateGridStore)}
|
||||
/>
|
||||
);
|
@ -1 +1,2 @@
|
||||
export * from './accounts-container';
|
||||
export * from './accounts-settings';
|
||||
|
@ -38,7 +38,7 @@ export const FillsContainer = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const useFillsStore = create<DataGridSlice>()(
|
||||
export const useFillsStore = create<DataGridSlice>()(
|
||||
persist(createDataGridSlice, {
|
||||
name: 'vega_fills_store',
|
||||
})
|
||||
|
@ -0,0 +1,8 @@
|
||||
import { GridSettings } from '../grid-settings/grid-settings';
|
||||
import { useFillsStore } from './fills-container';
|
||||
|
||||
export const FillsSettings = () => (
|
||||
<GridSettings
|
||||
updateGridStore={useFillsStore((store) => store.updateGridStore)}
|
||||
/>
|
||||
);
|
@ -1 +1,2 @@
|
||||
export * from './fills-container';
|
||||
export * from './fills-settings';
|
||||
|
@ -45,7 +45,7 @@ export const FundingPaymentsContainer = ({
|
||||
);
|
||||
};
|
||||
|
||||
const useFundingPaymentsStore = create<DataGridSlice>()(
|
||||
export const useFundingPaymentsStore = create<DataGridSlice>()(
|
||||
persist(createDataGridSlice, {
|
||||
name: 'vega_funding_payments_store',
|
||||
})
|
||||
|
@ -0,0 +1,8 @@
|
||||
import { GridSettings } from '../grid-settings/grid-settings';
|
||||
import { useFundingPaymentsStore } from './funding-payments-container';
|
||||
|
||||
export const FundingPaymentsSettings = () => (
|
||||
<GridSettings
|
||||
updateGridStore={useFundingPaymentsStore((store) => store.updateGridStore)}
|
||||
/>
|
||||
);
|
@ -1 +1,2 @@
|
||||
export * from './funding-payments-container';
|
||||
export * from './funding-payments-settings';
|
||||
|
24
apps/trading/components/grid-settings/grid-settings.tsx
Normal file
24
apps/trading/components/grid-settings/grid-settings.tsx
Normal file
@ -0,0 +1,24 @@
|
||||
import { useT } from '../../lib/use-t';
|
||||
import type { DataGridStore } from '../../stores/datagrid-store-slice';
|
||||
import { TradingButton as Button } from '@vegaprotocol/ui-toolkit';
|
||||
|
||||
export const GridSettings = ({
|
||||
updateGridStore,
|
||||
}: {
|
||||
updateGridStore: (gridStore: DataGridStore) => void;
|
||||
}) => {
|
||||
const t = useT();
|
||||
return (
|
||||
<Button
|
||||
onClick={() =>
|
||||
updateGridStore({
|
||||
columnState: undefined,
|
||||
filterModel: undefined,
|
||||
})
|
||||
}
|
||||
size="extra-small"
|
||||
>
|
||||
{t('Reset Columns')}
|
||||
</Button>
|
||||
);
|
||||
};
|
@ -27,7 +27,7 @@ export const MarketHeader = () => {
|
||||
title={
|
||||
<Popover
|
||||
open={open}
|
||||
onChange={setOpen}
|
||||
onOpenChange={setOpen}
|
||||
trigger={
|
||||
<HeaderTitle>
|
||||
<span>
|
||||
|
@ -1,9 +1,5 @@
|
||||
import { act, renderHook } from '@testing-library/react';
|
||||
import {
|
||||
FilterStatusValue,
|
||||
STORAGE_KEY,
|
||||
useOrderListGridState,
|
||||
} from './orders-container';
|
||||
import { STORAGE_KEY, useOrderListGridState } from './orders-container';
|
||||
import { Filter } from '@vegaprotocol/orders';
|
||||
import { OrderType } from '@vegaprotocol/types';
|
||||
|
||||
@ -16,31 +12,6 @@ describe('useOrderListGridState', () => {
|
||||
return renderHook(() => useOrderListGridState(filter));
|
||||
};
|
||||
|
||||
it.each(Object.values(Filter))(
|
||||
'providers correct AgGrid filter for %s',
|
||||
(filter) => {
|
||||
const { result } = setup(filter);
|
||||
expect(typeof result.current.updateGridState).toBe('function');
|
||||
expect(result.current.gridState).toEqual({
|
||||
columnState: undefined,
|
||||
filterModel: {
|
||||
status: {
|
||||
value: FilterStatusValue[filter],
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
it('provides correct AgGrid filter for all', () => {
|
||||
const { result } = setup(undefined);
|
||||
expect(typeof result.current.updateGridState).toBe('function');
|
||||
expect(result.current.gridState).toEqual({
|
||||
columnState: undefined,
|
||||
filterModel: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
it.each(Object.values(Filter))(
|
||||
'sets and stores column state and filters for %s',
|
||||
(filter) => {
|
||||
@ -59,12 +30,7 @@ describe('useOrderListGridState', () => {
|
||||
|
||||
expect(result.current.gridState).toEqual({
|
||||
columnState: undefined,
|
||||
filterModel: {
|
||||
...filterModel,
|
||||
status: {
|
||||
value: FilterStatusValue[filter],
|
||||
},
|
||||
},
|
||||
filterModel,
|
||||
});
|
||||
|
||||
const columnState = [{ colId: 'status', width: 200 }];
|
||||
@ -77,12 +43,7 @@ describe('useOrderListGridState', () => {
|
||||
|
||||
expect(result.current.gridState).toEqual({
|
||||
columnState,
|
||||
filterModel: {
|
||||
...filterModel,
|
||||
status: {
|
||||
value: FilterStatusValue[filter],
|
||||
},
|
||||
},
|
||||
filterModel,
|
||||
});
|
||||
|
||||
const storeKeyMap = {
|
||||
|
@ -9,6 +9,7 @@ import type { DataGridStore } from '../../stores/datagrid-store-slice';
|
||||
import { OrderStatus } from '@vegaprotocol/types';
|
||||
import { Links } from '../../lib/links';
|
||||
import { useT } from '../../lib/use-t';
|
||||
import { GridSettings } from '../grid-settings/grid-settings';
|
||||
|
||||
const resolveNoRowsMessage = (
|
||||
filter: Filter | undefined,
|
||||
@ -38,6 +39,24 @@ export const FilterStatusValue = {
|
||||
[Filter.Rejected]: [OrderStatus.STATUS_REJECTED],
|
||||
};
|
||||
|
||||
export const DefaultFilterModel = {
|
||||
[Filter.Open]: {
|
||||
status: {
|
||||
value: FilterStatusValue[Filter.Open],
|
||||
},
|
||||
},
|
||||
[Filter.Closed]: {
|
||||
status: {
|
||||
value: FilterStatusValue[Filter.Closed],
|
||||
},
|
||||
},
|
||||
[Filter.Rejected]: {
|
||||
status: {
|
||||
value: FilterStatusValue[Filter.Rejected],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export interface OrderContainerProps {
|
||||
filter?: Filter;
|
||||
}
|
||||
@ -54,7 +73,8 @@ export const OrdersContainer = ({ filter }: OrderContainerProps) => {
|
||||
(newState) => {
|
||||
updateGridState(filter, newState);
|
||||
},
|
||||
AUTO_SIZE_COLUMNS
|
||||
AUTO_SIZE_COLUMNS,
|
||||
filter && DefaultFilterModel[filter]
|
||||
);
|
||||
|
||||
if (!pubKey) {
|
||||
@ -80,7 +100,7 @@ export const OrdersContainer = ({ filter }: OrderContainerProps) => {
|
||||
};
|
||||
|
||||
export const STORAGE_KEY = 'vega_order_list_store';
|
||||
const useOrderListStore = create<{
|
||||
export const useOrderListStore = create<{
|
||||
open: DataGridStore;
|
||||
closed: DataGridStore;
|
||||
rejected: DataGridStore;
|
||||
@ -149,34 +169,19 @@ export const useOrderListGridState = (filter: Filter | undefined) => {
|
||||
case Filter.Open: {
|
||||
return {
|
||||
columnState: store.open.columnState,
|
||||
filterModel: {
|
||||
...store.open.filterModel,
|
||||
status: {
|
||||
value: FilterStatusValue[Filter.Open],
|
||||
},
|
||||
},
|
||||
filterModel: store.open.filterModel,
|
||||
};
|
||||
}
|
||||
case Filter.Closed: {
|
||||
return {
|
||||
columnState: store.closed.columnState,
|
||||
filterModel: {
|
||||
...store.closed.filterModel,
|
||||
status: {
|
||||
value: FilterStatusValue[Filter.Closed],
|
||||
},
|
||||
},
|
||||
filterModel: store.closed.filterModel,
|
||||
};
|
||||
}
|
||||
case Filter.Rejected: {
|
||||
return {
|
||||
columnState: store.rejected.columnState,
|
||||
filterModel: {
|
||||
...store.rejected.filterModel,
|
||||
status: {
|
||||
value: FilterStatusValue[Filter.Rejected],
|
||||
},
|
||||
},
|
||||
filterModel: store.rejected.filterModel,
|
||||
};
|
||||
}
|
||||
default: {
|
||||
@ -187,3 +192,14 @@ export const useOrderListGridState = (filter: Filter | undefined) => {
|
||||
|
||||
return { gridState, updateGridState };
|
||||
};
|
||||
|
||||
export const OrdersSettings = ({ filter }: { filter?: Filter }) => {
|
||||
const updateGridState = useOrderListStore((state) => state.update);
|
||||
return (
|
||||
<GridSettings
|
||||
updateGridStore={(gridStore: DataGridStore) =>
|
||||
updateGridState(filter, gridStore)
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
@ -1 +1,2 @@
|
||||
export * from './positions-container';
|
||||
export * from './positions-settings';
|
||||
|
@ -0,0 +1,8 @@
|
||||
import { GridSettings } from '../grid-settings/grid-settings';
|
||||
import { usePositionsStore } from './positions-container';
|
||||
|
||||
export const PositionsSettings = () => (
|
||||
<GridSettings
|
||||
updateGridStore={usePositionsStore((store) => store.updateGridStore)}
|
||||
/>
|
||||
);
|
@ -1 +1,3 @@
|
||||
export * from './stop-orders-container';
|
||||
|
||||
export * from './stop-orders-settings';
|
||||
|
@ -35,7 +35,7 @@ export const StopOrdersContainer = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const useStopOrdersStore = create<DataGridSlice>()(
|
||||
export const useStopOrdersStore = create<DataGridSlice>()(
|
||||
persist(createDataGridSlice, {
|
||||
name: 'vega_stop_orders_store',
|
||||
})
|
||||
|
@ -0,0 +1,8 @@
|
||||
import { GridSettings } from '../grid-settings/grid-settings';
|
||||
import { useStopOrdersStore } from './stop-orders-container';
|
||||
|
||||
export const StopOrdersSettings = () => (
|
||||
<GridSettings
|
||||
updateGridStore={useStopOrdersStore((store) => store.updateGridStore)}
|
||||
/>
|
||||
);
|
@ -1 +1,2 @@
|
||||
export * from './trades-container';
|
||||
export * from './trades-settings';
|
||||
|
@ -17,7 +17,7 @@ export const TradesContainer = ({ marketId }: TradesContainerProps) => {
|
||||
return <TradesManager marketId={marketId} gridProps={gridStoreCallbacks} />;
|
||||
};
|
||||
|
||||
const useTradesStore = create<DataGridSlice>()(
|
||||
export const useTradesStore = create<DataGridSlice>()(
|
||||
persist(createDataGridSlice, {
|
||||
name: 'vega_trades_store',
|
||||
})
|
||||
|
@ -0,0 +1,8 @@
|
||||
import { GridSettings } from '../grid-settings/grid-settings';
|
||||
import { useTradesStore } from './trades-container';
|
||||
|
||||
export const TradesSettings = () => (
|
||||
<GridSettings
|
||||
updateGridStore={useTradesStore((store) => store.updateGridStore)}
|
||||
/>
|
||||
);
|
@ -65,16 +65,17 @@ def test_iceberg_open_order(continuous_market, vega: VegaServiceNull, page: Page
|
||||
page.wait_for_selector(".ag-center-cols-container .ag-row")
|
||||
|
||||
expect(
|
||||
page.locator(".ag-center-cols-container .ag-row [col-id='remaining']")
|
||||
page.locator(".ag-center-cols-container .ag-row [col-id='remaining']").first
|
||||
).to_have_text("99")
|
||||
expect(
|
||||
page.locator(".ag-center-cols-container .ag-row [col-id='size']")
|
||||
page.locator(".ag-center-cols-container .ag-row [col-id='size']").first
|
||||
).to_have_text("-102")
|
||||
page.pause()
|
||||
expect(
|
||||
page.locator(".ag-center-cols-container .ag-row [col-id='type'] ")
|
||||
page.locator(".ag-center-cols-container .ag-row [col-id='type'] ").first
|
||||
).to_have_text("Limit (Iceberg)")
|
||||
expect(
|
||||
page.locator(".ag-center-cols-container .ag-row [col-id='status']")
|
||||
page.locator(".ag-center-cols-container .ag-row [col-id='status']").first
|
||||
).to_have_text("Active")
|
||||
expect(page.get_by_test_id("price-10100000")).to_be_visible
|
||||
expect(page.get_by_test_id("ask-vol-10100000")).to_have_text("3")
|
||||
|
@ -16,11 +16,11 @@ def verify_data_grid(page: Page, data_test_id, expected_pattern):
|
||||
expect(
|
||||
page.locator(
|
||||
f'[data-testid^="tab-{data_test_id.lower()}"] >> .ag-center-cols-container .ag-row-first'
|
||||
)
|
||||
).first
|
||||
).to_be_visible()
|
||||
actual_text = page.locator(
|
||||
f'[data-testid^="tab-{data_test_id.lower()}"] >> .ag-center-cols-container .ag-row-first'
|
||||
).text_content()
|
||||
).first.text_content()
|
||||
lines = actual_text.strip().split("\n")
|
||||
for expected, actual in zip(expected_pattern, lines):
|
||||
# We are using regex so that we can run tests in different timezones.
|
||||
|
36
apps/trading/e2e/tests/settings/test_column_settings.py
Normal file
36
apps/trading/e2e/tests/settings/test_column_settings.py
Normal file
@ -0,0 +1,36 @@
|
||||
import pytest
|
||||
from playwright.sync_api import expect, Page
|
||||
|
||||
settings_icon = "icon-cog"
|
||||
settings_column_btn = "popover-trigger"
|
||||
settings_close_btn = "settings-close"
|
||||
split_view_view = "split-view-view"
|
||||
|
||||
@pytest.mark.usefixtures("page", "continuous_market", "auth", "risk_accepted")
|
||||
def test_column_settings_is_visible(continuous_market, page: Page):
|
||||
page.goto(f"/#/markets/{continuous_market}")
|
||||
expect(page.get_by_test_id(split_view_view).get_by_test_id(settings_column_btn)).to_be_visible()
|
||||
page.goto("/#/portfolio")
|
||||
expect(page.get_by_test_id(split_view_view).get_by_test_id(settings_column_btn).nth(0)).to_be_visible()
|
||||
expect(page.get_by_test_id(split_view_view).get_by_test_id(settings_column_btn).nth(1)).to_be_visible()
|
||||
page.goto(f"/#/markets/all")
|
||||
expect(page.get_by_test_id(settings_column_btn)).to_be_visible()
|
||||
page.click('[data-testid="Proposed markets"]')
|
||||
expect(page.get_by_test_id(settings_column_btn)).to_be_visible()
|
||||
page.click('[data-testid="Closed markets"]')
|
||||
expect(page.get_by_test_id(settings_column_btn)).to_be_visible()
|
||||
|
||||
@pytest.mark.usefixtures("page", "continuous_market", "auth", "risk_accepted")
|
||||
def test_can_reset_columns_state(continuous_market, page: Page):
|
||||
page.goto(f"/#/markets/all")
|
||||
col_market = page.locator('[col-id="tradableInstrument.instrument.code"]').first
|
||||
col_settlement_asset = page.locator('[col-id="tradableInstrument.instrument.product.settlementAsset.symbol"]').first
|
||||
col_market.drag_to(col_settlement_asset)
|
||||
|
||||
# Check the attribute of the dragged element
|
||||
attribute_value = col_market.get_attribute("aria-colindex")
|
||||
assert attribute_value != "1"
|
||||
page.get_by_test_id(settings_column_btn).click()
|
||||
page.get_by_role("button", name="Reset Columns").click()
|
||||
attribute_value_after_reset = col_market.get_attribute("aria-colindex")
|
||||
assert attribute_value_after_reset == "1"
|
@ -29,7 +29,7 @@ const AccountBreakdown = ({
|
||||
variables: { partyId, assetId },
|
||||
update: ({ data }) => {
|
||||
if (gridRef.current?.api && data?.breakdown) {
|
||||
gridRef.current?.api.setRowData(data?.breakdown);
|
||||
gridRef.current?.api.setGridOption('rowData', data?.breakdown);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -65,18 +65,9 @@ export const DateRangeFilter = forwardRef(
|
||||
useImperativeHandle(ref, () => {
|
||||
return {
|
||||
doesFilterPass(params: IDoesFilterPassParams) {
|
||||
const { api, colDef, column, columnApi, context } = props;
|
||||
const { column } = props;
|
||||
const { node } = params;
|
||||
const rowValue = props.valueGetter({
|
||||
api,
|
||||
colDef,
|
||||
column,
|
||||
columnApi,
|
||||
context,
|
||||
data: node.data,
|
||||
getValue: (field) => node.data[field],
|
||||
node,
|
||||
});
|
||||
const rowValue = props.getValue(node, column);
|
||||
if (
|
||||
value.start &&
|
||||
rowValue &&
|
||||
|
@ -19,18 +19,9 @@ export const SetFilter = forwardRef(
|
||||
useImperativeHandle(ref, () => {
|
||||
return {
|
||||
doesFilterPass(params: IDoesFilterPassParams) {
|
||||
const { api, colDef, column, columnApi, context } = props;
|
||||
const { column } = props;
|
||||
const { node } = params;
|
||||
const getValue = props.valueGetter({
|
||||
api,
|
||||
colDef,
|
||||
column,
|
||||
columnApi,
|
||||
context,
|
||||
data: node.data,
|
||||
getValue: (field) => node.data[field],
|
||||
node,
|
||||
});
|
||||
const getValue = props.getValue(node, column);
|
||||
return Array.isArray(value)
|
||||
? value.includes(getValue)
|
||||
: getValue === value;
|
||||
|
@ -61,7 +61,7 @@ describe('useDataGridEvents', () => {
|
||||
|
||||
// column state was not updated, so the default width provided by the
|
||||
// col def should be set
|
||||
expect(gridRef?.current?.columnApi.getColumnState()[0].width).toEqual(
|
||||
expect(gridRef?.current?.api.getColumnState()[0].width).toEqual(
|
||||
gridProps.columnDefs[0].width
|
||||
);
|
||||
// no filters set
|
||||
@ -107,16 +107,57 @@ describe('useDataGridEvents', () => {
|
||||
columnState: [colState],
|
||||
};
|
||||
|
||||
setup(initialState, jest.fn());
|
||||
setup(initialState, jest.fn(), undefined);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(gridRef?.current?.api.getFilterModel()['id']).toEqual(idFilter);
|
||||
expect(gridRef?.current?.columnApi.getColumnState()[0]).toEqual(
|
||||
expect(gridRef?.current?.api.getColumnState()[0]).toEqual(
|
||||
expect.objectContaining(colState)
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('applies default filter model', async () => {
|
||||
const idFilter = {
|
||||
filter: 1,
|
||||
filterType: 'number',
|
||||
type: 'equals',
|
||||
};
|
||||
|
||||
setup({}, jest.fn(), undefined, {
|
||||
id: idFilter,
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(gridRef?.current?.api.getFilterModel()['id']).toEqual(idFilter);
|
||||
});
|
||||
});
|
||||
|
||||
it('default filter overwrites stored filter model', async () => {
|
||||
const idFilter = {
|
||||
filter: 1,
|
||||
filterType: 'number',
|
||||
type: 'equals',
|
||||
};
|
||||
|
||||
setup(
|
||||
{
|
||||
filterModel: {
|
||||
id: { ...idFilter, filter: 2 },
|
||||
},
|
||||
},
|
||||
jest.fn(),
|
||||
undefined,
|
||||
{
|
||||
id: idFilter,
|
||||
}
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(gridRef?.current?.api.getFilterModel()['id']).toEqual(idFilter);
|
||||
});
|
||||
});
|
||||
|
||||
it('ignores events that were not made via the UI', async () => {
|
||||
const callback = jest.fn();
|
||||
const initialState = {
|
||||
@ -130,7 +171,7 @@ describe('useDataGridEvents', () => {
|
||||
|
||||
// Set col width multiple times
|
||||
await act(async () => {
|
||||
gridRef?.current?.columnApi.setColumnWidth('id', newWidth);
|
||||
gridRef?.current?.api.setColumnWidth('id', newWidth);
|
||||
});
|
||||
|
||||
expect(callback).not.toHaveBeenCalled();
|
||||
@ -150,14 +191,14 @@ describe('useDataGridEvents', () => {
|
||||
};
|
||||
|
||||
const { rerender } = setup(initialState, callback, ['id']);
|
||||
jest.spyOn(gridRef?.current?.columnApi, 'autoSizeColumns');
|
||||
if (gridRef?.current?.api) {
|
||||
jest.spyOn(gridRef?.current?.api, 'autoSizeColumns');
|
||||
}
|
||||
rerender(<TestComponent hookParams={[initialState, callback, ['id']]} />);
|
||||
act(() => {
|
||||
gridRef?.current?.api.setRowData([{ id: 'test-id' }]);
|
||||
gridRef?.current?.api.setGridOption('rowData', [{ id: 'test-id' }]);
|
||||
jest.advanceTimersByTime(GRID_EVENT_DEBOUNCE_TIME);
|
||||
});
|
||||
expect(gridRef?.current?.columnApi.autoSizeColumns).toHaveBeenCalledWith([
|
||||
'id',
|
||||
]);
|
||||
expect(gridRef?.current?.api.autoSizeColumns).toHaveBeenCalledWith(['id']);
|
||||
});
|
||||
});
|
||||
|
@ -7,8 +7,9 @@ import {
|
||||
type FirstDataRenderedEvent,
|
||||
type SortChangedEvent,
|
||||
type GridReadyEvent,
|
||||
GridApi,
|
||||
} from 'ag-grid-community';
|
||||
import { useCallback } from 'react';
|
||||
import { useCallback, useEffect, useRef } from 'react';
|
||||
|
||||
type State = {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
@ -19,8 +20,32 @@ type State = {
|
||||
export const useDataGridEvents = (
|
||||
state: State,
|
||||
callback: (data: State) => void,
|
||||
autoSizeColumns?: string[]
|
||||
autoSizeColumns?: string[],
|
||||
defaultFilterModel?: State['filterModel']
|
||||
) => {
|
||||
const apiRef = useRef<GridApi | undefined>();
|
||||
const hasStateRef = useRef(Boolean(state.columnState || state.filterModel));
|
||||
|
||||
useEffect(() => {
|
||||
if (apiRef.current?.isDestroyed()) {
|
||||
apiRef.current = undefined;
|
||||
}
|
||||
const hasState = Boolean(state.columnState || state.filterModel);
|
||||
if (apiRef.current && hasStateRef.current && !hasState) {
|
||||
if (!state.columnState) {
|
||||
apiRef.current.resetColumnState();
|
||||
apiRef.current.sizeColumnsToFit();
|
||||
if (autoSizeColumns?.length) {
|
||||
apiRef.current.autoSizeColumns(autoSizeColumns);
|
||||
}
|
||||
}
|
||||
if (!state.filterModel) {
|
||||
apiRef.current.setFilterModel(defaultFilterModel);
|
||||
}
|
||||
}
|
||||
hasStateRef.current = hasState;
|
||||
}, [state, defaultFilterModel, autoSizeColumns]);
|
||||
|
||||
/**
|
||||
* Callback for filter events
|
||||
*/
|
||||
@ -39,11 +64,7 @@ export const useDataGridEvents = (
|
||||
* store callback unnecessarily
|
||||
*/
|
||||
const onDebouncedColumnChange = useCallback(
|
||||
({
|
||||
columnApi,
|
||||
source,
|
||||
finished,
|
||||
}: ColumnResizedEvent | ColumnMovedEvent) => {
|
||||
({ api, source, finished }: ColumnResizedEvent | ColumnMovedEvent) => {
|
||||
if (!finished) return;
|
||||
|
||||
// only call back on user interactions, and not events triggered from the api
|
||||
@ -57,7 +78,7 @@ export const useDataGridEvents = (
|
||||
return;
|
||||
}
|
||||
|
||||
const columnState = columnApi.getColumnState();
|
||||
const columnState = api.getColumnState();
|
||||
|
||||
callback({ columnState });
|
||||
},
|
||||
@ -68,8 +89,8 @@ export const useDataGridEvents = (
|
||||
* Callback for sort and visible events
|
||||
*/
|
||||
const onColumnChange = useCallback(
|
||||
({ columnApi }: SortChangedEvent | ColumnVisibleEvent) => {
|
||||
const columnState = columnApi.getColumnState();
|
||||
({ api }: SortChangedEvent | ColumnVisibleEvent) => {
|
||||
const columnState = api.getColumnState();
|
||||
callback({ columnState });
|
||||
},
|
||||
[callback]
|
||||
@ -80,11 +101,11 @@ export const useDataGridEvents = (
|
||||
* State only applied if found, otherwise columns sized to fit available space
|
||||
*/
|
||||
const onGridReady = useCallback(
|
||||
({ api, columnApi }: GridReadyEvent) => {
|
||||
if (!api || !columnApi) return;
|
||||
|
||||
({ api }: GridReadyEvent) => {
|
||||
apiRef.current = api;
|
||||
if (!api) return;
|
||||
if (state.columnState) {
|
||||
columnApi.applyColumnState({
|
||||
api.applyColumnState({
|
||||
state: state.columnState,
|
||||
applyOrder: true,
|
||||
});
|
||||
@ -92,18 +113,18 @@ export const useDataGridEvents = (
|
||||
api.sizeColumnsToFit();
|
||||
}
|
||||
|
||||
if (state.filterModel) {
|
||||
api.setFilterModel(state.filterModel);
|
||||
if (state.filterModel || defaultFilterModel) {
|
||||
api.setFilterModel({ ...state.filterModel, ...defaultFilterModel });
|
||||
}
|
||||
},
|
||||
[state]
|
||||
[state, defaultFilterModel]
|
||||
);
|
||||
|
||||
const onFirstDataRendered = useCallback(
|
||||
({ columnApi }: FirstDataRenderedEvent) => {
|
||||
if (!columnApi) return;
|
||||
({ api }: FirstDataRenderedEvent) => {
|
||||
if (!api) return;
|
||||
if (!state?.columnState && autoSizeColumns?.length) {
|
||||
columnApi.autoSizeColumns(autoSizeColumns);
|
||||
api.autoSizeColumns(autoSizeColumns);
|
||||
}
|
||||
},
|
||||
[state, autoSizeColumns]
|
||||
|
@ -36,7 +36,7 @@ export const FundingPaymentsManager = ({
|
||||
dataProvider: fundingPaymentsWithMarketProvider,
|
||||
update: ({ data }) => {
|
||||
if (data?.length && gridRef.current?.api) {
|
||||
gridRef.current?.api.setRowData(data);
|
||||
gridRef.current?.api.setGridOption('rowData', data);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -235,6 +235,7 @@
|
||||
"Rejected": "Rejected",
|
||||
"Required epochs": "Required epochs",
|
||||
"Required for next tier": "Required for next tier",
|
||||
"Reset Columns": "Reset Columns",
|
||||
"Resources": "Resources",
|
||||
"Rewards": "Rewards",
|
||||
"Rewards history": "Rewards history",
|
||||
|
@ -15,7 +15,7 @@ const Template: ComponentStory<typeof Popover> = (args) => {
|
||||
<div>
|
||||
<Popover
|
||||
open={open}
|
||||
onChange={setOpen}
|
||||
onOpenChange={setOpen}
|
||||
trigger={<Button variant="primary">Trigger</Button>}
|
||||
>
|
||||
{args.children}
|
||||
|
@ -4,29 +4,29 @@ export interface PopoverProps extends PopoverPrimitive.PopoverProps {
|
||||
trigger: React.ReactNode | string;
|
||||
children: React.ReactNode;
|
||||
open?: boolean;
|
||||
onChange?: (open: boolean) => void;
|
||||
sideOffset?: number;
|
||||
alignOffset?: number;
|
||||
sideOffset?: PopoverPrimitive.PopperContentProps['sideOffset'];
|
||||
alignOffset?: PopoverPrimitive.PopperContentProps['alignOffset'];
|
||||
align?: PopoverPrimitive.PopperContentProps['align'];
|
||||
}
|
||||
|
||||
export const Popover = ({
|
||||
trigger,
|
||||
children,
|
||||
open,
|
||||
onChange,
|
||||
sideOffset = 17,
|
||||
alignOffset = 0,
|
||||
align = 'start',
|
||||
...props
|
||||
}: PopoverProps) => {
|
||||
return (
|
||||
<PopoverPrimitive.Root open={open} onOpenChange={(x) => onChange?.(x)}>
|
||||
<PopoverPrimitive.Root {...props}>
|
||||
<PopoverPrimitive.Trigger data-testid="popover-trigger">
|
||||
{trigger}
|
||||
</PopoverPrimitive.Trigger>
|
||||
<PopoverPrimitive.Portal>
|
||||
<PopoverPrimitive.Content
|
||||
data-testid="popover-content"
|
||||
align="start"
|
||||
className="rounded bg-vega-clight-800 dark:bg-vega-cdark-800 text-default border border-default"
|
||||
align={align}
|
||||
className="rounded bg-vega-clight-700 dark:bg-vega-cdark-700 text-default border border-vega-clight-500 dark:border-vega-cdark-500"
|
||||
sideOffset={sideOffset}
|
||||
alignOffset={alignOffset}
|
||||
>
|
||||
|
@ -7,6 +7,9 @@ import {
|
||||
import classNames from 'classnames';
|
||||
import type { ReactElement, ReactNode } from 'react';
|
||||
import { Children, isValidElement, useRef, useState } from 'react';
|
||||
import { VegaIcon } from '../icon/vega-icons/vega-icon';
|
||||
import { VegaIconNames } from '../icon/vega-icons/vega-icon-record';
|
||||
import { Popover } from '../popover/popover';
|
||||
export interface TabsProps extends TabsPrimitive.TabsProps {
|
||||
children: (ReactElement<TabProps> | null)[];
|
||||
}
|
||||
@ -18,12 +21,9 @@ export const Tabs = ({
|
||||
onValueChange,
|
||||
...props
|
||||
}: TabsProps) => {
|
||||
const [activeTab, setActiveTab] = useState<string | undefined>(() => {
|
||||
if (defaultValue) {
|
||||
return defaultValue;
|
||||
}
|
||||
return children.find((v) => v)?.props.id;
|
||||
});
|
||||
const [activeTab, setActiveTab] = useState<string | undefined>(
|
||||
() => value || defaultValue || children.find((v) => v)?.props.id
|
||||
);
|
||||
|
||||
// Bunch of refs in order to detect wrapping in side the tabs so that we
|
||||
// can apply a bg color
|
||||
@ -42,8 +42,13 @@ export const Tabs = ({
|
||||
<TabsPrimitive.Root
|
||||
{...props}
|
||||
value={value || activeTab}
|
||||
onValueChange={onValueChange || setActiveTab}
|
||||
className="h-full grid grid-rows-[min-content_1fr]"
|
||||
onValueChange={(value) => {
|
||||
setActiveTab(value);
|
||||
if (onValueChange) {
|
||||
onValueChange(value);
|
||||
}
|
||||
}}
|
||||
className="h-full grid grid-rows-[min-content_1fr] relative"
|
||||
>
|
||||
<div
|
||||
ref={wrapperRef}
|
||||
@ -87,7 +92,7 @@ export const Tabs = ({
|
||||
</TabsPrimitive.List>
|
||||
<div
|
||||
ref={menuRef}
|
||||
className={classNames('flex-1 p-1', {
|
||||
className={classNames('flex justify-end flex-1 p-1', {
|
||||
'bg-vega-clight-700 dark:bg-vega-cdark-700': wrapped,
|
||||
})}
|
||||
>
|
||||
@ -101,12 +106,26 @@ export const Tabs = ({
|
||||
})}
|
||||
>
|
||||
{child.props.menu}
|
||||
{isValidElement(child.props.settings) && (
|
||||
<Popover
|
||||
align="end"
|
||||
trigger={
|
||||
<span className="flex items-center justify-center h-6 w-6">
|
||||
<VegaIcon name={VegaIconNames.COG} size={16} />
|
||||
</span>
|
||||
}
|
||||
>
|
||||
<div className="p-2 lg:p-4 lg:min-w-[290px] flex justify-end">
|
||||
{child.props.settings}
|
||||
</div>
|
||||
</Popover>
|
||||
)}
|
||||
</TabsPrimitive.Content>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
<div className="h-full overflow-auto">
|
||||
<div className="relative h-full overflow-auto">
|
||||
{Children.map(children, (child) => {
|
||||
if (!isValidElement(child) || child.props.hidden) return null;
|
||||
return (
|
||||
@ -134,6 +153,7 @@ interface TabProps {
|
||||
hidden?: boolean;
|
||||
overflowHidden?: boolean;
|
||||
menu?: ReactNode;
|
||||
settings?: ReactNode;
|
||||
}
|
||||
|
||||
export const Tab = ({ children, ...props }: TabProps) => {
|
||||
|
@ -49,8 +49,8 @@
|
||||
"@web3-react/metamask": "^8.1.2-beta.0",
|
||||
"@web3-react/walletconnect": "8.1.3-beta.0",
|
||||
"@web3-react/walletconnect-v2": "^8.1.3-beta.0",
|
||||
"ag-grid-community": "^29.3.5",
|
||||
"ag-grid-react": "^29.3.5",
|
||||
"ag-grid-community": "^31.0.1",
|
||||
"ag-grid-react": "^31.0.1",
|
||||
"allotment": "1.19.2",
|
||||
"alpha-lyrae": "vegaprotocol/alpha-lyrae",
|
||||
"apollo-link-timeout": "^4.0.0",
|
||||
|
17
yarn.lock
17
yarn.lock
@ -8609,16 +8609,17 @@ aes-js@^3.1.2:
|
||||
resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.1.2.tgz#db9aabde85d5caabbfc0d4f2a4446960f627146a"
|
||||
integrity sha512-e5pEa2kBnBOgR4Y/p20pskXI74UEz7de8ZGVo58asOtvSVG5YAbJeELPZxOmt+Bnz3rX753YKhfIn4X4l1PPRQ==
|
||||
|
||||
ag-grid-community@^29.3.5:
|
||||
version "29.3.5"
|
||||
resolved "https://registry.yarnpkg.com/ag-grid-community/-/ag-grid-community-29.3.5.tgz#16897896d10fa3ecac79279aad50d3aaa17c5f33"
|
||||
integrity sha512-LxUo21f2/CH31ACEs1C7Q/ggGGI1fQPSTB4aY5OThmM+lBkygZ7QszBE8jpfgWOIjvjdtcdIeQbmbjkHeMsA7A==
|
||||
ag-grid-community@^31.0.1, ag-grid-community@~31.0.1:
|
||||
version "31.0.1"
|
||||
resolved "https://registry.yarnpkg.com/ag-grid-community/-/ag-grid-community-31.0.1.tgz#26022b29a7b90a0515076837d630ac9cd24cf28d"
|
||||
integrity sha512-RZQlW1DTOJHsUR/tnbnTJQKgAnDlHi05YYyTe5AgNor/1TlX1hoYdcqrGsJjvcHQgTjeEgzWOL0yf+KcqXZzxg==
|
||||
|
||||
ag-grid-react@^29.3.5:
|
||||
version "29.3.5"
|
||||
resolved "https://registry.yarnpkg.com/ag-grid-react/-/ag-grid-react-29.3.5.tgz#0eae8934d372c7751e98789542fc663aee0ad6ad"
|
||||
integrity sha512-Eg0GJ8hEBuxdVaN5g+qITOzhw0MGL9avL0Oaajr+p7QRtq2pIFHLZSknWsCBzUTjidiu75WZMKwlZjtGEuafdQ==
|
||||
ag-grid-react@^31.0.1:
|
||||
version "31.0.1"
|
||||
resolved "https://registry.yarnpkg.com/ag-grid-react/-/ag-grid-react-31.0.1.tgz#c7e3cf029ea1b97ab7f1d5134c8bb0086b4d2aac"
|
||||
integrity sha512-9nmYPsgH1YUDUDOTiyaFsysoNAx/y72ovFJKuOffZC1V7OrQMadyP6DbqGFWCqzzoLJOY7azOr51dDQzAIXLpw==
|
||||
dependencies:
|
||||
ag-grid-community "~31.0.1"
|
||||
prop-types "^15.8.1"
|
||||
|
||||
agent-base@5:
|
||||
|
Loading…
Reference in New Issue
Block a user