Compare commits

...
Author SHA1 Message Date
maciek e2e2b8c455 Merge remote-tracking branch 'origin/main' into chore/4792-aggrid-autosize-selected-columns-main 2023-09-28 08:24:06 +02:00
Radosław Szpiech 7ac3a68ac9 chore(trading): add possibility to manualy trigger console-test (#4899) 2023-09-27 15:18:32 +02:00
Radosław Szpiech 2640ccb20a chore(trading): change runner for mainnet compatible vega version (#4907) 2023-09-27 14:42:12 +02:00
Maciek d78de10855 chore(trading): remove underlines on tooltips (#4884) 2023-09-26 13:45:33 -04:00
Matthew Russell bb402c02f6 chore(trading): make volume bars color match candle color (#4881) 2023-09-26 12:08:12 -04:00
Bartłomiej Głownia 8a9b1c7874 feat(deal-ticket): amend fee estimates for postOnly orders and when market is in auction (#4843) 2023-09-26 11:57:47 -04:00
Matthew Russell a7e8b0eb01 fix(market-depth): ensure scroll bar doesn't show on orderbook (#4882) 2023-09-26 11:54:42 -04:00
Bartłomiej Głownia 89b3c06107 feat(deal-ticket): show worst case instead of ranges in estimated values (#4870) 2023-09-26 11:53:45 -04:00
maciek 54430b7d64 chore: add handle of autosizing selected columns - add also on positions table 2023-09-26 15:43:02 +02:00
maciek 9a21bad81f Merge remote-tracking branch 'origin/main' into chore/4792-aggrid-autosize-selected-columns-main 2023-09-26 12:06:35 +02:00
Radosław Szpiech cd5c73d3fd chore(trading): temporary disable console-test to unblock CI queue (#4885) 2023-09-26 10:45:27 +01:00
maciek 917e5c2773 chore: add handle of autosizing selected columns - fix failing cypress tests 2023-09-26 11:45:09 +02:00
Joe Tsang b3a5ab022d chore(ci): update genesis file (#4887) 2023-09-26 10:44:55 +01:00
maciek 192dd749cc chore: add handle of autosizing selected columns - add unit test 2023-09-26 11:44:18 +02:00
maciek 5aa3f238a9 chore: add handle of autosizing selected columns 2023-09-26 11:37:31 +02:00
Mikołaj Młodzikowski 496d1f5c68 feat(ci): parse if there are any changes 2023-09-25 18:10:01 -04:00
Mikołaj Młodzikowski e914e7bb70 fix(ci): provide proper ipfs process 2023-09-25 18:09:31 -04:00
Matthew Russell 71a36c2382 fix(trading): remove upgrade banner [main] (#4877) 2023-09-25 17:27:01 -04:00
Matthew Russell 1c6a307bcd fix(wallet): reduce time to check for wallet running [main] (#4876) 2023-09-25 17:26:40 -04:00
Matthew Russell ef4a740b91 fix(trading): allotment breaking [main] (#4875) 2023-09-25 17:26:06 -04:00
Sam Keen 2d4be5fcb3 fix(governance): mainnet rewards query looping (#4865) 2023-09-25 09:59:38 +00:00
m.rayandMatthew Russell 835f2b793f chore(trading): remove static assets console coming from vega.xyz (#4825)
Co-authored-by: Matthew Russell <mattrussell36@gmail.com>
2023-09-19 23:54:07 -07:00
69 changed files with 474 additions and 350 deletions
+8 -8
View File
@@ -175,14 +175,14 @@ jobs:
preview_explorer: ${{ env.PREVIEW_EXPLORER }}
preview_tools: ${{ env.PREVIEW_TOOLS }}
console-e2e:
needs: build-sources
name: '(CI) console python'
uses: ./.github/workflows/console-test-run.yml
secrets: inherit
if: ${{ contains(fromJSON(needs.build-sources.outputs.projects), 'trading') && github.event_name == 'pull_request' }}
with:
github-sha: ${{ github.event.pull_request.head.sha || github.sha }}
# console-e2e:
# needs: build-sources
# name: '(CI) console python'
# uses: ./.github/workflows/console-test-run.yml
# secrets: inherit
# if: ${{ contains(fromJSON(needs.build-sources.outputs.projects), 'trading') && github.event_name == 'pull_request' }}
# with:
# github-sha: ${{ github.event.pull_request.head.sha || github.sha }}
cypress:
needs: build-sources
+35 -7
View File
@@ -6,20 +6,28 @@ on:
github-sha:
required: true
type: string
workflow_dispatch:
inputs:
console-test-branch:
type: choice
description: 'main: v0.72.14, develop: v0.73.0-preview7'
options:
- main
- develop
jobs:
run-tests:
name: run-tests
runs-on: console-test
runs-on: 8-cores
timeout-minutes: 20
steps:
#----------------------------------------------
# check-out frontend-monorepo
#----------------------------------------------
- name: Checkout console test repo
- name: Checkout frontend-monorepo
uses: actions/checkout@v3
with:
ref: ${{ inputs.github-sha }}
ref: ${{ inputs.github-sha || github.sha }}
#----------------------------------------------
# cache node modules
#----------------------------------------------
@@ -65,32 +73,42 @@ jobs:
uses: actions/checkout@v3
with:
repository: vegaprotocol/console-test
ref: ${{ inputs.console-test-branch }}
path: './console-test'
- name: Load console test envs
id: console-test-env
uses: falti/dotenv-action@v1.0.4
with:
path: './console-test/.env.${{ inputs.console-test-branch }}'
export-variables: true
keys-case: upper
log-variables: true
#----------------------------------------------
# install dependencies if cache does not exist
#----------------------------------------------
- name: Install dependencies
working-directory: ./console-test
if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true'
run: poetry install --no-interaction --no-root
#----------------------------------------------
# install vega binaries
#----------------------------------------------
- name: Install vega binaries
working-directory: ./console-test
run: poetry run python -m vega_sim.tools.load_binaries --force
run: poetry run python -m vega_sim.tools.load_binaries --force --version ${{ env.VEGA_VERSION }}
#----------------------------------------------
# install playwright
#----------------------------------------------
- name: install playwright
run: poetry run playwright install
run: poetry run playwright install --with-deps chromium
working-directory: ./console-test
#----------------------------------------------
# run tests
#----------------------------------------------
- name: Run tests
working-directory: ./console-test
run: poetry run pytest -v -s --numprocesses 2 --dist loadfile --durations=20
run: poetry run pytest -v -s --numprocesses 4 --dist loadfile --durations=15
- name: Check files
run: |
ls -al .
@@ -105,3 +123,13 @@ jobs:
name: playwright-trace
path: ./traces/
retention-days: 15
#----------------------------------------------
# ----- upload logs -----
#----------------------------------------------
- name: Upload worker logs
uses: actions/upload-artifact@v3
if: always()
with:
name: worker-logs
path: ./logs/
retention-days: 15
+1 -1
View File
@@ -19,7 +19,7 @@ jobs:
matrix:
project: ${{ fromJSON(inputs.projects) }}
name: ${{ matrix.project }}
runs-on: self-hosted-runner
runs-on: mainnet-compatible-runner
timeout-minutes: 120
steps:
# Checks if skip cache was requested
+8 -6
View File
@@ -155,10 +155,10 @@ jobs:
- name: Sanity check docker image
run: |
echo "Check ipfs-hash"
docker run --rm --entrypoint /bin/sh ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local -c 'cat /ipfs-hash'
docker run --rm --entrypoint /bin/sh ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local -c 'cat /ipfs-hash' > ${{ matrix.app }}-ipfs-hash
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local /bin/sh -c 'cat /ipfs-hash'
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local /bin/sh -c 'cat /ipfs-hash' > ${{ matrix.app }}-ipfs-hash
echo "List html directory"
docker run --rm --entrypoint /bin/sh ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local -c 'apk add --update tree; tree /usr/share/nginx/html'
docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local /bin/sh -c 'apk add --update tree; tree /usr/share/nginx/html'
- name: Publish dist as docker image (ghcr)
uses: docker/build-push-action@v3
@@ -329,7 +329,9 @@ jobs:
fi
# create commit
commit_msg="Automated hash update from ${{ github.ref }}"
git commit -m "$commit_msg"
git push -u origin "main"
if ! git diff --cached --exit-code; then
commit_msg="Automated hash update from ${{ github.ref }}"
git commit -m "$commit_msg"
git push -u origin "main"
fi
)
+1 -1
View File
@@ -118,7 +118,7 @@ On top of that there are two possible scenarios for running docker image - using
to run ipfs on port 3000:
```bash
docker run -p 3000:80 [TAG] ipfs
docker run -p 3000:80 [TAG] /run-ipfs.sh
```
to run nginx on port 3000:
@@ -4,7 +4,7 @@ import { AssetTypeMapping, AssetStatusMapping } from '@vegaprotocol/assets';
import { t } from '@vegaprotocol/i18n';
import { ButtonLink } from '@vegaprotocol/ui-toolkit';
import type { AgGridReact } from 'ag-grid-react';
import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid';
import { AgGrid } from '@vegaprotocol/datagrid';
import type { VegaICellRendererParams } from '@vegaprotocol/datagrid';
import { useRef, useLayoutEffect } from 'react';
import { BREAKPOINT_MD } from '../../config/breakpoints';
@@ -4,7 +4,7 @@ import { t } from '@vegaprotocol/i18n';
import { ButtonLink } from '@vegaprotocol/ui-toolkit';
import type { AgGridReact } from 'ag-grid-react';
import type { ColDef } from 'ag-grid-community';
import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid';
import { AgGrid } from '@vegaprotocol/datagrid';
import type {
VegaICellRendererParams,
VegaValueGetterParams,
@@ -2,7 +2,7 @@ import type { ProposalListFieldsFragment } from '@vegaprotocol/proposals';
import { VoteProgress } from '@vegaprotocol/proposals';
import type { AgGridReact } from 'ag-grid-react';
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid';
import { AgGrid } from '@vegaprotocol/datagrid';
import type {
VegaICellRendererParams,
VegaValueFormatterParams,
@@ -105,7 +105,7 @@ export const ProposalsTable = ({ data }: ProposalsTableProps) => {
? new BigNumber(0)
: yesTokens.multipliedBy(100).dividedBy(totalTokensVoted);
return (
<div className="uppercase flex h-full items-center justify-center pt-2">
<div className="flex items-center justify-center h-full pt-2 uppercase">
<VoteProgress
threshold={requiredMajorityPercentage}
progress={yesPercentage}
@@ -1,4 +1,4 @@
import { useMemo, useEffect, useState, useCallback } from 'react';
import { useMemo, useEffect, useState, useCallback, useRef } from 'react';
import { useTranslation } from 'react-i18next';
import { AsyncRenderer, Pagination } from '@vegaprotocol/ui-toolkit';
import { removePaginationWrapper } from '@vegaprotocol/utils';
@@ -86,12 +86,18 @@ export const EpochIndividualRewards = ({
[epochId, page, refetch, delegationsPagination, pubKey]
);
const prevEpochIdRef = useRef<number | null>(null);
useEffect(() => {
// when the epoch changes, we want to refetch the data to update the current page
if (data) {
if (prevEpochIdRef.current === null) {
prevEpochIdRef.current = epochId;
} else if (epochId !== prevEpochIdRef.current) {
// When the epoch changes, we want to refetch the data to update the current page
refetchData();
}
}, [epochId, data, refetchData]);
prevEpochIdRef.current = epochId;
}, [epochId, refetchData]);
return (
<AsyncRenderer
@@ -3,7 +3,7 @@ import { forwardRef, useMemo, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useNavigate } from 'react-router-dom';
import { Button, Icon } from '@vegaprotocol/ui-toolkit';
import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid';
import { AgGrid } from '@vegaprotocol/datagrid';
import { useAppState } from '../../../../contexts/app-state/app-state-context';
import { BigNumber } from '../../../../lib/bignumber';
import {
@@ -85,17 +85,17 @@ const TopThirdCellRenderer = (
}}
className="grid grid-cols-[60px_1fr] w-full h-full py-4 px-0 text-sm text-white text-center overflow-scroll"
>
<div className="text-xs text-left px-3">
<div className="px-3 text-xs text-left">
{params?.data?.rankingDisplay}
</div>
<div className="whitespace-normal px-3">
<div className="px-3 whitespace-normal">
<div className="mb-4">
<Button
data-testid="show-all-validators"
rightIcon={
<Icon
name="arrow-right"
className="fill-current mr-2 align-text-top"
className="mr-2 align-text-top fill-current"
/>
}
className="inline-flex items-center"
@@ -103,7 +103,7 @@ const TopThirdCellRenderer = (
{t('Reveal top validators')}
</Button>
</div>
<p className="font-semibold text-white mb-0">
<p className="mb-0 font-semibold text-white">
{t(
'Validators with too great a stake share will have the staking rewards for their delegators penalised.'
)}
@@ -1,7 +1,7 @@
import { forwardRef, useMemo, useRef } from 'react';
import { useTranslation } from 'react-i18next';
import { useNavigate } from 'react-router-dom';
import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid';
import { AgGrid } from '@vegaprotocol/datagrid';
import { useAppState } from '../../../../contexts/app-state/app-state-context';
import { BigNumber } from '../../../../lib/bignumber';
import {
@@ -24,9 +24,7 @@ describe('deal ticker order validation', { tags: '@smoke' }, () => {
beforeEach(() => {
cy.mockTradingPage();
cy.getByTestId('deal-ticket-fee-margin-required').within(() => {
cy.get('button').click();
});
cy.getByTestId('deal-ticket-fee-margin-required').click();
});
describe('limit order', () => {
@@ -111,6 +109,7 @@ describe('deal ticker order validation', { tags: '@smoke' }, () => {
'Total margin available100.01 tDAI'
);
});
cy.getByTestId('deal-ticket-fee-margin-required').click();
});
it('must have current margin allocation', () => {
@@ -120,6 +119,7 @@ describe('deal ticker order validation', { tags: '@smoke' }, () => {
'Current margin allocation'
);
});
cy.getByTestId('deal-ticket-fee-margin-required').click();
});
it('should open usage breakdown dialog when clicked on current margin allocation', () => {
@@ -128,6 +128,7 @@ describe('deal ticker order validation', { tags: '@smoke' }, () => {
});
cy.getByTestId('usage-breakdown').should('exist');
cy.getByTestId('dialog-close').click();
cy.getByTestId('deal-ticket-fee-margin-required').click();
});
});
});
@@ -9,7 +9,7 @@ import {
testOrderAmendment,
} from '../support/order-validation';
const orderSymbol = 'market.tradableInstrument.instrument.code';
const orderSymbol = 'instrument-code';
const orderSize = 'size';
const orderType = 'type';
const orderStatus = 'status';
@@ -229,10 +229,7 @@ describe('subscribe orders', { tags: '@smoke' }, () => {
status: Schema.OrderStatus.STATUS_FILLED,
});
cy.getByTestId(`order-status-${orderId}`).should('have.text', 'Filled');
cy.get('[col-id="market.tradableInstrument.instrument.code"]').contains(
'[title="Future"]',
'Futr'
);
cy.get(`[col-id="${orderSymbol}"]`).contains('[title="Future"]', 'Futr');
});
it('must see a rejected order', () => {
@@ -86,8 +86,8 @@ describe('trades', { tags: '@smoke' }, () => {
});
it('copy price to deal ticket form', () => {
cy.getByTestId('Order').click();
// 6005-THIS-007
cy.getByTestId('order-type-Limit').click();
cy.get(colIdPrice).last().should('be.visible').click();
cy.getByTestId('order-price').should('have.value', '171.16898');
});
-4
View File
@@ -17,10 +17,6 @@ NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-ma
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-mainnet
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
# TAG name of the current app version - TODO: bump to the latest upon release
NX_APP_VERSION=v0.21.2-core-0.72.14
# Cosmic elevator flags
NX_SUCCESSOR_MARKETS=true
NX_STOP_ORDERS=true
+1 -1
View File
@@ -4,7 +4,7 @@ import type {
VegaICellRendererParams,
VegaValueFormatterParams,
} from '@vegaprotocol/datagrid';
import { AgGridLazy as AgGrid, COL_DEFS } from '@vegaprotocol/datagrid';
import { AgGrid, COL_DEFS } from '@vegaprotocol/datagrid';
import { useMemo } from 'react';
import { t } from '@vegaprotocol/i18n';
import type { ProductType } from '@vegaprotocol/types';
@@ -1,5 +1,5 @@
import type { TypedDataAgGrid } from '@vegaprotocol/datagrid';
import { AgGridLazy as AgGrid, PriceFlashCell } from '@vegaprotocol/datagrid';
import { AgGrid, PriceFlashCell } from '@vegaprotocol/datagrid';
import type { MarketMaybeWithData } from '@vegaprotocol/markets';
import { useColumnDefs } from './use-column-defs';
@@ -9,5 +9,11 @@ export const AnnouncementBanner = () => {
return null;
}
return <Banner app="console" configUrl={ANNOUNCEMENTS_CONFIG_URL} />;
return (
<Banner
app="console"
configUrl={ANNOUNCEMENTS_CONFIG_URL}
background="url('/banner-bg.jpg')"
/>
);
};
-1
View File
@@ -1,2 +1 @@
export * from './announcement-banner';
export * from './upgrade-banner';
@@ -1,84 +0,0 @@
import { useMemo, useState } from 'react';
import { gt, prerelease } from 'semver';
import {
ReleasesFeed,
useEnvironment,
useReleases,
Networks,
} from '@vegaprotocol/environment';
import { t } from '@vegaprotocol/i18n';
import {
CopyWithTooltip,
ExternalLink,
Intent,
NotificationBanner,
VegaIcon,
VegaIconNames,
} from '@vegaprotocol/ui-toolkit';
// v0.20.12-core-0.71.4 -> v0.20.12
// we need to strip the "core" suffix in order to determine whether a release
// is a pre-release (candidate); example: v.0.21.0-beta.1-core-0.71.4
const parseTagName = (tagName: string) => tagName.replace(/-core-[\d.]+$/i, '');
type UpgradeBannerProps = {
showVersionChange: boolean;
};
export const UpgradeBanner = ({ showVersionChange }: UpgradeBannerProps) => {
const [visible, setVisible] = useState(true);
const { data } = useReleases(ReleasesFeed.FrontEnd);
const { APP_VERSION, VEGA_ENV, VEGA_NETWORKS } = useEnvironment();
const CANONICAL_URL = VEGA_NETWORKS[VEGA_ENV] || 'https://console.vega.xyz';
const newest = useMemo(() => {
if (!APP_VERSION || !data) return undefined;
const newer = data.filter((r) => gt(r.tagName, APP_VERSION));
const valid =
// filter pre-releases on mainnet
VEGA_ENV === Networks.MAINNET
? newer?.filter((r) => !prerelease(parseTagName(r.tagName)))
: newer;
return valid.sort((a, b) => (gt(a.tagName, b.tagName) ? -1 : 1))[0];
}, [APP_VERSION, VEGA_ENV, data]);
if (!visible || !newest) {
return null;
}
return (
<NotificationBanner
intent={Intent.Warning}
onClose={() => {
setVisible(false);
}}
>
<div className="uppercase mb-1">
<ExternalLink href={CANONICAL_URL}>
{t('Upgrade to the latest version of Console')}
</ExternalLink>
</div>
<div data-testid="bookmark-message">
<a
className="underline"
href={newest.htmlUrl}
rel="noreferrer nofollow noopener"
target="_blank"
>
{t("View what's changed")}
</a>{' '}
{t(' or bookmark')}{' '}
<a className="underline" href={CANONICAL_URL}>
{t('console.vega.xyz')}
</a>{' '}
<CopyWithTooltip text={CANONICAL_URL}>
<button title={t('Copy %s', CANONICAL_URL)}>
<span className="sr-only">{t('Copy %s', CANONICAL_URL)}</span>
<VegaIcon size={14} name={VegaIconNames.COPY} />
</button>
</CopyWithTooltip>{' '}
{'to always see the latest version.'}
</div>
</NotificationBanner>
);
};
+1 -1
View File
@@ -53,7 +53,7 @@ export const HeaderStat = ({
<div data-testid="item-header" id={id}>
{heading}
</div>
<Tooltip description={description}>
<Tooltip description={description} underline>
<div
data-testid="item-value"
aria-labelledby={id}
@@ -28,14 +28,20 @@ export interface OrderContainerProps {
filter?: Filter;
}
const AUTO_SIZE_COLUMNS = ['instrument-code'];
export const OrdersContainer = ({ filter }: OrderContainerProps) => {
const { pubKey, isReadOnly } = useVegaWallet();
const onMarketClick = useMarketClickHandler(true);
const onOrderTypeClick = useMarketLiquidityClickHandler();
const { gridState, updateGridState } = useOrderListGridState(filter);
const gridStoreCallbacks = useDataGridEvents(gridState, (newState) => {
updateGridState(filter, newState);
});
const gridStoreCallbacks = useDataGridEvents(
gridState,
(newState) => {
updateGridState(filter, newState);
},
AUTO_SIZE_COLUMNS
);
if (!pubKey) {
return <Splash>{t('Please connect Vega wallet')}</Splash>;
@@ -10,6 +10,8 @@ import { create } from 'zustand';
import { persist } from 'zustand/middleware';
import { useMarketClickHandler } from '../../lib/hooks/use-market-click-handler';
const AUTO_SIZE_COLUMNS = ['marketCode'];
export const PositionsContainer = ({ allKeys }: { allKeys?: boolean }) => {
const onMarketClick = useMarketClickHandler(true);
const { pubKey, pubKeys, isReadOnly } = useVegaWallet();
@@ -17,7 +19,11 @@ export const PositionsContainer = ({ allKeys }: { allKeys?: boolean }) => {
const showClosed = usePositionsStore((store) => store.showClosedMarkets);
const gridStore = usePositionsStore((store) => store.gridStore);
const updateGridStore = usePositionsStore((store) => store.updateGridStore);
const gridStoreCallbacks = useDataGridEvents(gridStore, updateGridStore);
const gridStoreCallbacks = useDataGridEvents(
gridStore,
updateGridStore,
AUTO_SIZE_COLUMNS
);
if (!pubKey) {
return (
+1 -2
View File
@@ -38,7 +38,7 @@ import { AppLoader, DynamicLoader } from '../components/app-loader';
import { useDataProvider } from '@vegaprotocol/data-provider';
import { activeOrdersProvider } from '@vegaprotocol/orders';
import { useTelemetryApproval } from '../lib/hooks/use-telemetry-approval';
import { AnnouncementBanner, UpgradeBanner } from '../components/banner';
import { AnnouncementBanner } from '../components/banner';
import { Navbar } from '../components/navbar';
import classNames from 'classnames';
import {
@@ -115,7 +115,6 @@ function AppBody({ Component }: AppProps) {
/>
<ProtocolUpgradeInProgressNotification />
<ViewingBanner />
<UpgradeBanner showVersionChange={true} />
</div>
<div data-testid={`pathname-${location.pathname}`}>
<Component />
+8 -17
View File
@@ -4,33 +4,24 @@ export default function Document() {
return (
<>
<Head>
{/*
{/*
meta tags
- next advised against using _document for this, so they exist in our
- next advised against using _document for this, so they exist in our
- single page index.page.tsx
*/}
{/* icons */}
<link
rel="icon"
type="image/x-icon"
href="https://static.vega.xyz/favicon.ico"
/>
<link
rel="apple-touch-icon"
content="https://static.vega.xyz/favicon.ico"
/>
{/* fonts */}
{/* preload fonts */}
<link
rel="preload"
href="https://static.vega.xyz/AlphaLyrae-Medium.woff2"
href="/AlphaLyrae-Medium.woff2"
as="font"
type="font/woff2"
/>
{/* styles */}
<link rel="stylesheet" href="https://static.vega.xyz/fonts.css" />
{/* icons */}
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
<link rel="apple-touch-icon" content="/favicon.ico" />
{/* eslint-disable-next-line @next/next/no-css-tags */}
<link rel="stylesheet" href="/preloader.css" media="all" />
+3 -9
View File
@@ -19,17 +19,11 @@ export default function Index() {
<meta name="og:url" content="https://console.vega.xyz/" />
<meta name="og:title" content="Vega Protocol - Console" />
<meta name="og:site_name" content="Vega Protocol - Console" />
<meta name="og:image" content="https://static.vega.xyz/favicon.ico" />
<meta
name="twitter:card"
content="https://static.vega.xyz/favicon.ico"
/>
<meta name="og:image" content="./favicon.ico" />
<meta name="twitter:card" content="./favicon.ico" />
<meta name="twitter:title" content="Vega Protocol - Console" />
<meta name="twitter:description" content="Vega Protocol - Console" />
<meta
name="twitter:image"
content="https://static.vega.xyz/favicon.ico"
/>
<meta name="twitter:image" content="./favicon.ico" />
<meta name="twitter:image:alt" content="VEGA logo" />
<meta name="twitter:site" content="@vegaprotocol" />
</Head>
+10 -3
View File
@@ -1,6 +1,13 @@
@import 'ag-grid-community/styles/ag-grid.css';
@import 'ag-grid-community/styles/ag-theme-balham.css';
/** Load AlphaLyrae font */
@font-face {
font-family: AlphaLyrae;
src: url('/AlphaLyrae-Medium.woff2') format('woff2'),
url('/AlphaLyrae-Medium.woff') format('woff');
}
@tailwind base;
@tailwind components;
@tailwind utilities;
@@ -103,8 +110,8 @@ html [data-theme='light'] {
--pennant-color-depth-sell-fill: theme(colors.market.red.DEFAULT);
--pennant-color-depth-sell-stroke: theme(colors.market.red.650);
--pennant-color-volume-buy: theme(colors.market.green.300);
--pennant-color-volume-sell: theme(colors.market.red.300);
--pennant-color-volume-buy: theme(colors.market.green.DEFAULT);
--pennant-color-volume-sell: theme(colors.market.red.DEFAULT);
}
html [data-theme='dark'] {
@@ -125,7 +132,7 @@ html [data-theme='dark'] {
--pennant-color-depth-sell-stroke: theme(colors.market.red.DEFAULT);
--pennant-color-volume-buy: theme(colors.market.green.600);
--pennant-color-volume-sell: theme(colors.market.red.650);
--pennant-color-volume-sell: theme(colors.market.red.DEFAULT);
}
/**
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

-11
View File
@@ -1,11 +0,0 @@
#!/bin/sh
daemon="${1:-nginx}"
if [[ "$daemon" = "nginx" ]]; then
nginx -g 'daemon off;'
elif [[ "$daemon" = "ipfs" ]]; then
ipfs config profile apply server
ipfs config --json Addresses.Gateway '"/ip4/127.0.0.1/tcp/80"'
ipfs daemon
fi
+1 -2
View File
@@ -20,8 +20,7 @@ RUN sh docker/docker-build.sh
FROM --platform=amd64 nginx:1.23-alpine@sha256:6318314189b40e73145a48060bff4783a116c34cc7241532d0d94198fb2c9629
# configuration of system
EXPOSE 80
COPY docker/entrypoint.sh /entrypoint.sh
ENTRYPOINT [ "/entrypoint.sh" ]
COPY docker/run-ipfs.sh /run-ipfs.sh
# Copy dist
COPY docker/nginx.conf /etc/nginx/conf.d/default.conf
RUN rm -rf /usr/share/nginx/html/*
+1 -2
View File
@@ -1,7 +1,6 @@
FROM --platform=amd64 nginx:1.23-alpine@sha256:6318314189b40e73145a48060bff4783a116c34cc7241532d0d94198fb2c9629
EXPOSE 80
COPY docker/entrypoint.sh /entrypoint.sh
ENTRYPOINT [ "/entrypoint.sh" ]
COPY docker/run-ipfs.sh /run-ipfs.sh
COPY docker/nginx.conf /etc/nginx/conf.d/default.conf
RUN rm -rf /usr/share/nginx/html/*
COPY ./dist-result/ /usr/share/nginx/html/
+4
View File
@@ -0,0 +1,4 @@
#!/bin/sh
ipfs config profile apply server
ipfs config --json Addresses.Gateway '"/ip4/127.0.0.1/tcp/80"'
ipfs daemon
+1 -1
View File
@@ -18,7 +18,7 @@ import {
VegaIconNames,
TooltipCellComponent,
} from '@vegaprotocol/ui-toolkit';
import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid';
import { AgGrid } from '@vegaprotocol/datagrid';
import type {
IGetRowsParams,
IRowNode,
+1 -1
View File
@@ -13,7 +13,7 @@ import type {
VegaICellRendererParams,
} from '@vegaprotocol/datagrid';
import { ProgressBarCell } from '@vegaprotocol/datagrid';
import { AgGridLazy as AgGrid, PriceCell } from '@vegaprotocol/datagrid';
import { AgGrid, PriceCell } from '@vegaprotocol/datagrid';
import type { ColDef } from 'ag-grid-community';
import { accountValuesComparator } from './accounts-table';
import { MarginHealthChart } from './margin-health-chart';
+5 -3
View File
@@ -14,6 +14,7 @@ import {
export type AnnouncementBannerProps = {
app: AppNameType;
configUrl: string;
background?: string;
};
// run only if below the allowed maximum delay ~24.8 days (https://developer.mozilla.org/en-US/docs/Web/API/setTimeout#maximum_delay_value)
@@ -36,6 +37,7 @@ const doesEndInTheFuture = (now: Date, data: Announcement) => {
export const AnnouncementBanner = ({
app,
configUrl,
background,
}: AnnouncementBannerProps) => {
const [isVisible, setVisible] = useState(false);
const { data, reload } = useAnnouncement(app, configUrl);
@@ -79,10 +81,10 @@ export const AnnouncementBanner = ({
}
return (
<Banner className="relative px-10">
<Banner className="relative px-10" background={background}>
<div
data-testid="app-announcement"
className="relative font-alpha flex gap-2 justify-center text-center text-lg text-white"
className="relative flex justify-center text-lg text-center text-white font-alpha gap-2"
>
<span>{data.text}</span>{' '}
{data.urlText && data.url && (
@@ -90,7 +92,7 @@ export const AnnouncementBanner = ({
)}
</div>
<button
className="absolute right-0 top-0 p-4 w-10 h-full flex items-center justify-center text-white"
className="absolute top-0 right-0 flex items-center justify-center w-10 h-full p-4 text-white"
data-testid="app-announcement-close"
onClick={() => {
setVisible(false);
+1 -1
View File
@@ -1,4 +1,4 @@
export * from './lib/ag-grid/ag-grid-lazy';
export * from './lib/ag-grid/ag-grid';
export * from './lib/column-definitions';
@@ -1,17 +0,0 @@
import { forwardRef, lazy } from 'react';
import type { AgGridReactProps, AgGridReact } from 'ag-grid-react';
type Props = AgGridReactProps & {
style?: React.CSSProperties;
gridRef?: React.Ref<AgGridReact>;
};
export const AgGridLazyInternal = lazy(() =>
import('./ag-grid-lazy-themed').then((module) => ({
default: module.AgGridThemed,
}))
);
export const AgGridLazy = forwardRef<AgGridReact, Props>((props, ref) => (
<AgGridLazyInternal {...props} gridRef={ref} />
));
+12
View File
@@ -0,0 +1,12 @@
import { forwardRef } from 'react';
import type { AgGridReactProps, AgGridReact } from 'ag-grid-react';
import { AgGridThemed } from './ag-grid-themed';
type Props = AgGridReactProps & {
style?: React.CSSProperties;
gridRef?: React.Ref<AgGridReact>;
};
export const AgGrid = forwardRef<AgGridReact, Props>((props, ref) => (
<AgGridThemed {...props} gridRef={ref} />
));
@@ -1,9 +1,6 @@
import { act, render, waitFor } from '@testing-library/react';
import {
useDataGridEvents,
GRID_EVENT_DEBOUNCE_TIME,
} from './use-datagrid-events';
import { AgGridThemed } from './ag-grid/ag-grid-lazy-themed';
import { useDataGridEvents } from './use-datagrid-events';
import { AgGridThemed } from './ag-grid/ag-grid-themed';
import type { MutableRefObject } from 'react';
import { useRef } from 'react';
import type { AgGridReact } from 'ag-grid-react';
@@ -19,25 +16,29 @@ const gridProps = {
],
style: { width: 500, height: 300 },
};
const GRID_EVENT_DEBOUNCE_TIME = 300;
let gridRef: MutableRefObject<AgGridReact | null>;
function TestComponent({
hookParams,
}: {
hookParams: Parameters<typeof useDataGridEvents>;
}) {
const hookCallbacks = useDataGridEvents(...hookParams);
gridRef = useRef<AgGridReact | null>(null);
return <AgGridThemed gridRef={gridRef} {...gridProps} {...hookCallbacks} />;
}
// Not using render hook so I can pass event callbacks
// to a rendered grid
function setup(...args: Parameters<typeof useDataGridEvents>) {
let gridRef;
function TestComponent() {
const hookCallbacks = useDataGridEvents(...args);
gridRef = useRef<AgGridReact | null>(null);
return <AgGridThemed gridRef={gridRef} {...gridProps} {...hookCallbacks} />;
}
render(<TestComponent />);
return gridRef as unknown as MutableRefObject<AgGridReact>;
return render(<TestComponent hookParams={args} />);
}
describe('useDataGridEvents', () => {
const originalWarn = console.warn;
beforeAll(() => {
gridRef = undefined;
jest.useFakeTimers();
// disabling some ag grid warnings that are caused by test setup only
@@ -56,15 +57,15 @@ describe('useDataGridEvents', () => {
columnState: undefined,
};
const result = setup(initialState, callback);
setup(initialState, callback);
// column state was not updated, so the default width provided by the
// col def should be set
expect(result.current.columnApi.getColumnState()[0].width).toEqual(
expect(gridRef.current?.columnApi.getColumnState()[0].width).toEqual(
gridProps.columnDefs[0].width
);
// no filters set
expect(result.current.api.getFilterModel()).toEqual({});
expect(gridRef.current?.api.getFilterModel()).toEqual({});
// Set filter
const idFilter = {
@@ -73,7 +74,7 @@ describe('useDataGridEvents', () => {
type: 'equals',
};
await act(async () => {
result.current.api.setFilterModel({
gridRef.current?.api.setFilterModel({
id: idFilter,
});
});
@@ -89,7 +90,7 @@ describe('useDataGridEvents', () => {
},
});
callback.mockClear();
expect(result.current.api.getFilterModel()['id']).toEqual(idFilter);
expect(gridRef.current?.api.getFilterModel()['id']).toEqual(idFilter);
});
it('applies grid state on ready', async () => {
@@ -106,11 +107,11 @@ describe('useDataGridEvents', () => {
columnState: [colState],
};
const result = setup(initialState, jest.fn());
setup(initialState, jest.fn());
await waitFor(() => {
expect(result.current.api.getFilterModel()['id']).toEqual(idFilter);
expect(result.current.columnApi.getColumnState()[0]).toEqual(
expect(gridRef.current?.api.getFilterModel()['id']).toEqual(idFilter);
expect(gridRef.current?.columnApi.getColumnState()[0]).toEqual(
expect.objectContaining(colState)
);
});
@@ -123,13 +124,13 @@ describe('useDataGridEvents', () => {
columnState: undefined,
};
const result = setup(initialState, callback);
setup(initialState, callback);
const newWidth = 400;
// Set col width multiple times
await act(async () => {
result.current.columnApi.setColumnWidth('id', newWidth);
gridRef.current?.columnApi.setColumnWidth('id', newWidth);
});
expect(callback).not.toHaveBeenCalled();
@@ -140,4 +141,23 @@ describe('useDataGridEvents', () => {
expect(callback).toHaveBeenCalledTimes(0);
});
it('columns for autosizing should be handle', () => {
const callback = jest.fn();
const initialState = {
filterModel: undefined,
columnState: undefined,
};
const { rerender } = setup(initialState, callback, ['id']);
jest.spyOn(gridRef.current?.columnApi, 'autoSizeColumns');
rerender(<TestComponent hookParams={[initialState, callback, ['id']]} />);
act(() => {
gridRef.current?.api.setRowData([{ id: 'test-id' }]);
jest.advanceTimersByTime(GRID_EVENT_DEBOUNCE_TIME);
});
expect(gridRef.current?.columnApi.autoSizeColumns).toHaveBeenCalledWith([
'id',
]);
});
});
+15 -2
View File
@@ -6,6 +6,7 @@ import type {
FilterChangedEvent,
FirstDataRenderedEvent,
SortChangedEvent,
GridReadyEvent,
} from 'ag-grid-community';
import { useCallback } from 'react';
@@ -17,7 +18,8 @@ type State = {
export const useDataGridEvents = (
state: State,
callback: (data: State) => void
callback: (data: State) => void,
autoSizeColumns?: string[]
) => {
/**
* Callback for filter events
@@ -78,7 +80,7 @@ export const useDataGridEvents = (
* State only applied if found, otherwise columns sized to fit available space
*/
const onGridReady = useCallback(
({ api, columnApi }: FirstDataRenderedEvent) => {
({ api, columnApi }: GridReadyEvent) => {
if (!api || !columnApi) return;
if (state.columnState) {
@@ -97,6 +99,16 @@ export const useDataGridEvents = (
[state]
);
const onFirstDataRendered = useCallback(
({ columnApi }: FirstDataRenderedEvent) => {
if (!columnApi) return;
if (!state?.columnState && autoSizeColumns?.length) {
columnApi.autoSizeColumns(autoSizeColumns);
}
},
[state, autoSizeColumns]
);
return {
onGridReady,
// these events don't use the 'finished' flag
@@ -106,5 +118,6 @@ export const useDataGridEvents = (
// these trigger a lot so this callback uses the 'finished' flag
onColumnMoved: onDebouncedColumnChange,
onColumnResized: onDebouncedColumnChange,
onFirstDataRendered,
};
};
@@ -12,6 +12,7 @@ import { formatRange, formatValue } from '@vegaprotocol/utils';
import { marketMarginDataProvider } from '@vegaprotocol/accounts';
import { useDataProvider } from '@vegaprotocol/data-provider';
import * as AccordionPrimitive from '@radix-ui/react-accordion';
import * as Schema from '@vegaprotocol/types';
import {
MARGIN_DIFF_TOOLTIP_TEXT,
@@ -37,14 +38,16 @@ export interface DealTicketFeeDetailsProps {
assetSymbol: string;
order: OrderSubmissionBody['orderSubmission'];
market: Market;
isMarketInAuction?: boolean;
}
export const DealTicketFeeDetails = ({
assetSymbol,
order,
market,
isMarketInAuction,
}: DealTicketFeeDetailsProps) => {
const feeEstimate = useEstimateFees(order);
const feeEstimate = useEstimateFees(order, isMarketInAuction);
const { settlementAsset: asset } =
market.tradableInstrument.instrument.product;
const { decimals: assetDecimals, quantum } = asset;
@@ -64,7 +67,7 @@ export const DealTicketFeeDetails = ({
<>
<span>
{t(
`An estimate of the most you would be expected to pay in fees, in the market's settlement asset ${assetSymbol}.`
`An estimate of the most you would be expected to pay in fees, in the market's settlement asset ${assetSymbol}. Fees estimated are "taker" fees and will only be payable if the order trades aggressively. Rebate equal to the maker portion will be paid to the trader if the order trades passively.`
)}
</span>
<FeesBreakdown
@@ -87,6 +90,7 @@ export interface DealTicketMarginDetailsProps {
onMarketClick?: (marketId: string, metaKey?: boolean) => void;
assetSymbol: string;
positionEstimate: EstimatePositionQuery['estimatePosition'];
side: Schema.Side;
}
export const DealTicketMarginDetails = ({
@@ -96,6 +100,7 @@ export const DealTicketMarginDetails = ({
market,
onMarketClick,
positionEstimate,
side,
}: DealTicketMarginDetailsProps) => {
const [breakdownDialog, setBreakdownDialog] = useState(false);
const { pubKey: partyId } = useVegaWallet();
@@ -165,10 +170,7 @@ export const DealTicketMarginDetails = ({
: '0',
assetDecimals
)}
formattedValue={formatRange(
deductionFromCollateralBestCase > 0
? deductionFromCollateralBestCase.toString()
: '0',
formattedValue={formatValue(
deductionFromCollateralWorstCase > 0
? deductionFromCollateralWorstCase.toString()
: '0',
@@ -187,8 +189,7 @@ export const DealTicketMarginDetails = ({
marginEstimate?.worstCase.initialLevel,
assetDecimals
)}
formattedValue={formatRange(
marginEstimate?.bestCase.initialLevel,
formattedValue={formatValue(
marginEstimate?.worstCase.initialLevel,
assetDecimals,
quantum
@@ -200,6 +201,7 @@ export const DealTicketMarginDetails = ({
}
let liquidationPriceEstimate = emptyValue;
let liquidationPriceEstimateRange = emptyValue;
if (liquidationEstimate) {
const liquidationEstimateBestCaseIncludingBuyOrders = BigInt(
@@ -209,8 +211,7 @@ export const DealTicketMarginDetails = ({
liquidationEstimate.bestCase.including_sell_orders.replace(/\..*/, '')
);
const liquidationEstimateBestCase =
liquidationEstimateBestCaseIncludingBuyOrders >
liquidationEstimateBestCaseIncludingSellOrders
side === Schema.Side.SIDE_BUY
? liquidationEstimateBestCaseIncludingBuyOrders
: liquidationEstimateBestCaseIncludingSellOrders;
@@ -221,14 +222,19 @@ export const DealTicketMarginDetails = ({
liquidationEstimate.worstCase.including_sell_orders.replace(/\..*/, '')
);
const liquidationEstimateWorstCase =
liquidationEstimateWorstCaseIncludingBuyOrders >
liquidationEstimateWorstCaseIncludingSellOrders
side === Schema.Side.SIDE_BUY
? liquidationEstimateWorstCaseIncludingBuyOrders
: liquidationEstimateWorstCaseIncludingSellOrders;
// The estimate order query API gives us the liquidation price in formatted by asset decimals.
// We need to calculate it with asset decimals, but display it with market decimals precision until the API changes.
liquidationPriceEstimate = formatRange(
liquidationPriceEstimate = formatValue(
liquidationEstimateWorstCase.toString(),
assetDecimals,
undefined,
market.decimalPlaces
);
liquidationPriceEstimateRange = formatRange(
(liquidationEstimateBestCase < liquidationEstimateWorstCase
? liquidationEstimateBestCase
: liquidationEstimateWorstCase
@@ -284,11 +290,9 @@ export const DealTicketMarginDetails = ({
assetDecimals
) ?? '-'
}
noUnderline
>
<div className="font-mono text-right">
{formatRange(
marginRequiredBestCase,
{formatValue(
marginRequiredWorstCase,
assetDecimals,
quantum
@@ -346,7 +350,7 @@ export const DealTicketMarginDetails = ({
{projectedMargin}
<KeyValue
label={t('Liquidation')}
value={liquidationPriceEstimate}
value={liquidationPriceEstimateRange}
formattedValue={liquidationPriceEstimate}
symbol={quoteName}
labelDescription={LIQUIDATION_PRICE_ESTIMATE_TOOLTIP_TEXT}
@@ -36,7 +36,7 @@ import {
formatValue,
} from '@vegaprotocol/utils';
import { activeOrdersProvider } from '@vegaprotocol/orders';
import { getDerivedPrice } from '@vegaprotocol/markets';
import { getDerivedPrice, isMarketInAuction } from '@vegaprotocol/markets';
import {
validateExpiration,
validateMarketState,
@@ -182,6 +182,7 @@ export const DealTicket = ({
const iceberg = watch('iceberg');
const peakSize = watch('peakSize');
const expiresAt = watch('expiresAt');
const postOnly = watch('postOnly');
useEffect(() => {
const size = storedFormValues?.[dealTicketType]?.size;
@@ -211,6 +212,7 @@ export const DealTicket = ({
size: rawSize,
timeInForce,
type,
postOnly,
},
market.id,
market.decimalPlaces,
@@ -219,8 +221,7 @@ export const DealTicket = ({
const price =
normalizedOrder &&
marketPrice &&
getDerivedPrice(normalizedOrder, marketPrice);
getDerivedPrice(normalizedOrder, marketPrice ?? undefined);
const notionalSize = getNotionalSize(
price,
@@ -474,6 +475,7 @@ export const DealTicket = ({
}
assetSymbol={assetSymbol}
market={market}
isMarketInAuction={isMarketInAuction(marketData.marketTradingMode)}
/>
</div>
<Controller
@@ -676,6 +678,7 @@ export const DealTicket = ({
)}
</Button>
<DealTicketMarginDetails
side={normalizedOrder.side}
onMarketClick={onMarketClick}
assetSymbol={assetSymbol}
marginAccountBalance={marginAccountBalance}
@@ -47,7 +47,7 @@ export const KeyValue = ({
<Tooltip description={labelDescription}>
<div className="text-muted">{label}</div>
</Tooltip>
<Tooltip description={`${value ?? '-'} ${symbol || ''}`} noUnderline>
<Tooltip description={`${value ?? '-'} ${symbol || ''}`}>
{valueElement}
</Tooltip>
</div>
@@ -0,0 +1,78 @@
import { renderHook } from '@testing-library/react';
import { useEstimateFees } from './use-estimate-fees';
import { Side, OrderTimeInForce, OrderType } from '@vegaprotocol/types';
import type { EstimateFeesQuery } from './__generated__/EstimateOrder';
const data: EstimateFeesQuery = {
estimateFees: {
totalFeeAmount: '12',
fees: {
infrastructureFee: '2',
liquidityFee: '4',
makerFee: '6',
},
},
};
const mockUseEstimateFeesQuery = jest.fn((...args) => ({
data,
}));
jest.mock('./__generated__/EstimateOrder', () => ({
...jest.requireActual('@vegaprotocol/data-provider'),
useEstimateFeesQuery: jest.fn((...args) => mockUseEstimateFeesQuery(...args)),
}));
jest.mock('@vegaprotocol/wallet', () => ({
useVegaWallet: () => ({ pubKey: 'pubKey' }),
}));
describe('useEstimateFees', () => {
it('returns 0 as estimated values if order is postOnly', () => {
const { result } = renderHook(() =>
useEstimateFees({
marketId: 'marketId',
side: Side.SIDE_BUY,
size: '1',
price: '1',
timeInForce: OrderTimeInForce.TIME_IN_FORCE_FOK,
type: OrderType.TYPE_LIMIT,
postOnly: true,
})
);
expect(result.current).toEqual({
totalFeeAmount: '0',
fees: {
infrastructureFee: '0',
liquidityFee: '0',
makerFee: '0',
},
});
expect(mockUseEstimateFeesQuery.mock.lastCall?.[0].skip).toBeTruthy();
});
it('divide values by 2 if market is in auction', () => {
const { result } = renderHook(() =>
useEstimateFees(
{
marketId: 'marketId',
side: Side.SIDE_BUY,
size: '1',
price: '1',
timeInForce: OrderTimeInForce.TIME_IN_FORCE_FOK,
type: OrderType.TYPE_LIMIT,
},
true
)
);
expect(result.current).toEqual({
totalFeeAmount: '6',
fees: {
infrastructureFee: '1',
liquidityFee: '2',
makerFee: '3',
},
});
});
});
@@ -1,13 +1,16 @@
import { useVegaWallet } from '@vegaprotocol/wallet';
import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
import type { EstimateFeesQuery } from './__generated__/EstimateOrder';
import { useEstimateFeesQuery } from './__generated__/EstimateOrder';
export const useEstimateFees = (
order?: OrderSubmissionBody['orderSubmission']
) => {
const { pubKey } = useVegaWallet();
const divideByTwo = (n: string) => (BigInt(n) / BigInt(2)).toString();
export const useEstimateFees = (
order?: OrderSubmissionBody['orderSubmission'],
isMarketInAuction?: boolean
): EstimateFeesQuery['estimateFees'] | undefined => {
const { pubKey } = useVegaWallet();
const { data } = useEstimateFeesQuery({
variables: order && {
marketId: order.marketId,
@@ -19,7 +22,28 @@ export const useEstimateFees = (
type: order.type,
},
fetchPolicy: 'no-cache',
skip: !pubKey || !order?.size || !order?.price,
skip: !pubKey || !order?.size || !order?.price || order.postOnly,
});
return data?.estimateFees;
if (order?.postOnly) {
return {
totalFeeAmount: '0',
fees: {
infrastructureFee: '0',
liquidityFee: '0',
makerFee: '0',
},
};
}
return isMarketInAuction && data?.estimateFees
? {
totalFeeAmount: divideByTwo(data.estimateFees.totalFeeAmount),
fees: {
infrastructureFee: divideByTwo(
data.estimateFees.fees.infrastructureFee
),
liquidityFee: divideByTwo(data.estimateFees.fees.liquidityFee),
makerFee: divideByTwo(data.estimateFees.fees.makerFee),
},
}
: data?.estimateFees;
};
+1 -1
View File
@@ -6,7 +6,7 @@ import {
isNumeric,
} from '@vegaprotocol/utils';
import type { ColDef } from 'ag-grid-community';
import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid';
import { AgGrid } from '@vegaprotocol/datagrid';
import type {
VegaICellRendererParams,
VegaValueFormatterParams,
+2 -2
View File
@@ -15,7 +15,7 @@ import {
import { t } from '@vegaprotocol/i18n';
import * as Schema from '@vegaprotocol/types';
import {
AgGridLazy as AgGrid,
AgGrid,
positiveClassNames,
negativeClassNames,
MarketNameCell,
@@ -300,7 +300,7 @@ const FeesBreakdownTooltip = ({
return (
<div
data-testid="fee-breakdown-tooltip"
className="max-w-sm bg-vega-light-100 dark:bg-vega-dark-100 border border-vega-light-200 dark:border-vega-dark-200 px-4 py-2 z-20 rounded text-sm break-word text-black dark:text-white"
className="z-20 max-w-sm px-4 py-2 text-sm text-black border rounded bg-vega-light-100 dark:bg-vega-dark-100 border-vega-light-200 dark:border-vega-dark-200 break-word dark:text-white"
>
{role === MAKER && (
<>
+1 -1
View File
@@ -7,7 +7,7 @@ import {
} from '@vegaprotocol/utils';
import { t } from '@vegaprotocol/i18n';
import type { TypedDataAgGrid } from '@vegaprotocol/datagrid';
import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid';
import { AgGrid } from '@vegaprotocol/datagrid';
import { TooltipCellComponent } from '@vegaprotocol/ui-toolkit';
import type {
ColDef,
+1 -1
View File
@@ -175,7 +175,7 @@ export const Orderbook = ({
);
return (
<div className="h-full text-xs grid grid-rows-[1fr_min-content]">
<div className="h-full text-xs grid grid-rows-[1fr_min-content] overflow-hidden">
<div>
<ReactVirtualizedAutoSizer>
{({ width, height }) => {
@@ -60,6 +60,7 @@ export const FeesBreakdown = ({
.plus(fees.infrastructureFee)
.plus(fees.liquidityFee)
.toString();
if (totalFees === '0') return null;
const formatValue = (value: string | number | null | undefined): string => {
return value && !isNaN(Number(value))
? addDecimalsFormatNumber(value, decimals)
+1 -1
View File
@@ -33,7 +33,7 @@ export const getDerivedPrice = (
type: Schema.OrderType;
price?: string | undefined;
},
marketPrice: string
marketPrice?: string
) => {
// If order type is market we should use either the mark price
// or the uncrossing price. If order type is limit use the price
@@ -17,7 +17,7 @@ import {
import type { ForwardedRef } from 'react';
import { memo, forwardRef, useMemo } from 'react';
import {
AgGridLazy as AgGrid,
AgGrid,
SetFilter,
DateRangeFilter,
negativeClassNames,
@@ -79,6 +79,7 @@ export const OrderListTable = memo<
() => [
{
headerName: t('Market'),
colId: 'instrument-code',
field: 'market.tradableInstrument.instrument.code',
cellRenderer: 'MarketNameCell',
cellRendererParams: { idPath: 'market.id', onMarketClick },
@@ -18,7 +18,7 @@ import {
} from '@vegaprotocol/ui-toolkit';
import { memo, useMemo } from 'react';
import {
AgGridLazy as AgGrid,
AgGrid,
SetFilter,
DateRangeFilter,
negativeClassNames,
+1 -1
View File
@@ -8,7 +8,7 @@ import type {
VegaICellRendererParams,
} from '@vegaprotocol/datagrid';
import {
AgGridLazy as AgGrid,
AgGrid,
COL_DEFS,
PriceFlashCell,
signedNumberCssClassRules,
@@ -100,7 +100,8 @@ describe('ProposalsList', () => {
const container = within(
document.querySelector(rowContainerSelector) as HTMLElement
);
expect(container.getAllByRole('row')).toHaveLength(
expect(await container.findAllByRole('row')).toHaveLength(
// @ts-ignore data is mocked
mock?.result?.data.proposalsConnection.edges.length
);
@@ -1,5 +1,5 @@
import type { FC } from 'react';
import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid';
import { AgGrid } from '@vegaprotocol/datagrid';
import { t } from '@vegaprotocol/i18n';
import * as Types from '@vegaprotocol/types';
import { removePaginationWrapper } from '@vegaprotocol/utils';
+1 -1
View File
@@ -4,7 +4,7 @@ import type {
VegaICellRendererParams,
VegaValueFormatterParams,
} from '@vegaprotocol/datagrid';
import { AgGridLazy as AgGrid, NumericCell } from '@vegaprotocol/datagrid';
import { AgGrid, NumericCell } from '@vegaprotocol/datagrid';
import {
addDecimal,
addDecimalsFormatNumber,
@@ -4,14 +4,27 @@ import type { ReactNode } from 'react';
export interface BannerProps {
children?: ReactNode;
className?: string;
background?: string;
}
export const AnnouncementBanner = ({ className, children }: BannerProps) => {
const bannerClasses = classnames(
"bg-[url('https://static.vega.xyz/assets/img/banner-bg.jpg')] bg-cover bg-center bg-no-repeat",
'p-4',
className
);
export const AnnouncementBanner = ({
className,
children,
background = 'url("https://static.vega.xyz/assets/img/banner-bg.jpg")',
}: BannerProps) => {
const bannerClasses = classnames('p-4', className);
return <div className={bannerClasses}>{children}</div>;
return (
<div
className={bannerClasses}
style={{
background,
backgroundRepeat: 'no-repeat',
backgroundPosition: 'center',
backgroundSize: 'cover',
}}
>
{children}
</div>
);
};
@@ -19,14 +19,14 @@ export interface TooltipProps {
align?: 'start' | 'center' | 'end';
side?: 'top' | 'right' | 'bottom' | 'left';
sideOffset?: number;
noUnderline?: boolean;
underline?: boolean;
}
export const TOOLTIP_TRIGGER_CLASS_NAME = (noUnderline?: boolean) =>
classNames(
{ 'underline underline-offset-2': !noUnderline },
'decoration-neutral-400 dark:decoration-neutral-400 decoration-dashed'
);
export const TOOLTIP_TRIGGER_CLASS_NAME = (underline?: boolean) =>
classNames({
'underline underline-offset-2 decoration-neutral-400 dark:decoration-neutral-400 decoration-dashed':
underline,
});
// Conditionally rendered tooltip if description content is provided.
export const Tooltip = ({
@@ -36,12 +36,12 @@ export const Tooltip = ({
sideOffset,
align = 'start',
side = 'bottom',
noUnderline,
underline,
}: TooltipProps) =>
description ? (
<Provider delayDuration={200} skipDelayDuration={100}>
<Root open={open}>
<Trigger asChild className={TOOLTIP_TRIGGER_CLASS_NAME(noUnderline)}>
<Trigger asChild className={TOOLTIP_TRIGGER_CLASS_NAME(underline)}>
{children}
</Trigger>
{description && (
@@ -155,8 +155,7 @@ const ConnectDialogContainer = ({
const isDesktopWalletRunning = useIsWalletServiceRunning(
walletUrl,
connectors['jsonRpc'],
appChainId
connectors['jsonRpc']
);
const snapStatus = useSnapStatus(
@@ -0,0 +1,41 @@
import { renderHook, waitFor } from '@testing-library/react';
import { JsonRpcConnector } from './connectors';
import { useIsWalletServiceRunning } from './use-is-wallet-service-running';
describe('useIsWalletServiceRunning', () => {
it('returns true if wallet is running', async () => {
const url = 'https://foo.bar.com';
const connector = new JsonRpcConnector();
const spyOnCheckCompat = jest
.spyOn(connector, 'checkCompat')
.mockResolvedValue(true);
const { result } = renderHook(() =>
useIsWalletServiceRunning(url, connector)
);
expect(result.current).toBe(null);
await waitFor(() => {
expect(spyOnCheckCompat).toHaveBeenCalled();
expect(result.current).toBe(true);
});
});
it('returns false if wallet is not running', async () => {
const url = 'https://foo.bar.com';
const connector = new JsonRpcConnector();
const spyOnCheckCompat = jest
.spyOn(connector, 'checkCompat')
.mockRejectedValue(false);
const { result } = renderHook(() =>
useIsWalletServiceRunning(url, connector)
);
expect(result.current).toBe(null);
await waitFor(() => {
expect(spyOnCheckCompat).toHaveBeenCalled();
expect(result.current).toBe(false);
});
});
});
@@ -0,0 +1,39 @@
import { useEffect, useState } from 'react';
import type { JsonRpcConnector } from './connectors';
export const useIsWalletServiceRunning = (
url: string,
connector: JsonRpcConnector | undefined
) => {
const [isRunning, setIsRunning] = useState<boolean | null>(null);
useEffect(() => {
if (!connector) return;
if (url && url !== connector.url) {
connector.url = url;
}
const check = async () => {
try {
// we are not checking wallet compatibility here, only that the wallet is running
await connector.checkCompat();
setIsRunning(true);
} catch {
setIsRunning(false);
}
};
// check immediately
check();
// check every second for quick feedback to the user
const interval = setInterval(check, 1000);
return () => {
clearInterval(interval);
};
}, [connector, url]);
return isRunning;
};
@@ -1,47 +0,0 @@
import { useCallback, useEffect, useState } from 'react';
import type { JsonRpcConnector } from './connectors';
import { ClientErrors } from './connectors';
export const useIsWalletServiceRunning = (
url: string,
connector: JsonRpcConnector | undefined,
appChainId: string
) => {
const [run, setRun] = useState<boolean | null>(null);
const checkState = useCallback(async () => {
if (!connector) return false;
if (url && url !== connector.url) {
connector.url = url;
}
try {
await connector.checkCompat();
const chainIdResult = await connector.getChainId();
if (chainIdResult.chainID !== appChainId) {
throw ClientErrors.WRONG_NETWORK;
}
} catch (e) {
return false;
}
return true;
}, [connector, url, appChainId]);
useEffect(() => {
if (!connector) return;
let interval: NodeJS.Timeout;
checkState().then((value) => {
setRun(value);
interval = setInterval(async () => {
setRun(await checkState());
}, 1000 * 10);
});
return () => {
clearInterval(interval);
};
}, [checkState, connector]);
return run;
};
+1 -1
View File
@@ -20,7 +20,7 @@ import type {
VegaICellRendererParams,
VegaValueFormatterParams,
} from '@vegaprotocol/datagrid';
import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid';
import { AgGrid } from '@vegaprotocol/datagrid';
import { EtherscanLink } from '@vegaprotocol/environment';
import type { WithdrawalFieldsFragment } from './__generated__/Withdrawal';
import {
-1
View File
@@ -87,7 +87,6 @@
"recharts": "^2.1.2",
"recursive-key-filter": "^1.0.2",
"regenerator-runtime": "0.13.7",
"semver": "^7.5.1",
"toml": "^3.0.0",
"tslib": "^2.3.0",
"uuid": "^8.3.2",
-7
View File
@@ -22591,13 +22591,6 @@ semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0:
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
semver@^7.5.1:
version "7.5.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.1.tgz#c90c4d631cf74720e46b21c1d37ea07edfab91ec"
integrity sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==
dependencies:
lru-cache "^6.0.0"
semver@^7.5.3:
version "7.5.4"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e"