From 08648eedf23247e2ba599d6ad76534c282a0ed71 Mon Sep 17 00:00:00 2001 From: fairlighteth <31534717+fairlighteth@users.noreply.github.com> Date: Mon, 9 Dec 2024 20:54:30 +0000 Subject: [PATCH 01/14] feat: move tooltips --- .../ordersTable/pure/OrderStatusBox/index.tsx | 27 ++- .../OrderRow/EstimatedExecutionPrice.tsx | 12 +- .../OrderRow/OrderWarning.tsx | 145 ++++++++++++++++ .../OrdersTableContainer/OrderRow/index.tsx | 164 +++++------------- 4 files changed, 226 insertions(+), 122 deletions(-) create mode 100644 apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/OrderWarning.tsx diff --git a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrderStatusBox/index.tsx b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrderStatusBox/index.tsx index f066c74d6b..f5fd7bc2c0 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrderStatusBox/index.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrderStatusBox/index.tsx @@ -39,21 +39,41 @@ const Wrapper = styled.div<{ left: 0; top: 0; background: var(--statusBackground); - /* opacity: 0.14; */ z-index: 1; border-radius: ${({ withWarning }) => (withWarning ? '9px 0 0 9px' : '9px')}; } ` +const StatusContent = styled.div` + display: flex; + align-items: center; + gap: 4px; + position: relative; + z-index: 2; +` + type OrderStatusBoxProps = { order: ParsedOrder widthAuto?: boolean withWarning?: boolean onClick?: Command + WarningTooltip?: React.ComponentType<{ children: React.ReactNode }> } -export function OrderStatusBox({ order, widthAuto, withWarning, onClick }: OrderStatusBoxProps) { +export function OrderStatusBox({ order, widthAuto, withWarning, onClick, WarningTooltip }: OrderStatusBoxProps) { const { title, color, background } = getOrderStatusTitleAndColor(order) + + const content = ( + + {title} + {withWarning && WarningTooltip && ( + + <> + + )} + + ) + return ( - {/* Status overrides for special cases */} - {title} + {content} ) } diff --git a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/EstimatedExecutionPrice.tsx b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/EstimatedExecutionPrice.tsx index 586becae8b..925db7a65d 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/EstimatedExecutionPrice.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/EstimatedExecutionPrice.tsx @@ -74,6 +74,8 @@ export type EstimatedExecutionPriceProps = TokenAmountProps & { amountDifference?: CurrencyAmount percentageFee?: Percent amountFee?: CurrencyAmount + warningText?: string + WarningTooltip?: React.FC<{ children: React.ReactNode }> } export function EstimatedExecutionPrice(props: EstimatedExecutionPriceProps) { @@ -86,6 +88,8 @@ export function EstimatedExecutionPrice(props: EstimatedExecutionPriceProps) { percentageFee, amountFee, amount, + warningText, + WarningTooltip, ...rest } = props @@ -108,10 +112,16 @@ export function EstimatedExecutionPrice(props: EstimatedExecutionPriceProps) { ) + const unfillableLabel = {warningText || 'UNFILLABLE'} + return ( {isUnfillable ? ( - UNFILLABLE + WarningTooltip ? ( + {unfillableLabel} + ) : ( + unfillableLabel + ) ) : !absoluteDifferenceAmount ? ( {content} ) : ( diff --git a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/OrderWarning.tsx b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/OrderWarning.tsx new file mode 100644 index 0000000000..433f1abdbf --- /dev/null +++ b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/OrderWarning.tsx @@ -0,0 +1,145 @@ +import React from 'react' + +import AlertTriangle from '@cowprotocol/assets/cow-swap/alert.svg' +import { Command } from '@cowprotocol/types' +import { ButtonSecondary, TokenSymbol, UI, HoverTooltip } from '@cowprotocol/ui' + +import SVG from 'react-inlinesvg' + +import * as styledEl from './styled' + +interface WarningProps { + symbol: string + isScheduled: boolean +} + +interface AllowanceWarningProps extends WarningProps { + approve: Command +} + +function BalanceWarning({ symbol, isScheduled }: WarningProps) { + return ( + +

Insufficient token balance

+

+ Insufficient{' '} + + + {' '} + balance detected. +
+
+ {isScheduled ? ( + <> + If the balance remains insufficient at creation time, this order portion will not be created. Add more{' '} + + + {' '} + before that time. + + ) : ( + <> + The order remains open. Execution requires sufficient{' '} + + + {' '} + balance. + + )} +

+
+ ) +} + +function AllowanceWarning({ symbol, isScheduled, approve }: AllowanceWarningProps) { + return ( + +

Insufficient token allowance

+

+ {isScheduled ? ( + <> + Insufficient allowance granted for{' '} + + + + . If allowance remains insufficient at creation time, this portion will not be created. Approve the{' '} + + + {' '} + token before creation. + + ) : ( + <> + The order remains open. Execution requires adequate allowance for{' '} + + + + . Approve the token to proceed. + + )} +

+ + Approve + +
+ ) +} + +interface WarningTooltipProps { + children: React.ReactNode + hasEnoughBalance: boolean + hasEnoughAllowance: boolean + hasValidPendingPermit: boolean | undefined + inputTokenSymbol: string + isOrderScheduled: boolean + onApprove: Command + showIcon?: boolean +} + +export function WarningTooltip({ + children, + hasEnoughBalance, + hasEnoughAllowance, + hasValidPendingPermit, + inputTokenSymbol, + isOrderScheduled, + onApprove, + showIcon = false, +}: WarningTooltipProps) { + const withAllowanceWarning = hasEnoughAllowance === false && hasValidPendingPermit === false + + const tooltipContent = ( + + {hasEnoughBalance === false && } + {withAllowanceWarning && ( + + )} + + ) + + if (showIcon) { + return ( + + } + /> + {children} + + ) + } + + return ( + + {children} + + ) +} diff --git a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/index.tsx b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/index.tsx index 5303ca82be..83c2cc774a 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/index.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/index.tsx @@ -1,18 +1,15 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react' -import AlertTriangle from '@cowprotocol/assets/cow-swap/alert.svg' import { ZERO_FRACTION } from '@cowprotocol/common-const' import { useTimeAgo } from '@cowprotocol/common-hooks' import { getAddress, getEtherscanLink } from '@cowprotocol/common-utils' import { SupportedChainId } from '@cowprotocol/cow-sdk' import { TokenLogo } from '@cowprotocol/tokens' import { Command, UiOrderType } from '@cowprotocol/types' -import { ButtonSecondary, Loader, TokenAmount, TokenSymbol, UI } from '@cowprotocol/ui' +import { Loader, TokenAmount, UI } from '@cowprotocol/ui' import { PercentDisplay, percentIsAlmostHundred } from '@cowprotocol/ui' import { Currency, CurrencyAmount, Percent, Price } from '@uniswap/sdk-core' -import SVG from 'react-inlinesvg' - import { CREATING_STATES, OrderStatus } from 'legacy/state/orders/actions' import { PendingOrderPrices } from 'modules/orders/state/pendingOrdersPricesAtom' @@ -32,6 +29,7 @@ import { ParsedOrder } from 'utils/orderUtils/parseOrder' import { EstimatedExecutionPrice } from './EstimatedExecutionPrice' import { OrderContextMenu } from './OrderContextMenu' +import { WarningTooltip } from './OrderWarning' import * as styledEl from './styled' import { OrderParams } from '../../../utils/getOrderParams' @@ -70,85 +68,6 @@ function CurrencySymbolItem({ amount }: { amount: CurrencyAmount }) { return } -function BalanceWarning(params: { symbol: string; isScheduled: boolean }) { - const { symbol, isScheduled } = params - - return ( - -

Insufficient balance

-

- Your wallet currently has insufficient{' '} - - - {' '} - balance to execute this order. -
-
- {isScheduled ? ( - <> - If there are not enough funds for this order by creation time, this part won't be created. Top up your{' '} - - - {' '} - balance before then to have it created. - - ) : ( - <> - The order is still open and will become executable when you top up your{' '} - - - {' '} - balance. - - )} -

-
- ) -} -function AllowanceWarning(params: { symbol: string; isScheduled: boolean; approve: Command }) { - const { symbol, isScheduled } = params - - return ( - -

Insufficient approval for this order

-

- {isScheduled ? ( - <> - You haven't given CoW Swap sufficient allowance to spend{' '} - - - - . -
- If there's not enough allowance for this order by creation time, this part won't be created. Approve{' '} - - - {' '} - in your account token page before then to have it created. - - ) : ( - <> - This order is still open and valid, but you haven't given CoW Swap sufficient allowance to spend{' '} - - - - . -
- The order will become executable when you approve{' '} - - - {' '} - in your account token page. - - )} -

- - Approve - -
- ) -} - export interface OrderRowProps { order: ParsedOrder prices: PendingOrderPrices | undefined | null @@ -163,7 +82,7 @@ export interface OrderRowProps { onClick: Command orderActions: OrderActions hasValidPendingPermit?: boolean | undefined - children?: JSX.Element + children?: React.ReactNode } export function OrderRow({ @@ -179,8 +98,8 @@ export function OrderRow({ onClick, prices, spotPrice, - children, hasValidPendingPermit, + children, }: OrderRowProps) { const { buyAmount, rateInfoParams, hasEnoughAllowance, hasEnoughBalance, chainId } = orderParams const { creationTime, expirationTime, status } = order @@ -239,6 +158,12 @@ export function OrderRow({ const inputTokenSymbol = order.inputToken.symbol || '' + const getWarningText = () => { + if (hasEnoughBalance === false) return 'Insufficient balance' + if (hasEnoughAllowance === false) return 'Insufficient allowance' + return 'Unfillable' + } + return ( ( + orderActions.approveOrderToken(order.inputToken)} + {...props} + /> + )} /> ) : prices === null || !estimatedExecutionPrice || isOrderCreating ? ( @@ -409,40 +346,33 @@ export function OrderRow({ {/* Status label */} - {children ? ( - children - ) : ( - <> - - {withWarning && ( - - } - text={ - - {hasEnoughBalance === false && ( - - )} - {withAllowanceWarning && ( - orderActions.approveOrderToken(order.inputToken)} - symbol={inputTokenSymbol} - isScheduled={isOrderScheduled} - /> - )} - - } - /> - - )} - - )} + ( + orderActions.approveOrderToken(order.inputToken)} + showIcon={true} + {...props} + /> + ) + : undefined + } + /> + {/* Children (e.g. ToggleExpandButton for parent orders) */} + {children} + {/* Action content menu */} Date: Tue, 10 Dec 2024 09:37:59 +0000 Subject: [PATCH 02/14] feat: refactor table layout --- .../MultipleCancellationMenu/index.tsx | 6 +- .../containers/OrdersTableWidget/index.tsx | 9 +- .../OrderRow/EstimatedExecutionPrice.tsx | 29 +- .../OrdersTableContainer/OrderRow/index.tsx | 252 ++++++++---------- .../pure/OrdersTableContainer/OrdersTable.tsx | 17 +- .../pure/OrdersTableContainer/OrdersTabs.tsx | 2 +- .../pure/OrdersTableContainer/TableGroup.tsx | 6 +- .../pure/OrdersTableContainer/index.tsx | 6 +- .../pure/OrdersTableContainer/styled.tsx | 65 +++-- .../OrdersTableContainer/tableHeaders.tsx | 48 ++-- 10 files changed, 201 insertions(+), 239 deletions(-) diff --git a/apps/cowswap-frontend/src/modules/ordersTable/containers/MultipleCancellationMenu/index.tsx b/apps/cowswap-frontend/src/modules/ordersTable/containers/MultipleCancellationMenu/index.tsx index 74d18e4712..ea38bb0bb6 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/containers/MultipleCancellationMenu/index.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/containers/MultipleCancellationMenu/index.tsx @@ -22,7 +22,7 @@ const Wrapper = styled.div<{ hasSelectedItems: boolean }>` align-items: center; justify-content: space-between; gap: 6px; - margin: 0 10px 0 ${({ hasSelectedItems }) => (hasSelectedItems ? '' : 'auto')}; + margin: 0 0 0 ${({ hasSelectedItems }) => (hasSelectedItems ? '' : 'auto')}; ${Media.upToSmall()} { width: 100%; @@ -38,7 +38,7 @@ const ActionButton = styled.button` font-weight: 600; text-decoration: none; font-size: 13px; - padding: 10px 15px; + padding: 7px 12px; margin: 0; gap: 5px; border: 0; @@ -65,7 +65,7 @@ const TextButton = styled.button` color: var(${UI.COLOR_TEXT_OPACITY_70}); font-size: 12px; font-weight: 500; - padding: 5px 10px; + padding: 5px; cursor: pointer; background: none; outline: none; diff --git a/apps/cowswap-frontend/src/modules/ordersTable/containers/OrdersTableWidget/index.tsx b/apps/cowswap-frontend/src/modules/ordersTable/containers/OrdersTableWidget/index.tsx index ab493401ca..6b65d107fe 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/containers/OrdersTableWidget/index.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/containers/OrdersTableWidget/index.tsx @@ -40,8 +40,8 @@ import { OrdersReceiptModal } from '../OrdersReceiptModal' import { useGetAlternativeOrderModalContextCallback, useSelectReceiptOrder } from '../OrdersReceiptModal/hooks' const SearchInputContainer = styled.div` - margin: 16px 0; - padding: 0 16px; + margin: 0; + padding: 0 0 0 16px; position: relative; ` @@ -266,9 +266,8 @@ export function OrdersTableWidget({ ordersPermitStatus={ordersPermitStatus} injectedWidgetParams={injectedWidgetParams} > - {currentTabId === OPEN_TAB.id && orders.length > 0 && ( - - )} + {(currentTabId === OPEN_TAB.id || currentTabId === 'all' || currentTabId === 'unfillable') && + orders.length > 0 && } diff --git a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/EstimatedExecutionPrice.tsx b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/EstimatedExecutionPrice.tsx index 925db7a65d..8449637019 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/EstimatedExecutionPrice.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/EstimatedExecutionPrice.tsx @@ -27,19 +27,6 @@ export const EstimatedExecutionPriceWrapper = styled.span<{ hasWarning: boolean; color: inherit; } - // Triangle warning icon override - ${styledEl.WarningIndicator} { - padding: 0 0 0 3px; - - svg { - --size: 18px; - width: var(--size); - height: var(--size); - min-width: var(--size); - min-height: var(--size); - } - } - // Popover container override > div > div, > span { @@ -49,21 +36,15 @@ export const EstimatedExecutionPriceWrapper = styled.span<{ hasWarning: boolean; ` const UnfillableLabel = styled.span` - width: 100%; - max-width: 90px; - background: var(${UI.COLOR_DANGER_BG}); - color: var(${UI.COLOR_DANGER_TEXT}); + width: auto; + color: var(${UI.COLOR_DANGER}); position: relative; - border-radius: 9px; display: flex; align-items: center; justify-content: center; - font-size: 11px; - font-weight: 600; - padding: 6px 2px; - margin: 0 4px 0 0; - letter-spacing: 0.2px; - text-transform: uppercase; + font-size: inherit; + font-weight: 500; + line-height: 1.1; ` export type EstimatedExecutionPriceProps = TokenAmountProps & { diff --git a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/index.tsx b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/index.tsx index 83c2cc774a..7c61f9f303 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/index.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/index.tsx @@ -74,7 +74,7 @@ export interface OrderRowProps { spotPrice: Price | undefined | null isRateInverted: boolean showLimitPrice: boolean - isOpenOrdersTab: boolean + isHistoryTab: boolean isRowSelectable: boolean isRowSelected: boolean isChild?: boolean @@ -89,7 +89,7 @@ export function OrderRow({ order, isRateInverted: isGloballyInverted, showLimitPrice, - isOpenOrdersTab, + isHistoryTab, isRowSelectable, isRowSelected, isChild, @@ -165,14 +165,9 @@ export function OrderRow({ } return ( - + {/*Checkbox for multiple cancellation*/} - {isRowSelectable && isOpenOrdersTab && ( + {isRowSelectable && !isHistoryTab && ( - {/* Fills at / Limit price */} - {isOpenOrdersTab && ( - - {showLimitPrice ? ( - - + {/* Fills at / Limit price */} + + {showLimitPrice ? ( + + + + ) : ( + <> + {getIsFinalizedOrder(order) ? ( + '-' + ) : prices && estimatedExecutionPrice ? ( + + ( + orderActions.approveOrderToken(order.inputToken)} + {...props} + /> + )} + /> + + ) : prices === null || !estimatedExecutionPrice || isOrderCreating ? ( + '-' + ) : ( + + )} + + )} + + + {/* Distance to market */} + + {isUnfillable ? ( + '-' + ) : priceDiffs?.percentage && Number(priceDiffs.percentage.toFixed(4)) >= MIN_PERCENTAGE_TO_DISPLAY ? ( + + {priceDiffs.percentage.toFixed(2)}% + + ) : ( + '-' + )} + + + {/* Market price */} + + {spotPrice ? ( + + ) : spotPrice === null ? ( + '-' + ) : ( + + )} + + + {/* Expires and Created for open orders */} + + {expirationTimeAgo} + {isScheduledCreating ? 'Creating...' : creationTimeAgo} + + + ) : ( + <> + {/* History tab columns */} + + {executedPriceInverted ? ( + - - ) : ( - <> - {getIsFinalizedOrder(order) ? ( - '-' - ) : prices && estimatedExecutionPrice ? ( - - ( - orderActions.approveOrderToken(order.inputToken)} - {...props} - /> - )} - /> - - ) : prices === null || !estimatedExecutionPrice || isOrderCreating ? ( - '-' - ) : ( - - )} - - )} - - )} - - {/* Distance to market */} - {isOpenOrdersTab && ( - - {priceDiffs?.percentage && Number(priceDiffs.percentage.toFixed(4)) >= MIN_PERCENTAGE_TO_DISPLAY ? ( - - {priceDiffs.percentage.toFixed(2)}% - - ) : ( - '-' - )} - - )} + ) : ( + '-' + )} + - {/* Market price */} - {isOpenOrdersTab && ( - - {spotPrice ? ( - - ) : spotPrice === null ? ( - '-' - ) : ( - - )} - - )} - - {/* Execution price */} - {!isOpenOrdersTab && ( - - - - - - )} + + {order.status === OrderStatus.FULFILLED && fulfillmentTimeAgo ? fulfillmentTimeAgo : '-'} + - {/* Execution price for closed orders */} - {!isOpenOrdersTab && ( - - {executedPriceInverted ? ( - - ) : ( - '-' - )} - + {creationTimeAgo} + )} - {/* Execution time for closed orders */} - {!isOpenOrdersTab && ( - - {order.status === OrderStatus.FULFILLED && fulfillmentTimeAgo ? fulfillmentTimeAgo : '-'} - - )} - - {/* Creation time for closed orders */} - {!isOpenOrdersTab && {creationTimeAgo}} - - {/* Expires and Created for open orders */} - {isOpenOrdersTab && ( - - {expirationTimeAgo} - {isScheduledCreating ? 'Creating...' : creationTimeAgo} - - )} - - {/* TODO: Enable once there is back-end support */} - {/* {!isOpenOrdersTab && ordersTableFeatures.DISPLAY_EXECUTION_TIME && ( - - {order.status === OrderStatus.FULFILLED ? executedTimeAgo : '-'} - - )} */} - {/* Filled % */} diff --git a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrdersTable.tsx b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrdersTable.tsx index 27fb18d58d..afcfe97356 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrdersTable.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrdersTable.tsx @@ -20,7 +20,7 @@ import { TableGroup } from './TableGroup' import { createTableHeaders } from './tableHeaders' import { OrderActions } from './types' -import { ALL_ORDERS_TAB, HISTORY_TAB, OPEN_TAB, UNFILLABLE_TAB, ORDERS_TABLE_PAGE_SIZE } from '../../const/tabs' +import { HISTORY_TAB, ORDERS_TABLE_PAGE_SIZE } from '../../const/tabs' import { useGetBuildOrdersTableUrl } from '../../hooks/useGetBuildOrdersTableUrl' import { getOrderParams } from '../../utils/getOrderParams' import { @@ -176,11 +176,12 @@ export function OrdersTable({ const tableHeaders = useMemo(() => createTableHeaders(showLimitPrice, setShowLimitPrice), [showLimitPrice]) const visibleHeaders = useMemo(() => { + const isHistoryTab = currentTab === HISTORY_TAB.id return tableHeaders.filter((header) => { - if (currentTab === OPEN_TAB.id || currentTab === UNFILLABLE_TAB.id || currentTab === ALL_ORDERS_TAB.id) { - return header.showInOpenOrders - } - return header.showInClosedOrders + // If showInHistory is not defined, show the header in all tabs + if (header.showInHistory === undefined) return true + // Otherwise, show based on the showInHistory value + return header.showInHistory === isHistoryTab }) }, [tableHeaders, currentTab]) @@ -188,7 +189,7 @@ export function OrdersTable({ <> - + {visibleHeaders.map((header) => { if (header.id === 'checkbox' && (!isRowSelectable || currentTab === HISTORY_TAB.id)) { return null @@ -244,7 +245,7 @@ export function OrdersTable({ key={order.id} isRowSelectable={isRowSelectable} isRowSelected={!!selectedOrdersMap[order.id]} - isOpenOrdersTab={currentTab !== HISTORY_TAB.id} + isHistoryTab={currentTab === HISTORY_TAB.id} order={order} spotPrice={spotPrice} prices={pendingOrdersPrices[order.id]} @@ -265,7 +266,7 @@ export function OrdersTable({ key={item.parent.id} isRowSelectable={isRowSelectable} isRowSelected={!!selectedOrdersMap[item.parent.id]} - isOpenOrdersTab={currentTab !== HISTORY_TAB.id} + isHistoryTab={currentTab === HISTORY_TAB.id} spotPrice={spotPrice} prices={pendingOrdersPrices[item.parent.id]} isRateInverted={false} diff --git a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrdersTabs.tsx b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrdersTabs.tsx index b4c66dd120..ce129d5d03 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrdersTabs.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrdersTabs.tsx @@ -23,7 +23,7 @@ const TabButton = styled(Link)<{ active: string }>` border: 1px solid var(${UI.COLOR_TEXT_OPACITY_10}); text-decoration: none; font-size: 13px; - padding: 10px 14px; + padding: 10px; border: 0; outline: none; cursor: pointer; diff --git a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/TableGroup.tsx b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/TableGroup.tsx index 52ef2543e8..d545967624 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/TableGroup.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/TableGroup.tsx @@ -34,7 +34,7 @@ export interface TableGroupProps { spotPrice: Price | undefined | null isRateInverted: boolean showLimitPrice: boolean - isOpenOrdersTab: boolean + isHistoryTab: boolean isRowSelectable: boolean isRowSelected: boolean orderActions: OrderActions @@ -49,7 +49,7 @@ export function TableGroup(props: TableGroupProps) { spotPrice, isRateInverted, showLimitPrice, - isOpenOrdersTab, + isHistoryTab, isRowSelectable, isRowSelected, orderActions, @@ -70,7 +70,7 @@ export function TableGroup(props: TableGroupProps) { const commonProps = { isRowSelectable, - isOpenOrdersTab, + isHistoryTab, spotPrice, prices, isRateInverted, diff --git a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/index.tsx b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/index.tsx index a438eda7a3..37fc9c0813 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/index.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/index.tsx @@ -131,7 +131,8 @@ const TopContainer = styled.div` const TabsContainer = styled.div<{ withSingleChild: boolean }>` display: flex; align-items: center; - justify-content: flex-end; + justify-content: space-between; + width: 100%; ${Media.upToMedium()} { ${({ withSingleChild }) => @@ -309,9 +310,6 @@ export function OrdersTableContainer({ return ( -

- Orders -

{children && {children}} diff --git a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/styled.tsx b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/styled.tsx index 21d541505d..0b9b7ccca2 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/styled.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/styled.tsx @@ -1,34 +1,34 @@ import { Media, UI } from '@cowprotocol/ui' import { transparentize } from 'color2k' -import styled, { css } from 'styled-components/macro' +import styled from 'styled-components/macro' import { RateWrapper } from 'common/pure/RateInfo' -export const TableHeader = styled.div<{ isOpenOrdersTab: boolean; isRowSelectable: boolean }>` +export const TableHeader = styled.div<{ isHistoryTab: boolean; isRowSelectable: boolean }>` --height: 38px; --checkboxSize: 16px; --checkBoxBorderRadius: 3px; display: grid; gap: 14px; - grid-template-columns: ${({ isOpenOrdersTab, isRowSelectable }) => - `${isRowSelectable && isOpenOrdersTab ? 'var(--checkboxSize)' : ''} 3fr 2fr 1fr 1.4fr 1.4fr 0.7fr 108px 24px`}; + grid-template-columns: ${({ isHistoryTab, isRowSelectable }) => + !isHistoryTab + ? `${isRowSelectable ? 'var(--checkboxSize)' : ''} minmax(200px,2.5fr) minmax(110px,1fr) minmax(70px,0.5fr) minmax(110px,1fr) minmax(110px,1fr) minmax(70px,0.5fr) minmax(80px,0.8fr) 40px` + : `minmax(200px, 2.5fr) + repeat(3, minmax(110px, 1fr)) + minmax(80px, 0.8fr) + minmax(100px, 1fr) + 40px `}; grid-template-rows: minmax(var(--height), 1fr); align-items: center; border: none; padding: 0 12px; - border-radius: 6px; background: var(${UI.COLOR_PAPER_DARKER}); - - ${Media.upToLargeAlt()} { - ${({ isRowSelectable, isOpenOrdersTab }) => css` - grid-template-columns: ${`${ - isRowSelectable && isOpenOrdersTab ? 'var(--checkboxSize) minmax(200px,2fr)' : 'minmax(200px,2fr)' - } repeat(2,minmax(110px,2fr)) ${ - isOpenOrdersTab ? 'minmax(140px,2.2fr) minmax(100px,1fr) minmax(100px,1fr)' : 'minmax(110px,2fr)' - } minmax(50px,1fr) 108px 24px`}; - `} - } + border-top: none; + border-right: none; + border-left: none; + border-image: initial; + border-bottom: 1px solid var(--cow-color-text-opacity-10); ${Media.upToSmall()} { --checkboxSize: 24px; @@ -45,32 +45,22 @@ export const TableRow = styled(TableHeader)<{ isChildOrder?: boolean }>` background: var(${UI.COLOR_PAPER_DARKER}); } - > div:first-child { - margin: 0; - - &::before { - display: ${({ isChildOrder }) => (isChildOrder ? 'inline-block' : 'none')}; - color: ${({ theme }) => transparentize(theme.text, 0.5)}; - content: '↳'; - text-decoration: none !important; - } + > div { + display: flex; + align-items: center; } > div:first-child { - margin-left: ${({ isChildOrder }) => (isChildOrder ? '5px' : '')}; + margin: 0; &::before { display: ${({ isChildOrder }) => (isChildOrder ? 'inline-block' : 'none')}; - color: ${({ theme }) => transparentize(theme.info, 0.6)}; + color: ${({ theme }) => transparentize(theme.text, 0.5)}; content: '↳'; text-decoration: none !important; } } - &:last-child { - border-bottom: 0; - } - ${RateWrapper} { text-align: left; } @@ -125,20 +115,24 @@ export const TableRowCheckbox = styled.input` margin: 0; outline: 0; opacity: 0.5; + z-index: 5; &:checked { border-color: var(${UI.COLOR_PRIMARY}); background: var(${UI.COLOR_PRIMARY}); opacity: 1; + z-index: 6; } &:checked + ${CheckboxCheckmark}::after { display: block; + z-index: 6; } &:indeterminate { background: var(${UI.COLOR_PRIMARY}); border-color: var(${UI.COLOR_PRIMARY}); + z-index: 6; } &:indeterminate + ${CheckboxCheckmark}::after { @@ -147,15 +141,18 @@ export const TableRowCheckbox = styled.input` border-width: 2px 0 0 0; top: calc(50% + 3px); transform: none; + z-index: 6; ${Media.upToSmall()} { top: calc(50% + 4px); } } - &[disabled], - &[disabled] + ${CheckboxCheckmark} { - cursor: default; + &:disabled { + cursor: not-allowed; + opacity: 0.1; + background: var(${UI.COLOR_TEXT}); + z-index: 6; } ` @@ -172,10 +169,12 @@ export const TableRowCheckboxWrapper = styled.label` background: var(${UI.COLOR_PRIMARY}); border-color: var(${UI.COLOR_PRIMARY}); opacity: 0.5; + z-index: 6; + ${CheckboxCheckmark}::after { display: block; border-color: var(${UI.COLOR_BUTTON_TEXT}); + z-index: 6; } } ` diff --git a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/tableHeaders.tsx b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/tableHeaders.tsx index a8b81403cf..68c670c151 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/tableHeaders.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/tableHeaders.tsx @@ -21,12 +21,23 @@ const StyledArrowControl = styled.div` } ` +const HeaderElement = styled.div<{ doubleRow?: boolean }>` + display: flex; + flex-direction: column; + gap: 3px; + + i { + font-style: normal; + opacity: 0.7; + font-size: 0.85em; + } +` + export interface TableHeaderConfig { id: string content: ReactNode doubleRow?: boolean - showInOpenOrders?: boolean - showInClosedOrders?: boolean + showInHistory?: boolean width?: string extraComponent?: ReactNode } @@ -38,18 +49,15 @@ export const createTableHeaders = ( { id: 'checkbox', content: null, - showInOpenOrders: true, }, { id: 'trade', content: Sell → Buy, - showInOpenOrders: true, - showInClosedOrders: true, }, { id: 'fillsAt', content: showLimitPrice ? Limit price : Fills at, - showInOpenOrders: true, + showInHistory: false, extraComponent: ( setShowLimitPrice(!showLimitPrice)}> @@ -59,46 +67,56 @@ export const createTableHeaders = ( { id: 'distanceToMarket', content: Distance to market, - showInOpenOrders: true, + showInHistory: false, }, { id: 'limitPrice', content: Limit price, - showInClosedOrders: true, + showInHistory: true, }, { id: 'marketPrice', content: Market price, - showInOpenOrders: true, + showInHistory: false, + }, + { + id: 'expiration', + content: ( + + Expiration + + Creation + + + ), + showInHistory: false, + doubleRow: true, }, { id: 'executionPrice', content: Execution price, - showInClosedOrders: true, + showInHistory: true, }, { id: 'executionTime', content: Execution time, - showInClosedOrders: true, + showInHistory: true, }, { id: 'creationTime', content: Creation time, - showInClosedOrders: true, + showInHistory: true, }, { id: 'filled', content: Filled, - showInClosedOrders: true, }, { id: 'status', content: Status, - showInClosedOrders: true, }, { id: 'actions', content: null, - showInClosedOrders: true, }, ] From 73486b55eb90d74699af68f6ee845ac1d7d38981 Mon Sep 17 00:00:00 2001 From: fairlighteth <31534717+fairlighteth@users.noreply.github.com> Date: Tue, 10 Dec 2024 10:01:19 +0000 Subject: [PATCH 03/14] feat: add pending execution logic --- .../OrdersTableContainer/OrderRow/index.tsx | 53 ++++++++++--------- 1 file changed, 29 insertions(+), 24 deletions(-) diff --git a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/index.tsx b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/index.tsx index 7c61f9f303..a01e63b5e8 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/index.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/index.tsx @@ -214,30 +214,35 @@ export function OrderRow({ '-' ) : prices && estimatedExecutionPrice ? ( - ( - orderActions.approveOrderToken(order.inputToken)} - {...props} - /> - )} - /> + {priceDiffs?.percentage && + Math.abs(Number(priceDiffs.percentage.toFixed(4))) <= MIN_PERCENTAGE_TO_DISPLAY ? ( + ⚡️ Pending execution + ) : ( + ( + orderActions.approveOrderToken(order.inputToken)} + {...props} + /> + )} + /> + )} ) : prices === null || !estimatedExecutionPrice || isOrderCreating ? ( '-' From 3184856f4c3228f22c517f5d0c796e74dfb540f7 Mon Sep 17 00:00:00 2001 From: fairlighteth <31534717+fairlighteth@users.noreply.github.com> Date: Tue, 10 Dec 2024 10:08:09 +0000 Subject: [PATCH 04/14] feat: remove prop cosmos --- .../ordersTable/pure/OrdersTableContainer/index.cosmos.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/index.cosmos.tsx b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/index.cosmos.tsx index ac58ea8d83..bfcf1f7bdc 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/index.cosmos.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/index.cosmos.tsx @@ -67,7 +67,6 @@ export default ( tabs={tabs} isSafeViaWc={false} allowsOffchainSigning={true} - isOpenOrdersTab={true} isWalletConnected={true} selectedOrders={[]} balancesAndAllowances={balancesAndAllowances} From 385d6f1fb79d180705b50c83a0c787b3ff095708 Mon Sep 17 00:00:00 2001 From: fairlighteth <31534717+fairlighteth@users.noreply.github.com> Date: Tue, 10 Dec 2024 11:24:03 +0000 Subject: [PATCH 05/14] feat: improve search --- .../containers/OrdersTableWidget/index.tsx | 50 +++++++++++-------- .../pure/OrdersTableContainer/index.tsx | 40 +++++++++------ 2 files changed, 54 insertions(+), 36 deletions(-) diff --git a/apps/cowswap-frontend/src/modules/ordersTable/containers/OrdersTableWidget/index.tsx b/apps/cowswap-frontend/src/modules/ordersTable/containers/OrdersTableWidget/index.tsx index 6b65d107fe..22b5c43cdb 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/containers/OrdersTableWidget/index.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/containers/OrdersTableWidget/index.tsx @@ -38,6 +38,7 @@ import { parseOrdersTableUrl } from '../../utils/parseOrdersTableUrl' import { MultipleCancellationMenu } from '../MultipleCancellationMenu' import { OrdersReceiptModal } from '../OrdersReceiptModal' import { useGetAlternativeOrderModalContextCallback, useSelectReceiptOrder } from '../OrdersReceiptModal/hooks' +import { UI } from '@cowprotocol/ui' const SearchInputContainer = styled.div` margin: 0; @@ -50,7 +51,7 @@ const SearchIcon = styled(Search)` left: 28px; top: 50%; transform: translateY(-50%); - color: ${({ theme }) => theme.textSecondary}; + color: var(${UI.COLOR_TEXT_OPACITY_50}); width: 16px; height: 16px; ` @@ -58,17 +59,18 @@ const SearchIcon = styled(Search)` const SearchInput = styled.input` width: 100%; padding: 8px 12px 8px 36px; - border: 1px solid ${({ theme }) => theme.grey}; + border: 1px solid var(${UI.COLOR_PAPER_DARKER}); border-radius: 8px; - font-size: 14px; + font-size: 13px; + font-weight: 500; &::placeholder { - color: ${({ theme }) => theme.textSecondary}; + color: var(${UI.COLOR_TEXT_OPACITY_50}); } &:focus { outline: none; - border-color: ${({ theme }) => theme.blue}; + border-color: var(${UI.COLOR_TEXT}); } ` @@ -214,32 +216,37 @@ export function OrdersTableWidget({ const inputToken = parsedOrder.inputToken const outputToken = parsedOrder.outputToken - // Check symbols (case-insensitive) - if ( - inputToken.symbol?.toLowerCase().includes(searchTermLower) || - outputToken.symbol?.toLowerCase().includes(searchTermLower) - ) { - return true - } + // First check for token symbols (case-insensitive) + const symbolMatch = [inputToken.symbol, outputToken.symbol].some((symbol) => { + return symbol?.toLowerCase().includes(searchTermLower) + }) + + if (symbolMatch) return true - // Clean up the search term but preserve '0x' prefix + // If not a symbol match, check for address matches + // Clean up the search term but preserve '0x' prefix if present const hasPrefix = searchTermLower.startsWith('0x') - const cleanedSearch = searchTermLower.replace(/[^0-9a-fx]/g, '') // Allow 'x' for '0x' + const cleanedSearch = searchTermLower.replace(/[^0-9a-fx]/g, '') // For exact address matches (40 or 42 chars), do strict comparison if (cleanedSearch.length === 40 || cleanedSearch.length === 42) { - const searchTermNormalized = cleanedSearch.startsWith('0x') ? cleanedSearch : `0x${cleanedSearch}` + const searchTermNormalized = hasPrefix ? cleanedSearch : `0x${cleanedSearch}` return [inputToken.address, outputToken.address].some( (address) => address.toLowerCase() === searchTermNormalized.toLowerCase(), ) } - // For partial address matches, allow includes + // For partial address matches const searchWithoutPrefix = hasPrefix ? cleanedSearch.slice(2) : cleanedSearch - return [inputToken.address, outputToken.address].some((address) => { - const addressWithoutPrefix = address.slice(2).toLowerCase() - return addressWithoutPrefix.includes(searchWithoutPrefix.toLowerCase()) - }) + if (searchWithoutPrefix.length >= 2) { + // Only search if we have at least 2 characters + return [inputToken.address, outputToken.address].some((address) => { + const addressWithoutPrefix = address.slice(2).toLowerCase() + return addressWithoutPrefix.includes(searchWithoutPrefix.toLowerCase()) + }) + } + + return false }) }, [orders, searchTerm]) @@ -265,6 +272,7 @@ export function OrdersTableWidget({ pendingActivities={pendingActivity} ordersPermitStatus={ordersPermitStatus} injectedWidgetParams={injectedWidgetParams} + searchTerm={searchTerm} > {(currentTabId === OPEN_TAB.id || currentTabId === 'all' || currentTabId === 'unfillable') && orders.length > 0 && } @@ -273,7 +281,7 @@ export function OrdersTableWidget({ setSearchTerm(e.target.value)} /> diff --git a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/index.tsx b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/index.tsx index 37fc9c0813..2310274643 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/index.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/index.tsx @@ -185,6 +185,7 @@ interface OrdersProps { pendingOrdersPrices: any getSpotPrice: any ordersPermitStatus: any + searchTerm?: string } export function OrdersTableContainer({ @@ -206,6 +207,7 @@ export function OrdersTableContainer({ pendingActivities, ordersPermitStatus, injectedWidgetParams, + searchTerm, }: OrdersProps) { const currentTab = useMemo(() => { const activeTab = tabs.find((tab) => tab.isActive) @@ -252,13 +254,15 @@ export function OrdersTableContainer({

- {currentTab === ALL_ORDERS_TAB.id - ? 'No orders' - : currentTab === UNFILLABLE_TAB.id - ? 'No unfillable orders' - : currentTab === OPEN_TAB.id - ? 'No open orders' - : 'No orders history'} + {searchTerm + ? 'No matching orders found' + : currentTab === ALL_ORDERS_TAB.id + ? 'No orders' + : currentTab === UNFILLABLE_TAB.id + ? 'No unfillable orders' + : currentTab === OPEN_TAB.id + ? 'No open orders' + : 'No order history'}

@@ -266,6 +270,8 @@ export function OrdersTableContainer({ Use the to see {currentTab === HISTORY_TAB.id ? 'orders history' : 'your orders'} + ) : searchTerm ? ( + Try adjusting your search term or clearing the filter ) : ( <> @@ -273,14 +279,18 @@ export function OrdersTableContainer({ {currentTab === UNFILLABLE_TAB.id ? 'unfillable' : currentTab === OPEN_TAB.id ? 'open' : ''} orders at the moment. {' '} -
- Time to create a new one!{' '} - {orderType === TabOrderTypes.LIMIT ? ( - - Learn more - - - ) : null} + {(currentTab === OPEN_TAB.id || currentTab === ALL_ORDERS_TAB.id) && ( + <> +
+ Time to create a new one!{' '} + {orderType === TabOrderTypes.LIMIT ? ( + + Learn more + + + ) : null} + + )} )}

From 12827640cbc63f452ffa07aaef704f1cd3eb5579 Mon Sep 17 00:00:00 2001 From: fairlighteth <31534717+fairlighteth@users.noreply.github.com> Date: Tue, 10 Dec 2024 11:33:42 +0000 Subject: [PATCH 06/14] feat: row height change --- .../modules/ordersTable/pure/OrdersTableContainer/styled.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/styled.tsx b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/styled.tsx index 0b9b7ccca2..211d00c523 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/styled.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/styled.tsx @@ -6,7 +6,7 @@ import styled from 'styled-components/macro' import { RateWrapper } from 'common/pure/RateInfo' export const TableHeader = styled.div<{ isHistoryTab: boolean; isRowSelectable: boolean }>` - --height: 38px; + --height: 51px; --checkboxSize: 16px; --checkBoxBorderRadius: 3px; display: grid; From 080f1f06096bc96b845b1085f1e4d871ec83072b Mon Sep 17 00:00:00 2001 From: fairlighteth <31534717+fairlighteth@users.noreply.github.com> Date: Tue, 10 Dec 2024 11:40:00 +0000 Subject: [PATCH 07/14] feat: fix statusbox warning position --- .../ordersTable/pure/OrderStatusBox/index.tsx | 32 +++++++++---------- .../pure/OrdersTableContainer/styled.tsx | 5 --- 2 files changed, 15 insertions(+), 22 deletions(-) diff --git a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrderStatusBox/index.tsx b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrderStatusBox/index.tsx index f5fd7bc2c0..5e40b59f38 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrderStatusBox/index.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrderStatusBox/index.tsx @@ -63,27 +63,25 @@ type OrderStatusBoxProps = { export function OrderStatusBox({ order, widthAuto, withWarning, onClick, WarningTooltip }: OrderStatusBoxProps) { const { title, color, background } = getOrderStatusTitleAndColor(order) - const content = ( - - {title} + const content = {title} + + return ( + <> + + {content} + {withWarning && WarningTooltip && ( <> )} - - ) - - return ( - - {content} - + ) } diff --git a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/styled.tsx b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/styled.tsx index 211d00c523..df631e75e1 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/styled.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/styled.tsx @@ -45,11 +45,6 @@ export const TableRow = styled(TableHeader)<{ isChildOrder?: boolean }>` background: var(${UI.COLOR_PAPER_DARKER}); } - > div { - display: flex; - align-items: center; - } - > div:first-child { margin: 0; From 86a4b19dc039129faee4c3a574edadda038047b5 Mon Sep 17 00:00:00 2001 From: fairlighteth <31534717+fairlighteth@users.noreply.github.com> Date: Tue, 10 Dec 2024 12:13:20 +0000 Subject: [PATCH 08/14] feat: style filled progressbar --- .../OrdersTableContainer/OrderRow/index.tsx | 10 +++++---- .../OrdersTableContainer/OrderRow/styled.tsx | 22 +++++++++++-------- .../pure/OrdersTableContainer/styled.tsx | 2 +- 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/index.tsx b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/index.tsx index a01e63b5e8..c04bd9af66 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/index.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/index.tsx @@ -308,10 +308,12 @@ export function OrderRow({ {/* Filled % */} - - - - + + + + + + {/* Status label */} diff --git a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/styled.tsx b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/styled.tsx index a6bf6f35f9..231c719c19 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/styled.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/styled.tsx @@ -103,13 +103,15 @@ export const CellElement = styled.div<{ gap: 5px; height: 100%; display: flex; - flex-direction: row; + flex-flow: row nowrap; align-items: ${({ doubleRow }) => (doubleRow ? 'flex-start' : 'center')}; text-align: left; cursor: ${({ clickable }) => (clickable ? 'pointer' : '')}; > b { font-weight: 500; + width: 100%; + text-align: left; } ${({ doubleRow }) => @@ -174,12 +176,10 @@ export const CurrencyAmountWrapper = styled.div<{ clickable?: boolean }>` ` export const ProgressBarWrapper = styled.div` - width: 100%; - max-width: 50%; + flex: 1; align-items: center; flex-flow: row nowrap; gap: 8px; - flex-direction: row-reverse; padding: 0; font-size: 12px; font-weight: 500; @@ -187,11 +187,7 @@ export const ProgressBarWrapper = styled.div` display: flex; text-align: left; background: transparent; - justify-content: center; - - > b { - line-height: 1; - } + justify-content: flex-start; ` export const ProgressBar = styled.div<{ value: string }>` @@ -212,6 +208,14 @@ export const ProgressBar = styled.div<{ value: string }>` } ` +export const FilledPercentageContainer = styled.div` + display: grid; + grid-template-columns: minmax(50px, auto) auto; + gap: 4px; + align-items: center; + width: 100%; +` + export const ExecuteCellWrapper = styled.div` width: 100%; display: flex; diff --git a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/styled.tsx b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/styled.tsx index df631e75e1..193af8de41 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/styled.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/styled.tsx @@ -13,7 +13,7 @@ export const TableHeader = styled.div<{ isHistoryTab: boolean; isRowSelectable: gap: 14px; grid-template-columns: ${({ isHistoryTab, isRowSelectable }) => !isHistoryTab - ? `${isRowSelectable ? 'var(--checkboxSize)' : ''} minmax(200px,2.5fr) minmax(110px,1fr) minmax(70px,0.5fr) minmax(110px,1fr) minmax(110px,1fr) minmax(70px,0.5fr) minmax(80px,0.8fr) 40px` + ? `${isRowSelectable ? 'var(--checkboxSize)' : ''} minmax(200px,2.5fr) minmax(110px,1fr) minmax(70px,0.5fr) minmax(110px,1fr) minmax(110px,1fr) minmax(80px,90px) minmax(80px,0.8fr) 40px` : `minmax(200px, 2.5fr) repeat(3, minmax(110px, 1fr)) minmax(80px, 0.8fr) From 9c33683d6e783eaa8ced5f01a8141d3f344d7a3b Mon Sep 17 00:00:00 2001 From: fairlighteth <31534717+fairlighteth@users.noreply.github.com> Date: Tue, 10 Dec 2024 13:25:30 +0000 Subject: [PATCH 09/14] feat: add limit price to order history --- .../pure/OrdersTableContainer/OrderRow/index.tsx | 14 ++++++++++++++ .../pure/OrdersTableContainer/styled.tsx | 6 +++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/index.tsx b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/index.tsx index c04bd9af66..50a50a44af 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/index.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/index.tsx @@ -286,6 +286,20 @@ export function OrderRow({ ) : ( <> {/* History tab columns */} + {/* Limit price */} + + + + + {/* Execution price */} {executedPriceInverted ? ( !isHistoryTab - ? `${isRowSelectable ? 'var(--checkboxSize)' : ''} minmax(200px,2.5fr) minmax(110px,1fr) minmax(70px,0.5fr) minmax(110px,1fr) minmax(110px,1fr) minmax(80px,90px) minmax(80px,0.8fr) 40px` + ? `${isRowSelectable ? 'var(--checkboxSize)' : ''} minmax(200px,2.5fr) minmax(110px,1fr) minmax(70px,0.5fr) minmax(110px,1fr) minmax(110px,1fr) minmax(80px,90px) minmax(80px,0.8fr) 24px` : `minmax(200px, 2.5fr) - repeat(3, minmax(110px, 1fr)) + repeat(4, minmax(110px, 1fr)) minmax(80px, 0.8fr) minmax(100px, 1fr) - 40px `}; + 24px `}; grid-template-rows: minmax(var(--height), 1fr); align-items: center; border: none; From 46955a3dff22bd4eda6ea35ea36fefa70cdc7787 Mon Sep 17 00:00:00 2001 From: fairlighteth <31534717+fairlighteth@users.noreply.github.com> Date: Tue, 10 Dec 2024 14:07:01 +0000 Subject: [PATCH 10/14] feat: correct execute soon tooltip --- .../OrderRow/EstimatedExecutionPrice.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/EstimatedExecutionPrice.tsx b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/EstimatedExecutionPrice.tsx index 8449637019..c463b38ba1 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/EstimatedExecutionPrice.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/EstimatedExecutionPrice.tsx @@ -110,7 +110,9 @@ export function EstimatedExecutionPrice(props: EstimatedExecutionPriceProps) { wrapInContainer={true} content={ - {!isNegativeDifference ? ( + {isNegativeDifference && Math.abs(Number(percentageDifferenceInverted?.toFixed(4) ?? 0)) <= 0.01 ? ( + <>Will execute soon! + ) : ( <> Market price needs to go {marketPriceNeedsToGoDown ? 'down 📉' : 'up 📈'} by  @@ -122,8 +124,6 @@ export function EstimatedExecutionPrice(props: EstimatedExecutionPriceProps) {  to execute your order. - ) : ( - <>Will execute soon! )} } From 3c87f040f97a0bda62f9a5e9a095736adb0b659c Mon Sep 17 00:00:00 2001 From: fairlighteth <31534717+fairlighteth@users.noreply.github.com> Date: Tue, 10 Dec 2024 17:09:35 +0000 Subject: [PATCH 11/14] feat: order table layout and warning indicator styling --- .../OrderRow/EstimatedExecutionPrice.tsx | 47 +++++++++++++++---- .../OrderRow/OrderWarning.tsx | 5 +- .../OrdersTableContainer/OrderRow/index.tsx | 43 +++++++---------- .../OrdersTableContainer/OrderRow/styled.tsx | 2 +- .../pure/OrdersTableContainer/styled.tsx | 10 ++-- .../OrdersTableContainer/tableHeaders.tsx | 7 ++- 6 files changed, 70 insertions(+), 44 deletions(-) diff --git a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/EstimatedExecutionPrice.tsx b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/EstimatedExecutionPrice.tsx index c463b38ba1..cda6d61cd5 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/EstimatedExecutionPrice.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/EstimatedExecutionPrice.tsx @@ -1,5 +1,6 @@ import AlertTriangle from '@cowprotocol/assets/cow-swap/alert.svg' import { ZERO_FRACTION } from '@cowprotocol/common-const' +import { Command } from '@cowprotocol/types' import { UI } from '@cowprotocol/ui' import { SymbolElement, TokenAmount, TokenAmountProps } from '@cowprotocol/ui' import { HoverTooltip } from '@cowprotocol/ui' @@ -45,6 +46,27 @@ const UnfillableLabel = styled.span` font-size: inherit; font-weight: 500; line-height: 1.1; + flex-flow: row wrap; + align-items: center; + justify-content: flex-start; + gap: 3px; +` + +const ApprovalLink = styled.button` + background: none; + border: none; + padding: 0; + margin: 0; + cursor: pointer; + font-size: inherit; + color: inherit; + text-decoration: underline; + color: var(${UI.COLOR_PRIMARY}); + font-weight: 500; + + &:hover { + opacity: 1; + } ` export type EstimatedExecutionPriceProps = TokenAmountProps & { @@ -56,11 +78,14 @@ export type EstimatedExecutionPriceProps = TokenAmountProps & { percentageFee?: Percent amountFee?: CurrencyAmount warningText?: string - WarningTooltip?: React.FC<{ children: React.ReactNode }> + WarningTooltip?: React.FC<{ children: React.ReactNode; showIcon: boolean }> + onApprove?: Command } export function EstimatedExecutionPrice(props: EstimatedExecutionPriceProps) { const { + amount, + tokenSymbol, isInverted, isUnfillable, canShowWarning, @@ -68,9 +93,9 @@ export function EstimatedExecutionPrice(props: EstimatedExecutionPriceProps) { amountDifference, percentageFee, amountFee, - amount, warningText, WarningTooltip, + onApprove, ...rest } = props @@ -89,20 +114,24 @@ export function EstimatedExecutionPrice(props: EstimatedExecutionPriceProps) { const content = ( <> - + ) - const unfillableLabel = {warningText || 'UNFILLABLE'} + const unfillableLabel = ( + + {warningText} + {warningText === 'Insufficient allowance' && onApprove && ( + Set approval + )} + {WarningTooltip && {null}} + + ) return ( {isUnfillable ? ( - WarningTooltip ? ( - {unfillableLabel} - ) : ( - unfillableLabel - ) +
{unfillableLabel}
) : !absoluteDifferenceAmount ? ( {content} ) : ( diff --git a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/OrderWarning.tsx b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/OrderWarning.tsx index 433f1abdbf..bcdef8dc5f 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/OrderWarning.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/OrderWarning.tsx @@ -79,7 +79,7 @@ function AllowanceWarning({ symbol, isScheduled, approve }: AllowanceWarningProp )}

- Approve + Set allowance ) @@ -106,7 +106,8 @@ export function WarningTooltip({ onApprove, showIcon = false, }: WarningTooltipProps) { - const withAllowanceWarning = hasEnoughAllowance === false && hasValidPendingPermit === false + const withAllowanceWarning = + hasEnoughAllowance === false && (hasValidPendingPermit === false || hasValidPendingPermit === undefined) const tooltipContent = ( diff --git a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/index.tsx b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/index.tsx index 50a50a44af..f9d97f77b9 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/index.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/index.tsx @@ -164,6 +164,19 @@ export function OrderRow({ return 'Unfillable' } + const renderWarningTooltip = (showIcon?: boolean) => (props: { children: React.ReactNode }) => ( + orderActions.approveOrderToken(order.inputToken)} + showIcon={showIcon} + {...props} + /> + ) + return ( {/*Checkbox for multiple cancellation*/} @@ -230,17 +243,8 @@ export function OrderRow({ canShowWarning={getUiOrderType(order) !== UiOrderType.SWAP && !isUnfillable} isUnfillable={withWarning} warningText={getWarningText()} - WarningTooltip={(props) => ( - orderActions.approveOrderToken(order.inputToken)} - {...props} - /> - )} + onApprove={() => orderActions.approveOrderToken(order.inputToken)} + WarningTooltip={renderWarningTooltip()} /> )} @@ -337,22 +341,7 @@ export function OrderRow({ order={order} withWarning={withWarning} onClick={onClick} - WarningTooltip={ - withWarning - ? (props) => ( - orderActions.approveOrderToken(order.inputToken)} - showIcon={true} - {...props} - /> - ) - : undefined - } + WarningTooltip={withWarning ? renderWarningTooltip(true) : undefined} />
diff --git a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/styled.tsx b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/styled.tsx index 231c719c19..5e5be94741 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/styled.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/styled.tsx @@ -210,7 +210,7 @@ export const ProgressBar = styled.div<{ value: string }>` export const FilledPercentageContainer = styled.div` display: grid; - grid-template-columns: minmax(50px, auto) auto; + grid-template-columns: 50px 36px; gap: 4px; align-items: center; width: 100%; diff --git a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/styled.tsx b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/styled.tsx index 85c9761f02..3d26af0759 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/styled.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/styled.tsx @@ -6,23 +6,24 @@ import styled from 'styled-components/macro' import { RateWrapper } from 'common/pure/RateInfo' export const TableHeader = styled.div<{ isHistoryTab: boolean; isRowSelectable: boolean }>` - --height: 51px; + --header-height: 26px; + --row-height: 41px; --checkboxSize: 16px; --checkBoxBorderRadius: 3px; display: grid; gap: 14px; grid-template-columns: ${({ isHistoryTab, isRowSelectable }) => !isHistoryTab - ? `${isRowSelectable ? 'var(--checkboxSize)' : ''} minmax(200px,2.5fr) minmax(110px,1fr) minmax(70px,0.5fr) minmax(110px,1fr) minmax(110px,1fr) minmax(80px,90px) minmax(80px,0.8fr) 24px` + ? `${isRowSelectable ? 'var(--checkboxSize)' : ''} minmax(200px,2.5fr) minmax(140px,1fr) minmax(70px,0.5fr) minmax(110px,1fr) minmax(110px,1fr) minmax(80px,90px) minmax(80px,0.8fr) 24px` : `minmax(200px, 2.5fr) repeat(4, minmax(110px, 1fr)) minmax(80px, 0.8fr) minmax(100px, 1fr) 24px `}; - grid-template-rows: minmax(var(--height), 1fr); + grid-template-rows: minmax(var(--header-height), 1fr); align-items: center; border: none; - padding: 0 12px; + padding: 5px 12px; background: var(${UI.COLOR_PAPER_DARKER}); border-top: none; border-right: none; @@ -37,6 +38,7 @@ export const TableHeader = styled.div<{ isHistoryTab: boolean; isRowSelectable: ` export const TableRow = styled(TableHeader)<{ isChildOrder?: boolean }>` + grid-template-rows: minmax(var(--row-height), 1fr); background: ${({ isChildOrder }) => (isChildOrder ? `var(${UI.COLOR_PAPER_DARKER})` : 'transparent')}; transition: background var(${UI.ANIMATION_DURATION}) ease-in-out; display: grid; diff --git a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/tableHeaders.tsx b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/tableHeaders.tsx index 68c670c151..bc238ad724 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/tableHeaders.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/tableHeaders.tsx @@ -66,7 +66,12 @@ export const createTableHeaders = ( }, { id: 'distanceToMarket', - content: Distance to market, + content: ( + + Distance
+ to market +
+ ), showInHistory: false, }, { From 0657687ec9a82b949c22ffe11feafec8e9242147 Mon Sep 17 00:00:00 2001 From: fairlighteth <31534717+fairlighteth@users.noreply.github.com> Date: Tue, 10 Dec 2024 17:40:59 +0000 Subject: [PATCH 12/14] feat: modify table layout --- .../pure/OrdersTableContainer/styled.tsx | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/styled.tsx b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/styled.tsx index 3d26af0759..2217520404 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/styled.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/styled.tsx @@ -5,6 +5,18 @@ import styled from 'styled-components/macro' import { RateWrapper } from 'common/pure/RateInfo' +export const TableWrapper = styled.div` + width: 100%; + overflow-x: auto; + -webkit-overflow-scrolling: touch; /* Smooth scrolling on iOS */ + + ${Media.upToSmall()} { + margin: 0 -12px; /* Negative margin to allow full-width scrolling */ + padding: 0 12px; + width: calc(100% + 24px); + } +` + export const TableHeader = styled.div<{ isHistoryTab: boolean; isRowSelectable: boolean }>` --header-height: 26px; --row-height: 41px; @@ -14,12 +26,13 @@ export const TableHeader = styled.div<{ isHistoryTab: boolean; isRowSelectable: gap: 14px; grid-template-columns: ${({ isHistoryTab, isRowSelectable }) => !isHistoryTab - ? `${isRowSelectable ? 'var(--checkboxSize)' : ''} minmax(200px,2.5fr) minmax(140px,1fr) minmax(70px,0.5fr) minmax(110px,1fr) minmax(110px,1fr) minmax(80px,90px) minmax(80px,0.8fr) 24px` + ? `${isRowSelectable ? 'var(--checkboxSize)' : ''} + minmax(200px,2.5fr) minmax(140px,1fr) minmax(70px,0.5fr) minmax(110px,1fr) minmax(110px,1fr) minmax(80px,90px) minmax(80px,0.8fr) 24px` : `minmax(200px, 2.5fr) repeat(4, minmax(110px, 1fr)) minmax(80px, 0.8fr) minmax(100px, 1fr) - 24px `}; + 24px `}; grid-template-rows: minmax(var(--header-height), 1fr); align-items: center; border: none; @@ -30,6 +43,7 @@ export const TableHeader = styled.div<{ isHistoryTab: boolean; isRowSelectable: border-left: none; border-image: initial; border-bottom: 1px solid var(--cow-color-text-opacity-10); + min-width: 888px; /* Minimum width to prevent too much squeezing */ ${Media.upToSmall()} { --checkboxSize: 24px; From 544da0cda6c82f73a60d75fe1d7a34cd883823c7 Mon Sep 17 00:00:00 2001 From: fairlighteth <31534717+fairlighteth@users.noreply.github.com> Date: Tue, 10 Dec 2024 17:55:40 +0000 Subject: [PATCH 13/14] feat: improve token search --- .../containers/OrdersTableWidget/index.tsx | 19 ++++++++++++++++++- .../OrderRow/OrderWarning.tsx | 2 +- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/apps/cowswap-frontend/src/modules/ordersTable/containers/OrdersTableWidget/index.tsx b/apps/cowswap-frontend/src/modules/ordersTable/containers/OrdersTableWidget/index.tsx index 22b5c43cdb..264af3f262 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/containers/OrdersTableWidget/index.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/containers/OrdersTableWidget/index.tsx @@ -211,12 +211,29 @@ export function OrdersTableWidget({ const searchTermLower = searchTerm.toLowerCase().trim() + // First try exact symbol matches (case-insensitive) + const exactMatches = orders.filter((order) => { + const parsedOrder = getParsedOrderFromTableItem(order) + const inputToken = parsedOrder.inputToken + const outputToken = parsedOrder.outputToken + + return [inputToken.symbol, outputToken.symbol].some((symbol) => { + return symbol?.toLowerCase() === searchTermLower + }) + }) + + // If we have exact matches, return those + if (exactMatches.length > 0) { + return exactMatches + } + + // Otherwise, fall back to partial matches and address search return orders.filter((order) => { const parsedOrder = getParsedOrderFromTableItem(order) const inputToken = parsedOrder.inputToken const outputToken = parsedOrder.outputToken - // First check for token symbols (case-insensitive) + // Check for partial symbol matches (case-insensitive) const symbolMatch = [inputToken.symbol, outputToken.symbol].some((symbol) => { return symbol?.toLowerCase().includes(searchTermLower) }) diff --git a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/OrderWarning.tsx b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/OrderWarning.tsx index bcdef8dc5f..a182904498 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/OrderWarning.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/OrderRow/OrderWarning.tsx @@ -79,7 +79,7 @@ function AllowanceWarning({ symbol, isScheduled, approve }: AllowanceWarningProp )}

- Set allowance + Set approval ) From ceea64f45fc3faf849c001b2a23e64ae8e0097bb Mon Sep 17 00:00:00 2001 From: fairlighteth <31534717+fairlighteth@users.noreply.github.com> Date: Tue, 10 Dec 2024 22:42:17 +0000 Subject: [PATCH 14/14] feat: restore table layout element --- .../ordersTable/pure/OrdersTableContainer/styled.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/styled.tsx b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/styled.tsx index 2217520404..d51e2fa1d1 100644 --- a/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/styled.tsx +++ b/apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/styled.tsx @@ -62,16 +62,20 @@ export const TableRow = styled(TableHeader)<{ isChildOrder?: boolean }>` } > div:first-child { - margin: 0; + margin-left: ${({ isChildOrder }) => (isChildOrder ? '5px' : '')}; &::before { display: ${({ isChildOrder }) => (isChildOrder ? 'inline-block' : 'none')}; - color: ${({ theme }) => transparentize(theme.text, 0.5)}; + color: ${({ theme }) => transparentize(theme.info, 0.6)}; content: '↳'; text-decoration: none !important; } } + &:last-child { + border-bottom: 0; + } + ${RateWrapper} { text-align: left; }