Compare commits

...
Author SHA1 Message Date
Matthew Russell 72cb5b9764 fix: accounts actions hear text in test 2023-05-17 20:34:10 -07:00
Matthew Russell 8f8e509c9e chore: update e2e tests 2023-05-17 19:48:38 -07:00
Matthew Russell d7bf9f887f feat: allow transfer dialog to be opened with selected asset 2023-05-17 19:46:48 -07:00
Matthew Russell 5fab1e738c chore: add missing export for order action dropdown 2023-05-17 18:09:51 -07:00
Matthew Russell fd6a459ac3 fix: add asset id to mock position 2023-05-17 18:09:51 -07:00
Matthew Russell 4260c0508f chore: remove stray logs 2023-05-17 18:09:51 -07:00
Matthew Russell 93fa5c77e8 chore: remove unused import 2023-05-17 18:09:51 -07:00
Matthew Russell d220574d02 chore: update text 2023-05-17 18:09:51 -07:00
Matthew Russell 414483dc1f test: fix fills and orders table tests 2023-05-17 18:09:51 -07:00
Matthew Russell 6ff0358b87 feat: add logic to change actions cell width for different order list filter states 2023-05-17 18:09:51 -07:00
Matthew Russell f997ca5480 chore: update deposit to trade button logic as now we want the column smaller 2023-05-17 18:09:51 -07:00
Matthew Russell 6e3e44742f chore: add shared col defs for row actions 2023-05-17 18:09:51 -07:00
Matthew Russell fb3505b995 feat: tidy up icons 2023-05-17 18:09:51 -07:00
Matthew Russell 01c32ffd0a feat: add transfer and view asset to accounts table actions 2023-05-17 18:09:51 -07:00
Matthew Russell 5312a7e0e7 feat: update fills dropdown with buy/sell order ids 2023-05-17 18:09:51 -07:00
Matthew Russell d4e2ace760 feat: open asset dialog from position asset column 2023-05-17 18:09:51 -07:00
Matthew Russell cba5cd317d feat: add dropdown for position dropdown 2023-05-17 18:09:51 -07:00
Matthew Russell 34dbe5cb27 feat: update market active, proposed and closed lists 2023-05-17 18:09:51 -07:00
Matthew Russell 79c255c740 chore: move proposals components into correct dir 2023-05-17 18:09:51 -07:00
Matthew Russell 71bd1a097d chore: remove borders from rows 2023-05-17 18:09:51 -07:00
Matthew Russell 09d4a01b2e feat: fix size of close button and pin column 2023-05-17 18:09:51 -07:00
Matthew Russell ae31339a61 feat: add dropdown for fills, add items for accounts dropdown 2023-05-17 18:09:51 -07:00
Matthew Russell f327ccd361 chore: move market table actions to market-list lib 2023-05-17 18:09:51 -07:00
Matthew Russell 1a66518ea5 feat: add dropdown for orders table 2023-05-17 18:09:51 -07:00
Matthew Russell 6d0d163aca test: update e2e tests to test dropdown 2023-05-17 18:09:51 -07:00
Matthew Russell 34fb65ecf0 feat: updated closed table test 2023-05-17 18:09:51 -07:00
Matthew Russell 8021872a30 feat: add component to closed table 2023-05-17 18:09:51 -07:00
Matthew Russell 0ac588edba feat: add actions for market list 2023-05-17 18:09:50 -07:00
dexturr 0be934edca chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-18 00:16:39 +00:00
Matthew Russell 653688c1dd fix(governance): clear wallet state if user changes to a non existent party (#3813) 2023-05-17 19:25:14 +00:00
dexturr 34400be18a chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-17 18:09:58 +00:00
Sam Keen d4a0a4a42c fix(governance): updated page titles (#3810) 2023-05-17 16:16:19 +00:00
Joe Tsang fabf643ce7 chore(ci): fix nightly test runner (#3804) 2023-05-17 16:21:10 +01:00
Sam Keen 45e210092c fix(governance): ensure no negative overstaked penalty (#3794) 2023-05-17 14:41:55 +00:00
Ciaran McGhie 1dc3b3fd05 fix(ui-toolkit): add keys to healthbar segments (#3797) 2023-05-17 15:14:11 +01:00
Sam Keen 0a80e3e39d fix(governance): avoid unknown pubkey causing validator page error (#3755) 2023-05-17 13:21:00 +00:00
Sam Keen 7b8d9dc94b feat(governance): validator tables refocused on stake (#3780) 2023-05-17 14:14:23 +01:00
Daniel c0320c2468 feat(ci): update DNS for mainnet console when new version is released (#3783) 2023-05-17 14:45:06 +02:00
Sam Keen 11173d6614 fix(governance): point to correct data for displayed LP rewards (#3800) 2023-05-17 12:20:51 +00:00
dexturr e3324331e2 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-17 12:11:33 +00:00
Maciek 0a6e3cb6f5 chore(trading): refactor docs links resolver (#3782) 2023-05-17 12:10:31 +02:00
Sam Keen 68ede90609 feat(3779): proposal terms in table, full proposal json, description … (#3793) 2023-05-17 08:23:25 +00:00
145 changed files with 1761 additions and 995 deletions
+2 -2
View File
@@ -20,7 +20,7 @@ jobs:
project: ${{ fromJSON(inputs.projects) }}
name: ${{ matrix.project }}
runs-on: self-hosted-runner
timeout-minutes: 40
timeout-minutes: 60
steps:
# Checks if skip cache was requested
- name: Set skip-nx-cache flag
@@ -98,4 +98,4 @@ jobs:
if: ${{ failure() }}
with:
name: test-report-${{ matrix.project }}
path: frontend-monorepo/apps/trading-e2e/cypress/reports
path: frontend-monorepo/apps/${{ matrix.project }}/cypress/reports
+25 -26
View File
@@ -191,37 +191,36 @@ jobs:
-d '{"query": "mutation{triggerDeploy(siteId:\"f8f2e051-f18e-49e6-b876-0a39369dc0d8\"){id status}}"}' \
https://api.fleek.co/graphql
- name: Checkout vega.xyz
- name: Update vega.trading DNS to redirect to the new console
if: ${{ matrix.app == 'trading' && github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') }}
uses: actions/checkout@v3
with:
repository: vegaprotocol/vega.xyz
path: './vega-xyz'
token: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }}
- name: Update hash on interstitial page
if: ${{ matrix.app == 'trading' && github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') }}
env:
GH_TOKEN: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }}
run: |
curl -L https://dist.ipfs.tech/kubo/v0.20.0/kubo_v0.20.0_linux-amd64.tar.gz -o kubo.tgz
tar -xzf kubo.tgz
export PATH="$PATH:$PWD/kubo"
which ipfs
new_hash=$(cat ${{ matrix.app }}-ipfs-hash)
cd vega-xyz
./interstital-allow-update.sh ${new_hash}
git config --global user.email "vega-ci-bot@vega.xyz"
git config --global user.name "vega-ci-bot"
git add interstitial-allow.json netlify.toml
commit_msg="feat(ci): Update CID for console release @ ${{ github.ref }}"
git commit -m "${commit_msg}"
git push origin main
new_cid=$(ipfs cid format -v 1 -b base32 $new_hash)
# branch_name=${{ github.ref_name }}-hash-update
# git checkout -b "${branch_name}"
# git add interstitial-allow.json netlify.toml
# git push -u origin "${branch_name}"
# pr_url="$(gh pr create --title "${commit_msg}" --body 'update ipfs hash for console @ ${{ github.ref }}')"
# echo $pr_url
# gh pr merge --admin --auto $pr_url
# Generate console URL
new_console_url_type=ipfs
# new_console_url_type=ipns
new_console_url_domain=cf-ipfs.com
# new_console_url_domain=dweb.link
new_console_url="https://${new_cid}.${new_console_url_type}.${new_console_url_domain}/"
echo "new_console_url=${new_console_url}"
# Update record in DNSimple
# docs: https://developer.dnsimple.com/v2/zones/records/#updateZoneRecord
dnsimple_account_id=84895
dnsimple_zone_name=vega.trading
dnsimple_record_id=44409591
# see: https://dnsimple.com/a/84895/domains/vega.trading/records/44409591/edit
curl -H 'Authorization: Bearer ${{ secrets.DNSIMPLE_API_TOKEN }}' \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-X PATCH \
-d "{
\"content\": \"${new_console_url}\"
}" \
https://api.dnsimple.com/v2/${dnsimple_account_id}/zones/${dnsimple_zone_name}/records/${dnsimple_record_id}
+1 -1
View File
@@ -49,4 +49,4 @@ cypress.env.json
.next
#cypress
/apps/trading-e2e/cypress/reports/
/apps/**/cypress/reports/
+2 -1
View File
@@ -1,10 +1,11 @@
const { defineConfig } = require('cypress');
module.exports = defineConfig({
projectId: 'et4snf',
reporter: '../../node_modules/cypress-mochawesome-reporter',
e2e: {
setupNodeEvents(on, config) {
require('cypress-mochawesome-reporter/plugin')(on);
require('@cypress/grep/src/plugin')(config);
return config;
},
+1
View File
@@ -15,5 +15,6 @@
import '@vegaprotocol/cypress';
import './common.functions.js';
import 'cypress-mochawesome-reporter/register';
import registerCypressGrep from '@cypress/grep';
registerCypressGrep();
@@ -3,6 +3,7 @@ import { Header } from './header';
import { MemoryRouter } from 'react-router-dom';
jest.mock('@vegaprotocol/environment', () => ({
...jest.requireActual('@vegaprotocol/environment'),
NetworkSwitcher: () => (
<div data-testid="network-switcher">NetworkSwitcher</div>
),
+3 -5
View File
@@ -32,9 +32,9 @@
line-height: calc(min(var(--ag-line-height, 26px), 26px) - 4px);
}
.vega-ag-grid .ag-row {
border-width: 1px 0;
border-bottom: 1px solid transparent;
.vega-ag-grid .ag-row,
.vega-ag-grid .ag-cell {
border-width: 0;
}
/* Light variables */
@@ -46,7 +46,6 @@
--ag-header-column-separator-color: theme(colors.neutral[300]);
--ag-row-border-color: theme(colors.white);
--ag-row-hover-color: theme(colors.neutral[100]);
--ag-font-size: 12px;
}
/* Dark variables */
@@ -58,7 +57,6 @@
--ag-header-column-separator-color: theme(colors.neutral[600]);
--ag-row-border-color: theme(colors.black);
--ag-row-hover-color: theme(colors.neutral[800]);
--ag-font-size: 12px;
}
.voteicon svg {
+2 -1
View File
@@ -1,10 +1,11 @@
const { defineConfig } = require('cypress');
module.exports = defineConfig({
projectId: 'et4snf',
reporter: '../../node_modules/cypress-mochawesome-reporter',
e2e: {
setupNodeEvents(on, config) {
require('cypress-mochawesome-reporter/plugin')(on);
require('@cypress/grep/src/plugin')(config);
return config;
},
@@ -63,7 +63,6 @@ context(
});
it('should have option to go to last and newest page', function () {
waitForBeginningOfEpoch();
cy.getByTestId('goto-last-page').click();
cy.getByTestId('epoch-total-rewards-table')
.last()
+1
View File
@@ -8,6 +8,7 @@ import './wallet-eth.functions.ts';
import './wallet-teardown.functions.ts';
import './wallet-vega.functions.ts';
import './proposal.functions.ts';
import 'cypress-mochawesome-reporter/register';
import registerCypressGrep from '@cypress/grep';
import { aliasGQLQuery } from '@vegaprotocol/cypress';
import { chainIdQuery, statisticsQuery } from '@vegaprotocol/mock';
+17 -4
View File
@@ -52,6 +52,7 @@ import {
} from './components/telemetry-dialog/telemetry-dialog';
import { useLocalStorage } from '@vegaprotocol/react-helpers';
import { useTranslation } from 'react-i18next';
import { isPartyNotFoundError } from './lib/party';
const cache: InMemoryCacheConfig = {
typePolicies: {
@@ -211,24 +212,36 @@ const AppContainer = () => {
enabled: true,
environment: VEGA_ENV,
release: GIT_COMMIT_HASH,
beforeSend(event) {
beforeSend(event, hint) {
const error = hint?.originalException;
const errorIsString = typeof error === 'string';
const errorIsObject = error instanceof Error;
const requestUrl = event.request?.url;
const transaction = event.transaction;
if (
(errorIsString && isPartyNotFoundError({ message: error })) ||
(errorIsObject && isPartyNotFoundError(error))
) {
// This error is caused by a pubkey making an API request before
// it has interacted with the chain. This isn't needed in Sentry.
return null;
}
const updatedRequest =
requestUrl && requestUrl.includes('/test?')
requestUrl && requestUrl.includes('/claim?')
? { ...event.request, url: removeQueryParams(requestUrl) }
: event.request;
const updatedTransaction =
transaction && transaction.includes('/test?')
transaction && transaction.includes('/claim?')
? removeQueryParams(transaction)
: transaction;
const updatedBreadcrumbs = event.breadcrumbs?.map((breadcrumb) => {
if (
breadcrumb.type === 'navigation' &&
breadcrumb.data?.to?.includes('/test?')
breadcrumb.data?.to?.includes('/claim?')
) {
return {
...breadcrumb,
@@ -1,6 +1,6 @@
import { Link } from '@vegaprotocol/ui-toolkit';
import { useTranslation } from 'react-i18next';
import { ExternalLinks } from '@vegaprotocol/utils';
import { ExternalLinks } from '@vegaprotocol/environment';
export const DownloadWalletPrompt = () => {
const { t } = useTranslation();
@@ -26,6 +26,7 @@ import type {
WalletDelegationFieldsFragment,
} from './__generated__/Delegations';
import { DelegationsDocument } from './__generated__/Delegations';
import { isPartyNotFoundError } from '../../lib/party';
export const usePollForDelegations = () => {
const { token: vegaToken } = useContracts();
@@ -75,6 +76,7 @@ export const usePollForDelegations = () => {
})
.then((res) => {
if (!mounted) return;
const canonisedDelegations = removePaginationWrapper(
res.data.party?.delegationsConnection?.edges
);
@@ -203,6 +205,15 @@ export const usePollForDelegations = () => {
setDelegatedNodes(delegatedAmounts);
})
.catch((err: Error) => {
// if party isn't found, dont log to Sentry, just clear state as, user
// will not have any delagations or accounts
if (isPartyNotFoundError(err)) {
setDelegations([]);
setAccounts([]);
setDelegatedNodes([]);
setCurrentStakeAvailable(new BigNumber(0));
return;
}
Sentry.captureException(err);
// If query fails stop interval. Its almost certain that the query
// will just continue to fail
@@ -594,7 +594,9 @@
"numberOfAgainstVotes": "Number of votes against",
"yesPercentage": "Yes percentage",
"noPercentage": "No percentage",
"proposalTerms": "Proposal terms",
"proposalJson": "Full proposal JSON",
"proposalDetails": "Proposal details",
"proposalDescription": "Description",
"currentlySetTo": "Currently expected to ",
"currently": "currently",
"finalOutcomeMayDiffer": "Final outcome may differ",
+8
View File
@@ -0,0 +1,8 @@
export const PARTY_NOT_FOUND = 'failed to get party for ID';
export const isPartyNotFoundError = (error: { message: string }) => {
if (error.message.includes(PARTY_NOT_FOUND)) {
return true;
}
return false;
};
+2 -1
View File
@@ -12,7 +12,8 @@ import { useRefreshAfterEpoch } from '../../hooks/use-refresh-after-epoch';
import { ProposalsListItem } from '../proposals/components/proposals-list-item';
import { ProtocolUpgradeProposalsListItem } from '../proposals/components/protocol-upgrade-proposals-list-item/protocol-upgrade-proposals-list-item';
import Routes from '../routes';
import { ExternalLinks, removePaginationWrapper } from '@vegaprotocol/utils';
import { ExternalLinks } from '@vegaprotocol/environment';
import { removePaginationWrapper } from '@vegaprotocol/utils';
import { useNodesQuery } from '../staking/home/__generated__/Nodes';
import { useProposalsQuery } from '../proposals/proposals/__generated__/Proposals';
import {
@@ -0,0 +1 @@
export { ProposalDescription } from './proposal-description';
@@ -0,0 +1,51 @@
import ReactMarkdown from 'react-markdown';
import classnames from 'classnames';
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Icon, RoundedWrapper } from '@vegaprotocol/ui-toolkit';
import { SubHeading } from '../../../../components/heading';
export const ProposalDescription = ({
description,
}: {
description: string;
}) => {
const { t } = useTranslation();
const [showDescription, setShowDescription] = useState(false);
const showDescriptionIconClasses = classnames('mb-4', {
'rotate-180': showDescription,
});
return (
<section data-testid="proposal-description">
<button
onClick={() => setShowDescription(!showDescription)}
data-testid="proposal-description-toggle"
>
<div className="flex items-center gap-3">
<SubHeading title={t('proposalDescription')} />
<div className={showDescriptionIconClasses}>
<Icon name="chevron-down" size={8} />
</div>
</div>
</button>
{showDescription && (
<RoundedWrapper paddingBottom={true} marginBottomLarge={true}>
<div className="p-2">
<ReactMarkdown
className="react-markdown-container"
/* Prevents HTML embedded in the description from rendering */
skipHtml={true}
/* Stops users embedding images which could be used for tracking */
disallowedElements={['img']}
linkTarget="_blank"
>
{description}
</ReactMarkdown>
</div>
</RoundedWrapper>
)}
</section>
);
};
@@ -206,28 +206,6 @@ describe('Proposal header', () => {
).not.toBeInTheDocument();
});
it('Renders Freeform proposal - long rationale (105 chars) - details', () => {
renderComponent(
generateProposal({
id: 'long',
rationale: {
title: '0x0',
description:
'Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Aenean dolor.',
},
terms: {
change: {
__typename: 'NewFreeform',
},
},
}),
false
);
expect(screen.getByTestId('proposal-description')).toHaveTextContent(
/Class aptent/
);
});
// Remove once proposals have rationale and re-enable above tests
it('Renders Freeform proposal - id for title', () => {
renderComponent(
@@ -5,7 +5,6 @@ import { Heading, SubHeading } from '../../../../components/heading';
import type { ReactNode } from 'react';
import type { ProposalFieldsFragment } from '../../proposals/__generated__/Proposals';
import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
import ReactMarkdown from 'react-markdown';
import { truncateMiddle } from '../../../../lib/truncate-middle';
import { CurrentProposalState } from '../current-proposal-state';
import { ProposalInfoLabel } from '../proposal-info-label';
@@ -23,12 +22,7 @@ export const ProposalHeader = ({
let details: ReactNode;
let proposalType = '';
let title = proposal?.rationale.title.trim();
let description = proposal?.rationale.description.trim();
if (title?.length === 0 && description && description.length > 0) {
title = description;
description = '';
}
const title = proposal?.rationale.title.trim();
const titleContent = shorten(title ?? '', 100);
@@ -145,23 +139,6 @@ export const ProposalHeader = ({
{details}
</div>
)}
{description && !isListItem && (
<div data-testid="proposal-description">
{/*<div className="uppercase mr-2">{t('ProposalDescription')}:</div>*/}
<SubHeading title={t('ProposalDescription')} />
<ReactMarkdown
className="react-markdown-container"
/* Prevents HTML embedded in the description from rendering */
skipHtml={true}
/* Stops users embedding images which could be used for tracking */
disallowedElements={['img']}
linkTarget="_blank"
>
{description}
</ReactMarkdown>
</div>
)}
</>
);
};
@@ -0,0 +1 @@
export { ProposalJson } from './proposal-json';
@@ -1,15 +1,15 @@
import classnames from 'classnames';
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Icon, SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
import { SubHeading } from '../../../../components/heading';
import type { PartialDeep } from 'type-fest';
import type * as Schema from '@vegaprotocol/types';
import { useState } from 'react';
import classnames from 'classnames';
import type { ProposalFieldsFragment } from '../../proposals/__generated__/Proposals';
import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
export const ProposalTermsJson = ({
terms,
export const ProposalJson = ({
proposal,
}: {
terms: PartialDeep<Schema.ProposalTerms>;
proposal: ProposalFieldsFragment | ProposalQuery['proposal'];
}) => {
const { t } = useTranslation();
const [showDetails, setShowDetails] = useState(false);
@@ -18,20 +18,20 @@ export const ProposalTermsJson = ({
});
return (
<section>
<section data-testid="proposal-json">
<button
onClick={() => setShowDetails(!showDetails)}
data-testid="proposal-terms-toggle"
data-testid="proposal-json-toggle"
>
<div className="flex items-center gap-3">
<SubHeading title={t('proposalTerms')} />
<SubHeading title={t('proposalJson')} />
<div className={showDetailsIconClasses}>
<Icon name="chevron-down" size={8} />
</div>
</div>
</button>
{showDetails && <SyntaxHighlighter data={terms} />}
{showDetails && <SyntaxHighlighter data={proposal} />}
</section>
);
};
@@ -1 +0,0 @@
export { ProposalTermsJson } from './proposal-terms-json';
@@ -0,0 +1 @@
export { ProposalTerms } from './proposal-terms';
@@ -0,0 +1,142 @@
import {
RoundedWrapper,
KeyValueTable,
KeyValueTableRow,
Icon,
} from '@vegaprotocol/ui-toolkit';
import { BigNumber } from '../../../../lib/bignumber';
import { SubHeading } from '../../../../components/heading';
import { useTranslation } from 'react-i18next';
import { useState } from 'react';
import classnames from 'classnames';
interface ProposalTermsProps {
data: Record<string, unknown>;
}
const getParsedValue = (value: unknown) => {
if (typeof value === 'string') {
try {
// Check if value is a number string - if so use bignumber to maintain precision
if (/^\d+(\.\d+)?$/.test(value)) {
return new BigNumber(value).toString();
} else {
// This would convert, for example, a JSON object ('{"key":"value"}')
// into an actual JS object ({key: "value"})
return JSON.parse(value);
}
} catch (error) {
return value;
}
} else {
return value;
}
};
const RenderKeyValue = ({
title,
value,
}: {
title: string;
value: string | number;
}) => (
<KeyValueTable>
<KeyValueTableRow>
{title}
{value}
</KeyValueTableRow>
</KeyValueTable>
);
const RenderArray = ({ title, array }: { title: string; array: unknown[] }) => {
if (array.every((item) => typeof item === 'string')) {
return <RenderKeyValue title={title} value={array.join(', ')} />;
} else {
return (
<div>
<div className="mb-2">{title}</div>
{array.map((item, index) => (
<div key={index}>
<ProposalTermsRenderer data={item as Record<string, unknown>} />
</div>
))}
</div>
);
}
};
// Working with 'unknown' type as a proposal's terms can be in many shapes
const RenderTerm = ({ title, value }: { title: string; value: unknown }) => {
const parsedValue = getParsedValue(value);
if (parsedValue === null || typeof parsedValue === 'boolean') {
return <RenderKeyValue title={title} value={String(parsedValue)} />;
} else if (
typeof parsedValue === 'string' ||
typeof parsedValue === 'number'
) {
return <RenderKeyValue title={title} value={parsedValue} />;
} else if (typeof parsedValue === 'object') {
if (Array.isArray(parsedValue)) {
return <RenderArray title={title} array={parsedValue} />;
} else {
return (
<div>
<div className="my-2">{title}</div>
<ProposalTermsRenderer
data={parsedValue as Record<string, unknown>}
/>
</div>
);
}
} else if (parsedValue === undefined) {
return <span>{'undefined'}</span>;
} else {
return <span>{String(parsedValue)}</span>;
}
};
const ProposalTermsRenderer = ({ data }: ProposalTermsProps) => {
return (
<RoundedWrapper paddingBottom={true}>
{Object.keys(data)
.filter(
(key) =>
!['__typename', 'closingDatetime', 'enactmentDatetime'].includes(
key
)
)
.map((key, index) => (
<div key={index}>
<RenderTerm title={key} value={data[key]} />
</div>
))}
</RoundedWrapper>
);
};
export const ProposalTerms = ({ data }: ProposalTermsProps) => {
const { t } = useTranslation();
const [showTerms, setShowTerms] = useState(false);
const showTermsIconClasses = classnames('mb-4', {
'rotate-180': showTerms,
});
return (
<section data-testid="proposal-terms">
<button
onClick={() => setShowTerms(!showTerms)}
data-testid="proposal-terms-toggle"
>
<div className="flex items-center gap-3">
<SubHeading title={t('proposalDetails')} />
<div className={showTermsIconClasses}>
<Icon name="chevron-down" size={8} />
</div>
</div>
</button>
{showTerms && <ProposalTermsRenderer data={data} />}
</section>
);
};
@@ -25,8 +25,11 @@ jest.mock('../proposal-detail-header/proposal-header', () => ({
jest.mock('../proposal-change-table', () => ({
ProposalChangeTable: () => <div data-testid="proposal-change-table"></div>,
}));
jest.mock('../proposal-terms-json', () => ({
ProposalTermsJson: () => <div data-testid="proposal-terms-json"></div>,
jest.mock('../proposal-json', () => ({
ProposalJson: () => <div data-testid="proposal-json"></div>,
}));
jest.mock('../proposal-terms/proposal-terms', () => ({
ProposalTerms: () => <div data-testid="proposal-terms"></div>,
}));
jest.mock('../proposal-votes-table', () => ({
ProposalVotesTable: () => <div data-testid="proposal-votes-table"></div>,
@@ -49,7 +52,8 @@ it('renders each section', async () => {
render(<Proposal proposal={proposal as ProposalQuery['proposal']} />);
expect(await screen.findByTestId('proposal-header')).toBeInTheDocument();
expect(screen.getByTestId('proposal-change-table')).toBeInTheDocument();
expect(screen.getByTestId('proposal-terms-json')).toBeInTheDocument();
expect(screen.getByTestId('proposal-json')).toBeInTheDocument();
expect(screen.getByTestId('proposal-terms')).toBeInTheDocument();
expect(screen.getByTestId('proposal-votes-table')).toBeInTheDocument();
expect(screen.getByTestId('proposal-vote-details')).toBeInTheDocument();
expect(screen.queryByTestId('proposal-list-asset')).not.toBeInTheDocument();
@@ -6,8 +6,10 @@ import { AsyncRenderer, RoundedWrapper } from '@vegaprotocol/ui-toolkit';
import { ProposalHeader } from '../proposal-detail-header/proposal-header';
import type { ProposalFieldsFragment } from '../../proposals/__generated__/Proposals';
import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
import { ProposalDescription } from '../proposal-description';
import { ProposalChangeTable } from '../proposal-change-table';
import { ProposalTermsJson } from '../proposal-terms-json';
import { ProposalJson } from '../proposal-json';
import { ProposalTerms } from '../proposal-terms';
import { ProposalVotesTable } from '../proposal-votes-table';
import { VoteDetails } from '../vote-details';
import { ListAsset } from '../list-asset';
@@ -20,7 +22,7 @@ export enum ProposalType {
PROPOSAL_NETWORK_PARAMETER = 'PROPOSAL_NETWORK_PARAMETER',
PROPOSAL_FREEFORM = 'PROPOSAL_FREEFORM',
}
interface ProposalProps {
export interface ProposalProps {
proposal: ProposalFieldsFragment | ProposalQuery['proposal'];
}
@@ -78,9 +80,11 @@ export const Proposal = ({ proposal }: ProposalProps) => {
<AsyncRenderer data={params} loading={loading} error={error}>
<section data-testid="proposal">
<ProposalHeader proposal={proposal} isListItem={false} />
<div className="my-10">
<ProposalChangeTable proposal={proposal} />
</div>
{proposal.terms.change.__typename === 'NewAsset' &&
proposal.terms.change.source.__typename === 'ERC20' &&
proposal.id ? (
@@ -90,7 +94,20 @@ export const Proposal = ({ proposal }: ProposalProps) => {
lifetimeLimit={proposal.terms.change.source.lifetimeLimit}
/>
) : null}
<div className="mb-12">
<div className="mb-4">
<ProposalDescription description={proposal.rationale.description} />
</div>
<div className="mb-4">
<ProposalTerms data={proposal.terms} />
</div>
<div className="mb-6">
<ProposalJson proposal={proposal} />
</div>
<div className="mb-10">
<RoundedWrapper paddingBottom={true}>
<VoteDetails
proposal={proposal}
@@ -102,10 +119,10 @@ export const Proposal = ({ proposal }: ProposalProps) => {
/>
</RoundedWrapper>
</div>
<div className="mb-4">
<ProposalVotesTable proposal={proposal} proposalType={proposalType} />
</div>
<ProposalTermsJson terms={proposal.terms} />
</section>
</AsyncRenderer>
);
@@ -8,12 +8,11 @@ import { ProposalsListFilter } from '../proposals-list-filter';
import Routes from '../../../routes';
import { Button, VegaIcon, VegaIconNames } from '@vegaprotocol/ui-toolkit';
import { Link } from 'react-router-dom';
import { createDocsLinks, ExternalLinks } from '@vegaprotocol/utils';
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
import type { ProposalQuery } from '../../proposal/__generated__/Proposal';
import type { ProposalFieldsFragment } from '../../proposals/__generated__/Proposals';
import type { ProtocolUpgradeProposalFieldsFragment } from '@vegaprotocol/proposals';
import { useEnvironment } from '@vegaprotocol/environment';
import { DocsLinks, ExternalLinks } from '@vegaprotocol/environment';
interface ProposalsListProps {
proposals: Array<ProposalFieldsFragment | ProposalQuery['proposal']>;
@@ -36,7 +35,6 @@ export const ProposalsList = ({
protocolUpgradeProposals,
lastBlockHeight,
}: ProposalsListProps) => {
const { VEGA_DOCS_URL } = useEnvironment();
const { t } = useTranslation();
const [filterString, setFilterString] = useState('');
const sortedProposals = proposals.reduce(
@@ -83,9 +81,9 @@ export const ProposalsList = ({
marginBottom={false}
title={t('pageTitleProposals')}
/>
{VEGA_DOCS_URL && (
{DocsLinks && (
<div className="xs:justify-self-end" data-testid="new-proposal-link">
<ExternalLink href={createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE}>
<ExternalLink href={DocsLinks.PROPOSALS_GUIDE}>
<Button variant="primary" size="sm">
<div className="flex items-center gap-1">
{t('NewProposal')}
@@ -2,9 +2,10 @@ import { render, screen } from '@testing-library/react';
import { ProposalFormTerms } from './proposal-form-terms';
jest.mock('@vegaprotocol/environment', () => ({
useEnvironment: () => ({
VEGA_DOCS_URL: 'https://docs.vega.xyz',
}),
...jest.requireActual('@vegaprotocol/environment'),
DocsLinks: {
PROPOSALS_GUIDE: 'https://docs.vega.xyz/tutorials/proposals',
},
}));
const renderComponent = () => {
@@ -5,8 +5,7 @@ import {
ExternalLink,
TextArea,
} from '@vegaprotocol/ui-toolkit';
import { createDocsLinks } from '@vegaprotocol/utils';
import { useEnvironment } from '@vegaprotocol/environment';
import { DocsLinks } from '@vegaprotocol/environment';
import type { UseFormRegisterReturn } from 'react-hook-form';
interface ProposalFormTermsProps {
@@ -22,23 +21,20 @@ export const ProposalFormTerms = ({
labelOverride,
docsLink,
}: ProposalFormTermsProps) => {
const { VEGA_DOCS_URL } = useEnvironment();
const { t } = useTranslation();
return (
<FormGroup
label={labelOverride || t('ProposalTerms')}
labelFor="proposal-terms"
>
{docsLink && VEGA_DOCS_URL && (
{docsLink && DocsLinks && (
<div className="mt-[-4px] mb-2 text-sm font-light">
<span className="mr-1">{t('ProposalTermsText')}</span>
<ExternalLink
href={`${
createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE
}${docsLink}`}
href={`${DocsLinks.PROPOSALS_GUIDE}${docsLink}`}
target="_blank"
>
{`${createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE}${docsLink}`}
{`${DocsLinks.PROPOSALS_GUIDE}${docsLink}`}
</ExternalLink>
</div>
)}
@@ -10,9 +10,10 @@ import type { MockedResponse } from '@apollo/client/testing';
import { NetworkParamsDocument } from '@vegaprotocol/network-parameters';
jest.mock('@vegaprotocol/environment', () => ({
useEnvironment: () => ({
VEGA_DOCS_URL: 'https://docs.vega.xyz',
}),
...jest.requireActual('@vegaprotocol/environment'),
DocsLinks: {
PROPOSALS_GUIDE: 'https://docs.vega.xyz/tutorials/proposals',
},
}));
const updateMarketNetworkParamsQueryMock: MockedResponse<NetworkParamsQuery> = {
@@ -5,7 +5,7 @@ import {
useProposalSubmit,
deadlineToRoundedHours,
} from '@vegaprotocol/proposals';
import { useEnvironment } from '@vegaprotocol/environment';
import { useEnvironment, DocsLinks } from '@vegaprotocol/environment';
import {
ProposalFormDescription,
ProposalFormSubheader,
@@ -17,7 +17,6 @@ import {
import { ProposalMinRequirements } from '../../components/shared';
import { AsyncRenderer, ExternalLink } from '@vegaprotocol/ui-toolkit';
import { Heading } from '../../../../components/heading';
import { createDocsLinks } from '@vegaprotocol/utils';
import {
NetworkParams,
useNetworkParams,
@@ -42,7 +41,7 @@ export const ProposeFreeform = () => {
NetworkParams.governance_proposal_freeform_minProposerBalance,
NetworkParams.spam_protection_proposal_min_tokens,
]);
const { VEGA_DOCS_URL, VEGA_EXPLORER_URL } = useEnvironment();
const { VEGA_EXPLORER_URL } = useEnvironment();
const { t } = useTranslation();
const {
register,
@@ -111,17 +110,13 @@ export const ProposeFreeform = () => {
userAction={ProposalUserAction.CREATE}
/>
{VEGA_DOCS_URL && (
{DocsLinks && (
<p className="text-sm" data-testid="proposal-docs-link">
<span className="mr-1">{t('ProposalTermsText')}</span>
<ExternalLink
href={`${
createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE
}${DOCS_LINK}`}
href={`${DocsLinks.PROPOSALS_GUIDE}${DOCS_LINK}`}
target="_blank"
>{`${
createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE
}${DOCS_LINK}`}</ExternalLink>
>{`${DocsLinks.PROPOSALS_GUIDE}${DOCS_LINK}`}</ExternalLink>
</p>
)}
@@ -10,9 +10,10 @@ import { NetworkParamsDocument } from '@vegaprotocol/network-parameters';
import type { MockedResponse } from '@apollo/client/testing';
jest.mock('@vegaprotocol/environment', () => ({
useEnvironment: () => ({
VEGA_DOCS_URL: 'https://docs.vega.xyz',
}),
...jest.requireActual('@vegaprotocol/environment'),
DocsLinks: {
PROPOSALS_GUIDE: 'https://docs.vega.xyz/tutorials/proposals',
},
}));
const updateMarketNetworkParamsQueryMock: MockedResponse<NetworkParamsQuery> = {
@@ -1,10 +1,7 @@
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useForm } from 'react-hook-form';
import {
createDocsLinks,
suitableForSyntaxHighlighter,
} from '@vegaprotocol/utils';
import { suitableForSyntaxHighlighter } from '@vegaprotocol/utils';
import { useNetworkParams } from '@vegaprotocol/network-parameters';
import {
getClosingTimestamp,
@@ -12,7 +9,7 @@ import {
useProposalSubmit,
doesValueEquateToParam,
} from '@vegaprotocol/proposals';
import { useEnvironment } from '@vegaprotocol/environment';
import { useEnvironment, DocsLinks } from '@vegaprotocol/environment';
import {
ProposalFormDescription,
ProposalFormSubheader,
@@ -84,7 +81,7 @@ export const ProposeNetworkParameter = () => {
loading: networkParamsLoading,
error: networkParamsError,
} = useNetworkParams();
const { VEGA_EXPLORER_URL, VEGA_DOCS_URL } = useEnvironment();
const { VEGA_EXPLORER_URL } = useEnvironment();
const { t } = useTranslation();
const {
register,
@@ -175,17 +172,13 @@ export const ProposeNetworkParameter = () => {
userAction={ProposalUserAction.CREATE}
/>
{VEGA_DOCS_URL && (
{DocsLinks && (
<p className="text-sm" data-testid="proposal-docs-link">
<span className="mr-1">{t('ProposalTermsText')}</span>
<ExternalLink
href={`${
createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE
}${DOCS_LINK}`}
href={`${DocsLinks.PROPOSALS_GUIDE}${DOCS_LINK}`}
target="_blank"
>{`${
createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE
}${DOCS_LINK}`}</ExternalLink>
>{`${DocsLinks.PROPOSALS_GUIDE}${DOCS_LINK}`}</ExternalLink>
</p>
)}
@@ -10,9 +10,10 @@ import type { MockedResponse } from '@apollo/client/testing';
import { NetworkParamsDocument } from '@vegaprotocol/network-parameters';
jest.mock('@vegaprotocol/environment', () => ({
useEnvironment: () => ({
VEGA_DOCS_URL: 'https://docs.vega.xyz',
}),
...jest.requireActual('@vegaprotocol/environment'),
DocsLinks: {
PROPOSALS_GUIDE: 'https://docs.vega.xyz/tutorials/proposals',
},
}));
const newAssetNetworkParamsQueryMock: MockedResponse<NetworkParamsQuery> = {
@@ -7,8 +7,8 @@ import {
useProposalSubmit,
doesValueEquateToParam,
} from '@vegaprotocol/proposals';
import { useEnvironment } from '@vegaprotocol/environment';
import { createDocsLinks, validateJson } from '@vegaprotocol/utils';
import { useEnvironment, DocsLinks } from '@vegaprotocol/environment';
import { validateJson } from '@vegaprotocol/utils';
import {
NetworkParams,
useNetworkParams,
@@ -53,7 +53,7 @@ export const ProposeNewAsset = () => {
NetworkParams.governance_proposal_asset_minProposerBalance,
NetworkParams.spam_protection_proposal_min_tokens,
]);
const { VEGA_EXPLORER_URL, VEGA_DOCS_URL } = useEnvironment();
const { VEGA_EXPLORER_URL } = useEnvironment();
const { t } = useTranslation();
const {
register,
@@ -142,17 +142,13 @@ export const ProposeNewAsset = () => {
userAction={ProposalUserAction.CREATE}
/>
{VEGA_DOCS_URL && (
{DocsLinks && (
<p className="text-sm" data-testid="proposal-docs-link">
<span className="mr-1">{t('ProposalTermsText')}</span>
<ExternalLink
href={`${
createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE
}${DOCS_LINK}`}
href={`${DocsLinks.PROPOSALS_GUIDE}${DOCS_LINK}`}
target="_blank"
>{`${
createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE
}${DOCS_LINK}`}</ExternalLink>
>{`${DocsLinks.PROPOSALS_GUIDE}${DOCS_LINK}`}</ExternalLink>
</p>
)}
@@ -10,9 +10,10 @@ import type { NetworkParamsQuery } from '@vegaprotocol/network-parameters';
import { NetworkParamsDocument } from '@vegaprotocol/network-parameters';
jest.mock('@vegaprotocol/environment', () => ({
useEnvironment: () => ({
VEGA_DOCS_URL: 'https://docs.vega.xyz',
}),
...jest.requireActual('@vegaprotocol/environment'),
DocsLinks: {
PROPOSALS_GUIDE: 'https://docs.vega.xyz/tutorials/proposals',
},
}));
const newMarketNetworkParamsQueryMock: MockedResponse<NetworkParamsQuery> = {
@@ -6,8 +6,8 @@ import {
useProposalSubmit,
doesValueEquateToParam,
} from '@vegaprotocol/proposals';
import { useEnvironment } from '@vegaprotocol/environment';
import { createDocsLinks, validateJson } from '@vegaprotocol/utils';
import { useEnvironment, DocsLinks } from '@vegaprotocol/environment';
import { validateJson } from '@vegaprotocol/utils';
import {
NetworkParams,
useNetworkParams,
@@ -51,7 +51,7 @@ export const ProposeNewMarket = () => {
NetworkParams.governance_proposal_market_minProposerBalance,
NetworkParams.spam_protection_proposal_min_tokens,
]);
const { VEGA_EXPLORER_URL, VEGA_DOCS_URL } = useEnvironment();
const { VEGA_EXPLORER_URL } = useEnvironment();
const { t } = useTranslation();
const {
register,
@@ -132,17 +132,13 @@ export const ProposeNewMarket = () => {
userAction={ProposalUserAction.CREATE}
/>
{VEGA_DOCS_URL && (
{DocsLinks && (
<p className="text-sm" data-testid="proposal-docs-link">
<span className="mr-1">{t('ProposalTermsText')}</span>
<ExternalLink
href={`${
createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE
}${DOCS_LINK}`}
href={`${DocsLinks.PROPOSALS_GUIDE}${DOCS_LINK}`}
target="_blank"
>{`${
createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE
}${DOCS_LINK}`}</ExternalLink>
>{`${DocsLinks.PROPOSALS_GUIDE}${DOCS_LINK}`}</ExternalLink>
</p>
)}
@@ -2,12 +2,11 @@ import Routes from '../../routes';
import { useTranslation } from 'react-i18next';
import { Link } from 'react-router-dom';
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
import { useEnvironment } from '@vegaprotocol/environment';
import { useEnvironment, DocsLinks } from '@vegaprotocol/environment';
import { Heading } from '../../../components/heading';
import { createDocsLinks } from '@vegaprotocol/utils';
export const Propose = () => {
const { VEGA_DOCS_URL, VEGA_EXPLORER_URL } = useEnvironment();
const { VEGA_EXPLORER_URL } = useEnvironment();
const { t } = useTranslation();
return (
@@ -15,14 +14,11 @@ export const Propose = () => {
<section className="pb-6">
<Heading title={t('NewProposal')} />
<div className="text-sm">
{VEGA_DOCS_URL && (
{DocsLinks && (
<p>
<span className="mr-1">{t('ProposalTermsText')}</span>
<ExternalLink
href={createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE}
target="_blank"
>
{createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE}
<ExternalLink href={DocsLinks.PROPOSALS_GUIDE} target="_blank">
{DocsLinks.PROPOSALS_GUIDE}
</ExternalLink>
</p>
)}
@@ -1,6 +1,6 @@
import { useForm } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import { useEnvironment } from '@vegaprotocol/environment';
import { useEnvironment, DocsLinks } from '@vegaprotocol/environment';
import { Heading } from '../../../../components/heading';
import {
AsyncRenderer,
@@ -9,7 +9,7 @@ import {
InputError,
TextArea,
} from '@vegaprotocol/ui-toolkit';
import { createDocsLinks, validateJson } from '@vegaprotocol/utils';
import { validateJson } from '@vegaprotocol/utils';
import {
NetworkParams,
useNetworkParams,
@@ -39,7 +39,7 @@ export const ProposeRaw = () => {
NetworkParams.governance_proposal_freeform_minProposerBalance,
NetworkParams.spam_protection_proposal_min_tokens,
]);
const { VEGA_EXPLORER_URL, VEGA_DOCS_URL } = useEnvironment();
const { VEGA_EXPLORER_URL } = useEnvironment();
const { t } = useTranslation();
const {
register,
@@ -79,14 +79,11 @@ export const ProposeRaw = () => {
spamProtectionMin={params.spam_protection_proposal_min_tokens}
/>
{VEGA_DOCS_URL && (
{DocsLinks && (
<p className="text-sm" data-testid="proposal-docs-link">
<span className="mr-1">{t('ProposalTermsText')}</span>
<ExternalLink
href={createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE}
target="_blank"
>
{createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE}
<ExternalLink href={DocsLinks.PROPOSALS_GUIDE} target="_blank">
{DocsLinks.PROPOSALS_GUIDE}
</ExternalLink>
</p>
)}
@@ -10,9 +10,10 @@ import type { MockedResponse } from '@apollo/client/testing';
import { NetworkParamsDocument } from '@vegaprotocol/network-parameters';
jest.mock('@vegaprotocol/environment', () => ({
useEnvironment: () => ({
VEGA_DOCS_URL: 'https://docs.vega.xyz',
}),
...jest.requireActual('@vegaprotocol/environment'),
DocsLinks: {
PROPOSALS_GUIDE: 'https://docs.vega.xyz/tutorials/proposals',
},
}));
const updateAssetNetworkParamsQueryMock: MockedResponse<NetworkParamsQuery> = {
@@ -6,8 +6,8 @@ import {
useProposalSubmit,
doesValueEquateToParam,
} from '@vegaprotocol/proposals';
import { useEnvironment } from '@vegaprotocol/environment';
import { createDocsLinks, validateJson } from '@vegaprotocol/utils';
import { useEnvironment, DocsLinks } from '@vegaprotocol/environment';
import { validateJson } from '@vegaprotocol/utils';
import {
NetworkParams,
useNetworkParams,
@@ -51,7 +51,7 @@ export const ProposeUpdateAsset = () => {
NetworkParams.governance_proposal_updateAsset_minProposerBalance,
NetworkParams.spam_protection_proposal_min_tokens,
]);
const { VEGA_EXPLORER_URL, VEGA_DOCS_URL } = useEnvironment();
const { VEGA_EXPLORER_URL } = useEnvironment();
const { t } = useTranslation();
const {
register,
@@ -132,17 +132,13 @@ export const ProposeUpdateAsset = () => {
userAction={ProposalUserAction.CREATE}
/>
{VEGA_DOCS_URL && (
{DocsLinks && (
<p className="text-sm" data-testid="proposal-docs-link">
<span className="mr-1">{t('ProposalTermsText')}</span>
<ExternalLink
href={`${
createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE
}${DOCS_LINK}`}
href={`${DocsLinks.PROPOSALS_GUIDE}${DOCS_LINK}`}
target="_blank"
>{`${
createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE
}${DOCS_LINK}`}</ExternalLink>
>{`${DocsLinks.PROPOSALS_GUIDE}${DOCS_LINK}`}</ExternalLink>
</p>
)}
@@ -7,8 +7,8 @@ import {
getEnactmentTimestamp,
useProposalSubmit,
} from '@vegaprotocol/proposals';
import { useEnvironment } from '@vegaprotocol/environment';
import { createDocsLinks, validateJson } from '@vegaprotocol/utils';
import { useEnvironment, DocsLinks } from '@vegaprotocol/environment';
import { validateJson } from '@vegaprotocol/utils';
import {
NetworkParams,
useNetworkParams,
@@ -98,7 +98,7 @@ export const ProposeUpdateMarket = () => {
const [selectedMarket, setSelectedMarket] = useState<string | undefined>(
undefined
);
const { VEGA_EXPLORER_URL, VEGA_DOCS_URL } = useEnvironment();
const { VEGA_EXPLORER_URL } = useEnvironment();
const { t } = useTranslation();
const {
register,
@@ -181,17 +181,13 @@ export const ProposeUpdateMarket = () => {
userAction={ProposalUserAction.CREATE}
/>
{VEGA_DOCS_URL && (
{DocsLinks && (
<p className="text-sm" data-testid="proposal-docs-link">
<span className="mr-1">{t('ProposalTermsText')}</span>
<ExternalLink
href={`${
createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE
}${DOCS_LINK}`}
href={`${DocsLinks.PROPOSALS_GUIDE}${DOCS_LINK}`}
target="_blank"
>{`${
createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE
}${DOCS_LINK}`}</ExternalLink>
>{`${DocsLinks.PROPOSALS_GUIDE}${DOCS_LINK}`}</ExternalLink>
</p>
)}
@@ -25,7 +25,7 @@ const mockData = {
amount: '0',
percentageOfTotal: '0',
},
ACCOUNT_TYPE_FEES_LIQUIDITY: {
ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES: {
amount: '0',
percentageOfTotal: '0',
},
@@ -55,7 +55,9 @@ describe('EpochIndividualRewardsTable', () => {
expect(
getByTestId('ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES')
).toBeInTheDocument();
expect(getByTestId('ACCOUNT_TYPE_FEES_LIQUIDITY')).toBeInTheDocument();
expect(
getByTestId('ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES')
).toBeInTheDocument();
expect(
getByTestId('ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS')
).toBeInTheDocument();
@@ -24,7 +24,7 @@ describe('generateEpochIndividualRewardsList', () => {
};
const reward3: RewardFieldsFragment = {
rewardType: AccountType.ACCOUNT_TYPE_FEES_LIQUIDITY,
rewardType: AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES,
amount: '200',
percentageOfTotal: '0.2',
receivedAt: new Date(),
@@ -34,7 +34,7 @@ describe('generateEpochIndividualRewardsList', () => {
};
const reward4: RewardFieldsFragment = {
rewardType: AccountType.ACCOUNT_TYPE_FEES_LIQUIDITY,
rewardType: AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES,
amount: '100',
percentageOfTotal: '0.1',
receivedAt: new Date(),
@@ -44,7 +44,7 @@ describe('generateEpochIndividualRewardsList', () => {
};
const reward5: RewardFieldsFragment = {
rewardType: AccountType.ACCOUNT_TYPE_FEES_LIQUIDITY,
rewardType: AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES,
amount: '150',
percentageOfTotal: '0.15',
receivedAt: new Date(),
@@ -105,7 +105,7 @@ describe('generateEpochIndividualRewardsList', () => {
amount: '0',
percentageOfTotal: '0',
},
[AccountType.ACCOUNT_TYPE_FEES_LIQUIDITY]: {
[AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES]: {
amount: '0',
percentageOfTotal: '0',
},
@@ -172,7 +172,7 @@ describe('generateEpochIndividualRewardsList', () => {
amount: '0',
percentageOfTotal: '0',
},
[AccountType.ACCOUNT_TYPE_FEES_LIQUIDITY]: {
[AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES]: {
amount: '200',
percentageOfTotal: '0.2',
},
@@ -202,7 +202,7 @@ describe('generateEpochIndividualRewardsList', () => {
amount: '0',
percentageOfTotal: '0',
},
[AccountType.ACCOUNT_TYPE_FEES_LIQUIDITY]: {
[AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES]: {
amount: '0',
percentageOfTotal: '0',
},
@@ -237,7 +237,7 @@ describe('generateEpochIndividualRewardsList', () => {
amount: '0',
percentageOfTotal: '0',
},
[AccountType.ACCOUNT_TYPE_FEES_LIQUIDITY]: {
[AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES]: {
amount: '100',
percentageOfTotal: '0.1',
},
@@ -285,7 +285,7 @@ describe('generateEpochIndividualRewardsList', () => {
amount: '0',
percentageOfTotal: '0',
},
[AccountType.ACCOUNT_TYPE_FEES_LIQUIDITY]: {
[AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES]: {
amount: '150',
percentageOfTotal: '0.15',
},
@@ -320,7 +320,7 @@ describe('generateEpochIndividualRewardsList', () => {
amount: '0',
percentageOfTotal: '0',
},
[AccountType.ACCOUNT_TYPE_FEES_LIQUIDITY]: {
[AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES]: {
amount: '200',
percentageOfTotal: '0.2',
},
@@ -350,7 +350,7 @@ describe('generateEpochIndividualRewardsList', () => {
amount: '0',
percentageOfTotal: '0',
},
[AccountType.ACCOUNT_TYPE_FEES_LIQUIDITY]: {
[AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES]: {
amount: '0',
percentageOfTotal: '0',
},
@@ -395,7 +395,7 @@ describe('generateEpochIndividualRewardsList', () => {
amount: '0',
percentageOfTotal: '0',
},
[AccountType.ACCOUNT_TYPE_FEES_LIQUIDITY]: {
[AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES]: {
amount: '100',
percentageOfTotal: '0.1',
},
@@ -29,7 +29,7 @@ const rewardsList = [
amount: '0',
},
{
rewardType: AccountType.ACCOUNT_TYPE_FEES_LIQUIDITY,
rewardType: AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES,
amount: '0',
},
{
@@ -78,7 +78,9 @@ describe('EpochTotalRewardsTable', () => {
expect(
getByTestId('ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES')
).toBeInTheDocument();
expect(getByTestId('ACCOUNT_TYPE_FEES_LIQUIDITY')).toBeInTheDocument();
expect(
getByTestId('ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES')
).toBeInTheDocument();
expect(
getByTestId('ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS')
).toBeInTheDocument();
@@ -162,9 +162,10 @@ describe('generateEpochAssetRewardsList', () => {
},
],
[
AccountType.ACCOUNT_TYPE_FEES_LIQUIDITY,
AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES,
{
rewardType: AccountType.ACCOUNT_TYPE_FEES_LIQUIDITY,
rewardType:
AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES,
amount: '0',
},
],
@@ -227,7 +228,7 @@ describe('generateEpochAssetRewardsList', () => {
node: {
epoch: 2,
assetId: '1',
rewardType: AccountType.ACCOUNT_TYPE_FEES_LIQUIDITY,
rewardType: AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES,
amount: '5',
},
},
@@ -287,9 +288,10 @@ describe('generateEpochAssetRewardsList', () => {
},
],
[
AccountType.ACCOUNT_TYPE_FEES_LIQUIDITY,
AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES,
{
rewardType: AccountType.ACCOUNT_TYPE_FEES_LIQUIDITY,
rewardType:
AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES,
amount: '0',
},
],
@@ -351,9 +353,10 @@ describe('generateEpochAssetRewardsList', () => {
},
],
[
AccountType.ACCOUNT_TYPE_FEES_LIQUIDITY,
AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES,
{
rewardType: AccountType.ACCOUNT_TYPE_FEES_LIQUIDITY,
rewardType:
AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES,
amount: '5',
},
],
@@ -416,7 +419,7 @@ describe('generateEpochAssetRewardsList', () => {
node: {
epoch: 2,
assetId: '1',
rewardType: AccountType.ACCOUNT_TYPE_FEES_LIQUIDITY,
rewardType: AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES,
amount: '6',
},
},
@@ -424,7 +427,7 @@ describe('generateEpochAssetRewardsList', () => {
node: {
epoch: 2,
assetId: '1',
rewardType: AccountType.ACCOUNT_TYPE_FEES_LIQUIDITY,
rewardType: AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES,
amount: '27',
},
},
@@ -497,9 +500,10 @@ describe('generateEpochAssetRewardsList', () => {
},
],
[
AccountType.ACCOUNT_TYPE_FEES_LIQUIDITY,
AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES,
{
rewardType: AccountType.ACCOUNT_TYPE_FEES_LIQUIDITY,
rewardType:
AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES,
amount: '33',
},
],
@@ -561,9 +565,10 @@ describe('generateEpochAssetRewardsList', () => {
},
],
[
AccountType.ACCOUNT_TYPE_FEES_LIQUIDITY,
AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES,
{
rewardType: AccountType.ACCOUNT_TYPE_FEES_LIQUIDITY,
rewardType:
AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES,
amount: '0',
},
],
@@ -637,9 +642,10 @@ describe('generateEpochAssetRewardsList', () => {
},
],
[
AccountType.ACCOUNT_TYPE_FEES_LIQUIDITY,
AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES,
{
rewardType: AccountType.ACCOUNT_TYPE_FEES_LIQUIDITY,
rewardType:
AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES,
amount: '0',
},
],
@@ -11,7 +11,6 @@ import {
ExternalLink,
} from '@vegaprotocol/ui-toolkit';
import { useVegaWallet } from '@vegaprotocol/wallet';
import { createDocsLinks } from '@vegaprotocol/utils';
import {
useNetworkParams,
NetworkParams,
@@ -21,7 +20,7 @@ import { EpochCountdown } from '../../../components/epoch-countdown';
import { Heading, SubHeading } from '../../../components/heading';
import { EpochIndividualRewards } from '../epoch-individual-rewards/epoch-individual-rewards';
import { useRefreshAfterEpoch } from '../../../hooks/use-refresh-after-epoch';
import { useEnvironment } from '@vegaprotocol/environment';
import { DocsLinks } from '@vegaprotocol/environment';
import { ConnectToSeeRewards } from '../connect-to-see-rewards';
import { EpochTotalRewards } from '../epoch-total-rewards/epoch-total-rewards';
@@ -29,7 +28,6 @@ type RewardsView = 'total' | 'individual';
export const RewardsPage = () => {
const { t } = useTranslation();
const { VEGA_DOCS_URL } = useEnvironment();
const { pubKey, pubKeys } = useVegaWallet();
const [toggleRewardsView, setToggleRewardsView] =
useState<RewardsView>('total');
@@ -68,9 +66,9 @@ export const RewardsPage = () => {
<Heading title={t('pageTitleRewards')} />
<p className="mb-12">
{t('rewardsIntro')}{' '}
{VEGA_DOCS_URL && (
{DocsLinks && (
<ExternalLink
href={createDocsLinks(VEGA_DOCS_URL).REWARDS_GUIDE}
href={DocsLinks.REWARDS_GUIDE}
target="_blank"
data-testid="rewards-guide-link"
className="text-white"
@@ -26,7 +26,7 @@ export const RowAccountTypes = {
columnTitle: 'rewardsColPriceMakingHeader',
description: 'rewardsColPriceMakingTooltip',
},
[AccountType.ACCOUNT_TYPE_FEES_LIQUIDITY]: {
[AccountType.ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES]: {
columnTitle: 'rewardsColLiquidityProvisionHeader',
description: 'rewardsColLiquidityProvisionTooltip',
},
+7 -4
View File
@@ -229,7 +229,7 @@ const redirects = [
const routerConfig = [
{
path: Routes.HOME,
element: <LazyHome name="Token" />,
element: <LazyHome name="Home" />,
},
{
path: Routes.PROPOSALS,
@@ -291,7 +291,7 @@ const routerConfig = [
// Not lazy as loaded when a user first hits the site
children: [
{
element: <Home name="Home" />,
element: <Home name="Token" />,
index: true,
},
{
@@ -325,8 +325,11 @@ const routerConfig = [
},
],
},
{ path: 'associate', element: <LazyStakingAssociate /> },
{ path: 'disassociate', element: <LazyStakingDisassociate /> },
{ path: 'associate', element: <LazyStakingAssociate name="Associate" /> },
{
path: 'disassociate',
element: <LazyStakingDisassociate name="Disassociate" />,
},
],
},
{
@@ -1,12 +1,14 @@
import { useEthereumConfig } from '@vegaprotocol/web3';
import { StakingWalletsContainer } from './components/staking-wallets-container/staking-wallets-container';
import { StakingWalletsContainer } from './components/staking-wallets-container';
import { AssociatePage } from './associate-page';
import { AssociatePageNoVega } from './associate-page-no-vega';
import { Heading } from '../../../components/heading';
import React from 'react';
import { useTranslation } from 'react-i18next';
import { useDocumentTitle } from '../../../hooks/use-document-title';
import type { RouteChildProps } from '../../index';
export const AssociateContainer = () => {
export const AssociateContainer = ({ name }: RouteChildProps) => {
useDocumentTitle(name);
const { t } = useTranslation();
const { config } = useEthereumConfig();
@@ -39,7 +39,7 @@ jest.mock('@vegaprotocol/wallet', () => ({
}));
const renderComponent = () => {
return render(<Disassociate />);
return render(<Disassociate name="Disassociate" />);
};
describe('Disassociate', () => {
@@ -3,10 +3,12 @@ import { useWeb3React } from '@web3-react/core';
import { EthConnectPrompt } from '../../../components/eth-connect-prompt';
import { DisassociatePage } from './components/disassociate-page';
import { Heading } from '../../../components/heading';
import React from 'react';
import { useTranslation } from 'react-i18next';
import { useDocumentTitle } from '../../../hooks/use-document-title';
import type { RouteChildProps } from '../../index';
export const DisassociateContainer = () => {
export const DisassociateContainer = ({ name }: RouteChildProps) => {
useDocumentTitle(name);
const { t } = useTranslation();
const { account } = useWeb3React();
const { pubKey } = useVegaWallet();
@@ -1,14 +1,12 @@
import { useTranslation } from 'react-i18next';
import { EpochData } from './epoch-data';
import { useEnvironment } from '@vegaprotocol/environment';
import { DocsLinks } from '@vegaprotocol/environment';
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
import { createDocsLinks } from '@vegaprotocol/utils';
import { Heading } from '../../../components/heading';
import React from 'react';
export const Staking = () => {
const { t } = useTranslation();
const { VEGA_DOCS_URL } = useEnvironment();
return (
<>
@@ -16,9 +14,9 @@ export const Staking = () => {
<section>
<p className="mb-12">
{t('stakingIntro')}{' '}
{VEGA_DOCS_URL && (
{DocsLinks && (
<ExternalLink
href={createDocsLinks(VEGA_DOCS_URL).STAKING_GUIDE}
href={DocsLinks.STAKING_GUIDE}
target="_blank"
data-testid="staking-guide-link"
className="text-white"
@@ -131,20 +131,25 @@ export const ConsensusValidatorsTable = ({
const gridRef = useRef<AgGridReact | null>(null);
const thirdOfTotalStake = useMemo(
() => new BigNumber(totalStake).dividedBy(3),
[totalStake]
);
const nodes = useMemo(() => {
if (!data) return [];
let canonisedNodes = data
.sort((a, b) => {
const aVotingPower = new BigNumber(a.rankingScore.votingPower);
const bVotingPower = new BigNumber(b.rankingScore.votingPower);
return bVotingPower.minus(aVotingPower).toNumber();
const aStakedTotal = new BigNumber(a.stakedTotal);
const bStakedTotal = new BigNumber(b.stakedTotal);
return bStakedTotal.minus(aStakedTotal).toNumber();
})
.map((node, index) => {
const votingPowerRanking = index + 1;
const stakedTotalRanking = index + 1;
return {
...node,
votingPowerRanking,
stakedTotalRanking,
};
})
.map(
@@ -157,7 +162,7 @@ export const ConsensusValidatorsTable = ({
stakedTotal,
rankingScore: { stakeScore, votingPower },
pendingStake,
votingPowerRanking,
stakedTotalRanking,
stakedByUser,
pendingUserStake,
userStakeShare,
@@ -175,7 +180,7 @@ export const ConsensusValidatorsTable = ({
return {
id,
[ValidatorFields.RANKING_INDEX]: votingPowerRanking,
[ValidatorFields.RANKING_INDEX]: stakedTotalRanking,
[ValidatorFields.VALIDATOR]: {
avatarUrl: logo,
name,
@@ -236,16 +241,12 @@ export const ConsensusValidatorsTable = ({
return canonisedNodes;
}
// The point of identifying and hiding the group that could halt the network
// is that we assume the top 1/3 of stake is held by considerably less than
// 1/3 of the validators and we really want people not to stake any more to
// that group, because we want to make it require as many difference
// validators to collude as possible to halt the network, so we hide them.
const { topThird, remaining } = canonisedNodes.reduce(
(acc, node) => {
if (acc.cumulativeScore < 100 / 3) {
acc.cumulativeScore += parseFloat(
node[ValidatorFields.NORMALISED_VOTING_POWER]
if (acc.cumulativeScore.isLessThan(thirdOfTotalStake)) {
const prev = acc.cumulativeScore;
acc.cumulativeScore = prev.plus(
new BigNumber(node[ValidatorFields.STAKE])
);
acc.topThird.push(node);
return acc;
@@ -253,61 +254,70 @@ export const ConsensusValidatorsTable = ({
acc.remaining.push(node);
return acc;
},
{ topThird: [], remaining: [], cumulativeScore: 0 } as {
{ topThird: [], remaining: [], cumulativeScore: new BigNumber(0) } as {
topThird: CanonisedConsensusNodeProps[];
remaining: CanonisedConsensusNodeProps[];
cumulativeScore: number;
cumulativeScore: BigNumber;
}
);
// We need to combine the top third of validators into a single node, this
// way the combined values can be passed to AG grid so that the combined cell's
// values are correct for ordering.
const combinedTopThird = topThird.reduce((acc, node) => {
const {
[ValidatorFields.STAKE]: stake,
[ValidatorFields.STAKE_SHARE]: stakeShare,
[ValidatorFields.PENDING_STAKE]: pendingStake,
[ValidatorFields.NORMALISED_VOTING_POWER]: normalisedVotingPower,
[ValidatorFields.TOTAL_PENALTIES]: totalPenalties,
} = node;
const combinedTopThird = topThird.reduce(
(acc, node) => {
const {
[ValidatorFields.STAKE]: stake,
[ValidatorFields.STAKE_SHARE]: stakeShare,
[ValidatorFields.PENDING_STAKE]: pendingStake,
[ValidatorFields.NORMALISED_VOTING_POWER]: normalisedVotingPower,
[ValidatorFields.TOTAL_PENALTIES]: totalPenalties,
} = node;
const {
[ValidatorFields.STAKE]: accStake,
[ValidatorFields.STAKE_SHARE]: accStakeShare,
[ValidatorFields.PENDING_STAKE]: accPendingStake,
[ValidatorFields.NORMALISED_VOTING_POWER]: accNormalisedVotingPower,
[ValidatorFields.TOTAL_PENALTIES]: accTotalPenalties,
} = acc;
const {
[ValidatorFields.STAKE]: accStake,
[ValidatorFields.STAKE_SHARE]: accStakeShare,
[ValidatorFields.PENDING_STAKE]: accPendingStake,
[ValidatorFields.NORMALISED_VOTING_POWER]: accNormalisedVotingPower,
[ValidatorFields.TOTAL_PENALTIES]: accTotalPenalties,
} = acc;
return {
...acc,
[ValidatorFields.STAKE]: toBigNum(accStake, decimals)
.plus(toBigNum(stake, decimals))
.toString(),
[ValidatorFields.STAKE_SHARE]: formatNumberPercentage(
new BigNumber(parseFloat(accStakeShare)).plus(
new BigNumber(parseFloat(stakeShare))
return {
...acc,
[ValidatorFields.STAKE]: new BigNumber(accStake)
.plus(new BigNumber(stake))
.toString(),
[ValidatorFields.STAKE_SHARE]: formatNumberPercentage(
new BigNumber(parseFloat(accStakeShare)).plus(
new BigNumber(parseFloat(stakeShare))
),
2
),
2
),
[ValidatorFields.PENDING_STAKE]: toBigNum(accPendingStake, decimals)
.plus(toBigNum(pendingStake, decimals))
.toString(),
[ValidatorFields.NORMALISED_VOTING_POWER]: formatNumberPercentage(
new BigNumber(parseFloat(accNormalisedVotingPower)).plus(
new BigNumber(parseFloat(normalisedVotingPower))
[ValidatorFields.PENDING_STAKE]: toBigNum(accPendingStake, decimals)
.plus(toBigNum(pendingStake, decimals))
.toString(),
[ValidatorFields.NORMALISED_VOTING_POWER]: formatNumberPercentage(
new BigNumber(parseFloat(accNormalisedVotingPower)).plus(
new BigNumber(parseFloat(normalisedVotingPower))
),
2
),
2
),
[ValidatorFields.TOTAL_PENALTIES]: formatNumberPercentage(
new BigNumber(parseFloat(accTotalPenalties)).plus(
new BigNumber(parseFloat(totalPenalties))
[ValidatorFields.TOTAL_PENALTIES]: formatNumberPercentage(
new BigNumber(parseFloat(accTotalPenalties)).plus(
new BigNumber(parseFloat(totalPenalties))
),
2
),
2
),
};
});
};
},
{
[ValidatorFields.STAKE]: '0',
[ValidatorFields.STAKE_SHARE]: '0',
[ValidatorFields.PENDING_STAKE]: '0',
[ValidatorFields.NORMALISED_VOTING_POWER]: '0',
[ValidatorFields.TOTAL_PENALTIES]: '0',
}
);
return [
{
@@ -322,6 +332,7 @@ export const ConsensusValidatorsTable = ({
decimals,
hideTopThird,
previousEpochData,
thirdOfTotalStake,
totalStake,
validatorsView,
]);
@@ -352,6 +363,7 @@ export const ConsensusValidatorsTable = ({
headerTooltip: t('StakeDescription').toString(),
cellRenderer: TotalStakeRenderer,
width: 120,
sort: 'desc',
},
{
field: ValidatorFields.PENDING_STAKE,
@@ -373,7 +385,6 @@ export const ConsensusValidatorsTable = ({
headerTooltip: t('NormalisedVotingPowerDescription').toString(),
cellRenderer: VotingPowerRenderer,
width: 200,
sort: 'desc',
},
{
field: ValidatorFields.TOTAL_PENALTIES,
@@ -57,16 +57,16 @@ export const StandbyPendingValidatorsTable = ({
return data
.sort((a, b) => {
const aVotingPower = new BigNumber(a.rankingScore.votingPower);
const bVotingPower = new BigNumber(b.rankingScore.votingPower);
return bVotingPower.minus(aVotingPower).toNumber();
const aStakedTotal = new BigNumber(a.stakedTotal);
const bStakedTotal = new BigNumber(b.stakedTotal);
return bStakedTotal.minus(aStakedTotal).toNumber();
})
.map((node, index) => {
const votingPowerRanking = index + 1;
const stakedTotalRanking = index + 1;
return {
...node,
votingPowerRanking,
stakedTotalRanking,
};
})
.map(
@@ -79,7 +79,7 @@ export const StandbyPendingValidatorsTable = ({
stakedTotal,
rankingScore: { stakeScore },
pendingStake,
votingPowerRanking,
stakedTotalRanking,
stakedByUser,
pendingUserStake,
userStakeShare,
@@ -125,7 +125,7 @@ export const StandbyPendingValidatorsTable = ({
return {
id,
[ValidatorFields.RANKING_INDEX]: votingPowerRanking,
[ValidatorFields.RANKING_INDEX]: stakedTotalRanking,
[ValidatorFields.VALIDATOR]: {
avatarUrl,
name,
@@ -166,7 +166,7 @@ export const StandbyPendingValidatorsTable = ({
: undefined,
[ValidatorFields.PENDING_USER_STAKE]: pendingUserStake,
[ValidatorFields.USER_STAKE_SHARE]: userStakeShare
? formatNumberPercentage(new BigNumber(userStakeShare))
? formatNumberPercentage(new BigNumber(userStakeShare), 2)
: undefined,
};
}
@@ -210,6 +210,7 @@ export const StandbyPendingValidatorsTable = ({
headerTooltip: t('StakeDescription').toString(),
cellRenderer: TotalStakeRenderer,
width: 120,
sort: 'desc',
},
{
field: ValidatorFields.PENDING_STAKE,
@@ -233,7 +234,6 @@ export const StandbyPendingValidatorsTable = ({
}),
cellRenderer: StakeNeededForPromotionRenderer,
width: 210,
sort: 'asc',
},
{
field: ValidatorFields.TOTAL_PENALTIES,
@@ -2,12 +2,8 @@ import { useMemo, useState } from 'react';
import { Trans, useTranslation } from 'react-i18next';
import BigNumber from 'bignumber.js';
import * as Schema from '@vegaprotocol/types';
import {
createDocsLinks,
removePaginationWrapper,
toBigNum,
} from '@vegaprotocol/utils';
import { useEnvironment } from '@vegaprotocol/environment';
import { removePaginationWrapper, toBigNum } from '@vegaprotocol/utils';
import { DocsLinks } from '@vegaprotocol/environment';
import { Link as UTLink, Toggle } from '@vegaprotocol/ui-toolkit';
import { formatNumber } from '../../../../lib/format-number';
@@ -42,7 +38,6 @@ export const ValidatorTables = ({
previousEpochData,
}: ValidatorsTableProps) => {
const { t } = useTranslation();
const { VEGA_DOCS_URL } = useEnvironment();
const {
appState: { decimals },
} = useAppState();
@@ -213,12 +208,12 @@ export const ValidatorTables = ({
<>
<SubHeading title={t('status-pending')} />
<p>
{VEGA_DOCS_URL && (
{DocsLinks && (
<>
<span>{t('pendingDescription1')} </span>
<span>
<UTLink
href={createDocsLinks(VEGA_DOCS_URL).STAKING_GUIDE}
href={DocsLinks.STAKING_GUIDE}
target="_blank"
data-testid="validator-forum-link"
>
@@ -1,4 +1,3 @@
import { useEffect, useState } from 'react';
import { ENV } from '../../../config';
import { Callout, Intent, Splash } from '@vegaprotocol/ui-toolkit';
import { useVegaWallet } from '@vegaprotocol/wallet';
@@ -10,6 +9,7 @@ import { usePreviousEpochQuery } from '../__generated__/PreviousEpoch';
import type { ReactElement } from 'react';
import type { StakingQuery } from '../__generated__/Staking';
import type { PreviousEpochQuery } from '../__generated__/PreviousEpoch';
import { isPartyNotFoundError } from '../../../lib/party';
// TODO should only request a single node. When migrating from deprecated APIs we should address this.
@@ -39,21 +39,9 @@ export const NodeContainer = ({
}
: undefined,
},
errorPolicy: 'all',
});
const [isRefetching, setIsRefetching] = useState(false);
useEffect(() => {
if (error && error.message.includes('failed to get party for ID')) {
setIsRefetching(true);
// The API errors if there is a pubkey, but it hasn't interacted with the
// chain before. In that case, retry the query with empty pubKey
refetch({
partyId: '',
}).finally(() => setIsRefetching(false));
}
}, [error, refetch, delegationsPagination]);
const { data: previousEpochData } = usePreviousEpochQuery({
variables: {
epochId: (Number(data?.epoch.id) - 1).toString(),
@@ -63,7 +51,7 @@ export const NodeContainer = ({
useRefreshAfterEpoch(data?.epoch.timestamps.expiry, refetch);
if (error && !isRefetching) {
if (error && !isPartyNotFoundError(error)) {
return (
<Callout intent={Intent.Danger} title={t('Something went wrong')}>
<pre>
@@ -75,7 +63,7 @@ export const NodeContainer = ({
);
}
if (loading || isRefetching) {
if (loading) {
return (
<Splash>
<SplashLoader />
@@ -1,7 +1,11 @@
import React, { useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { useEnvironment } from '@vegaprotocol/environment';
import { createDocsLinks, ExternalLinks, toBigNum } from '@vegaprotocol/utils';
import {
useEnvironment,
DocsLinks,
ExternalLinks,
} from '@vegaprotocol/environment';
import { toBigNum } from '@vegaprotocol/utils';
import * as Schema from '@vegaprotocol/types';
import {
Link as UTLink,
@@ -64,7 +68,7 @@ export const ValidatorTable = ({
stakedTotal,
previousEpochData,
}: ValidatorTableProps) => {
const { ETHERSCAN_URL, VEGA_DOCS_URL } = useEnvironment();
const { ETHERSCAN_URL } = useEnvironment();
const { t } = useTranslation();
const {
appState: { decimals },
@@ -90,9 +94,9 @@ export const ValidatorTable = ({
<>
<p className="mb-12">
{t('validatorFormIntro')}{' '}
{VEGA_DOCS_URL && (
{DocsLinks && (
<ExternalLink
href={createDocsLinks(VEGA_DOCS_URL).STAKING_GUIDE}
href={DocsLinks.STAKING_GUIDE}
target="_blank"
data-testid="validator-table-staking-guide-link"
className="text-white"
+8 -3
View File
@@ -60,9 +60,14 @@ export const getOverstakingPenalty = (
}
return formatNumberPercentage(
new BigNumber(1)
.minus(new BigNumber(validatorScore).dividedBy(new BigNumber(stakeScore)))
.times(100),
BigNumber.max(
new BigNumber(1)
.minus(
new BigNumber(validatorScore).dividedBy(new BigNumber(stakeScore))
)
.times(100),
new BigNumber(0)
),
2
);
};
+2 -1
View File
@@ -3,7 +3,8 @@ import { Trans, useTranslation } from 'react-i18next';
import { Link } from 'react-router-dom';
import { Heading, SubHeading } from '../../components/heading';
import { ExternalLinks, toBigNum } from '@vegaprotocol/utils';
import { ExternalLinks } from '@vegaprotocol/environment';
import { toBigNum } from '@vegaprotocol/utils';
import { useAppState } from '../../contexts/app-state/app-state-context';
import { useDocumentTitle } from '../../hooks/use-document-title';
import type { RouteChildProps } from '..';
+3 -4
View File
@@ -40,9 +40,9 @@
line-height: calc(min(var(--ag-line-height, 26px), 26px) - 4px);
}
.vega-ag-grid .ag-row {
border-width: 1px 0;
border-bottom: 1px solid transparent;
.vega-ag-grid .ag-row,
.vega-ag-grid .ag-cell {
border-width: 0;
}
/* Dark variables */
@@ -54,7 +54,6 @@
--ag-header-column-separator-color: theme(colors.neutral[600]);
--ag-row-border-color: theme(colors.black);
--ag-row-hover-color: theme(colors.neutral[800]);
--ag-font-size: 12px;
}
.validators-table .ag-theme-balham-dark .ag-body-horizontal-scroll {
+324 -56
View File
@@ -36,12 +36,54 @@
"tranche_id": 58,
"tranche_start": "2023-05-11T00:00:00.000Z",
"tranche_end": "2023-06-11T00:00:00.000Z",
"total_added": "0",
"total_added": "11570",
"total_removed": "0",
"locked_amount": "0",
"deposits": [],
"locked_amount": "8953.108251194743961",
"deposits": [
{
"amount": "11447",
"user": "0x73F1955867a9b19ADFEa2cc3f425839607126ec7",
"tx": "0xd31ed81d798f6690586935dbc6e722b3d2a3b6a049be4565dc7a4894084f0a05"
},
{
"amount": "123",
"user": "0x6A228Fffda4D1B3C773b9ce38DA43592581b36FC",
"tx": "0xd6e8129942a80bb2a611c07347ed0f0917690e67cbd99cba1922b5c4aed2f179"
}
],
"withdrawals": [],
"users": []
"users": [
{
"address": "0x73F1955867a9b19ADFEa2cc3f425839607126ec7",
"deposits": [
{
"amount": "11447",
"user": "0x73F1955867a9b19ADFEa2cc3f425839607126ec7",
"tranche_id": 58,
"tx": "0xd31ed81d798f6690586935dbc6e722b3d2a3b6a049be4565dc7a4894084f0a05"
}
],
"withdrawals": [],
"total_tokens": "11447",
"withdrawn_tokens": "0",
"remaining_tokens": "11447"
},
{
"address": "0x6A228Fffda4D1B3C773b9ce38DA43592581b36FC",
"deposits": [
{
"amount": "123",
"user": "0x6A228Fffda4D1B3C773b9ce38DA43592581b36FC",
"tranche_id": 58,
"tx": "0xd6e8129942a80bb2a611c07347ed0f0917690e67cbd99cba1922b5c4aed2f179"
}
],
"withdrawals": [],
"total_tokens": "123",
"withdrawn_tokens": "0",
"remaining_tokens": "123"
}
]
},
{
"tranche_id": 57,
@@ -80,10 +122,15 @@
"tranche_id": 56,
"tranche_start": "2023-04-20T00:00:00.000Z",
"tranche_end": "2023-05-20T00:00:00.000Z",
"total_added": "19242.125",
"total_added": "20139.125",
"total_removed": "2667.900599530005",
"locked_amount": "1760.572777247300418465",
"locked_amount": "1334.85414863040152049375",
"deposits": [
{
"amount": "897",
"user": "0xfaa18BFeb7bfe6AF79Ec6dA193A8737C06163AFd",
"tx": "0x0e321b8af82bbdc845f5b6c6d3cccd68f14d23cd5d3c33c3df17ba3a4885b0bc"
},
{
"amount": "188",
"user": "0x90Cf7B9958C3BbBCddAb52Ecc408535D4f3C4241",
@@ -318,6 +365,21 @@
}
],
"users": [
{
"address": "0xfaa18BFeb7bfe6AF79Ec6dA193A8737C06163AFd",
"deposits": [
{
"amount": "897",
"user": "0xfaa18BFeb7bfe6AF79Ec6dA193A8737C06163AFd",
"tranche_id": 56,
"tx": "0x0e321b8af82bbdc845f5b6c6d3cccd68f14d23cd5d3c33c3df17ba3a4885b0bc"
}
],
"withdrawals": [],
"total_tokens": "897",
"withdrawn_tokens": "0",
"remaining_tokens": "897"
},
{
"address": "0x90Cf7B9958C3BbBCddAb52Ecc408535D4f3C4241",
"deposits": [
@@ -964,8 +1026,8 @@
"tranche_id": 54,
"tranche_start": "2023-04-06T00:00:00.000Z",
"tranche_end": "2023-05-06T00:00:00.000Z",
"total_added": "14610",
"total_removed": "7227.45090157707",
"total_added": "14658",
"total_removed": "7275.45090157707",
"locked_amount": "0",
"deposits": [
{
@@ -973,6 +1035,11 @@
"user": "0x05659B08a8079E003eE37F26c29e52532728c034",
"tx": "0x83cb92910e0725b82b3459e025260c448f931224f7cb00a376351dbd75ae2733"
},
{
"amount": "48",
"user": "0x2a65Ae527C6Ff4665e048B0E0883c486A7BA4DBc",
"tx": "0x6d708d9b252c3ef0eb41c1bb5f412ae4a644ba3483bbdb329d403728c8257794"
},
{
"amount": "111",
"user": "0x90Cf7B9958C3BbBCddAb52Ecc408535D4f3C4241",
@@ -1190,6 +1257,11 @@
"user": "0xf9c6C5F942B94Db9dedC550956865cf99D743959",
"tx": "0x4fa5d02d920d90835694cbab1e41a66d317b2bc35860d07a5ccd70d12182116b"
},
{
"amount": "48",
"user": "0x2a65Ae527C6Ff4665e048B0E0883c486A7BA4DBc",
"tx": "0x54ac8f0ed6570e6ce5fc437f15744be4be5c716c08fa7cf58d23ed93ca29dc84"
},
{
"amount": "106.53500000286",
"user": "0x6F32AA5A6198329c16e438512F992a0548C856f9",
@@ -1259,6 +1331,28 @@
"withdrawn_tokens": "90",
"remaining_tokens": "0"
},
{
"address": "0x2a65Ae527C6Ff4665e048B0E0883c486A7BA4DBc",
"deposits": [
{
"amount": "48",
"user": "0x2a65Ae527C6Ff4665e048B0E0883c486A7BA4DBc",
"tranche_id": 54,
"tx": "0x6d708d9b252c3ef0eb41c1bb5f412ae4a644ba3483bbdb329d403728c8257794"
}
],
"withdrawals": [
{
"amount": "48",
"user": "0x2a65Ae527C6Ff4665e048B0E0883c486A7BA4DBc",
"tranche_id": 54,
"tx": "0x54ac8f0ed6570e6ce5fc437f15744be4be5c716c08fa7cf58d23ed93ca29dc84"
}
],
"total_tokens": "48",
"withdrawn_tokens": "48",
"remaining_tokens": "0"
},
{
"address": "0x90Cf7B9958C3BbBCddAb52Ecc408535D4f3C4241",
"deposits": [
@@ -5045,7 +5139,7 @@
"tranche_end": "2023-12-05T00:00:00.000Z",
"total_added": "86666.297",
"total_removed": "0",
"locked_amount": "47902.6878201683513969045",
"locked_amount": "47723.0811534878766318718",
"deposits": [
{
"amount": "86666.297",
@@ -5111,7 +5205,7 @@
"tranche_end": "2023-06-01T00:00:00.000Z",
"total_added": "2500",
"total_removed": "0",
"locked_amount": "202.53945996133505",
"locked_amount": "192.14902574277575",
"deposits": [
{
"amount": "2500",
@@ -5144,7 +5238,7 @@
"tranche_end": "2023-11-01T00:00:00.000Z",
"total_added": "15000.000000000000015",
"total_removed": "0",
"locked_amount": "13674.853751509662013674853751509662",
"locked_amount": "13613.188783212561013613188783212561",
"deposits": [
{
"amount": "1.5e-14",
@@ -5252,7 +5346,7 @@
"tranche_end": "2023-09-01T00:00:00.000Z",
"total_added": "17500",
"total_removed": "0",
"locked_amount": "10152.36560864532825",
"locked_amount": "10080.42314563204725",
"deposits": [
{
"amount": "12500",
@@ -5518,8 +5612,8 @@
"tranche_start": "2023-02-01T00:00:00.000Z",
"tranche_end": "2023-08-01T00:00:00.000Z",
"total_added": "37500",
"total_removed": "18500.56159815",
"locked_amount": "15692.99848449969375",
"total_removed": "18592.291570575",
"locked_amount": "15536.280885512584875",
"deposits": [
{
"amount": "7500",
@@ -5543,6 +5637,11 @@
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tx": "0xc25a025176872981def8433ef0982ba306737aaf2cf0867f2259fd19492af2b5"
},
{
"amount": "91.729972425",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tx": "0xd0166245f3cf9223b3bd9291215dfb0dda92cc5554380d0ec767077c33729cf5"
},
{
"amount": "164.727209925",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
@@ -5733,6 +5832,12 @@
"tranche_id": 34,
"tx": "0xc25a025176872981def8433ef0982ba306737aaf2cf0867f2259fd19492af2b5"
},
{
"amount": "91.729972425",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tranche_id": 34,
"tx": "0xd0166245f3cf9223b3bd9291215dfb0dda92cc5554380d0ec767077c33729cf5"
},
{
"amount": "164.727209925",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
@@ -5915,8 +6020,8 @@
}
],
"total_tokens": "7500",
"withdrawn_tokens": "4290.80292735",
"remaining_tokens": "3209.19707265"
"withdrawn_tokens": "4382.532899775",
"remaining_tokens": "3117.467100225"
},
{
"address": "0x0B4e6fcE839B01ef43DA6F890FAC7B1Afb004600",
@@ -5960,7 +6065,7 @@
"tranche_end": "2023-12-05T00:00:00.000Z",
"total_added": "129999.45",
"total_removed": "0",
"locked_amount": "47858.982644879740029465",
"locked_amount": "47679.539846683643054142",
"deposits": [
{
"amount": "129999.45",
@@ -5993,7 +6098,7 @@
"tranche_end": "2024-04-01T00:00:00.000Z",
"total_added": "54144.7663",
"total_removed": "0",
"locked_amount": "47301.94373541695517923511",
"locked_amount": "47190.04105878467927027815",
"deposits": [
{
"amount": "54144.7663",
@@ -6026,7 +6131,7 @@
"tranche_end": "2023-09-03T00:00:00.000Z",
"total_added": "62600",
"total_removed": "0",
"locked_amount": "18650.49049340436032",
"locked_amount": "18520.75866311516918",
"deposits": [
{
"amount": "10000",
@@ -6219,7 +6324,7 @@
"tranche_end": "2023-09-17T00:00:00.000Z",
"total_added": "5000",
"total_removed": "0",
"locked_amount": "1681.4366121258245",
"locked_amount": "1671.07464485033",
"deposits": [
{
"amount": "5000",
@@ -7288,7 +7393,7 @@
"tranche_end": "2023-06-02T00:00:00.000Z",
"total_added": "1939928.38",
"total_removed": "1709370.7872515768348",
"locked_amount": "83681.9872917193018111752",
"locked_amount": "79661.6924136466705951094",
"deposits": [
{
"amount": "1852091.69",
@@ -12809,10 +12914,15 @@
"tranche_id": 11,
"tranche_start": "2021-09-03T00:00:00.000Z",
"tranche_end": "2022-09-03T00:00:00.000Z",
"total_added": "57278.000000000000000003",
"total_added": "57398.000000000000000003",
"total_removed": "50196.35141572991",
"locked_amount": "0",
"deposits": [
{
"amount": "120",
"user": "0x05783022615f76de7E887aed81307aE39206Aa95",
"tx": "0x388bd7537d91f3a919522ae885ce8dd9ddf415e3df3d5de687c1d5653790fcfd"
},
{
"amount": "10",
"user": "0xfb269c54dC4b43Fe98EdacE28Ce0a36A03B375D8",
@@ -24512,6 +24622,21 @@
}
],
"users": [
{
"address": "0x05783022615f76de7E887aed81307aE39206Aa95",
"deposits": [
{
"amount": "120",
"user": "0x05783022615f76de7E887aed81307aE39206Aa95",
"tranche_id": 11,
"tx": "0x388bd7537d91f3a919522ae885ce8dd9ddf415e3df3d5de687c1d5653790fcfd"
}
],
"withdrawals": [],
"total_tokens": "120",
"withdrawn_tokens": "0",
"remaining_tokens": "120"
},
{
"address": "0xfb269c54dC4b43Fe98EdacE28Ce0a36A03B375D8",
"deposits": [
@@ -41160,7 +41285,7 @@
"tranche_end": "2023-06-05T00:00:00.000Z",
"total_added": "3732368.4671",
"total_removed": "715655.108029600523393",
"locked_amount": "153091.4042231713229007715616",
"locked_amount": "146913.610713584637088982725",
"deposits": [
{
"amount": "1998.95815",
@@ -42552,8 +42677,8 @@
"tranche_start": "2022-06-05T00:00:00.000Z",
"tranche_end": "2023-12-05T00:00:00.000Z",
"total_added": "15870102.715470999700000001",
"total_removed": "885240.49984321970795352",
"locked_amount": "5842539.8756085922637222718130454678926737",
"total_removed": "887801.96986137105506852",
"locked_amount": "5820633.81647585290817427255075677483590156",
"deposits": [
{
"amount": "16249.93",
@@ -43092,6 +43217,21 @@
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tx": "0xb048cb2dcdfc30508770a3a112ddbacd63210f740cc887559660522bd506612c"
},
{
"amount": "1007.907542",
"user": "0xF4c75FdbAe821C6B5DBB9f001bB23cBA58D1bA37",
"tx": "0x6a0d503d78cb1fd2291064c2d876cb8d2d91ad87c23ea6ff0b87b6443f8b434e"
},
{
"amount": "502.98404323406874",
"user": "0xe3eB4CF43C072658401996b71D43eE26E573562D",
"tx": "0x34f5294e12b0fcbfe0be234ce712cfbc52d4d75b159ca4e55610eb75efe43286"
},
{
"amount": "1050.578432917278375",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tx": "0x817fbcc3b4739be85ab9781a9a28eca24711a398f9e27b13403b0756fed908d0"
},
{
"amount": "10150.87581603206683",
"user": "0xe3eB4CF43C072658401996b71D43eE26E573562D",
@@ -45284,6 +45424,12 @@
"tranche_id": 2,
"tx": "0xb048cb2dcdfc30508770a3a112ddbacd63210f740cc887559660522bd506612c"
},
{
"amount": "1050.578432917278375",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tranche_id": 2,
"tx": "0x817fbcc3b4739be85ab9781a9a28eca24711a398f9e27b13403b0756fed908d0"
},
{
"amount": "913.910324501590625",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
@@ -46840,8 +46986,8 @@
}
],
"total_tokens": "259998.8875",
"withdrawn_tokens": "163472.318146307289625",
"remaining_tokens": "96526.569353692710375"
"withdrawn_tokens": "164522.896579224568",
"remaining_tokens": "95475.990920775432"
},
{
"address": "0x89051CAb67Bc7F8CC44F7e270c6EDaf1EC57676c",
@@ -47080,6 +47226,12 @@
"tranche_id": 2,
"tx": "0xc8835acd2e148eeaacde2a0df0ecad19c22717c7c51b207fdeac9a1af3f98c88"
},
{
"amount": "502.98404323406874",
"user": "0xe3eB4CF43C072658401996b71D43eE26E573562D",
"tranche_id": 2,
"tx": "0x34f5294e12b0fcbfe0be234ce712cfbc52d4d75b159ca4e55610eb75efe43286"
},
{
"amount": "10150.87581603206683",
"user": "0xe3eB4CF43C072658401996b71D43eE26E573562D",
@@ -47370,8 +47522,8 @@
}
],
"total_tokens": "150551.801",
"withdrawn_tokens": "94629.10697606348661",
"remaining_tokens": "55922.69402393651339"
"withdrawn_tokens": "95132.09101929755535",
"remaining_tokens": "55419.70998070244465"
},
{
"address": "0x4d982Ab0823fD2f48e934a7be2bb0a5374a26148",
@@ -47597,6 +47749,12 @@
"tranche_id": 2,
"tx": "0xdedcbf90e8f19c2a732ba2da663f59b5a19ad94800ddca6a3575019f19e9ca20"
},
{
"amount": "1007.907542",
"user": "0xF4c75FdbAe821C6B5DBB9f001bB23cBA58D1bA37",
"tranche_id": 2,
"tx": "0x6a0d503d78cb1fd2291064c2d876cb8d2d91ad87c23ea6ff0b87b6443f8b434e"
},
{
"amount": "1784.722222",
"user": "0xF4c75FdbAe821C6B5DBB9f001bB23cBA58D1bA37",
@@ -47857,8 +48015,8 @@
}
],
"total_tokens": "200000",
"withdrawn_tokens": "125368.96374",
"remaining_tokens": "74631.03626"
"withdrawn_tokens": "126376.871282",
"remaining_tokens": "73623.128718"
},
{
"address": "0x1b956E6c00E238194B331eddEFF72Cb5f28A8d01",
@@ -49240,7 +49398,7 @@
"tranche_start": "2021-11-05T00:00:00.000Z",
"tranche_end": "2023-05-05T00:00:00.000Z",
"total_added": "14597706.0446472999",
"total_removed": "6246751.954791069035514289",
"total_removed": "6411995.942894415700913537",
"locked_amount": "0",
"deposits": [
{
@@ -49455,6 +49613,36 @@
"user": "0xfc3b2D0b548d3edBb512CeE0Bb79Fb7FaD50AaF3",
"tx": "0x5c4a7a8fbab9c7c5899835a06397ea9f9dfbc434376dd0515482b8ba83944d67"
},
{
"amount": "52738.10729529675679353",
"user": "0x91715128a71c9C734CDC20E5EdEEeA02E72e428E",
"tx": "0x6e58fe35d24a3b99b2dbf1b967952645c6025c4bf40cece1fb80f5c323d1b16e"
},
{
"amount": "60704.453275555138884",
"user": "0x47FbE34Fd93416c63d35544dEE6c6f442Db8513d",
"tx": "0x21a962bdd6ba4dd4fc1229d2cf4801c0c8a7b54bb3be80881a15e2b3acdbf148"
},
{
"amount": "15176.2482394768129956",
"user": "0xcc2cf726A84e71301f9079FC177BA946aa98A694",
"tx": "0xacccd728b8095f4a66cd6b5126f589270f32f643086d7f3e6191eab13444e69f"
},
{
"amount": "12208.093275125918557286",
"user": "0x85E14d90C63f70421a098AC26a5aCaB3854a1ee8",
"tx": "0xcc751c50c669ee8908fb382e3712f6a3df7832acb43c8f8707351214cdc23892"
},
{
"amount": "12208.430575675159834467",
"user": "0x534200f54E753D998F9C2984B5971e4DB490e56F",
"tx": "0x24c682a7c0ee0f12ce81e921c0b2dfe8dd5e5a7d8ddbe5a7e5ebf61a908ca58b"
},
{
"amount": "12208.655442216878334365",
"user": "0x35022e6c85B50F4904C7BC7e692A9F3bbEE8D2CE",
"tx": "0xa4ff302beb1dbc78161fcfd4bc457af7a75d5c759d88c4067b961d3cc48db4f3"
},
{
"amount": "1257.7360413991436375",
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
@@ -55836,6 +56024,12 @@
}
],
"withdrawals": [
{
"amount": "12208.093275125918557286",
"user": "0x85E14d90C63f70421a098AC26a5aCaB3854a1ee8",
"tranche_id": 3,
"tx": "0xcc751c50c669ee8908fb382e3712f6a3df7832acb43c8f8707351214cdc23892"
},
{
"amount": "61458.259458207381442714",
"user": "0x85E14d90C63f70421a098AC26a5aCaB3854a1ee8",
@@ -55844,8 +56038,8 @@
}
],
"total_tokens": "73666.3527333333",
"withdrawn_tokens": "61458.259458207381442714",
"remaining_tokens": "12208.093275125918557286"
"withdrawn_tokens": "73666.3527333333",
"remaining_tokens": "0"
},
{
"address": "0xcc2cf726A84e71301f9079FC177BA946aa98A694",
@@ -55858,6 +56052,12 @@
}
],
"withdrawals": [
{
"amount": "15176.2482394768129956",
"user": "0xcc2cf726A84e71301f9079FC177BA946aa98A694",
"tranche_id": 3,
"tx": "0xacccd728b8095f4a66cd6b5126f589270f32f643086d7f3e6191eab13444e69f"
},
{
"amount": "3671.528996246291985",
"user": "0xcc2cf726A84e71301f9079FC177BA946aa98A694",
@@ -55908,8 +56108,8 @@
}
],
"total_tokens": "66299.71746",
"withdrawn_tokens": "51123.4692205231870044",
"remaining_tokens": "15176.2482394768129956"
"withdrawn_tokens": "66299.71746",
"remaining_tokens": "0"
},
{
"address": "0x66827bCD635f2bB1779d68c46aEB16541bCA6ba8",
@@ -56430,6 +56630,12 @@
}
],
"withdrawals": [
{
"amount": "60704.453275555138884",
"user": "0x47FbE34Fd93416c63d35544dEE6c6f442Db8513d",
"tranche_id": 3,
"tx": "0x21a962bdd6ba4dd4fc1229d2cf4801c0c8a7b54bb3be80881a15e2b3acdbf148"
},
{
"amount": "14686.9255071873432384",
"user": "0x47FbE34Fd93416c63d35544dEE6c6f442Db8513d",
@@ -56480,8 +56686,8 @@
}
],
"total_tokens": "265198.86984",
"withdrawn_tokens": "204494.416564444861116",
"remaining_tokens": "60704.453275555138884"
"withdrawn_tokens": "265198.86984",
"remaining_tokens": "0"
},
{
"address": "0x35022e6c85B50F4904C7BC7e692A9F3bbEE8D2CE",
@@ -56494,6 +56700,12 @@
}
],
"withdrawals": [
{
"amount": "12208.655442216878334365",
"user": "0x35022e6c85B50F4904C7BC7e692A9F3bbEE8D2CE",
"tranche_id": 3,
"tx": "0xa4ff302beb1dbc78161fcfd4bc457af7a75d5c759d88c4067b961d3cc48db4f3"
},
{
"amount": "61457.697291116421665635",
"user": "0x35022e6c85B50F4904C7BC7e692A9F3bbEE8D2CE",
@@ -56502,8 +56714,8 @@
}
],
"total_tokens": "73666.3527333333",
"withdrawn_tokens": "61457.697291116421665635",
"remaining_tokens": "12208.655442216878334365"
"withdrawn_tokens": "73666.3527333333",
"remaining_tokens": "0"
},
{
"address": "0xC62BC272187e0Fd48ed126B99ABD6e7943707E64",
@@ -56598,6 +56810,12 @@
}
],
"withdrawals": [
{
"amount": "12208.430575675159834467",
"user": "0x534200f54E753D998F9C2984B5971e4DB490e56F",
"tranche_id": 3,
"tx": "0x24c682a7c0ee0f12ce81e921c0b2dfe8dd5e5a7d8ddbe5a7e5ebf61a908ca58b"
},
{
"amount": "61457.922157658140165533",
"user": "0x534200f54E753D998F9C2984B5971e4DB490e56F",
@@ -56606,8 +56824,8 @@
}
],
"total_tokens": "73666.3527333333",
"withdrawn_tokens": "61457.922157658140165533",
"remaining_tokens": "12208.430575675159834467"
"withdrawn_tokens": "73666.3527333333",
"remaining_tokens": "0"
},
{
"address": "0x4020DC404D9470E0F08D2E7A8d6eBc54035CF42C",
@@ -56703,6 +56921,12 @@
}
],
"withdrawals": [
{
"amount": "52738.10729529675679353",
"user": "0x91715128a71c9C734CDC20E5EdEEeA02E72e428E",
"tranche_id": 3,
"tx": "0x6e58fe35d24a3b99b2dbf1b967952645c6025c4bf40cece1fb80f5c323d1b16e"
},
{
"amount": "12758.73908063512839093",
"user": "0x91715128a71c9C734CDC20E5EdEEeA02E72e428E",
@@ -56747,8 +56971,8 @@
}
],
"total_tokens": "230391.5181735",
"withdrawn_tokens": "177653.41087820324320647",
"remaining_tokens": "52738.10729529675679353"
"withdrawn_tokens": "230391.5181735",
"remaining_tokens": "0"
},
{
"address": "0xC6b2864fbCD2A8dEC8DEfD1D421bC1E450C370AD",
@@ -57167,7 +57391,7 @@
"tranche_start": "2021-10-05T00:00:00.000Z",
"tranche_end": "2023-04-05T00:00:00.000Z",
"total_added": "5778205.3912159303",
"total_removed": "3492469.400132244009296769",
"total_removed": "3521250.583356139543129269",
"locked_amount": "0",
"deposits": [
{
@@ -57317,6 +57541,11 @@
"user": "0x759C9ABABA492500c4c730bEB568B5b851Dec2c7",
"tx": "0xd4191eb657ad26e08faddde326514247ae4a88e8aefcc7592590f368010c4046"
},
{
"amount": "28781.1832238955338325",
"user": "0x91715128a71c9C734CDC20E5EdEEeA02E72e428E",
"tx": "0xf8179ed797f62e95dccb30c6efcbfa272d1e52efbcb94d04bfeb33312744755c"
},
{
"amount": "58898.87608135458795",
"user": "0x83b1a48376E045D26420200345414e6b93066396",
@@ -58186,6 +58415,12 @@
}
],
"withdrawals": [
{
"amount": "28781.1832238955338325",
"user": "0x91715128a71c9C734CDC20E5EdEEeA02E72e428E",
"tranche_id": 4,
"tx": "0xf8179ed797f62e95dccb30c6efcbfa272d1e52efbcb94d04bfeb33312744755c"
},
{
"amount": "9162.0421945609117395",
"user": "0x91715128a71c9C734CDC20E5EdEEeA02E72e428E",
@@ -58230,8 +58465,8 @@
}
],
"total_tokens": "165749.29365",
"withdrawn_tokens": "136968.1104261044661675",
"remaining_tokens": "28781.1832238955338325"
"withdrawn_tokens": "165749.29365",
"remaining_tokens": "0"
},
{
"address": "0x72e7BB93E73b2885a22CA29c34759361399a5C0e",
@@ -59383,8 +59618,8 @@
"tranche_start": "2022-06-05T00:00:00.000Z",
"tranche_end": "2023-06-05T00:00:00.000Z",
"total_added": "472355.6199999996",
"total_removed": "45345.4733895423416",
"locked_amount": "24258.2081069361612058598496600864",
"total_removed": "45451.7934047643416",
"locked_amount": "23279.30141156897471279865169965",
"deposits": [
{
"amount": "3000",
@@ -66048,6 +66283,16 @@
"user": "0xf0d681c15447dCfaa6002f17078944FCe75B5e26",
"tx": "0xca745232557385fff568386375d868633bd9542981dd07a6c471b4633dd5c9b8"
},
{
"amount": "69.499619482",
"user": "0x8c951C54F9cd08Cf81F770248e835D7A4F491a46",
"tx": "0xfee87c40eeb3d6681eaa844b65ddb52756356c3612e2c2c8606b96f4965bc195"
},
{
"amount": "36.82039574",
"user": "0x4eD2b3c68BB4fda084ce1591a210F4aC8b71234A",
"tx": "0xebbec73307d5d44428f791ad28622e6a075fa9a02d627f028db45a1042af473a"
},
{
"amount": "182.662252664",
"user": "0xb1169C6daAc76bAcaf0D8f87641Fc38fbabe569F",
@@ -80149,6 +80394,12 @@
}
],
"withdrawals": [
{
"amount": "36.82039574",
"user": "0x4eD2b3c68BB4fda084ce1591a210F4aC8b71234A",
"tranche_id": 5,
"tx": "0xebbec73307d5d44428f791ad28622e6a075fa9a02d627f028db45a1042af473a"
},
{
"amount": "26.662404872",
"user": "0x4eD2b3c68BB4fda084ce1591a210F4aC8b71234A",
@@ -80253,8 +80504,8 @@
}
],
"total_tokens": "400",
"withdrawn_tokens": "342.891159308",
"remaining_tokens": "57.108840692"
"withdrawn_tokens": "379.711555048",
"remaining_tokens": "20.288444952"
},
{
"address": "0x5c90765F50629570738fEe7b7FA82ae118f81Ed1",
@@ -86702,6 +86953,12 @@
}
],
"withdrawals": [
{
"amount": "69.499619482",
"user": "0x8c951C54F9cd08Cf81F770248e835D7A4F491a46",
"tranche_id": 5,
"tx": "0xfee87c40eeb3d6681eaa844b65ddb52756356c3612e2c2c8606b96f4965bc195"
},
{
"amount": "26.330974124",
"user": "0x8c951C54F9cd08Cf81F770248e835D7A4F491a46",
@@ -86722,8 +86979,8 @@
}
],
"total_tokens": "200",
"withdrawn_tokens": "120.251972348",
"remaining_tokens": "79.748027652"
"withdrawn_tokens": "189.75159183",
"remaining_tokens": "10.24840817"
},
{
"address": "0x3437f6ED844013852650851D769ae7939B5e0aec",
@@ -89264,7 +89521,7 @@
"tranche_start": "2021-12-05T00:00:00.000Z",
"tranche_end": "2022-06-05T00:00:00.000Z",
"total_added": "171288.42",
"total_removed": "71890.5995794947989",
"total_removed": "72069.2365096947989",
"locked_amount": "0",
"deposits": [
{
@@ -93524,6 +93781,11 @@
"user": "0x2A6Ea2aBEf3D7d7A76CBeF3c297eE0eF9a86BBA8",
"tx": "0x163b699e8a25073ad1ad45c8a8f9b1348eb0b648d3f4bc6f3f64648e0ad726bf"
},
{
"amount": "178.6369302",
"user": "0xC3d15bD936DDCb45b87BFF3Ff13445284a6c9d43",
"tx": "0x7381b77de572d356ae185a760ff839dbdc85cb97bf408b110f7779bb095ea293"
},
{
"amount": "250",
"user": "0x0E3407C9A94effa675471afe7A9D37e687C32141",
@@ -110020,6 +110282,12 @@
}
],
"withdrawals": [
{
"amount": "178.6369302",
"user": "0xC3d15bD936DDCb45b87BFF3Ff13445284a6c9d43",
"tranche_id": 6,
"tx": "0x7381b77de572d356ae185a760ff839dbdc85cb97bf408b110f7779bb095ea293"
},
{
"amount": "71.3630698",
"user": "0xC3d15bD936DDCb45b87BFF3Ff13445284a6c9d43",
@@ -110028,8 +110296,8 @@
}
],
"total_tokens": "250",
"withdrawn_tokens": "71.3630698",
"remaining_tokens": "178.6369302"
"withdrawn_tokens": "250",
"remaining_tokens": "0"
},
{
"address": "0x4A13d4dC5e06ACdA81C011D55a7DaAc332bC5Dbf",
@@ -318,10 +318,11 @@ describe('Closed markets', { tags: '@smoke' }, () => {
.should('have.text', product.settlementAsset.symbol);
// 6001-MARK-020
cy.get(rowSelector)
cy.get('.ag-pinned-right-cols-container')
.find('[col-id="market-actions"]')
.first()
.find('[col-id="id"]')
.should('have.text', settledMarket.id);
.find('button svg')
.should('exist');
});
// test market list for market in terminated state
@@ -373,5 +374,33 @@ describe('Closed markets', { tags: '@smoke' }, () => {
'have.text',
`Asset details - ${settlementAsset.symbol}`
);
cy.get('[data-testid="dialog-close"]').click();
});
it('can open row actions', () => {
cy.get('.ag-pinned-right-cols-container')
.find('[col-id="market-actions"]')
.first()
.find('button')
.click();
const dropdownContent = '[data-testid="market-actions-content"]';
const dropdownContentItem = '[role="menuitem"]';
cy.get(dropdownContent)
.find(dropdownContentItem)
.eq(0)
// Cannot click the copy button as it falls back to window.prompt, blocking the test.
.should('have.text', 'Copy Market ID');
cy.get(dropdownContent)
.find(dropdownContentItem)
.eq(1)
.find('a')
.then(($el) => {
const href = $el.attr('href');
expect(/\/markets\/0/.test(href || '')).to.equal(true);
})
.should('have.text', 'View on Explorer');
});
});
@@ -108,10 +108,9 @@ describe('deposit actions', { tags: '@smoke' }, () => {
it('Deposit to trade is visble', () => {
cy.getByTestId('Collateral').click();
cy.contains('[data-testid="deposit"]', 'Deposit to trade').should(
'be.visible'
);
cy.contains('[data-testid="deposit"]', 'Deposit to trade').click();
cy.contains('[data-testid="deposit"]', 'Deposit')
.should('be.visible')
.click();
cy.getByTestId('deposit-submit').should('be.visible');
});
});
@@ -48,7 +48,7 @@ describe('accounts', { tags: '@smoke' }, () => {
cy.getByTestId('tab-accounts')
.get(tradingAccountRowId)
.find('[col-id="accounts-actions"]')
.should('have.text', ' ');
.should('have.text', '');
cy.getByTestId('tab-accounts')
.get(tradingAccountRowId)
@@ -8,7 +8,6 @@ import {
import { tooltipMapping } from '@vegaprotocol/market-info';
import {
addDecimalsFormatNumber,
createDocsLinks,
formatNumberPercentage,
} from '@vegaprotocol/utils';
import { t } from '@vegaprotocol/i18n';
@@ -39,7 +38,7 @@ import { Link, useParams } from 'react-router-dom';
import { Links, Routes } from '../../pages/client-router';
import { useMarket, useStaticMarketData } from '@vegaprotocol/market-list';
import { useEnvironment } from '@vegaprotocol/environment';
import { DocsLinks } from '@vegaprotocol/environment';
const enum LiquidityTabs {
Active = 'active',
@@ -147,7 +146,6 @@ const LiquidityViewHeader = memo(({ marketId }: { marketId?: string }) => {
market?.tradableInstrument.instrument.product.settlementAsset.decimals || 0;
const symbol =
market?.tradableInstrument.instrument.product.settlementAsset.symbol;
const { VEGA_DOCS_URL } = useEnvironment();
const { params } = useNetworkParams([
NetworkParams.market_liquidity_stakeToCcyVolume,
@@ -216,10 +214,12 @@ const LiquidityViewHeader = memo(({ marketId }: { marketId?: string }) => {
<div className="break-word">{marketId}</div>
</HeaderStat>
<HeaderStat heading={t('Learn more')}>
{VEGA_DOCS_URL && (
<ExternalLink href={createDocsLinks(VEGA_DOCS_URL).LIQUIDITY}>
{DocsLinks ? (
<ExternalLink href={DocsLinks.LIQUIDITY}>
{t('Providing liquidity')}
</ExternalLink>
) : (
(null as React.ReactNode)
)}
</HeaderStat>
</Header>
@@ -214,7 +214,7 @@ describe('Closed', () => {
'Settlement price',
'Realised PNL',
'Settlement asset',
'Market ID',
'', // actions row
];
expect(headers).toHaveLength(expectedHeaders.length);
expect(headers.map((h) => h.textContent?.trim())).toEqual(expectedHeaders);
@@ -236,7 +236,7 @@ describe('Closed', () => {
addDecimalsFormatNumber(property.value, market.decimalPlaces),
addDecimalsFormatNumber(position.realisedPNL, market.decimalPlaces),
market.tradableInstrument.instrument.product.settlementAsset.symbol,
market.id,
'', // actions row
];
cells.forEach((cell, i) => {
expect(cell).toHaveTextContent(expectedValues[i]);
@@ -328,8 +328,13 @@ describe('Closed', () => {
// check that only included ids are shown
const cells = screen
.getAllByRole('gridcell')
.filter((cell) => cell.getAttribute('col-id') === 'id')
.map((cell) => cell.textContent?.trim());
.filter((cell) => cell.getAttribute('col-id') === 'code')
.map((cell) => {
const marketId = within(cell)
.getByTestId('market-code')
.getAttribute('data-market-id');
return marketId;
});
expect(cells).toEqual(expectedRows.map((m) => m.node.id));
});
});
+26 -5
View File
@@ -4,7 +4,7 @@ import type {
VegaICellRendererParams,
VegaValueFormatterParams,
} from '@vegaprotocol/datagrid';
import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid';
import { AgGridLazy as AgGrid, COL_DEFS } from '@vegaprotocol/datagrid';
import { useMemo } from 'react';
import { t } from '@vegaprotocol/i18n';
import { MarketState, MarketStateMapping } from '@vegaprotocol/types';
@@ -14,7 +14,10 @@ import {
} from '@vegaprotocol/utils';
import { usePositionsQuery } from '@vegaprotocol/positions';
import type { MarketMaybeWithData } from '@vegaprotocol/market-list';
import { closedMarketsWithDataProvider } from '@vegaprotocol/market-list';
import {
MarketTableActions,
closedMarketsWithDataProvider,
} from '@vegaprotocol/market-list';
import { useVegaWallet } from '@vegaprotocol/wallet';
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
import type { ColDef } from 'ag-grid-community';
@@ -121,6 +124,16 @@ const ClosedMarketsDataGrid = ({ rowData }: { rowData: Row[] }) => {
{
headerName: t('Market'),
field: 'code',
cellRenderer: ({
value,
data,
}: VegaICellRendererParams<Row, 'code'>) => {
return (
<span data-testid="market-code" data-market-id={data?.id}>
{value}
</span>
);
},
},
{
headerName: t('Description'),
@@ -262,9 +275,17 @@ const ClosedMarketsDataGrid = ({ rowData }: { rowData: Row[] }) => {
),
},
{
headerName: t('Market ID'),
field: 'id',
flex: 1,
colId: 'market-actions',
...COL_DEFS.actions,
cellRenderer: ({ data }: VegaICellRendererParams<Row>) => {
if (!data) return null;
return (
<MarketTableActions
marketId={data.id}
assetId={data.settlementAsset.id}
/>
);
},
},
];
return cols;
@@ -19,11 +19,10 @@ import { useCheckLiquidityStatus } from '@vegaprotocol/liquidity';
import { AuctionTrigger, MarketTradingMode } from '@vegaprotocol/types';
import {
addDecimalsFormatNumber,
createDocsLinks,
formatNumberPercentage,
} from '@vegaprotocol/utils';
import { t } from '@vegaprotocol/i18n';
import { useEnvironment } from '@vegaprotocol/environment';
import { DocsLinks } from '@vegaprotocol/environment';
interface Props {
marketId?: string;
@@ -47,8 +46,6 @@ export const MarketLiquiditySupplied = ({
params.market_liquidity_targetstake_triggering_ratio
);
const { VEGA_DOCS_URL } = useEnvironment();
const variables = useMemo(
() => ({
marketId: marketId || '',
@@ -131,11 +128,8 @@ export const MarketLiquiditySupplied = ({
<Link href={`/#/liquidity/${marketId}`} data-testid="view-liquidity-link">
{t('View liquidity provision table')}
</Link>
{VEGA_DOCS_URL && (
<ExternalLink
href={createDocsLinks(VEGA_DOCS_URL).LIQUIDITY}
className="mt-2"
>
{DocsLinks && (
<ExternalLink href={DocsLinks.LIQUIDITY} className="mt-2">
{t('Learn about providing liquidity')}
</ExternalLink>
)}
+4 -6
View File
@@ -5,6 +5,7 @@ import {
TOKEN_GOVERNANCE,
useEnvironment,
useLinks,
DocsLinks,
} from '@vegaprotocol/environment';
import { t } from '@vegaprotocol/i18n';
import { useGlobalStore } from '../../stores';
@@ -22,7 +23,6 @@ import {
} from '@vegaprotocol/ui-toolkit';
import { Links, Routes } from '../../pages/client-router';
import { createDocsLinks } from '@vegaprotocol/utils';
import { SettingsButton } from '../../client-pages/settings';
import {
ProtocolUpgradeCountdown,
@@ -34,7 +34,7 @@ export const Navbar = ({
}: {
theme: ComponentProps<typeof Navigation>['theme'];
}) => {
const { VEGA_DOCS_URL, GITHUB_FEEDBACK_URL } = useEnvironment();
const { GITHUB_FEEDBACK_URL } = useEnvironment();
const tokenLink = useLinks(DApp.Token);
const { marketId } = useGlobalStore((store) => ({
marketId: store.marketId,
@@ -92,15 +92,13 @@ export const Navbar = ({
{t('Governance')}
</NavExternalLink>
</NavigationItem>
{VEGA_DOCS_URL && GITHUB_FEEDBACK_URL && (
{DocsLinks?.NEW_TO_VEGA && GITHUB_FEEDBACK_URL && (
<NavigationItem>
<NavigationTrigger>{t('Resources')}</NavigationTrigger>
<NavigationContent>
<NavigationList>
<NavigationItem>
<NavExternalLink
href={createDocsLinks(VEGA_DOCS_URL).NEW_TO_VEGA}
>
<NavExternalLink href={DocsLinks.NEW_TO_VEGA}>
{t('Docs')}
</NavExternalLink>
</NavigationItem>
@@ -21,6 +21,7 @@ import { useVegaWallet, useVegaWalletDialogStore } from '@vegaprotocol/wallet';
import { Networks, useEnvironment } from '@vegaprotocol/environment';
import { WalletIcon } from '../icons/wallet';
import { useTransferDialog } from '@vegaprotocol/accounts';
import { useCopyTimeout } from '@vegaprotocol/react-helpers';
const MobileWalletButton = ({
isConnected,
@@ -237,21 +238,7 @@ export const VegaWalletConnectButton = () => {
};
const KeypairItem = ({ pk }: { pk: PubKey }) => {
const [copied, setCopied] = useState(false);
useEffect(() => {
// eslint-disable-next-line
let timeout: any;
if (copied) {
timeout = setTimeout(() => {
setCopied(false);
}, 800);
}
return () => {
clearTimeout(timeout);
};
}, [copied]);
const [copied, setCopied] = useCopyTimeout();
return (
<DropdownMenuRadioItem value={pk.publicKey}>
@@ -8,11 +8,10 @@ import {
import { RISK_ACCEPTED_KEY } from '../constants';
import { TelemetryApproval } from './telemetry-approval';
import {
DOCS_VEGA_WALLET,
GET_VEGA_WALLET_URL,
Networks,
useDocsLink,
useEnvironment,
DocsLinks,
ExternalLinks,
} from '@vegaprotocol/environment';
import { useLocalStorage } from '@vegaprotocol/react-helpers';
@@ -53,8 +52,6 @@ export const RiskNoticeDialog = ({ onClose, network }: Props) => {
const TestnetContent = ({ network }: { network: Networks }) => {
const { GITHUB_FEEDBACK_URL } = useEnvironment();
const docsLink = useDocsLink();
return (
<>
<p className="mb-4">
@@ -69,16 +66,16 @@ const TestnetContent = ({ network }: { network: Networks }) => {
[network]
)}
</p>
{GITHUB_FEEDBACK_URL && GET_VEGA_WALLET_URL && docsLink && (
{GITHUB_FEEDBACK_URL && DocsLinks && (
<ul className="list-disc pl-4">
<li className="mb-1">
<Link href={GET_VEGA_WALLET_URL} target="_blank">
<Link href={ExternalLinks.VEGA_WALLET_URL} target="_blank">
<span className="underline">{t('Get a Vega Wallet')}</span>{' '}
<VegaIcon name={VegaIconNames.OPEN_EXTERNAL} />
</Link>
</li>
<li className="mb-1">
<Link href={docsLink(DOCS_VEGA_WALLET)} target="_blank">
<Link href={DocsLinks.VEGA_WALLET_TOOLS_URL} target="_blank">
<span className="underline">{t('Learn about Vega Wallet')}</span>{' '}
<VegaIcon name={VegaIconNames.OPEN_EXTERNAL} />
</Link>
@@ -1,13 +1,13 @@
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
import { t } from '@vegaprotocol/i18n';
import {
BLOG,
DApp,
Networks,
TOKEN_NEW_MARKET_PROPOSAL,
TOKEN_PROPOSALS,
useEnvironment,
useLinks,
ExternalLinks,
} from '@vegaprotocol/environment';
import { ProposedMarkets } from './proposed-markets';
@@ -52,7 +52,7 @@ export const WelcomeNoticeDialog = () => {
</ExternalLink>
</li>
<li>
<ExternalLink target="_blank" href={BLOG}>
<ExternalLink target="_blank" href={ExternalLinks.BLOG}>
{t('Read about the mainnet launch')}
</ExternalLink>
</li>
+3 -5
View File
@@ -93,9 +93,9 @@ html [data-theme='light'] {
line-height: calc(min(var(--ag-line-height, 26px), 26px) - 4px);
}
.vega-ag-grid .ag-row {
border-width: 1px 0;
border-bottom: 1px solid transparent;
.vega-ag-grid .ag-row,
.vega-ag-grid .ag-cell {
border-width: 0;
}
/* Light variables */
@@ -107,7 +107,6 @@ html [data-theme='light'] {
--ag-header-column-separator-color: theme(colors.neutral[300]);
--ag-row-border-color: theme(colors.white);
--ag-row-hover-color: theme(colors.neutral[100]);
--ag-font-size: 12px;
}
/* Dark variables */
@@ -119,7 +118,6 @@ html [data-theme='light'] {
--ag-header-column-separator-color: theme(colors.neutral[600]);
--ag-row-border-color: theme(colors.black);
--ag-row-hover-color: theme(colors.neutral[800]);
--ag-font-size: 12px;
}
.ag-theme-balham-dark .ag-row.no-hover,
.ag-theme-balham-dark .ag-row.no-hover:hover,
@@ -0,0 +1,103 @@
import { ETHERSCAN_ADDRESS, useEtherscanLink } from '@vegaprotocol/environment';
import { t } from '@vegaprotocol/i18n';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuCopyItem,
DropdownMenuItem,
DropdownMenuTrigger,
Link,
VegaIcon,
VegaIconNames,
} from '@vegaprotocol/ui-toolkit';
import { useTransferDialog } from './transfer-dialog';
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
export const AccountsActionsDropdown = ({
assetId,
assetContractAddress,
onClickDeposit,
onClickWithdraw,
onClickBreakdown,
}: {
assetId: string;
assetContractAddress?: string;
onClickDeposit: () => void;
onClickWithdraw: () => void;
onClickBreakdown: () => void;
}) => {
const etherscanLink = useEtherscanLink();
const openTransferDialog = useTransferDialog((store) => store.open);
const openAssetDialog = useAssetDetailsDialogStore((store) => store.open);
return (
<DropdownMenu
trigger={
<DropdownMenuTrigger
className="hover:bg-vega-light-200 dark:hover:bg-vega-dark-200 p-0.5 focus:rounded-full hover:rounded-full"
data-testid="dropdown-menu"
>
<VegaIcon name={VegaIconNames.KEBAB} />
</DropdownMenuTrigger>
}
>
<DropdownMenuContent>
<DropdownMenuItem
key={'deposit'}
data-testid="deposit"
onClick={onClickDeposit}
>
<VegaIcon name={VegaIconNames.DEPOSIT} size={16} />
{t('Deposit')}
</DropdownMenuItem>
<DropdownMenuItem
key={'withdraw'}
data-testid="withdraw"
onClick={onClickWithdraw}
>
<VegaIcon name={VegaIconNames.WITHDRAW} size={16} />
{t('Withdraw')}
</DropdownMenuItem>
<DropdownMenuItem
key={'transfer'}
data-testid="transfer"
onClick={() => openTransferDialog(true, assetId)}
>
<VegaIcon name={VegaIconNames.TRANSFER} size={16} />
{t('Transfer')}
</DropdownMenuItem>
<DropdownMenuItem
key={'breakdown'}
data-testid="breakdown"
onClick={onClickBreakdown}
>
<VegaIcon name={VegaIconNames.BREAKDOWN} size={16} />
{t('Breakdown')}
</DropdownMenuItem>
<DropdownMenuItem
onClick={(e) => {
openAssetDialog(assetId, e.target as HTMLElement);
}}
>
<VegaIcon name={VegaIconNames.BREAKDOWN} size={16} />
{t('View asset')}
</DropdownMenuItem>
<DropdownMenuCopyItem value={assetId} text={t('Copy asset ID')} />
{assetContractAddress && (
<DropdownMenuItem>
<Link
href={etherscanLink(
ETHERSCAN_ADDRESS.replace(':hash', assetContractAddress)
)}
target="_blank"
>
<span className="flex gap-2">
<VegaIcon name={VegaIconNames.OPEN_EXTERNAL} size={16} />
{t('View on Etherscan')}
</span>
</Link>
</DropdownMenuItem>
)}
</DropdownMenuContent>
</DropdownMenu>
);
};
+58 -100
View File
@@ -9,14 +9,11 @@ import type {
VegaICellRendererParams,
VegaValueFormatterParams,
} from '@vegaprotocol/datagrid';
import { COL_DEFS } from '@vegaprotocol/datagrid';
import {
Button,
ButtonLink,
Dialog,
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
VegaIcon,
VegaIconNames,
} from '@vegaprotocol/ui-toolkit';
@@ -38,6 +35,7 @@ import type { AccountFields } from './accounts-data-provider';
import type { Asset } from '@vegaprotocol/types';
import BigNumber from 'bignumber.js';
import classNames from 'classnames';
import { AccountsActionsDropdown } from './accounts-actions-dropdown';
const colorClass = (percentageUsed: number, neutral = false) => {
return classNames({
@@ -109,7 +107,7 @@ export const AccountTable = forwardRef<AgGridReact, AccountTableProps>(
const [row, setRow] = useState<AccountFields>();
const pinnedAssetId = props.pinnedAsset?.id;
const pinnedAssetRow = useMemo(() => {
const pinnedAsset = useMemo(() => {
const currentPinnedAssetRow = props.rowData?.find(
(row) => row.asset.id === pinnedAssetId
);
@@ -143,6 +141,13 @@ export const AccountTable = forwardRef<AgGridReact, AccountTableProps>(
[pinnedAssetId, getRowHeight]
);
const accountForPinnedAsset = props?.rowData?.find(
(a) => a.asset.id === pinnedAssetId
);
const showDepositButton = accountForPinnedAsset
? new BigNumber(accountForPinnedAsset.total).isLessThanOrEqualTo(0)
: true;
return (
<>
<AgGrid
@@ -162,7 +167,7 @@ export const AccountTable = forwardRef<AgGridReact, AccountTableProps>(
comparator: accountValuesComparator,
}}
getRowHeight={getPinnedAssetRowHeight}
pinnedTopRowData={pinnedAssetRow ? [pinnedAssetRow] : undefined}
pinnedTopRowData={pinnedAsset ? [pinnedAsset] : undefined}
>
<AgGridColumn
headerName={t('Asset')}
@@ -266,104 +271,57 @@ export const AccountTable = forwardRef<AgGridReact, AccountTableProps>(
formatWithAssetDecimals(data, data?.total)
}
/>
{
<AgGridColumn
colId="accounts-actions"
headerName=""
sortable={false}
maxWidth={200}
type="rightAligned"
cellRenderer={({
data,
}: VegaICellRendererParams<AccountFields>) => {
if (!data) return null;
else {
if (
data.asset.id === pinnedAssetId &&
new BigNumber(data.total).isLessThanOrEqualTo(0)
) {
return (
<CenteredGridCellWrapper className="h-[30px] justify-end py-1">
<Button
size="xs"
variant="primary"
data-testid="deposit"
onClick={() => {
onClickDeposit && onClickDeposit(data.asset.id);
}}
>
{t('Deposit to trade')}
</Button>
</CenteredGridCellWrapper>
);
}
<AgGridColumn
colId="accounts-actions"
{...COL_DEFS.actions}
minWidth={showDepositButton ? 130 : COL_DEFS.actions.minWidth}
maxWidth={showDepositButton ? 130 : COL_DEFS.actions.maxWidth}
cellRenderer={({
data,
}: VegaICellRendererParams<AccountFields>) => {
if (!data) return null;
else {
if (showDepositButton && data.asset.id === pinnedAssetId) {
return (
!props.isReadOnly && (
<DropdownMenu
trigger={
<DropdownMenuTrigger
iconName="more"
className="hover:bg-vega-light-200 dark:hover:bg-vega-dark-200 p-0.5 focus:rounded-full hover:rounded-full"
data-testid="dropdown-menu"
></DropdownMenuTrigger>
}
<CenteredGridCellWrapper className="h-[30px] justify-end py-1">
<Button
size="xs"
variant="primary"
data-testid="deposit"
onClick={() => {
onClickDeposit && onClickDeposit(data.asset.id);
}}
>
<DropdownMenuContent>
<DropdownMenuItem
key={'deposit'}
data-testid="deposit"
onClick={() => {
onClickDeposit && onClickDeposit(data.asset.id);
}}
>
<span className="flex gap-2">
<VegaIcon
name={VegaIconNames.DEPOSIT}
size={16}
/>
{t('Deposit')}
</span>
</DropdownMenuItem>
<DropdownMenuItem
key={'withdraw'}
data-testid="withdraw"
onClick={() =>
onClickWithdraw && onClickWithdraw(data.asset.id)
}
>
<span className="flex gap-2">
<VegaIcon
name={VegaIconNames.WITHDRAW}
size={16}
/>
{t('Withdraw')}
</span>
</DropdownMenuItem>
<DropdownMenuItem
key={'breakdown'}
data-testid="breakdown"
onClick={() => {
setOpenBreakdown(!openBreakdown);
setRow(data);
}}
>
<span className="flex gap-2">
<VegaIcon
name={VegaIconNames.BREAKDOWN}
size={16}
/>
{t('Breakdown')}
</span>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
)
<VegaIcon name={VegaIconNames.DEPOSIT} /> {t('Deposit')}
</Button>
</CenteredGridCellWrapper>
);
}
}}
flex={1}
/>
}
return (
!props.isReadOnly && (
<AccountsActionsDropdown
assetId={data.asset.id}
assetContractAddress={
data.asset.source?.__typename === 'ERC20'
? data.asset.source.contractAddress
: undefined
}
onClickDeposit={() => {
onClickDeposit && onClickDeposit(data.asset.id);
}}
onClickWithdraw={() => {
onClickWithdraw && onClickWithdraw(data.asset.id);
}}
onClickBreakdown={() => {
setOpenBreakdown(!openBreakdown);
setRow(data);
}}
/>
)
);
}
}}
/>
</AgGrid>
<Dialog size="medium" open={openBreakdown} onChange={setOpenBreakdown}>
<div
+2 -1
View File
@@ -14,7 +14,7 @@ import { TransferForm } from './transfer-form';
import { useTransferDialog } from './transfer-dialog';
import { Lozenge } from '@vegaprotocol/ui-toolkit';
export const TransferContainer = () => {
export const TransferContainer = ({ assetId }: { assetId?: string }) => {
const { pubKey, pubKeys } = useVegaWallet();
const open = useTransferDialog((store) => store.open);
const { param } = useNetworkParam(NetworkParams.transfer_fee_factor);
@@ -59,6 +59,7 @@ export const TransferContainer = () => {
pubKey={pubKey}
pubKeys={pubKeys ? pubKeys?.map((pk) => pk.publicKey) : null}
assets={assets}
assetId={assetId}
feeFactor={param}
submitTransfer={transfer}
/>
+7 -5
View File
@@ -5,24 +5,26 @@ import { TransferContainer } from './transfer-container';
interface State {
isOpen: boolean;
assetId: string | undefined;
}
interface Actions {
open: (open?: boolean) => void;
open: (open?: boolean, assetId?: string) => void;
}
export const useTransferDialog = create<State & Actions>()((set) => ({
isOpen: false,
open: (open = true) => {
set(() => ({ isOpen: open }));
assetId: undefined,
open: (open = true, assetId) => {
set(() => ({ isOpen: open, assetId }));
},
}));
export const TransferDialog = () => {
const { isOpen, open } = useTransferDialog();
const { isOpen, open, assetId } = useTransferDialog();
return (
<Dialog title={t('Transfer')} open={isOpen} onChange={open} size="small">
<TransferContainer />
<TransferContainer assetId={assetId} />
</Dialog>
);
};
+7 -1
View File
@@ -41,6 +41,7 @@ interface TransferFormProps {
decimals: number;
balance: string;
}>;
assetId?: string;
feeFactor: string | null;
submitTransfer: (transfer: Transfer) => void;
}
@@ -49,6 +50,7 @@ export const TransferForm = ({
pubKey,
pubKeys,
assets,
assetId: initialAssetId,
feeFactor,
submitTransfer,
}: TransferFormProps) => {
@@ -59,7 +61,11 @@ export const TransferForm = ({
handleSubmit,
setValue,
formState: { errors },
} = useForm<FormFields>();
} = useForm<FormFields>({
defaultValues: {
asset: initialAssetId,
},
});
const amount = watch('amount');
const assetId = watch('asset');
+2
View File
@@ -1,6 +1,8 @@
export * from './lib/ag-grid/ag-grid-lazy';
export * from './lib/ag-grid/use-column-sizes';
export * from './lib/column-definitions';
export * from './lib/cells/cumulative-vol-cell';
export * from './lib/cells/flash-cell';
export * from './lib/cells/numeric-cell';
@@ -0,0 +1,12 @@
export const COL_DEFS = {
actions: {
headerName: '',
sortable: false,
resizable: false,
filter: false,
minWidth: 45,
maxWidth: 45,
type: 'rightAligned',
pinned: 'right',
},
};
@@ -2,8 +2,8 @@ import { useMemo } from 'react';
import { parseISO, isValid, isAfter } from 'date-fns';
import classNames from 'classnames';
import { useProposalOfMarketQuery } from '@vegaprotocol/proposals';
import { useEnvironment } from '@vegaprotocol/environment';
import { createDocsLinks, getDateTimeFormat } from '@vegaprotocol/utils';
import { DocsLinks } from '@vegaprotocol/environment';
import { getDateTimeFormat } from '@vegaprotocol/utils';
import { t } from '@vegaprotocol/i18n';
import * as Schema from '@vegaprotocol/types';
import { ExternalLink, SimpleGrid } from '@vegaprotocol/ui-toolkit';
@@ -23,7 +23,6 @@ export const TradingModeTooltip = ({
skip,
skipGrid,
}: TradingModeTooltipProps) => {
const { VEGA_DOCS_URL } = useEnvironment();
const { data: market } = useMarket(marketId);
const { data: marketData } = useStaticMarketData(marketId, skip);
const { marketTradingMode, trigger } = marketData || {};
@@ -102,9 +101,9 @@ export const TradingModeTooltip = ({
</span>
</>
)}
{VEGA_DOCS_URL && (
{DocsLinks && (
<ExternalLink
href={createDocsLinks(VEGA_DOCS_URL).AUCTION_TYPE_OPENING}
href={DocsLinks.AUCTION_TYPE_OPENING}
className="ml-1"
>
{t('Find out more')}
@@ -126,12 +125,9 @@ export const TradingModeTooltip = ({
'This market is in auction until it reaches sufficient liquidity.'
)}
</span>
{VEGA_DOCS_URL && (
{DocsLinks && (
<ExternalLink
href={
createDocsLinks(VEGA_DOCS_URL)
.AUCTION_TYPE_LIQUIDITY_MONITORING
}
href={DocsLinks.AUCTION_TYPE_LIQUIDITY_MONITORING}
className="ml-1"
>
{t('Find out more')}
@@ -151,12 +147,9 @@ export const TradingModeTooltip = ({
'This market may have sufficient liquidity but there are not enough priced limit orders in the order book, which are required to deploy liquidity commitment pegged orders.'
)}
</span>
{VEGA_DOCS_URL && (
{DocsLinks && (
<ExternalLink
href={
createDocsLinks(VEGA_DOCS_URL)
.AUCTION_TYPE_LIQUIDITY_MONITORING
}
href={DocsLinks.AUCTION_TYPE_LIQUIDITY_MONITORING}
className="ml-1"
>
{t('Find out more')}
@@ -174,12 +167,9 @@ export const TradingModeTooltip = ({
<span>
{t('This market is in auction due to high price volatility.')}
</span>{' '}
{VEGA_DOCS_URL && (
{DocsLinks && (
<ExternalLink
href={
createDocsLinks(VEGA_DOCS_URL)
.AUCTION_TYPE_PRICE_MONITORING
}
href={DocsLinks.AUCTION_TYPE_PRICE_MONITORING}
className="ml-1"
>
{t('Find out more')}
@@ -154,19 +154,21 @@ export const NetworkSwitcher = ({
<>
{advancedNetworkKeys.map((key) => (
<DropdownMenuItem key={key} data-testid="network-item-advanced">
<div className="mr-4">
<Link href={VEGA_NETWORKS[key]}>{envNameMapping[key]}</Link>
<NetworkLabel
isCurrent={current === key}
isAvailable={!!VEGA_NETWORKS[key]}
/>
<div className="w-full flex justify-between gap-2">
<div>
<Link href={VEGA_NETWORKS[key]}>{envNameMapping[key]}</Link>
<NetworkLabel
isCurrent={current === key}
isAvailable={!!VEGA_NETWORKS[key]}
/>
</div>
<span
className="hidden md:inline"
data-testid="network-item-description"
>
{envDescriptionMapping[key]}
</span>
</div>
<span
className="hidden md:inline"
data-testid="network-item-description"
>
{envDescriptionMapping[key]}
</span>
</DropdownMenuItem>
))}
</>
+38 -23
View File
@@ -4,6 +4,8 @@ import { Networks } from '../types';
import { useEnvironment } from './use-environment';
import { stripFullStops } from '@vegaprotocol/utils';
const VEGA_DOCS_URL = process.env['NX_VEGA_DOCS_URL'] || '';
type Net = Exclude<Networks, 'CUSTOM'>;
export enum DApp {
Explorer = 'Explorer',
@@ -50,6 +52,25 @@ const Links: { [k in DApp]: DAppLinks } = {
[DApp.Token]: TokenLinks,
};
export const DocsLinks = VEGA_DOCS_URL
? {
NEW_TO_VEGA: `${VEGA_DOCS_URL}/concepts/new-to-vega`,
AUCTION_TYPE_OPENING: `${VEGA_DOCS_URL}/concepts/trading-on-vega/trading-modes#auction-type-opening`,
AUCTION_TYPE_LIQUIDITY_MONITORING: `${VEGA_DOCS_URL}/concepts/trading-on-vega/trading-modes#auction-type-liquidity-monitoring`,
AUCTION_TYPE_PRICE_MONITORING: `${VEGA_DOCS_URL}/concepts/trading-on-vega/trading-modes#auction-type-price-monitoring`,
AUCTION_TYPE_CLOSING: `${VEGA_DOCS_URL}/concepts/trading-on-vega/trading-modes#auction-type-closing`,
STAKING_GUIDE: `${VEGA_DOCS_URL}/concepts/vega-chain/#staking-on-vega`,
REWARDS_GUIDE: `${VEGA_DOCS_URL}/concepts/trading-on-vega/fees-rewards#trading-rewards`,
VEGA_WALLET_CONCEPTS_URL: `${VEGA_DOCS_URL}/concepts/vega-wallet`,
VEGA_WALLET_TOOLS_URL: `${VEGA_DOCS_URL}/tools/vega-wallet`,
PROPOSALS_GUIDE: `${VEGA_DOCS_URL}/tutorials/proposals`,
NODE_OPERATORS: `${VEGA_DOCS_URL}/node-operators`,
LOSS_SOCIALIZATION: `${VEGA_DOCS_URL}/concepts/trading-on-vega/market-protections#loss-socialisation`,
POSITION_RESOLUTION: `${VEGA_DOCS_URL}/concepts/trading-on-vega/market-protections#position-resolution`,
LIQUIDITY: `${VEGA_DOCS_URL}/concepts/liquidity/provision`,
}
: undefined;
export const useLinks = (dapp: DApp, network?: Net) => {
const { VEGA_ENV, VEGA_EXPLORER_URL, VEGA_TOKEN_URL } = useEnvironment();
const fallback = {
@@ -84,19 +105,6 @@ export const useEtherscanLink = () => {
return link;
};
export const useDocsLink = () => {
const { VEGA_DOCS_URL } = useEnvironment();
const baseUrl = trim(VEGA_DOCS_URL, '/');
const link = useCallback(
(url?: string) => `${baseUrl}/${trim(url, '/') || ''}`,
[baseUrl]
);
return link;
};
// Vega blog
export const BLOG = 'https://blog.vega.xyz/';
// Governance pages
export const TOKEN_NEW_MARKET_PROPOSAL = '/proposals/propose/new-market';
export const TOKEN_NEW_NETWORK_PARAM_PROPOSAL =
@@ -125,19 +133,26 @@ export const useProtocolUpgradeProposalLink = () => {
// Explorer pages
export const EXPLORER_TX = '/txs/:hash';
export const EXPLORER_ORACLE = '/oracles/:id';
export const EXPLORER_MARKET = '/markets/:id';
// Etherscan pages
export const ETHERSCAN_ADDRESS = '/address/:hash';
export const ETHERSCAN_TX = '/tx/:hash';
// Console pages
export const CONSOLE_MARKET = '/markets/:marketId';
export const CONSOLE_MARKETS = '/markets/all';
export const CONSOLE_PORTFOLIO = '/portfolio';
export const CONSOLE_LIQUIDITY = 'liquidity/:marketId';
export const ExternalLinks = {
FEEDBACK: 'https://github.com/vegaprotocol/feedback/discussions',
GITHUB: 'https://github.com/vegaprotocol/token-frontend',
DISCORD: 'https://vega.xyz/discord',
GOVERNANCE_PAGE: 'https://vega.xyz/governance',
VALIDATOR_FORUM: 'https://community.vega.xyz/c/mainnet-validator-candidates',
MARGIN_CREDIT_RISK:
'https://vega.xyz/papers/margins-and-credit-risk.pdf#page=7',
VEGA_WALLET_URL: 'https://vega.xyz/wallet',
VEGA_WALLET_HOSTED_URL: 'https://vega-hosted-wallet.on.fleek.co/',
BLOG: 'https://blog.vega.xyz/',
};
// Vega XYZ
export const GET_VEGA_WALLET_URL = 'https://vega.xyz/wallet/';
// Docs
export const DOCS_VEGA_WALLET = '/tools/vega-wallet';
export const TokenStaticLinks = {
PROPOSAL_PAGE: ':tokenUrl/proposals/:proposalId',
UPDATE_PROPOSAL_PAGE: ':tokenUrl/proposals/propose/update-market',
};
@@ -0,0 +1,44 @@
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuCopyItem,
DropdownMenuTrigger,
VegaIcon,
VegaIconNames,
} from '@vegaprotocol/ui-toolkit';
import { t } from '@vegaprotocol/i18n';
export const FillActionsDropdown = ({
tradeId,
buyOrderId,
sellOrderId,
}: {
tradeId: string;
buyOrderId: string;
sellOrderId: string;
}) => {
return (
<DropdownMenu
trigger={
<DropdownMenuTrigger
className="hover:bg-vega-light-200 dark:hover:bg-vega-dark-200 p-0.5 focus:rounded-full hover:rounded-full"
data-testid="dropdown-menu"
>
<VegaIcon name={VegaIconNames.KEBAB} />
</DropdownMenuTrigger>
}
>
<DropdownMenuContent data-testid="market-actions-content">
<DropdownMenuCopyItem value={tradeId} text={t('Copy trade ID')} />
<DropdownMenuCopyItem
value={buyOrderId}
text={t('Copy buy order ID')}
/>
<DropdownMenuCopyItem
value={sellOrderId}
text={t('Copy sell order ID')}
/>
</DropdownMenuContent>
</DropdownMenu>
);
};
+4
View File
@@ -48,6 +48,7 @@ describe('FillsTable', () => {
'Role',
'Fee',
'Date',
'', // action column
];
expect(headers).toHaveLength(expectedHeaders.length);
expect(headers.map((h) => h.textContent?.trim())).toEqual(expectedHeaders);
@@ -77,6 +78,7 @@ describe('FillsTable', () => {
'Maker',
'2.00 BTC',
getDateTimeFormat().format(new Date(buyerFill.createdAt)),
'', // action column
];
cells.forEach((cell, i) => {
expect(cell).toHaveTextContent(expectedValues[i]);
@@ -111,6 +113,7 @@ describe('FillsTable', () => {
'Taker',
'0.03 BTC',
getDateTimeFormat().format(new Date(buyerFill.createdAt)),
'', // action column
];
cells.forEach((cell, i) => {
expect(cell).toHaveTextContent(expectedValues[i]);
@@ -145,6 +148,7 @@ describe('FillsTable', () => {
'-',
'0.03 BTC',
getDateTimeFormat().format(new Date(buyerFill.createdAt)),
'', // action column
];
cells.forEach((cell, i) => {
expect(cell).toHaveTextContent(expectedValues[i]);
+20 -1
View File
@@ -19,12 +19,17 @@ import {
positiveClassNames,
negativeClassNames,
MarketNameCell,
COL_DEFS,
} from '@vegaprotocol/datagrid';
import type {
VegaValueFormatterParams,
VegaICellRendererParams,
} from '@vegaprotocol/datagrid';
import type { VegaValueFormatterParams } from '@vegaprotocol/datagrid';
import { forwardRef } from 'react';
import BigNumber from 'bignumber.js';
import type { Trade } from './fills-data-provider';
import type { FillFieldsFragment } from './__generated__/Fills';
import { FillActionsDropdown } from './fill-actions-dropdown';
const TAKER = 'Taker';
const MAKER = 'Maker';
@@ -108,6 +113,20 @@ export const FillsTable = forwardRef<AgGridReact, Props>(
return value ? getDateTimeFormat().format(new Date(value)) : '';
}}
/>
<AgGridColumn
colId="fill-actions"
{...COL_DEFS.actions}
cellRenderer={({ data }: VegaICellRendererParams<Trade, 'id'>) => {
if (!data) return null;
return (
<FillActionsDropdown
buyOrderId={data.buyOrder}
sellOrderId={data.sellOrder}
tradeId={data.id}
/>
);
}}
/>
</AgGrid>
);
}
+1 -1
View File
@@ -1,5 +1,5 @@
{
"name": "@vegaprotocol/i18n",
"version": "0.0.2",
"version": "0.0.3",
"type": "commonjs"
}
@@ -1,5 +1,5 @@
import { useEnvironment } from '@vegaprotocol/environment';
import { removePaginationWrapper, TokenLinks } from '@vegaprotocol/utils';
import { TokenStaticLinks, useEnvironment } from '@vegaprotocol/environment';
import { removePaginationWrapper } from '@vegaprotocol/utils';
import { t } from '@vegaprotocol/i18n';
import { useDataProvider } from '@vegaprotocol/data-provider';
import * as Schema from '@vegaprotocol/types';
@@ -236,7 +236,7 @@ export const MarketInfoAccordion = ({
{VEGA_TOKEN_URL && (
<ExternalLink
className="mb-2 w-full"
href={generatePath(TokenLinks.PROPOSAL_PAGE, {
href={generatePath(TokenStaticLinks.PROPOSAL_PAGE, {
tokenUrl: VEGA_TOKEN_URL,
proposalId: market.proposal?.id || '',
})}
@@ -252,7 +252,7 @@ export const MarketInfoAccordion = ({
{VEGA_TOKEN_URL && (
<ExternalLink
className="w-full"
href={generatePath(TokenLinks.UPDATE_PROPOSAL_PAGE, {
href={generatePath(TokenStaticLinks.UPDATE_PROPOSAL_PAGE, {
tokenUrl: VEGA_TOKEN_URL,
})}
title={
@@ -1,4 +1,4 @@
import { ExternalLinks } from '@vegaprotocol/utils';
import { ExternalLinks } from '@vegaprotocol/environment';
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
import { t } from '@vegaprotocol/i18n';
import type { ReactNode } from 'react';
@@ -1 +1,2 @@
export * from './markets-container';
export * from './market-table-actions';
@@ -0,0 +1 @@
export * from './market-table-actions';
@@ -0,0 +1,59 @@
import { t } from '@vegaprotocol/i18n';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
DropdownMenuCopyItem,
Link,
VegaIcon,
VegaIconNames,
} from '@vegaprotocol/ui-toolkit';
import { DApp, EXPLORER_MARKET, useLinks } from '@vegaprotocol/environment';
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
export const MarketTableActions = ({
marketId,
assetId,
}: {
marketId: string;
assetId: string;
}) => {
const open = useAssetDetailsDialogStore((store) => store.open);
const linkCreator = useLinks(DApp.Explorer);
return (
<DropdownMenu
trigger={
<DropdownMenuTrigger
className="hover:bg-vega-light-200 dark:hover:bg-vega-dark-200 p-0.5 focus:rounded-full hover:rounded-full"
data-testid="dropdown-menu"
>
<VegaIcon name={VegaIconNames.KEBAB} />
</DropdownMenuTrigger>
}
>
<DropdownMenuContent data-testid="market-actions-content">
<DropdownMenuCopyItem value={marketId} text={t('Copy Market ID')} />
<DropdownMenuItem>
<Link
href={linkCreator(EXPLORER_MARKET.replace(':id', marketId))}
target="_blank"
>
<span className="flex gap-2">
<VegaIcon name={VegaIconNames.OPEN_EXTERNAL} size={16} />
{t('View on Explorer')}
</span>
</Link>
</DropdownMenuItem>
<DropdownMenuItem
onClick={(e) => {
open(assetId, e.target as HTMLElement);
}}
>
<VegaIcon name={VegaIconNames.OPEN_EXTERNAL} size={16} />
{t('View asset')}
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
);
};
@@ -7,6 +7,7 @@ import type {
VegaICellRendererParams,
TypedDataAgGrid,
} from '@vegaprotocol/datagrid';
import { COL_DEFS } from '@vegaprotocol/datagrid';
import {
AgGridLazy as AgGrid,
PriceFlashCell,
@@ -18,6 +19,7 @@ import { AgGridColumn } from 'ag-grid-react';
import type { AgGridReact } from 'ag-grid-react';
import * as Schema from '@vegaprotocol/types';
import type { MarketMaybeWithData } from '../../';
import { MarketTableActions } from '../../';
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
const { MarketTradingMode, AuctionTrigger } = Schema;
@@ -176,15 +178,13 @@ export const MarketListTable = forwardRef<
/>
<AgGridColumn
headerName={t('Settlement asset')}
field="tradableInstrument.instrument.product.settlementAsset.symbol"
field="tradableInstrument.instrument.product.settlementAsset"
cellRenderer={({
data,
value,
}: VegaICellRendererParams<
MarketMaybeWithData,
'tradableInstrument.instrument.product.settlementAsset.symbol'
'tradableInstrument.instrument.product.settlementAsset'
>) => {
const value =
data?.tradableInstrument.instrument.product.settlementAsset;
return value ? (
<ButtonLink
onClick={(e) => {
@@ -198,7 +198,23 @@ export const MarketListTable = forwardRef<
);
}}
/>
<AgGridColumn headerName={t('Market ID')} field="id" flex={1} />
<AgGridColumn
colId="market-actions"
{...COL_DEFS.actions}
cellRenderer={({
data,
}: VegaICellRendererParams<MarketMaybeWithData>) => {
if (!data) return null;
return (
<MarketTableActions
marketId={data.id}
assetId={
data.tradableInstrument.instrument.product.settlementAsset.id
}
/>
);
}}
/>
</AgGrid>
);
});
@@ -36,9 +36,12 @@ export const MarketsContainer = ({ onSelect }: MarketsContainerProps) => {
suppressNoRowsOverlay
onCellClicked={(cellEvent: CellClickedEvent) => {
const { data, column, event } = cellEvent;
// prevent navigating to the market page if any of the below cells are clicked
// event.preventDefault or event.stopPropagation dont seem to apply for aggird
const colId = column.getColId();
if (
[
'id',
'tradableInstrument.instrument.code',
'tradableInstrument.instrument.product.settlementAsset',
].includes(colId)
@@ -0,0 +1 @@
export * from './order-actions-dropdown';
@@ -0,0 +1,28 @@
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuCopyItem,
DropdownMenuTrigger,
VegaIcon,
VegaIconNames,
} from '@vegaprotocol/ui-toolkit';
import { t } from '@vegaprotocol/i18n';
export const OrderActionsDropdown = ({ id }: { id: string }) => {
return (
<DropdownMenu
trigger={
<DropdownMenuTrigger
className="hover:bg-vega-light-200 dark:hover:bg-vega-dark-200 p-0.5 focus:rounded-full hover:rounded-full"
data-testid="dropdown-menu"
>
<VegaIcon name={VegaIconNames.KEBAB} />
</DropdownMenuTrigger>
}
>
<DropdownMenuContent data-testid="market-actions-content">
<DropdownMenuCopyItem value={id} text={t('Copy order ID')} />
</DropdownMenuContent>
</DropdownMenu>
);
};
@@ -145,7 +145,7 @@ export const OrderListManager = ({
<OrderListTable
rowData={data as Order[]}
ref={gridRef}
readonlyStatusFilter={filter !== undefined}
filter={filter}
onGridReady={onGridReady}
cancel={cancel}
setEditOrder={setEditOrder}
@@ -160,7 +160,6 @@ describe('OrderListTable', () => {
);
});
const amendCell = getAmendCell();
expect(amendCell.getAllByRole('button')).toHaveLength(2);
await userEvent.click(amendCell.getByTestId('edit'));
expect(mockEdit).toHaveBeenCalledWith(order);
await userEvent.click(amendCell.getByTestId('cancel'));
@@ -187,7 +186,8 @@ describe('OrderListTable', () => {
);
});
const amendCell = getAmendCell();
expect(amendCell.queryAllByRole('button')).toHaveLength(0);
expect(amendCell.queryByTestId('edit')).not.toBeInTheDocument();
expect(amendCell.queryByTestId('cancel')).not.toBeInTheDocument();
});
it('shows if an order is a liquidity provision order and does not show order actions', async () => {
@@ -204,7 +204,8 @@ describe('OrderListTable', () => {
const amendCell = getAmendCell();
const typeCell = screen.getAllByRole('gridcell')[2];
expect(typeCell).toHaveTextContent('Liquidity provision');
expect(amendCell.queryAllByRole('button')).toHaveLength(0);
expect(amendCell.queryByTestId('edit')).not.toBeInTheDocument();
expect(amendCell.queryByTestId('cancel')).not.toBeInTheDocument();
});
it('shows if an order is a pegged order and does not show order actions', async () => {
@@ -225,7 +226,8 @@ describe('OrderListTable', () => {
const amendCell = getAmendCell();
const typeCell = screen.getAllByRole('gridcell')[2];
expect(typeCell).toHaveTextContent('Mid - 10.0 Peg limit');
expect(amendCell.queryAllByRole('button')).toHaveLength(0);
expect(amendCell.queryByTestId('edit')).not.toBeInTheDocument();
expect(amendCell.queryByTestId('cancel')).not.toBeInTheDocument();
});
it.each([
@@ -242,7 +244,7 @@ describe('OrderListTable', () => {
});
const amendCell = getAmendCell();
expect(amendCell.getAllByRole('button')).toHaveLength(2);
expect(amendCell.getAllByRole('button')).toHaveLength(3);
});
it.each([
@@ -251,19 +253,23 @@ describe('OrderListTable', () => {
Schema.OrderStatus.STATUS_FILLED,
Schema.OrderStatus.STATUS_REJECTED,
Schema.OrderStatus.STATUS_STOPPED,
])('does not show buttons for %s orders', async (status) => {
const order = generateOrder({
type: Schema.OrderType.TYPE_LIMIT,
status,
});
])(
'does not show edit and cancel buttons for %s orders',
async (status) => {
const order = generateOrder({
type: Schema.OrderType.TYPE_LIMIT,
status,
});
await act(async () => {
render(generateJsx({ rowData: [order] }));
});
await act(async () => {
render(generateJsx({ rowData: [order] }));
});
const amendCell = getAmendCell();
expect(amendCell.queryAllByRole('button')).toHaveLength(0);
});
const amendCell = getAmendCell();
expect(amendCell.queryByTestId('edit')).not.toBeInTheDocument();
expect(amendCell.queryByTestId('cancel')).not.toBeInTheDocument();
}
);
const getAmendCell = () => {
const cells = screen.getAllByRole('gridcell');

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