Compare commits

..
243 changed files with 5788 additions and 779 deletions
+28
View File
@@ -0,0 +1,28 @@
# path to a directory with all packages
storage: ../tmp/local-registry/storage
# a list of other known repositories we can talk to
uplinks:
npmjs:
url: https://registry.yarnpkg.com
maxage: 60m
packages:
'**':
# give all users (including non-authenticated users) full access
# because it is a local registry
access: $all
publish: $all
unpublish: $all
# if package is not available locally, proxy requests to npm registry
proxy: npmjs
# log settings
logs:
type: stdout
format: pretty
level: warn
publish:
allow_offline: true # set offline to true to allow publish offline
+1 -1
View File
@@ -136,7 +136,7 @@ The [`docker`](./docker) subfolder has some docker configurations for easily set
Using multistage dockerfile dist is compiled using [node](https://hub.docker.com/_/node) image and later packed to nginx as in [dist build](#dist-build). The multistage builds ensures consistent CPU architecture and build toolchains are used so that the result will be identical.
```bash
docker build --build-arg APP=[YOUR APP] --build-arg NODE_VERSION=20.9.1 --build-arg ENV_NAME=mainnet -t [TAG] -f docker/node-inside-docker.Dockerfile .
docker build --build-arg APP=[YOUR APP] --build-arg NODE_VERSION=20.11 --build-arg ENV_NAME=mainnet -t [TAG] -f docker/node-inside-docker.Dockerfile .
```
### Computing ipfs-hash of the build
+4 -2
View File
@@ -1,7 +1,9 @@
const { join } = require('path');
const { createGlobPatternsForDependencies } = require('@nx/react/tailwind');
const theme = require('../../libs/tailwindcss-config/src/theme');
const vegaCustomClasses = require('../../libs/tailwindcss-config/src/vega-custom-classes');
const { theme } = require('../../libs/tailwindcss-config/src/theme');
const {
vegaCustomClasses,
} = require('../../libs/tailwindcss-config/src/vega-custom-classes');
module.exports = {
content: [
+5 -3
View File
@@ -1,9 +1,11 @@
const { join } = require('path');
const { createGlobPatternsForDependencies } = require('@nx/react/tailwind');
const theme = require('../../libs/tailwindcss-config/src/theme');
const vegaCustomClasses = require('../../libs/tailwindcss-config/src/vega-custom-classes');
const { theme } = require('../../libs/tailwindcss-config/src/theme');
const {
vegaCustomClasses,
} = require('../../libs/tailwindcss-config/src/vega-custom-classes');
module.exports = {
export default {
content: [
join(__dirname, 'src/**/*.{js,ts,jsx,tsx}'),
'libs/ui-toolkit/src/utils/shared.ts',
+4 -2
View File
@@ -1,7 +1,9 @@
const { join } = require('path');
const { createGlobPatternsForDependencies } = require('@nx/react/tailwind');
const theme = require('../../libs/tailwindcss-config/src/theme');
const vegaCustomClasses = require('../../libs/tailwindcss-config/src/vega-custom-classes');
const { theme } = require('../../libs/tailwindcss-config/src/theme');
const {
vegaCustomClasses,
} = require('../../libs/tailwindcss-config/src/vega-custom-classes');
module.exports = {
content: [
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 547 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

@@ -1,63 +1,126 @@
import type { InMemoryCacheConfig } from '@apollo/client';
import {
AppFailure,
AppLoader,
NetworkLoader,
NodeFailure,
NodeGuard,
useEnvironment,
useNodeSwitcherStore,
} from '@vegaprotocol/environment';
import { type ReactNode } from 'react';
import { useEffect, type ReactNode, useState } from 'react';
import { Web3Provider } from './web3-provider';
import { useT } from '../../lib/use-t';
import { DataLoader } from './data-loader';
import { WalletProvider } from '@vegaprotocol/wallet-react';
import { useVegaWalletConfig } from '../../lib/hooks/use-vega-wallet-config';
import { Trans } from 'react-i18next';
import { Button, Loader, Splash, VLogo } from '@vegaprotocol/ui-toolkit';
const Failure = ({ reason }: { reason?: ReactNode }) => {
const t = useT();
const setNodeSwitcher = useNodeSwitcherStore((store) => store.setDialogOpen);
return (
<Splash>
<div className="border border-vega-red m-10 mx-auto w-4/5 max-w-3xl rounded-lg overflow-hidden animate-shake">
<div className="bg-vega-red text-white px-2 py-2 flex gap-1 items-center font-alpha calt uppercase">
<VLogo className="h-4" />
<span className="text-lg">{t('Failed to initialize the app')}</span>
</div>
<div className="p-4 text-left text-sm">
<p className="mb-4">{reason}</p>
<div className="text-center">
<Button className="border-2" onClick={() => setNodeSwitcher(true)}>
{t('Change node')}
</Button>
</div>
</div>
</div>
</Splash>
);
};
const Loading = () => {
const [showSlowNotification, setShowSlowNotification] = useState(false);
const t = useT();
const setNodeSwitcher = useNodeSwitcherStore((store) => store.setDialogOpen);
useEffect(() => {
const to = setTimeout(() => {
if (!showSlowNotification) setShowSlowNotification(true);
}, 5000);
return () => {
clearTimeout(to);
};
}, [showSlowNotification]);
return (
<Splash>
<div className="border border-transparent m-10 mx-auto w-4/5 max-w-3xl rounded-lg overflow-hidden">
<div className="mt-11 p-4 text-left text-sm">
<Loader />
{showSlowNotification && (
<>
<p className="mt-4 text-center">
{t(
"It looks like you're connection is slow, try switching to another node."
)}
</p>
<div className="mt-4 text-center">
<Button
className="border-2"
onClick={() => setNodeSwitcher(true)}
>
{t('Change node')}
</Button>
</div>
</>
)}
</div>
</div>
</Splash>
);
};
export const Bootstrapper = ({ children }: { children: ReactNode }) => {
const t = useT();
const { error, VEGA_URL } = useEnvironment();
const { error, VEGA_URL } = useEnvironment((state) => ({
error: state.error,
VEGA_URL: state.VEGA_URL,
}));
const config = useVegaWalletConfig();
if (!config) {
return <AppLoader />;
}
const ERR_DATA_LOADER = (
<Trans
i18nKey="It appears that the connection to the node <0>{{VEGA_URL}}</0> does not return necessary data, try switching to another node."
components={[
<span key="vega" className="text-muted">
{VEGA_URL}
</span>,
]}
values={{
VEGA_URL,
}}
/>
);
return (
<NetworkLoader
cache={cacheConfig}
skeleton={<AppLoader />}
failure={
<AppFailure title={t('Could not initialize app')} error={error} />
}
skeleton={<Loading />}
failure={<Failure reason={error} />}
>
<NodeGuard
skeleton={<AppLoader />}
failure={
<NodeFailure
title={t('Node: {{VEGA_URL}} is unsuitable', { VEGA_URL })}
/>
}
<DataLoader
skeleton={<Loading />}
failure={<Failure reason={ERR_DATA_LOADER} />}
>
<DataLoader
skeleton={<AppLoader />}
failure={
<AppFailure
title={t('Could not load market data or asset data')}
error={error}
/>
}
<Web3Provider
skeleton={<Loading />}
failure={<Failure reason={t('Could not configure web3 provider')} />}
>
<Web3Provider
skeleton={<AppLoader />}
failure={
<AppFailure title={t('Could not configure web3 provider')} />
}
>
<WalletProvider config={config}>{children}</WalletProvider>
</Web3Provider>
</DataLoader>
</NodeGuard>
<WalletProvider config={config}>{children}</WalletProvider>
</Web3Provider>
</DataLoader>
</NetworkLoader>
);
};
@@ -107,6 +170,9 @@ const cacheConfig: InMemoryCacheConfig = {
Fees: {
keyFields: false,
},
PartyProfile: {
keyFields: ['partyId'],
},
// The folling types are cached by the data provider and not by apollo
PositionUpdate: {
keyFields: false,
+40 -3
View File
@@ -8,6 +8,12 @@ import {
mockConfig,
MockedWalletProvider,
} from '@vegaprotocol/wallet-react/testing';
import { MockedProvider, type MockedResponse } from '@apollo/react-testing';
import {
PartyProfilesDocument,
type PartyProfilesQuery,
type PartyProfilesQueryVariables,
} from '../vega-wallet-connect-button/__generated__/PartyProfiles';
jest.mock('@vegaprotocol/proposals', () => ({
ProtocolUpgradeCountdown: () => null,
@@ -24,15 +30,45 @@ describe('Navbar', () => {
publicKey: '2'.repeat(64),
},
];
const key1Alias = 'key 1 alias';
const marketId = 'abc';
const navbarContent = 'navbar-menu-content';
const partyProfilesMock: MockedResponse<
PartyProfilesQuery,
PartyProfilesQueryVariables
> = {
request: {
query: PartyProfilesDocument,
variables: {
partyIds: mockKeys.map((k) => k.publicKey),
},
},
result: {
data: {
partiesProfilesConnection: {
edges: [
{
node: {
partyId: mockKeys[0].publicKey,
alias: key1Alias,
metadata: [],
},
},
],
},
},
},
};
const renderComponent = (initialEntries?: string[]) => {
return render(
<MemoryRouter initialEntries={initialEntries}>
<MockedWalletProvider>
<Navbar />
</MockedWalletProvider>
<MockedProvider mocks={[partyProfilesMock]}>
<MockedWalletProvider>
<Navbar />
</MockedWalletProvider>
</MockedProvider>
</MemoryRouter>
);
};
@@ -140,6 +176,7 @@ describe('Navbar', () => {
const activeKey = within(menu.getByTestId(/key-1+-mobile/));
expect(activeKey.getByText(mockKeys[0].name)).toBeInTheDocument();
expect(activeKey.getByTestId('icon-tick')).toBeInTheDocument();
expect(screen.getByText(key1Alias)).toBeInTheDocument();
const inactiveKey = within(menu.getByTestId(/key-2+-mobile/));
await userEvent.click(inactiveKey.getByText(mockKeys[1].name));
@@ -31,39 +31,27 @@ export const ProfileDialog = () => {
const pubKey = useProfileDialogStore((store) => store.pubKey);
const setOpen = useProfileDialogStore((store) => store.setOpen);
const { send, status, error, reset } = useSimpleTransaction({
onSuccess: () => {
refetch();
},
});
const profileEdge = data?.partiesProfilesConnection?.edges.find(
(e) => e.node.partyId === pubKey
);
const sendTx = (field: FormFields) => {
send({
updatePartyProfile: {
alias: field.alias,
metadata: [],
},
});
};
return (
<Dialog
open={open}
onChange={() => {
setOpen(undefined);
reset();
}}
title={t('Edit profile')}
>
<ProfileForm
<ProfileFormContainer
profile={profileEdge?.node}
status={status}
error={error}
onSubmit={sendTx}
onSuccess={() => {
refetch();
setTimeout(() => {
setOpen(undefined);
}, 1000);
}}
/>
</Dialog>
);
@@ -77,6 +65,32 @@ type Profile = NonNullable<
PartyProfilesQuery['partiesProfilesConnection']
>['edges'][number]['node'];
const ProfileFormContainer = ({
profile,
onSuccess,
}: {
profile: Profile | undefined;
onSuccess: () => void;
}) => {
const { send, status, error } = useSimpleTransaction({ onSuccess });
const sendTx = (field: FormFields) => {
send({
updatePartyProfile: {
alias: field.alias,
metadata: [],
},
});
};
return (
<ProfileForm
profile={profile}
status={status}
error={error}
onSubmit={sendTx}
/>
);
};
const ProfileForm = ({
profile,
onSubmit,
@@ -114,6 +128,14 @@ const ProfileForm = ({
const errorMessage = errors.alias?.message || error;
if (status === 'confirmed') {
return (
<p className="mt-2 mb-4 text-sm text-vega-green-600 dark:text-vega-green">
{t('Profile updated')}
</p>
);
}
return (
<form onSubmit={handleSubmit(onSubmit)} className="mt-3">
<FormGroup label="Alias" labelFor="alias">
@@ -131,12 +153,6 @@ const ProfileForm = ({
</p>
</InputError>
)}
{status === 'confirmed' && (
<p className="mt-2 mb-4 text-sm text-success">
{t('Profile updated')}
</p>
)}
</FormGroup>
<TradingButton
type="submit"
@@ -94,6 +94,7 @@ export const VegaWalletConnectButton = ({
<KeypairRadioGroup
pubKey={pubKey}
pubKeys={pubKeys}
activeKey={activeKey?.publicKey}
onSelect={selectPubKey}
/>
<TradingDropdownSeparator />
@@ -138,15 +139,18 @@ export const VegaWalletConnectButton = ({
const KeypairRadioGroup = ({
pubKey,
pubKeys,
activeKey,
onSelect,
}: {
pubKey: string | undefined;
pubKeys: Key[];
activeKey: string | undefined;
onSelect: (pubKey: string) => void;
}) => {
const { data } = usePartyProfilesQuery({
variables: { partyIds: pubKeys.map((pk) => pk.publicKey) },
skip: pubKeys.length <= 0,
fetchPolicy: 'cache-and-network',
});
return (
@@ -156,14 +160,27 @@ const KeypairRadioGroup = ({
(e) => e.node.partyId === pk.publicKey
);
return (
<KeypairItem key={pk.publicKey} pk={pk} alias={profile?.node.alias} />
<KeypairItem
key={pk.publicKey}
pk={pk}
isActive={activeKey === pk.publicKey}
alias={profile?.node.alias}
/>
);
})}
</TradingDropdownRadioGroup>
);
};
const KeypairItem = ({ pk, alias }: { pk: Key; alias: string | undefined }) => {
const KeypairItem = ({
pk,
isActive,
alias,
}: {
pk: Key;
alias: string | undefined;
isActive: boolean;
}) => {
const t = useT();
const [copied, setCopied] = useCopyTimeout();
const setOpen = useProfileDialogStore((store) => store.setOpen);
@@ -194,8 +211,13 @@ const KeypairItem = ({ pk, alias }: { pk: Key; alias: string | undefined }) => {
data-testid={`key-${pk.publicKey}`}
>
<Tooltip description={t('Public facing key alias. Click to edit')}>
<button data-testid="alias" onClick={() => setOpen(pk.publicKey)}>
<button
data-testid="alias"
onClick={() => setOpen(pk.publicKey)}
className="flex items-center gap-1"
>
{alias ? alias : t('No alias')}
{isActive && <VegaIcon name={VegaIconNames.EDIT} />}
</button>
</Tooltip>
</div>
@@ -12,6 +12,8 @@ import CopyToClipboard from 'react-copy-to-clipboard';
import { ViewType, useSidebar } from '../sidebar';
import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id';
import { useT } from '../../lib/use-t';
import { usePartyProfilesQuery } from '../vega-wallet-connect-button/__generated__/PartyProfiles';
import { useProfileDialogStore } from '../../stores/profile-dialog-store';
export const VegaWalletMenu = ({
setMenu,
@@ -23,6 +25,12 @@ export const VegaWalletMenu = ({
const currentRouteId = useGetCurrentRouteId();
const setViews = useSidebar((store) => store.setViews);
const { data } = usePartyProfilesQuery({
variables: { partyIds: pubKeys.map((pk) => pk.publicKey) },
skip: pubKeys.length <= 0,
fetchPolicy: 'cache-and-network',
});
const activeKey = useMemo(() => {
return pubKeys?.find((pk) => pk.publicKey === pubKey);
}, [pubKey, pubKeys]);
@@ -37,14 +45,21 @@ export const VegaWalletMenu = ({
return (
<div>
<div className="grow my-4" role="list">
{(pubKeys || []).map((pk) => (
<KeypairListItem
key={pk.publicKey}
pk={pk}
isActive={activeKey?.publicKey === pk.publicKey}
onSelectItem={onSelectItem}
/>
))}
{(pubKeys || []).map((pk) => {
const profile = data?.partiesProfilesConnection?.edges.find(
(e) => e.node.partyId === pk.publicKey
);
return (
<KeypairListItem
key={pk.publicKey}
pk={pk}
isActive={activeKey?.publicKey === pk.publicKey}
onSelectItem={onSelectItem}
alias={profile?.node.alias}
setMenu={setMenu}
/>
);
})}
</div>
<div className="flex flex-col gap-2 m-4">
@@ -72,18 +87,23 @@ export const VegaWalletMenu = ({
const KeypairListItem = ({
pk,
isActive,
alias,
onSelectItem,
setMenu,
}: {
pk: Key;
isActive: boolean;
alias: string | undefined;
onSelectItem: (pk: string) => void;
setMenu: (open: 'nav' | 'wallet' | null) => void;
}) => {
const t = useT();
const [copied, setCopied] = useCopyTimeout();
const setOpen = useProfileDialogStore((store) => store.setOpen);
return (
<div
className="flex flex-col w-full ml-4 mr-2 mb-4"
className="flex flex-col w-full px-4 mb-4"
data-testid={`key-${pk.publicKey}-mobile`}
>
<span className="flex gap-2 items-center mr-2">
@@ -106,6 +126,24 @@ const KeypairListItem = ({
</CopyToClipboard>
{copied && <span className="text-xs">{t('Copied')}</span>}
</span>
<span
className="flex gap-2 items-center"
data-testid={`key-${pk.publicKey}`}
>
<span className="truncate">{alias ? alias : t('No alias')}</span>
{isActive && (
<button
data-testid="alias"
onClick={() => {
setOpen(pk.publicKey);
setMenu(null);
}}
className="flex items-center gap-1"
>
<VegaIcon name={VegaIconNames.EDIT} />
</button>
)}
</span>
</div>
);
};
@@ -9,12 +9,14 @@ from actions.utils import next_epoch, change_keys
from wallet_config import MM_WALLET
from vega_sim.null_service import VegaServiceNull
@pytest.fixture(scope="module")
def setup_environment(request, browser) -> Generator[Tuple[Page, str, str], None, None]:
with init_vega(request) as vega_instance:
request.addfinalizer(lambda: cleanup_container(vega_instance))
tDAI_market, tDAI_asset_id = setup_market_with_reward_program(vega_instance)
tDAI_market, tDAI_asset_id = setup_market_with_reward_program(
vega_instance)
with init_page(vega_instance, browser, request) as page:
risk_accepted_setup(page)
@@ -147,14 +149,12 @@ def setup_market_with_reward_program(vega: VegaServiceNull):
return tDAI_market, tDAI_asset_id
def test_network_reward_pot( setup_environment: Tuple[Page, str, str],
) -> None:
def test_network_reward_pot(setup_environment: Tuple[Page, str, str],
) -> None:
page, tDAI_market, tDAI_asset_id = setup_environment
expect(page.get_by_test_id(TOTAL_REWARDS)).to_have_text("183.33333 tDAI")
def test_reward_multiplier(
setup_environment: Tuple[Page, str, str],
) -> None:
@@ -168,7 +168,6 @@ def test_reward_multiplier(
)
def test_reward_history(
setup_environment: Tuple[Page, str, str],
) -> None:
@@ -177,26 +176,37 @@ def test_reward_history(
expect((page.get_by_role(ROW).locator(PRICE_TAKING_COL_ID)).nth(1)).to_have_text(
"299.99999100.00%"
)
expect((page.get_by_role(ROW).locator(TOTAL_COL_ID)).nth(1)).to_have_text("299.99999")
expect((page.get_by_role(ROW).locator(TOTAL_COL_ID)).nth(
1)).to_have_text("299.99999")
page.get_by_test_id(EARNED_BY_ME_BUTTON).click()
expect((page.get_by_role(ROW).locator(TOTAL_COL_ID)).nth(1)).to_have_text(
"183.33333"
)
def test_staking_reward(
page: Page,
setup_environment: Tuple[Page, str, str],
):
page, tDAI_market, tDAI_asset_id = setup_environment
expect(page.get_by_test_id("active-rewards-card")).to_have_count(2)
staking_reward_card = page.get_by_test_id("active-rewards-card").nth(1)
expect(staking_reward_card).to_be_visible()
expect(staking_reward_card.get_by_test_id("entity-scope")).to_have_text("Individual")
expect(staking_reward_card.get_by_test_id("locked-for")).to_have_text("0 epochs")
expect(staking_reward_card.get_by_test_id("reward-value")).to_have_text("100.00")
expect(staking_reward_card.get_by_test_id("distribution-strategy")).to_have_text("Pro rata")
expect(staking_reward_card.get_by_test_id(
"entity-scope")).to_have_text("Individual")
expect(staking_reward_card.get_by_test_id(
"locked-for")).to_have_text("0 epochs")
expect(staking_reward_card.get_by_test_id(
"reward-value")).to_have_text("100.00")
expect(staking_reward_card.get_by_test_id(
"distribution-strategy")).to_have_text("Pro rata")
expect(staking_reward_card.get_by_test_id("dispatch-metric-info")).to_have_text(
"Staking rewards"
)
expect(staking_reward_card.get_by_test_id("assessed-over")).to_have_text("1 epoch")
expect(staking_reward_card.get_by_test_id("scope")).to_have_text("Individual")
expect(staking_reward_card.get_by_test_id("staking-requirement")).to_have_text("1.00")
expect(staking_reward_card.get_by_test_id("average-position")).to_have_text("0.00")
expect(staking_reward_card.get_by_test_id(
"assessed-over")).to_have_text("1 epoch")
expect(staking_reward_card.get_by_test_id(
"scope")).to_have_text("Individual")
expect(staking_reward_card.get_by_test_id(
"staking-requirement")).to_have_text("1.00")
expect(staking_reward_card.get_by_test_id(
"average-position")).to_have_text("0.00")
+29 -7
View File
@@ -4,11 +4,10 @@ export default function Document() {
return (
<>
<Head>
{/*
meta tags
- next advised against using _document for this, so they exist in our
- single page index.page.tsx
*/}
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, user-scalable=no"
/>
{/* preload fonts */}
<link
@@ -18,15 +17,38 @@ export default function Document() {
type="font/woff"
/>
<link
rel="preload"
href="/AlphaLyrae.woff2"
as="font"
type="font/woff2"
/>
{/* icons */}
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
<link rel="apple-touch-icon" content="/favicon.ico" />
<link
rel="apple-touch-icon"
sizes="180x180"
href="/apple-touch-icon.png"
/>
<link
rel="icon"
type="image/png"
sizes="32x32"
href="/favicon-32x32.png"
/>
<link
rel="icon"
type="image/png"
sizes="16x16"
href="/favicon-16x16.png"
/>
{/* scripts */}
<script src="/theme-setter.js" type="text/javascript" async />
{/* manifest */}
<link rel="manifest" href="/apps/trading/public/manifest.json" />
<link rel="manifest" href="/manifest.json" />
</Head>
<Html>
<body
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 265 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 281 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 15 KiB

+6 -6
View File
@@ -9,14 +9,14 @@
"background_color": "#ffffff",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
"src": "/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "cover.png",
"type": "image/png",
"sizes": "192x192"
"src": "/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
]
}
+4 -2
View File
@@ -1,7 +1,9 @@
const { join } = require('path');
const { createGlobPatternsForDependencies } = require('@nx/next/tailwind');
const theme = require('../../libs/tailwindcss-config/src/theme');
const vegaCustomClasses = require('../../libs/tailwindcss-config/src/vega-custom-classes');
const { theme } = require('../../libs/tailwindcss-config/src/theme');
const {
vegaCustomClasses,
} = require('../../libs/tailwindcss-config/src/vega-custom-classes');
module.exports = {
content: [
+5 -4
View File
@@ -1,14 +1,15 @@
# Build container
ARG NODE_VERSION
FROM --platform=amd64 node:${NODE_VERSION}-alpine3.16 as build
FROM --platform=amd64 node:${NODE_VERSION}-alpine3.18 as build
WORKDIR /app
# Argument to allow building of different apps
ARG APP
ARG ENV_NAME=""
RUN apk add --update --no-cache \
make==4.3-r0 \
gcc==11.2.1_git20220219-r2 \
g++==11.2.1_git20220219-r2
git \
make==4.4.1-r1 \
gcc==12.2.1_git20220924-r10 \
g++==12.2.1_git20220924-r10
COPY . ./
RUN yarn --pure-lockfile
# work around for different build process in trading
+1 -1
View File
@@ -1,4 +1,4 @@
const { getJestProjects } = require('@nx/jest');
import { getJestProjects } from '@nx/jest';
export default {
projects: getJestProjects(),
+1 -1
View File
@@ -19,7 +19,6 @@ import {
TradingButton,
} from '@vegaprotocol/ui-toolkit';
import type { Transfer } from '@vegaprotocol/wallet';
import { normalizeTransfer } from '@vegaprotocol/wallet';
import BigNumber from 'bignumber.js';
import type { ReactNode } from 'react';
import { useCallback, useEffect, useState } from 'react';
@@ -27,6 +26,7 @@ import { Controller, useForm } from 'react-hook-form';
import { AssetOption, Balance } from '@vegaprotocol/assets';
import { AccountType, AccountTypeMapping } from '@vegaprotocol/types';
import { useTransferFeeQuery } from './__generated__/TransferFee';
import { normalizeTransfer } from './utils';
interface FormFields {
toVegaKey: string;
+26
View File
@@ -0,0 +1,26 @@
import type { Exact } from 'type-fest';
import { type Transfer } from '@vegaprotocol/wallet';
import { removeDecimal } from '@vegaprotocol/utils';
import { type AccountType } from '@vegaprotocol/types';
export const normalizeTransfer = <T extends Exact<Transfer, T>>(
address: string,
amount: string,
fromAccountType: AccountType,
toAccountType: AccountType,
asset: {
id: string;
decimals: number;
}
): Transfer => {
return {
to: address,
fromAccountType,
toAccountType,
asset: asset.id,
amount: removeDecimal(amount, asset.decimals),
// oneOff or recurring required otherwise wallet will error
// default oneOff is immediate transfer
oneOff: {},
};
};
@@ -1,10 +1,9 @@
import { Controller, type Control } from 'react-hook-form';
import type { Market } from '@vegaprotocol/markets';
import type { OrderFormValues } from '../../hooks/use-form-values';
import { toDecimal, useValidateAmount } from '@vegaprotocol/utils';
import { determinePriceStep, useValidateAmount } from '@vegaprotocol/utils';
import {
TradingFormGroup,
TradingInputError,
Tooltip,
FormGroup,
Input,
@@ -30,31 +29,7 @@ export const DealTicketPriceTakeProfitStopLoss = ({
}: DealTicketPriceTakeProfitStopLossProps) => {
const t = useT();
const validateAmount = useValidateAmount();
const priceStep = toDecimal(market?.decimalPlaces);
const renderTakeProfitError = () => {
if (takeProfitError) {
return (
<TradingInputError testId="deal-ticket-take-profit-error-message">
{takeProfitError}
</TradingInputError>
);
}
return null;
};
const renderStopLossError = () => {
if (stopLossError) {
return (
<TradingInputError testId="deal-stop-loss-error-message">
{stopLossError}
</TradingInputError>
);
}
return null;
};
const priceStep = determinePriceStep(market);
return (
<div className="mb-2">
@@ -104,9 +79,9 @@ export const DealTicketPriceTakeProfitStopLoss = ({
{...field}
/>
</FormGroup>
{fieldState.error && (
{(fieldState.error || takeProfitError) && (
<InputError testId="deal-ticket-error-message-price-take-profit">
{fieldState.error.message}
{fieldState.error?.message || takeProfitError}
</InputError>
)}
</div>
@@ -154,9 +129,9 @@ export const DealTicketPriceTakeProfitStopLoss = ({
{...field}
/>
</FormGroup>
{fieldState.error && (
{(fieldState.error || stopLossError) && (
<InputError testId="deal-ticket-error-message-price-stop-loss">
{fieldState.error.message}
{fieldState.error?.message || stopLossError}
</InputError>
)}
</div>
@@ -165,8 +140,6 @@ export const DealTicketPriceTakeProfitStopLoss = ({
</TradingFormGroup>
</div>
</div>
{renderTakeProfitError()}
{renderStopLossError()}
</div>
);
};
@@ -1,7 +1,7 @@
import { Controller, type Control } from 'react-hook-form';
import type { Market } from '@vegaprotocol/markets';
import type { OrderFormValues } from '../../hooks/use-form-values';
import { toDecimal, useValidateAmount } from '@vegaprotocol/utils';
import { useValidateAmount } from '@vegaprotocol/utils';
import {
TradingFormGroup,
TradingInput,
@@ -9,6 +9,7 @@ import {
Tooltip,
} from '@vegaprotocol/ui-toolkit';
import { useT } from '../../use-t';
import { determineSizeStep } from '@vegaprotocol/utils';
export interface DealTicketSizeIcebergProps {
control: Control<OrderFormValues>;
@@ -29,7 +30,7 @@ export const DealTicketSizeIceberg = ({
}: DealTicketSizeIcebergProps) => {
const t = useT();
const validateAmount = useValidateAmount();
const sizeStep = toDecimal(market?.positionDecimalPlaces);
const sizeStep = determineSizeStep(market);
const renderPeakSizeError = () => {
if (peakSizeError) {
@@ -8,7 +8,6 @@ import {
formatForInput,
formatValue,
removeDecimal,
toDecimal,
useValidateAmount,
} from '@vegaprotocol/utils';
import { type Control, type UseFormWatch } from 'react-hook-form';
@@ -59,6 +58,7 @@ import { KeyValue } from './key-value';
import { useDataProvider } from '@vegaprotocol/data-provider';
import { stopOrdersProvider } from '@vegaprotocol/orders';
import { useT } from '../../use-t';
import { determinePriceStep, determineSizeStep } from '@vegaprotocol/utils';
export interface StopOrderProps {
market: Market;
@@ -904,8 +904,8 @@ export const StopOrder = ({ market, marketPrice, submit }: StopOrderProps) => {
market.tradableInstrument.instrument.metadata.tags
);
const sizeStep = toDecimal(market?.positionDecimalPlaces);
const priceStep = toDecimal(market?.decimalPlaces);
const sizeStep = determineSizeStep(market);
const priceStep = determinePriceStep(market);
useController({
name: 'type',
@@ -883,7 +883,7 @@ describe('DealTicket', () => {
'deal-ticket-error-message-price'
);
expect(errorMessage).toHaveTextContent(
'Price accepts up to 2 decimal places'
'Price must be a multiple of 0.01 for this market'
);
});
});
@@ -32,7 +32,6 @@ import {
toBigNum,
removeDecimal,
useValidateAmount,
toDecimal,
formatForInput,
formatValue,
} from '@vegaprotocol/utils';
@@ -82,6 +81,7 @@ import { DocsLinks } from '@vegaprotocol/environment';
import { useT } from '../../use-t';
import { DealTicketPriceTakeProfitStopLoss } from './deal-ticket-price-tp-sl';
import uniqueId from 'lodash/uniqueId';
import { determinePriceStep, determineSizeStep } from '@vegaprotocol/utils';
export const REDUCE_ONLY_TOOLTIP =
'"Reduce only" will ensure that this order will not increase the size of an open position. When the order is matched, it will only trade enough volume to bring your open volume towards 0 but never change the direction of your position. If applied to a limit order that is not instantly filled, the order will be stopped.';
@@ -419,11 +419,12 @@ export const DealTicket = ({
},
});
const priceStep = toDecimal(market?.decimalPlaces);
const sizeStep = toDecimal(market?.positionDecimalPlaces);
const sizeStep = determineSizeStep(market);
const quoteName = getQuoteName(market);
const isLimitType = type === Schema.OrderType.TYPE_LIMIT;
const priceStep = determinePriceStep(market);
return (
<form
onSubmit={
+1
View File
@@ -11,6 +11,7 @@ export function generateMarket(override?: PartialDeep<Market>): Market {
positionDecimalPlaces: 1,
tradingMode: Schema.MarketTradingMode.TRADING_MODE_CONTINUOUS,
state: Schema.MarketState.STATE_ACTIVE,
tickSize: '1',
marketTimestamps: {
__typename: 'MarketTimestamps',
close: '',
+7 -1
View File
@@ -20,5 +20,11 @@
"jest.config.ts",
"__mocks__"
],
"include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"]
"include": [
"**/*.js",
"**/*.jsx",
"**/*.ts",
"**/*.tsx",
"../utils/src/lib/step.ts"
]
}
@@ -1,16 +0,0 @@
import { Splash } from '@vegaprotocol/ui-toolkit';
export const AppFailure = ({
title,
error,
}: {
title: string;
error?: string | null;
}) => {
return (
<Splash>
<p className="mb-4 text-xl">{title}</p>
{error && <p className="mb-8 text-sm">{error}</p>}
</Splash>
);
};
@@ -1 +0,0 @@
export * from './app-failure';
-1
View File
@@ -1,4 +1,3 @@
export * from './app-failure';
export * from './app-loader';
export * from './network-loader';
export * from './network-switcher';
@@ -40,6 +40,16 @@ const mockStatsQuery = (
vegaTime: new Date().toISOString(),
chainId: 'test-chain-id',
},
networkParametersConnection: {
edges: [
{
node: {
key: 'a',
value: '1',
},
},
],
},
},
},
});
@@ -335,6 +345,16 @@ describe('RowData', () => {
vegaTime: new Date().toISOString(),
chainId: 'test-chain-id',
},
networkParametersConnection: {
edges: [
{
node: {
key: 'a',
value: '1',
},
},
],
},
},
},
};
@@ -1,4 +1,9 @@
import { TradingRadio } from '@vegaprotocol/ui-toolkit';
import {
CopyWithTooltip,
TradingRadio,
VegaIcon,
VegaIconNames,
} from '@vegaprotocol/ui-toolkit';
import { useEffect, useState } from 'react';
import { CUSTOM_NODE_KEY } from '../../types';
import {
@@ -127,8 +132,17 @@ export const RowData = ({
return (
<>
{id !== CUSTOM_NODE_KEY && (
<div className="break-all" data-testid="node">
<div className="break-all flex gap-2" data-testid="node">
<TradingRadio id={`node-url-${id}`} value={url} label={url} />
{url.length > 0 && url !== 'custom' && (
<span className="text-muted">
<CopyWithTooltip text={url}>
<button>
<VegaIcon name={VegaIconNames.COPY} />
</button>
</CopyWithTooltip>
</span>
)}
</div>
)}
<LayoutCell
@@ -39,6 +39,19 @@ export const getMockStatisticsResult = (
blockHeight: '11',
vegaTime: new Date().toISOString(),
},
networkParametersConnection: {
__typename: 'NetworkParametersConnection',
edges: [
{
__typename: 'NetworkParameterEdge',
node: {
__typename: 'NetworkParameter',
key: 'a',
value: '1',
},
},
],
},
});
export const getMockQueryResult = (env: Networks): NodeCheckQuery => ({
@@ -48,6 +61,19 @@ export const getMockQueryResult = (env: Networks): NodeCheckQuery => ({
blockHeight: '11',
vegaTime: new Date().toISOString(),
},
networkParametersConnection: {
__typename: 'NetworkParametersConnection',
edges: [
{
__typename: 'NetworkParameterEdge',
node: {
__typename: 'NetworkParameter',
key: 'a',
value: '1',
},
},
],
},
});
function getHandler<T>(
@@ -34,6 +34,16 @@ const createDefaultMockClient = () => {
blockHeight: '100',
vegaTime: new Date().toISOString(),
},
networkParametersConnection: {
edges: [
{
node: {
key: 'something',
value: 123,
},
},
],
},
},
}),
subscribe: () => ({
@@ -183,6 +193,16 @@ describe('useEnvironment', () => {
blockHeight: '100',
vegaTime: new Date(1).toISOString(),
},
networkParametersConnection: {
edges: [
{
node: {
key: 'something',
value: 123,
},
},
],
},
},
});
}, wait);
@@ -244,6 +264,16 @@ describe('useEnvironment', () => {
blockHeight: '100',
vegaTime: new Date().toISOString(),
},
networkParametersConnection: {
edges: [
{
node: {
key: 'something',
value: 123,
},
},
],
},
},
}),
subscribe: () => ({
+72 -54
View File
@@ -1,5 +1,5 @@
import { parse as tomlParse } from 'toml';
import { isValidUrl, LocalStorage } from '@vegaprotocol/utils';
import { LocalStorage, isValidUrl } from '@vegaprotocol/utils';
import { useEffect } from 'react';
import { create } from 'zustand';
import { createClient } from '@vegaprotocol/apollo-client';
@@ -22,6 +22,7 @@ import uniq from 'lodash/uniq';
import orderBy from 'lodash/orderBy';
import first from 'lodash/first';
import { canMeasureResponseTime, measureResponseTime } from '../utils/time';
import compact from 'lodash/compact';
type Client = ReturnType<typeof createClient>;
type ClientCollection = {
@@ -70,10 +71,19 @@ const fetchConfig = async (url?: string) => {
};
/**
* Find a suitable node by running a test query and test
* Find a suitable nodes by running a test query and test
* subscription, against a list of clients, first to resolve wins
*/
const findNode = async (clients: ClientCollection): Promise<string | null> => {
const findHealthyNodes = async (nodes: string[]) => {
const clients: ClientCollection = {};
nodes.forEach((url) => {
clients[url] = createClient({
url,
cacheConfig: undefined,
retry: false,
connectToDevTools: false,
});
});
const tests = Object.entries(clients).map((args) => testNode(...args));
try {
const nodes = await Promise.all(tests);
@@ -93,11 +103,10 @@ const findNode = async (clients: ClientCollection): Promise<string | null> => {
['desc', 'desc', 'asc']
);
const best = first(ordered);
return best ? best.url : null;
return ordered;
} catch (err) {
// All tests rejected, no suitable node found
return null;
return [];
}
};
@@ -142,6 +151,15 @@ const testQuery = (
})
.then((result) => {
if (result && !result.error) {
const netParams = compact(
result.data.networkParametersConnection.edges?.map((n) => n?.node)
);
if (netParams.length === 0) {
// any node that doesn't return the network parameters is considered
// failed
resolve(false);
return;
}
const res = {
blockHeight: Number(result.data.statistics.blockHeight),
vegaTime: new Date(result.data.statistics.vegaTime),
@@ -600,32 +618,34 @@ export const useEnvironment = create<EnvStore>()((set, get) => ({
}
const state = get();
const storedUrl = LocalStorage.getItem(STORAGE_KEY);
let storedUrl = LocalStorage.getItem(STORAGE_KEY);
if (!isValidUrl(storedUrl)) {
// remove invalid data from local storage
LocalStorage.removeItem(STORAGE_KEY);
storedUrl = null;
}
let nodes: string[] | undefined;
try {
nodes = await fetchConfig(state.VEGA_CONFIG_URL);
const enrichedNodes = uniq(
[...nodes, state.VEGA_URL, storedUrl].filter(Boolean) as string[]
nodes = uniq(
compact([
// url from local storage
storedUrl,
// url from state (if set via env var)
state.VEGA_URL,
// urls from network configuration
...(await fetchConfig(state.VEGA_CONFIG_URL)),
])
);
set({ nodes: enrichedNodes });
set({ nodes });
} catch (err) {
console.warn(`Could not fetch node config from ${state.VEGA_CONFIG_URL}`);
}
// Node url found in localStorage, if its valid attempt to connect
if (storedUrl) {
if (isValidUrl(storedUrl)) {
set({ VEGA_URL: storedUrl, status: 'success' });
return;
} else {
LocalStorage.removeItem(STORAGE_KEY);
}
}
// VEGA_URL env var is set and is a valid url no need to proceed
if (state.VEGA_URL) {
set({ status: 'success' });
// skip picking up the best node if VEGA_URL env variable is set
if (state.VEGA_URL && isValidUrl(state.VEGA_URL)) {
state.setUrl(state.VEGA_URL);
return;
}
@@ -639,37 +659,35 @@ export const useEnvironment = create<EnvStore>()((set, get) => ({
return;
}
// Create a map of node urls to client instances
const clients: ClientCollection = {};
nodes.forEach((url) => {
clients[url] = createClient({
url,
cacheConfig: undefined,
retry: false,
connectToDevTools: false,
});
const healthyNodes = await findHealthyNodes(nodes);
// A requested node is a node to which the app was previously connected
// or the one set via env variable.
const requestedNodeUrl = storedUrl || state.VEGA_URL;
const bestNode = first(healthyNodes);
const requestedNode = healthyNodes.find(
(n) => requestedNodeUrl && n.url === requestedNodeUrl
);
if (!requestedNode) {
// remove unhealthy node url from local storage
LocalStorage.removeItem(STORAGE_KEY);
}
// A node's url (VEGA_URL) is either the requested node (previously
// connected or taken form env variable) or the currently best available
// node.
const url = requestedNode?.url || bestNode?.url;
if (url != null) {
state.setUrl(url);
return;
}
set({
status: 'failed',
error: 'No suitable node found',
});
// Find a suitable node to connect to by attempting a query and a
// subscription, first to fulfill both will be the resulting url.
const url = await findNode(clients);
if (url !== null) {
set({
status: 'success',
VEGA_URL: url,
});
LocalStorage.setItem(STORAGE_KEY, url);
}
// Every node failed either to make a query or retrieve data from
// a subscription
else {
set({
status: 'failed',
error: 'No node found',
});
console.warn('No suitable vega node was found');
}
console.warn('No suitable node was found');
},
}));
@@ -28,6 +28,16 @@ const createStatsMock = (
blockHeight: blockHeight.toString(),
vegaTime: '12345',
},
networkParametersConnection: {
edges: [
{
node: {
key: 'a',
value: '1',
},
},
],
},
},
},
};
@@ -1,9 +1,19 @@
query NodeCheck {
# statistics needed to get the most recent node in terms of block height
statistics {
chainId
blockHeight
vegaTime
}
# net params needed to filter out the nodes that are not suitable
networkParametersConnection {
edges {
node {
key
value
}
}
}
}
subscription NodeCheckTimeUpdate {
+9 -1
View File
@@ -6,7 +6,7 @@ const defaultOptions = {} as const;
export type NodeCheckQueryVariables = Types.Exact<{ [key: string]: never; }>;
export type NodeCheckQuery = { __typename?: 'Query', statistics: { __typename?: 'Statistics', chainId: string, blockHeight: string, vegaTime: any } };
export type NodeCheckQuery = { __typename?: 'Query', statistics: { __typename?: 'Statistics', chainId: string, blockHeight: string, vegaTime: any }, networkParametersConnection: { __typename?: 'NetworkParametersConnection', edges?: Array<{ __typename?: 'NetworkParameterEdge', node: { __typename?: 'NetworkParameter', key: string, value: string } } | null> | null } };
export type NodeCheckTimeUpdateSubscriptionVariables = Types.Exact<{ [key: string]: never; }>;
@@ -21,6 +21,14 @@ export const NodeCheckDocument = gql`
blockHeight
vegaTime
}
networkParametersConnection {
edges {
node {
key
value
}
}
}
}
`;
+13
View File
@@ -12,6 +12,19 @@ export const statisticsQuery = (
blockHeight: '11',
vegaTime: new Date().toISOString(),
},
networkParametersConnection: {
__typename: 'NetworkParametersConnection',
edges: [
{
__typename: 'NetworkParameterEdge',
node: {
__typename: 'NetworkParameter',
key: 'a',
value: '1',
},
},
],
},
};
return merge(defaultResult, override);
+1
View File
@@ -54,6 +54,7 @@ export const generateFill = (override?: PartialDeep<Trade>) => {
decimalPlaces: 5,
state: MarketState.STATE_ACTIVE,
tradingMode: MarketTradingMode.TRADING_MODE_CONTINUOUS,
tickSize: '1',
fees: {
__typename: 'Fees',
factors: {
+4 -2
View File
@@ -1,7 +1,9 @@
const { join } = require('path');
const { createGlobPatternsForDependencies } = require('@nx/react/tailwind');
const theme = require('../tailwindcss-config/src/theme');
const vegaCustomClasses = require('../tailwindcss-config/src/vega-custom-classes');
const { theme } = require('../tailwindcss-config/src/theme');
const {
vegaCustomClasses,
} = require('../tailwindcss-config/src/vega-custom-classes');
module.exports = {
content: [
@@ -22,7 +22,7 @@ export const generateFundingPayment = (
decimalPlaces: 5,
state: MarketState.STATE_ACTIVE,
tradingMode: MarketTradingMode.TRADING_MODE_CONTINUOUS,
tickSize: '1',
fees: {
__typename: 'Fees',
factors: {
+4 -2
View File
@@ -1,7 +1,9 @@
const { join } = require('path');
const { createGlobPatternsForDependencies } = require('@nx/react/tailwind');
const theme = require('../tailwindcss-config/src/theme');
const vegaCustomClasses = require('../tailwindcss-config/src/vega-custom-classes');
const { theme } = require('../tailwindcss-config/src/theme');
const {
vegaCustomClasses,
} = require('../tailwindcss-config/src/vega-custom-classes');
module.exports = {
content: [
+3 -1
View File
@@ -485,5 +485,7 @@
"See all the live games on the cards below. Every on-chain game is community funded and designed. <0>Find out how to create one</0>.": "See all the live games on the cards below. Every on-chain game is community funded and designed. <0>Find out how to create one</0>.",
"Teams can earn rewards if they meet the goals set in the on-chain trading competitions. Track your earned rewards here, and see which teams are top of the leaderboard this month.": "Teams can earn rewards if they meet the goals set in the on-chain trading competitions. Track your earned rewards here, and see which teams are top of the leaderboard this month.",
"Currently no active games on the network.": "Currently no active games on the network.",
"Currently no active teams on the network.": "Currently no active teams on the network."
"Currently no active teams on the network.": "Currently no active teams on the network.",
"It looks like you're connection is slow, try switching to another node.": "It looks like you're connection is slow, try switching to another node.",
"It appears that the connection to the node <0>{{VEGA_URL}}</0> does not return necessary data, try switching to another node.": "It appears that the connection to the node <0>{{VEGA_URL}}</0> does not return necessary data, try switching to another node."
}
+4 -2
View File
@@ -1,7 +1,9 @@
const { join } = require('path');
const { createGlobPatternsForDependencies } = require('@nx/react/tailwind');
const theme = require('../tailwindcss-config/src/theme');
const vegaCustomClasses = require('../tailwindcss-config/src/vega-custom-classes');
const { theme } = require('../tailwindcss-config/src/theme');
const {
vegaCustomClasses,
} = require('../tailwindcss-config/src/vega-custom-classes');
module.exports = {
content: [
File diff suppressed because one or more lines are too long
@@ -139,6 +139,7 @@ query MarketInfo($marketId: ID!) {
id
decimalPlaces
positionDecimalPlaces
tickSize
state
tradingMode
linearSlippageFactor
File diff suppressed because one or more lines are too long
@@ -23,6 +23,7 @@ import {
} from '@vegaprotocol/ui-toolkit';
import {
addDecimalsFormatNumber,
determinePriceStep,
formatNumber,
formatNumberPercentage,
getDateTimeFormat,
@@ -320,6 +321,7 @@ export const KeyDetailsInfoPanel = ({
marketDecimalPlaces: market.decimalPlaces,
positionDecimalPlaces: market.positionDecimalPlaces,
settlementAssetDecimalPlaces: assetDecimals,
tickSize: determinePriceStep(market),
}
: {
name: market.tradableInstrument.instrument.name,
@@ -330,6 +332,7 @@ export const KeyDetailsInfoPanel = ({
marketDecimalPlaces: market.decimalPlaces,
positionDecimalPlaces: market.positionDecimalPlaces,
settlementAssetDecimalPlaces: assetDecimals,
tickSize: determinePriceStep(market),
}
}
parentData={
@@ -14,6 +14,7 @@ export const marketInfoQuery = (
positionDecimalPlaces: 0,
state: Schema.MarketState.STATE_ACTIVE,
tradingMode: Schema.MarketTradingMode.TRADING_MODE_CONTINUOUS,
tickSize: '1',
proposal: {
__typename: 'Proposal',
id: 'market-0',
+1
View File
@@ -2,6 +2,7 @@ fragment MarketFields on Market {
id
decimalPlaces
positionDecimalPlaces
tickSize
state
tradingMode
parentMarketID
+1
View File
@@ -37,6 +37,7 @@ export const createMarketFragment = (
positionDecimalPlaces: 0,
tradingMode: Schema.MarketTradingMode.TRADING_MODE_CONTINUOUS,
state: Schema.MarketState.STATE_ACTIVE,
tickSize: '1',
marketTimestamps: {
__typename: 'MarketTimestamps',
close: null,
+4 -2
View File
@@ -1,7 +1,9 @@
const { join } = require('path');
const { createGlobPatternsForDependencies } = require('@nx/react/tailwind');
const theme = require('../tailwindcss-config/src/theme');
const vegaCustomClasses = require('../tailwindcss-config/src/vega-custom-classes');
const { theme } = require('../tailwindcss-config/src/theme');
const {
vegaCustomClasses,
} = require('../tailwindcss-config/src/vega-custom-classes');
module.exports = {
content: [
@@ -11,6 +11,7 @@ export const generateOrder = (partialOrder?: PartialDeep<Order>) => {
__typename: 'Market',
id: 'market-id',
decimalPlaces: 1,
tickSize: '1',
fees: {
__typename: 'Fees',
factors: {
@@ -21,6 +21,7 @@ export const generateStopOrder = (
__typename: 'Market',
id: 'market-id',
decimalPlaces: 1,
tickSize: '1',
fees: {
__typename: 'Fees',
factors: {
@@ -3,7 +3,6 @@ import { type AgGridReact } from 'ag-grid-react';
import { Pagination, type useDataGridEvents } from '@vegaprotocol/datagrid';
import { Splash } from '@vegaprotocol/ui-toolkit';
import { useDataProvider } from '@vegaprotocol/data-provider';
import { normalizeOrderAmendment } from '@vegaprotocol/wallet';
import { useVegaTransactionStore } from '@vegaprotocol/web3';
import type { OrderTxUpdateFieldsFragment } from '@vegaprotocol/web3';
import { OrderEditDialog } from '../order-list/order-edit-dialog';
@@ -12,6 +11,7 @@ import { OrderViewDialog } from '../order-list/order-view-dialog';
import { OrderListTable } from '../order-list';
import { ordersWithMarketProvider } from '../order-data-provider/order-data-provider';
import { useT } from '../../use-t';
import { normalizeOrderAmendment } from '../../utils';
export enum Filter {
'Open' = 'Open',
@@ -17,6 +17,7 @@ describe('OrderEditDialog', () => {
);
const editOrder = await screen.findByTestId('edit-order');
const limitPrice = within(editOrder).getByLabelText('Price');
await userEvent.clear(limitPrice);
await userEvent.type(limitPrice, '0.111111');
const submitButton = within(editOrder).getByRole('button', {
name: 'Update',
@@ -24,7 +25,7 @@ describe('OrderEditDialog', () => {
await userEvent.click(submitButton);
const inputErrorText = within(editOrder).getByTestId('input-error-text');
expect(inputErrorText).toHaveTextContent(
'Price accepts up to 1 decimal places'
'Price must be a multiple of 0.1 for this market'
);
});
});
@@ -4,6 +4,8 @@ import {
addDecimal,
addDecimalsFormatNumber,
useValidateAmount,
determinePriceStep,
determineSizeStep,
} from '@vegaprotocol/utils';
import { Size } from '@vegaprotocol/datagrid';
import * as Schema from '@vegaprotocol/types';
@@ -52,8 +54,10 @@ export const OrderEditDialog = ({
},
});
const step = toDecimal(order.market?.decimalPlaces ?? 0);
const stepSize = toDecimal(order.market?.positionDecimalPlaces ?? 0);
const step = order.market ? determinePriceStep(order.market) : toDecimal(0);
const stepSize = order.market
? determineSizeStep(order.market)
: toDecimal(0);
return (
<Dialog
@@ -117,9 +121,11 @@ export const OrderEditDialog = ({
required: t('You need to provide a price'),
validate: {
min: (value) =>
Number(value) > 0
Number(value) >= Number(step)
? true
: t('The price cannot be negative'),
: t('Price cannot be lower than {{step}}', {
step,
}),
validate: validateAmount(step, t('Price')),
},
})}
@@ -139,7 +145,11 @@ export const OrderEditDialog = ({
required: t('You need to provide a size'),
validate: {
min: (value) =>
Number(value) > 0 ? true : t('The size cannot be negative'),
Number(value) >= Number(stepSize)
? true
: t('Size cannot be lower than {{stepSize}}', {
stepSize,
}),
validate: validateAmount(stepSize, t('Size')),
},
})}
@@ -22,6 +22,7 @@ describe('OrderViewDialog', () => {
positionDecimalPlaces: 3,
state: MarketState.STATE_ACTIVE,
tradingMode: MarketTradingMode.TRADING_MODE_CONTINUOUS,
tickSize: '1',
fees: {
__typename: 'Fees',
factors: {
+56
View File
@@ -0,0 +1,56 @@
import { OrderTimeInForce } from '@vegaprotocol/types';
import { normalizeOrderAmendment } from './utils';
describe('normalizeOrderAmendment', () => {
type Order = Parameters<typeof normalizeOrderAmendment>[0];
type Market = Parameters<typeof normalizeOrderAmendment>[1];
const order: Order = {
id: '123',
timeInForce: OrderTimeInForce.TIME_IN_FORCE_GTT,
size: '100',
expiresAt: '2022-01-01T00:00:00.000Z',
};
const market: Market = {
id: '456',
decimalPlaces: 1,
positionDecimalPlaces: 1,
};
it('sets and formats order id, market id, expires and timeInForce as given', () => {
const orderAmendment = normalizeOrderAmendment(order, market, '1', '1');
expect(orderAmendment.orderId).toEqual('123');
expect(orderAmendment.marketId).toEqual('456');
expect(orderAmendment.expiresAt).toEqual('1640995200000000000');
expect(orderAmendment.timeInForce).toEqual(
OrderTimeInForce.TIME_IN_FORCE_GTT
);
});
it.each([
['1.1', 1, '11'],
['1.1', 2, '110'],
['0.001', 8, '100000'],
])('sets and formats price', (price, decimalPlaces, output) => {
const orderAmendment = normalizeOrderAmendment(
order,
{ ...market, decimalPlaces },
price,
'1'
);
expect(orderAmendment.price).toEqual(output);
});
it.each([
['9', 1, -10],
['90', 2, 8900],
['0.001', 8, 99900],
])('sets and formats size delta', (size, positionDecimalPlaces, output) => {
const orderAmendment = normalizeOrderAmendment(
order,
{ ...market, positionDecimalPlaces },
'1',
size
);
expect(orderAmendment.sizeDelta).toEqual(output);
});
});
+25
View File
@@ -0,0 +1,25 @@
import BigNumber from 'bignumber.js';
import type { Exact } from 'type-fest';
import { type OrderAmendment } from '@vegaprotocol/wallet';
import { removeDecimal, toNanoSeconds } from '@vegaprotocol/utils';
import { type Market, type Order } from '@vegaprotocol/types';
export const normalizeOrderAmendment = <T extends Exact<OrderAmendment, T>>(
order: Pick<Order, 'id' | 'timeInForce' | 'size' | 'expiresAt'>,
market: Pick<Market, 'id' | 'decimalPlaces' | 'positionDecimalPlaces'>,
price: string,
size: string
): OrderAmendment => ({
orderId: order.id,
marketId: market.id,
price: removeDecimal(price, market.decimalPlaces),
timeInForce: order.timeInForce,
sizeDelta: size
? new BigNumber(removeDecimal(size, market.positionDecimalPlaces))
.minus(order.size)
.toNumber()
: 0,
expiresAt: order.expiresAt
? toNanoSeconds(order.expiresAt) // Wallet expects timestamp in nanoseconds
: undefined,
});
+4 -2
View File
@@ -1,7 +1,9 @@
const { join } = require('path');
const { createGlobPatternsForDependencies } = require('@nx/react/tailwind');
const theme = require('../tailwindcss-config/src/theme');
const vegaCustomClasses = require('../tailwindcss-config/src/vega-custom-classes');
const { theme } = require('../tailwindcss-config/src/theme');
const {
vegaCustomClasses,
} = require('../tailwindcss-config/src/vega-custom-classes');
module.exports = {
content: [
+4 -2
View File
@@ -1,7 +1,9 @@
const { join } = require('path');
const { createGlobPatternsForDependencies } = require('@nx/react/tailwind');
const theme = require('../tailwindcss-config/src/theme');
const vegaCustomClasses = require('../tailwindcss-config/src/vega-custom-classes');
const { theme } = require('../tailwindcss-config/src/theme');
const {
vegaCustomClasses,
} = require('../tailwindcss-config/src/vega-custom-classes');
module.exports = {
content: [
+12
View File
@@ -13,6 +13,18 @@
{
"files": ["*.js", "*.jsx"],
"rules": {}
},
{
"files": ["*.json"],
"parser": "jsonc-eslint-parser",
"rules": {
"@nx/dependency-checks": [
"error",
{
"ignoredFiles": ["{projectRoot}/rollup.config.{js,ts,mjs,mts}"]
}
]
}
}
]
}
+29
View File
@@ -0,0 +1,29 @@
{
"jsc": {
"target": "es2017",
"parser": {
"syntax": "typescript",
"decorators": true,
"dynamicImport": true
},
"transform": {
"decoratorMetadata": true,
"legacyDecorator": true
},
"keepClassNames": true,
"externalHelpers": true,
"loose": true
},
"module": {
"type": "es6"
},
"sourceMaps": true,
"exclude": [
"jest.config.ts",
".*\\.spec.tsx?$",
".*\\.test.tsx?$",
"./src/jest-setup.ts$",
"./**/jest-setup.ts$",
".*.js$"
]
}
-15
View File
@@ -1,15 +0,0 @@
module.exports = {
displayName: 'tailwindcss-config',
preset: '../../jest.preset.js',
globals: {},
transform: {
'^.+\\.[tj]s$': [
'ts-jest',
{
tsconfig: '<rootDir>/tsconfig.spec.json',
},
],
},
moduleFileExtensions: ['ts', 'js', 'html'],
coverageDirectory: '../../coverage/libs/tailwindcss-config',
};
+4 -1
View File
@@ -1,4 +1,7 @@
{
"name": "@vegaprotocol/tailwindcss-config",
"version": "0.0.5"
"version": "0.0.6",
"dependencies": {
"tailwindcss": "3.3.3"
}
}
+14 -12
View File
@@ -5,28 +5,30 @@
"projectType": "library",
"targets": {
"build": {
"executor": "@nx/js:tsc",
"executor": "@nx/rollup:rollup",
"outputs": ["{options.outputPath}"],
"format": ["esm", "cjs"],
"options": {
"outputPath": "dist/libs/tailwindcss-config",
"main": "libs/tailwindcss-config/src/index.js",
"main": "libs/tailwindcss-config/src/index.ts",
"tsConfig": "libs/tailwindcss-config/tsconfig.lib.json",
"assets": ["libs/tailwindcss-config/*.md"]
"assets": [],
"project": "libs/tailwindcss-config/package.json",
"compiler": "swc",
"format": ["esm", "cjs"]
}
},
"publish": {
"command": "node tools/scripts/publish.mjs tailwindcss-config {args.ver} {args.tag}",
"dependsOn": ["build"]
},
"lint": {
"executor": "@nx/eslint:lint",
"outputs": ["{options.outputFile}"],
"options": {
"lintFilePatterns": ["libs/tailwindcss-config/**/*.js"]
}
},
"test": {
"executor": "@nx/jest:jest",
"outputs": ["{workspaceRoot}/coverage/libs/tailwindcss-config"],
"options": {
"jestConfig": "libs/tailwindcss-config/jest.config.js"
"lintFilePatterns": [
"libs/tailwindcss-config/**/*.ts",
"libs/tailwindcss-config/package.json"
]
}
}
},
-11
View File
@@ -1,11 +0,0 @@
const theme = require('./theme');
const themelite = require('./theme-lite');
const vegaCustomClasses = require('./vega-custom-classes');
const { VegaColours } = require('./vega-colours');
module.exports = {
theme,
themelite,
plugins: [vegaCustomClasses],
VegaColours,
};
+4
View File
@@ -0,0 +1,4 @@
export { theme } from './theme';
export { themeLite } from './theme-lite';
export { vegaCustomClasses } from './vega-custom-classes';
export { VegaColours } from './vega-colours';
@@ -1,8 +1,8 @@
const defaultTheme = require('tailwindcss/defaultTheme');
const colors = require('tailwindcss/colors');
const theme = require('./theme');
import defaultTheme from 'tailwindcss/defaultTheme';
import colors from 'tailwindcss/colors';
import { theme } from './theme';
module.exports = {
export const themeLite = {
...theme,
colors: {
...theme.colors,
@@ -1,4 +1,4 @@
module.exports = {
export const theme = {
screens: {
xs: '500px',
sm: '640px',
@@ -1,4 +1,4 @@
const VegaColours = {
export const VegaColours = {
yellow: {
DEFAULT: '#D7FB50',
dark: '#9BE106',
@@ -32,7 +32,3 @@ const VegaColours = {
400: '#626262',
},
};
module.exports = {
VegaColours,
};
@@ -1,8 +1,8 @@
const plugin = require('tailwindcss/plugin');
const colors = require('tailwindcss/colors');
const themelite = require('./theme-lite');
import plugin from 'tailwindcss/plugin';
import colors from 'tailwindcss/colors';
import { themeLite } from './theme-lite';
const vegaCustomClassesLite = plugin(function ({ addUtilities }) {
export const vegaCustomClassesLite = plugin(function ({ addUtilities }) {
addUtilities({
'.percent-change-up::before': {
content: ' ',
@@ -35,19 +35,19 @@ const vegaCustomClassesLite = plugin(function ({ addUtilities }) {
textTransform: 'uppercase',
textDecoration: 'none',
backgroundColor: 'rgba(0, 143, 74, 0.1)',
border: `1px solid ${themelite.colors.darkerGreen}`,
color: themelite.colors.darkerGreen,
border: `1px solid ${themeLite.colors.darkerGreen}`,
color: themeLite.colors.darkerGreen,
'&:hover': {
backgroundColor: themelite.colors.darkerGreen,
backgroundColor: themeLite.colors.darkerGreen,
color: colors.white,
},
'&.selected': {
backgroundColor: themelite.colors.darkerGreen,
backgroundColor: themeLite.colors.darkerGreen,
color: colors.white,
},
},
'.buyButtonDark': {
color: themelite.colors.darkerGreen,
color: themeLite.colors.darkerGreen,
'&:hover': {
color: colors.black,
},
@@ -59,19 +59,19 @@ const vegaCustomClassesLite = plugin(function ({ addUtilities }) {
textTransform: 'uppercase',
textDecoration: 'none',
backgroundColor: 'rgba(255, 8, 126, 0.1)',
border: `1px solid ${themelite.colors.pink}`,
color: themelite.colors.pink,
border: `1px solid ${themeLite.colors.pink}`,
color: themeLite.colors.pink,
'&:hover': {
color: colors.white,
backgroundColor: themelite.colors.pink,
backgroundColor: themeLite.colors.pink,
},
'&.selected': {
backgroundColor: themelite.colors.pink,
backgroundColor: themeLite.colors.pink,
color: colors.white,
},
},
'.sellButtonDark': {
color: themelite.colors.pink,
color: themeLite.colors.pink,
'&:hover': {
color: colors.black,
},
@@ -110,5 +110,3 @@ const vegaCustomClassesLite = plugin(function ({ addUtilities }) {
// },
});
});
module.exports = vegaCustomClassesLite;
@@ -1,8 +1,8 @@
const plugin = require('tailwindcss/plugin');
const colors = require('tailwindcss/colors');
const theme = require('./theme');
import plugin from 'tailwindcss/plugin';
import colors from 'tailwindcss/colors';
import { theme } from './theme';
const vegaCustomClasses = plugin(function ({ addUtilities }) {
export const vegaCustomClasses = plugin(function ({ addUtilities }) {
addUtilities({
'.calt': {
fontFeatureSettings: "'calt'",
@@ -32,7 +32,7 @@ const vegaCustomClasses = plugin(function ({ addUtilities }) {
'.dark .syntax-highlighter-wrapper .hljs': {
background: theme.colors.vega.cdark[900],
color: theme.colors.vega.green.DEFAULT,
border: 0,
border: '0',
},
'.syntax-highlighter-wrapper .hljs-literal': {
color: theme.colors.vega.pink.DEFAULT,
@@ -60,5 +60,3 @@ const vegaCustomClasses = plugin(function ({ addUtilities }) {
},
});
});
module.exports = vegaCustomClasses;
@@ -1,9 +0,0 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"module": "commonjs",
"types": ["jest", "node"]
},
"include": ["**/*.test.ts", "**/*.spec.ts", "**/*.d.ts"]
}
-12
View File
@@ -1,12 +0,0 @@
{
"presets": [
[
"@nx/react/babel",
{
"runtime": "automatic",
"useBuiltIns": "usage"
}
]
],
"plugins": []
}
+13 -1
View File
@@ -1,5 +1,5 @@
{
"extends": ["plugin:@nx/react", "../../.eslintrc.json"],
"extends": ["../../.eslintrc.json"],
"ignorePatterns": ["!**/*", "__generated__"],
"overrides": [
{
@@ -13,6 +13,18 @@
{
"files": ["*.js", "*.jsx"],
"rules": {}
},
{
"files": ["*.json"],
"parser": "jsonc-eslint-parser",
"rules": {
"@nx/dependency-checks": [
"error",
{
"ignoredFiles": ["{projectRoot}/rollup.config.{js,ts,mjs,mts}"]
}
]
}
}
]
}
+29
View File
@@ -0,0 +1,29 @@
{
"jsc": {
"target": "es2017",
"parser": {
"syntax": "typescript",
"decorators": true,
"dynamicImport": true
},
"transform": {
"decoratorMetadata": true,
"legacyDecorator": true
},
"keepClassNames": true,
"externalHelpers": true,
"loose": true
},
"module": {
"type": "es6"
},
"sourceMaps": true,
"exclude": [
"jest.config.ts",
".*\\.spec.tsx?$",
".*\\.test.tsx?$",
"./src/jest-setup.ts$",
"./**/jest-setup.ts$",
".*.js$"
]
}
+22 -3
View File
@@ -1,11 +1,30 @@
/* eslint-disable */
import { readFileSync } from 'fs';
// Reading the SWC compilation config and remove the "exclude"
// for the test files to be compiled by SWC
const { exclude: _, ...swcJestConfig } = JSON.parse(
readFileSync(`${__dirname}/.swcrc`, 'utf-8')
);
// disable .swcrc look-up by SWC core because we're passing in swcJestConfig ourselves.
// If we do not disable this, SWC Core will read .swcrc and won't transform our test files due to "exclude"
if (swcJestConfig.swcrc === undefined) {
swcJestConfig.swcrc = false;
}
// Uncomment if using global setup/teardown files being transformed via swc
// https://nx.dev/packages/jest/documents/overview#global-setup/teardown-with-nx-libraries
// jest needs EsModule Interop to find the default exported setup/teardown functions
// swcJestConfig.module.noInterop = false;
export default {
displayName: 'types',
preset: '../../jest.preset.js',
transform: {
'^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nx/react/plugins/jest',
'^.+\\.[tj]sx?$': ['babel-jest', { presets: ['@nx/react/babel'] }],
'^.+\\.[tj]s$': ['@swc/jest', swcJestConfig],
},
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
moduleFileExtensions: ['ts', 'js', 'html'],
testEnvironment: 'node',
coverageDirectory: '../../coverage/libs/types',
};
+4 -1
View File
@@ -1,4 +1,7 @@
{
"name": "@vegaprotocol/types",
"version": "0.0.6"
"version": "0.0.7",
"dependencies": {},
"type": "module",
"module": "./index.js"
}
+20 -15
View File
@@ -3,38 +3,34 @@
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "libs/types/src",
"projectType": "library",
"tags": [],
"targets": {
"build": {
"executor": "@nx/rollup:rollup",
"outputs": ["{options.outputPath}"],
"options": {
"outputPath": "dist/libs/types",
"main": "libs/types/src/index.ts",
"tsConfig": "libs/types/tsconfig.lib.json",
"assets": [],
"project": "libs/types/package.json",
"entryFile": "libs/types/src/index.ts",
"rollupConfig": "@nx/react/plugins/bundle-rollup",
"compiler": "babel",
"format": ["esm", "cjs"],
"assets": [
{
"glob": "libs/types/README.md",
"input": ".",
"output": "."
}
]
"compiler": "swc",
"format": ["esm"]
}
},
"publish": {
"command": "node tools/scripts/publish.mjs types {args.ver} {args.tag}",
"dependsOn": ["build"]
},
"lint": {
"executor": "@nx/eslint:lint",
"outputs": ["{options.outputFile}"],
"options": {
"lintFilePatterns": ["libs/types/**/*.{ts,tsx,js,jsx}"]
"lintFilePatterns": ["libs/types/**/*.ts", "libs/types/package.json"]
}
},
"test": {
"executor": "@nx/jest:jest",
"outputs": ["{workspaceRoot}/coverage/libs/types"],
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
"options": {
"jestConfig": "libs/types/jest.config.ts"
}
@@ -45,6 +41,15 @@
"commands": ["npx graphql-codegen --config=libs/types/codegen.yml"],
"parallel": false
}
},
"local-registry": {
"executor": "@nx/js:verdaccio",
"options": {
"port": 4873,
"config": ".verdaccio/config.yml",
"storage": "tmp/local-registry/storage"
}
}
}
},
"tags": []
}
+3 -5
View File
@@ -1,17 +1,15 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"jsx": "react-jsx",
"allowJs": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"module": "esnext",
"forceConsistentCasingInFileNames": true,
"strict": true,
"noImplicitOverride": true,
"noPropertyAccessFromIndexSignature": false,
"noPropertyAccessFromIndexSignature": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true
},
"files": [],
"include": [],
"references": [
{
+3 -16
View File
@@ -2,22 +2,9 @@
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"declaration": true,
"types": ["node"]
},
"files": [
"../../node_modules/@nx/react/typings/cssmodule.d.ts",
"../../node_modules/@nx/react/typings/image.d.ts"
],
"exclude": [
"**/*.spec.ts",
"**/*.test.ts",
"**/*.spec.tsx",
"**/*.test.tsx",
"**/*.spec.js",
"**/*.test.js",
"**/*.spec.jsx",
"**/*.test.jsx",
"jest.config.ts"
],
"include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"]
"include": ["src/**/*.ts"],
"exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"]
}
+4 -10
View File
@@ -6,15 +6,9 @@
"types": ["jest", "node"]
},
"include": [
"**/*.test.ts",
"**/*.spec.ts",
"**/*.test.tsx",
"**/*.spec.tsx",
"**/*.test.js",
"**/*.spec.js",
"**/*.test.jsx",
"**/*.spec.jsx",
"**/*.d.ts",
"jest.config.ts"
"jest.config.ts",
"src/**/*.test.ts",
"src/**/*.spec.ts",
"src/**/*.d.ts"
]
}
+4 -1
View File
@@ -1,4 +1,7 @@
{
"name": "@vegaprotocol/ui-toolkit",
"version": "0.12.9"
"version": "0.12.9",
"devDependencies": {
"@vegaprotocol/tailwindcss-config": "0.0.6"
}
}
+4 -2
View File
@@ -1,7 +1,9 @@
const { join } = require('path');
const { createGlobPatternsForDependencies } = require('@nx/react/tailwind');
const theme = require('../tailwindcss-config/src/theme');
const vegaCustomClasses = require('../tailwindcss-config/src/vega-custom-classes');
const { theme } = require('../tailwindcss-config/src/theme');
const {
vegaCustomClasses,
} = require('../tailwindcss-config/src/vega-custom-classes');
module.exports = {
content: [
+13 -1
View File
@@ -1,6 +1,6 @@
{
"extends": ["../../.eslintrc.json"],
"ignorePatterns": ["!**/*"],
"ignorePatterns": ["!**/*", "__generated__"],
"overrides": [
{
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
@@ -32,6 +32,18 @@
{
"files": ["*.js", "*.jsx"],
"rules": {}
},
{
"files": ["*.json"],
"parser": "jsonc-eslint-parser",
"rules": {
"@nx/dependency-checks": [
"error",
{
"ignoredFiles": ["{projectRoot}/rollup.config.{js,ts,mjs,mts}"]
}
]
}
}
]
}
+1 -3
View File
@@ -15,9 +15,7 @@
"loose": true
},
"module": {
"type": "commonjs",
"strict": true,
"noInterop": true
"type": "es6"
},
"sourceMaps": true,
"exclude": [
+21 -7
View File
@@ -1,16 +1,30 @@
/* eslint-disable */
import { readFileSync } from 'fs';
// Reading the SWC compilation config and remove the "exclude"
// for the test files to be compiled by SWC
const { exclude: _, ...swcJestConfig } = JSON.parse(
readFileSync(`${__dirname}/.swcrc`, 'utf-8')
);
// disable .swcrc look-up by SWC core because we're passing in swcJestConfig ourselves.
// If we do not disable this, SWC Core will read .swcrc and won't transform our test files due to "exclude"
if (swcJestConfig.swcrc === undefined) {
swcJestConfig.swcrc = false;
}
// Uncomment if using global setup/teardown files being transformed via swc
// https://nx.dev/packages/jest/documents/overview#global-setup/teardown-with-nx-libraries
// jest needs EsModule Interop to find the default exported setup/teardown functions
// swcJestConfig.module.noInterop = false;
export default {
displayName: 'utils',
preset: '../../jest.preset.js',
globals: {},
transform: {
'^.+\\.[tj]s$': [
'ts-jest',
{
tsconfig: '<rootDir>/tsconfig.spec.json',
},
],
'^.+\\.[tj]s$': ['@swc/jest', swcJestConfig],
},
moduleFileExtensions: ['ts', 'js', 'html'],
testEnvironment: 'jsdom',
coverageDirectory: '../../coverage/libs/utils',
};

Some files were not shown because too many files have changed in this diff Show More