Compare commits

...

6 Commits

Author SHA1 Message Date
88264d890d Remove '.git' from .dockerignore; the Vega build process uses git commands ('rev-parse') to navigate 2024-03-29 18:52:21 -07:00
Alessio
26b78f878b Add a simple path prefix for static assets 2024-03-29 11:12:26 -07:00
Art
054c0377b4
chore(governance): lp votes for batch proposal (#5914)
Co-authored-by: Dariusz Majcherczyk <dariusz.majcherczyk@gmail.com>
2024-03-11 13:10:34 +01:00
Matthew Russell
29bcbd06fb
fix(trading,types): fix default build and type generation commands (#5959) 2024-03-11 10:06:59 +00:00
Matthew Russell
1d721dc748
fix(trading): party alias snags (#5947)
Co-authored-by: Dariusz Majcherczyk <dariusz.majcherczyk@gmail.com>
2024-03-08 17:29:41 +00:00
Matthew Russell
1d71a839b3
fix(trading): manifest.json and woff preloading (#5950) 2024-03-08 17:27:36 +00:00
33 changed files with 342 additions and 106 deletions

View File

@ -4,6 +4,5 @@ tmp/*
.dockerignore .dockerignore
dockerfiles dockerfiles
node_modules node_modules
.git
.github .github
.vscode .vscode

View File

@ -38,6 +38,7 @@ import { differenceInHours, format, formatDistanceToNowStrict } from 'date-fns';
import { DATE_FORMAT_DETAILED } from '../../../../lib/date-formats'; import { DATE_FORMAT_DETAILED } from '../../../../lib/date-formats';
import { MarketName } from '../proposal/market-name'; import { MarketName } from '../proposal/market-name';
import { Indicator } from '../proposal/indicator'; import { Indicator } from '../proposal/indicator';
import { type ProposalNode } from '../proposal/proposal-utils';
const ProposalTypeTags = ({ const ProposalTypeTags = ({
proposal, proposal,
@ -540,10 +541,12 @@ const BatchProposalStateText = ({
export const ProposalHeader = ({ export const ProposalHeader = ({
proposal, proposal,
restData,
isListItem = true, isListItem = true,
voteState, voteState,
}: { }: {
proposal: Proposal | BatchProposal; proposal: Proposal | BatchProposal;
restData?: ProposalNode | null;
isListItem?: boolean; isListItem?: boolean;
voteState?: VoteState | null; voteState?: VoteState | null;
}) => { }) => {
@ -595,7 +598,7 @@ export const ProposalHeader = ({
)} )}
</div> </div>
<ProposalDetails proposal={proposal} /> <ProposalDetails proposal={proposal} />
<VoteBreakdown proposal={proposal} /> <VoteBreakdown proposal={proposal} restData={restData} />
</> </>
); );
}; };

View File

@ -91,6 +91,28 @@ export type ProposalNode = {
proposal: ProposalData; proposal: ProposalData;
proposalType: ProposalNodeType; proposalType: ProposalNodeType;
proposals: SubProposalData[]; proposals: SubProposalData[];
yes?: [
{
partyId: string;
elsPerMarket?: [
{
marketId: string;
els: string;
}
];
}
];
no?: [
{
partyId: string;
elsPerMarket?: [
{
marketId: string;
els: string;
}
];
}
];
}; };
type SingleProposalNode = ProposalNode & { type SingleProposalNode = ProposalNode & {

View File

@ -48,6 +48,7 @@ export const Proposal = ({ proposal, restData }: ProposalProps) => {
<ProposalHeader <ProposalHeader
proposal={proposal} proposal={proposal}
restData={restData}
isListItem={false} isListItem={false}
voteState={voteState} voteState={voteState}
/> />

View File

@ -17,6 +17,7 @@ import {
import { useBatchVoteInformation } from '../../hooks/use-vote-information'; import { useBatchVoteInformation } from '../../hooks/use-vote-information';
import { MarketName } from '../proposal/market-name'; import { MarketName } from '../proposal/market-name';
import { Indicator } from '../proposal/indicator'; import { Indicator } from '../proposal/indicator';
import { type ProposalNode } from '../proposal/proposal-utils';
export const CompactVotes = ({ number }: { number: BigNumber }) => ( export const CompactVotes = ({ number }: { number: BigNumber }) => (
<CompactNumber <CompactNumber
@ -110,24 +111,64 @@ const Status = ({ reached, threshold, text, testId }: StatusProps) => {
export const VoteBreakdown = ({ export const VoteBreakdown = ({
proposal, proposal,
restData,
}: { }: {
proposal: Proposal | BatchProposal; proposal: Proposal | BatchProposal;
restData?: ProposalNode | null;
}) => { }) => {
if (proposal.__typename === 'Proposal') { if (proposal.__typename === 'Proposal') {
return <VoteBreakdownNormal proposal={proposal} />; return <VoteBreakdownNormal proposal={proposal} />;
} }
if (proposal.__typename === 'BatchProposal') { if (proposal.__typename === 'BatchProposal') {
return <VoteBreakdownBatch proposal={proposal} />; return <VoteBreakdownBatch proposal={proposal} restData={restData} />;
} }
return null; return null;
}; };
const VoteBreakdownBatch = ({ proposal }: { proposal: BatchProposal }) => { const VoteBreakdownBatch = ({
proposal,
restData,
}: {
proposal: BatchProposal;
restData?: ProposalNode | null;
}) => {
const [fullBreakdown, setFullBreakdown] = useState(false); const [fullBreakdown, setFullBreakdown] = useState(false);
const { t } = useTranslation(); const { t } = useTranslation();
const yesELS =
restData?.yes?.reduce((all, y) => {
if (y.elsPerMarket) {
y.elsPerMarket.forEach((item) => {
const share = Number(item.els);
if (all[item.marketId]) {
all[item.marketId].push(share);
} else {
all[item.marketId] = [share];
}
return all;
});
}
return all;
}, {} as Record<string, number[]>) || {};
const noELS =
restData?.no?.reduce((all, y) => {
if (y.elsPerMarket) {
y.elsPerMarket.forEach((item) => {
const share = Number(item.els);
if (all[item.marketId]) {
all[item.marketId].push(share);
} else {
all[item.marketId] = [share];
}
return all;
});
}
return all;
}, {} as Record<string, number[]>) || {};
const voteInfo = useBatchVoteInformation({ const voteInfo = useBatchVoteInformation({
terms: compact( terms: compact(
proposal.subProposals ? proposal.subProposals.map((p) => p?.terms) : [] proposal.subProposals ? proposal.subProposals.map((p) => p?.terms) : []
@ -194,6 +235,8 @@ const VoteBreakdownBatch = ({ proposal }: { proposal: BatchProposal }) => {
proposal={proposal} proposal={proposal}
votes={proposal.votes} votes={proposal.votes}
terms={p.terms} terms={p.terms}
yesELS={yesELS}
noELS={noELS}
/> />
); );
})} })}
@ -254,6 +297,8 @@ const VoteBreakdownBatch = ({ proposal }: { proposal: BatchProposal }) => {
proposal={proposal} proposal={proposal}
votes={proposal.votes} votes={proposal.votes}
terms={p.terms} terms={p.terms}
yesELS={yesELS}
noELS={noELS}
/> />
); );
})} })}
@ -271,17 +316,17 @@ const VoteBreakdownBatchSubProposal = ({
votes, votes,
terms, terms,
indicator, indicator,
yesELS,
noELS,
}: { }: {
proposal: BatchProposal; proposal: BatchProposal;
votes: VoteFieldsFragment; votes: VoteFieldsFragment;
terms: ProposalTermsFieldsFragment; terms: ProposalTermsFieldsFragment;
indicator?: number; indicator?: number;
yesELS: Record<string, number[]>;
noELS: Record<string, number[]>;
}) => { }) => {
const { t } = useTranslation(); const { t } = useTranslation();
const voteInfo = useVoteInformation({
votes,
terms,
});
const isProposalOpen = proposal?.state === ProposalState.STATE_OPEN; const isProposalOpen = proposal?.state === ProposalState.STATE_OPEN;
const isUpdateMarket = terms?.change?.__typename === 'UpdateMarket'; const isUpdateMarket = terms?.change?.__typename === 'UpdateMarket';
@ -294,6 +339,15 @@ const VoteBreakdownBatchSubProposal = ({
marketId = terms.change.market.id; marketId = terms.change.market.id;
} }
const voteInfo = useVoteInformation({
votes,
terms,
// yes votes ELS for this specific proposal (market)
yesELS: marketId ? yesELS[marketId] : undefined,
// no votes ELS for this specific proposal (market)
noELS: marketId ? noELS[marketId] : undefined,
});
const marketName = marketId ? ( const marketName = marketId ? (
<> <>
: <MarketName marketId={marketId} /> : <MarketName marketId={marketId} />

View File

@ -8,13 +8,18 @@ import {
type VoteFieldsFragment, type VoteFieldsFragment,
} from '../__generated__/Proposals'; } from '../__generated__/Proposals';
import { type ProposalChangeType } from '../types'; import { type ProposalChangeType } from '../types';
import sum from 'lodash/sum';
export const useVoteInformation = ({ export const useVoteInformation = ({
votes, votes,
terms, terms,
yesELS,
noELS,
}: { }: {
votes: VoteFieldsFragment; votes: VoteFieldsFragment;
terms: ProposalTermsFieldsFragment; terms: ProposalTermsFieldsFragment;
yesELS?: number[];
noELS?: number[];
}) => { }) => {
const { const {
appState: { totalSupply, decimals }, appState: { totalSupply, decimals },
@ -31,7 +36,9 @@ export const useVoteInformation = ({
paramsForChange, paramsForChange,
votes, votes,
totalSupply, totalSupply,
decimals decimals,
yesELS,
noELS
); );
}; };
@ -72,7 +79,11 @@ const getVoteData = (
}, },
votes: ProposalFieldsFragment['votes'], votes: ProposalFieldsFragment['votes'],
totalSupply: BigNumber, totalSupply: BigNumber,
decimals: number decimals: number,
/** A list of ELS yes votes */
yesELS?: number[],
/** A list if ELS no votes */
noELS?: number[]
) => { ) => {
const requiredMajorityPercentage = params.requiredMajority const requiredMajorityPercentage = params.requiredMajority
? new BigNumber(params.requiredMajority).times(100) ? new BigNumber(params.requiredMajority).times(100)
@ -86,17 +97,31 @@ const getVoteData = (
addDecimal(votes.no.totalTokens ?? 0, decimals) addDecimal(votes.no.totalTokens ?? 0, decimals)
); );
const noEquityLikeShareWeight = !votes.no.totalEquityLikeShareWeight let noEquityLikeShareWeight = !votes.no.totalEquityLikeShareWeight
? new BigNumber(0) ? new BigNumber(0)
: new BigNumber(votes.no.totalEquityLikeShareWeight).times(100); : new BigNumber(votes.no.totalEquityLikeShareWeight).times(100);
// there's no meaningful `totalEquityLikeShareWeight` in batch proposals,
// it has to be deduced from `elsPerMarket` of `no` votes of given proposal
// data. (by REST DATA)
if (noELS != null) {
const noTotalELS = sum(noELS);
noEquityLikeShareWeight = new BigNumber(noTotalELS).times(100);
}
const yesTokens = new BigNumber( const yesTokens = new BigNumber(
addDecimal(votes.yes.totalTokens ?? 0, decimals) addDecimal(votes.yes.totalTokens ?? 0, decimals)
); );
const yesEquityLikeShareWeight = !votes.yes.totalEquityLikeShareWeight let yesEquityLikeShareWeight = !votes.yes.totalEquityLikeShareWeight
? new BigNumber(0) ? new BigNumber(0)
: new BigNumber(votes.yes.totalEquityLikeShareWeight).times(100); : new BigNumber(votes.yes.totalEquityLikeShareWeight).times(100);
// there's no meaningful `totalEquityLikeShareWeight` in batch proposals,
// it has to be deduced from `elsPerMarket` of `yes` votes of given proposal
// data. (by REST DATA)
if (noELS != null) {
const yesTotalELS = sum(yesELS);
yesEquityLikeShareWeight = new BigNumber(yesTotalELS).times(100);
}
const totalTokensVoted = yesTokens.plus(noTokens); const totalTokensVoted = yesTokens.plus(noTokens);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 547 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -1,22 +0,0 @@
{
"name": "Vega Protocol - Trading",
"short_name": "Console",
"description": "Vega Protocol - Trading dApp",
"start_url": "/",
"display": "standalone",
"orientation": "portrait",
"theme_color": "#000000",
"background_color": "#ffffff",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
}
]
}

View File

@ -170,6 +170,9 @@ const cacheConfig: InMemoryCacheConfig = {
Fees: { Fees: {
keyFields: false, keyFields: false,
}, },
PartyProfile: {
keyFields: ['partyId'],
},
// The folling types are cached by the data provider and not by apollo // The folling types are cached by the data provider and not by apollo
PositionUpdate: { PositionUpdate: {
keyFields: false, keyFields: false,

View File

@ -8,6 +8,12 @@ import {
mockConfig, mockConfig,
MockedWalletProvider, MockedWalletProvider,
} from '@vegaprotocol/wallet-react/testing'; } from '@vegaprotocol/wallet-react/testing';
import { MockedProvider, type MockedResponse } from '@apollo/react-testing';
import {
PartyProfilesDocument,
type PartyProfilesQuery,
type PartyProfilesQueryVariables,
} from '../vega-wallet-connect-button/__generated__/PartyProfiles';
jest.mock('@vegaprotocol/proposals', () => ({ jest.mock('@vegaprotocol/proposals', () => ({
ProtocolUpgradeCountdown: () => null, ProtocolUpgradeCountdown: () => null,
@ -24,15 +30,45 @@ describe('Navbar', () => {
publicKey: '2'.repeat(64), publicKey: '2'.repeat(64),
}, },
]; ];
const key1Alias = 'key 1 alias';
const marketId = 'abc'; const marketId = 'abc';
const navbarContent = 'navbar-menu-content'; const navbarContent = 'navbar-menu-content';
const partyProfilesMock: MockedResponse<
PartyProfilesQuery,
PartyProfilesQueryVariables
> = {
request: {
query: PartyProfilesDocument,
variables: {
partyIds: mockKeys.map((k) => k.publicKey),
},
},
result: {
data: {
partiesProfilesConnection: {
edges: [
{
node: {
partyId: mockKeys[0].publicKey,
alias: key1Alias,
metadata: [],
},
},
],
},
},
},
};
const renderComponent = (initialEntries?: string[]) => { const renderComponent = (initialEntries?: string[]) => {
return render( return render(
<MemoryRouter initialEntries={initialEntries}> <MemoryRouter initialEntries={initialEntries}>
<MockedProvider mocks={[partyProfilesMock]}>
<MockedWalletProvider> <MockedWalletProvider>
<Navbar /> <Navbar />
</MockedWalletProvider> </MockedWalletProvider>
</MockedProvider>
</MemoryRouter> </MemoryRouter>
); );
}; };
@ -140,6 +176,7 @@ describe('Navbar', () => {
const activeKey = within(menu.getByTestId(/key-1+-mobile/)); const activeKey = within(menu.getByTestId(/key-1+-mobile/));
expect(activeKey.getByText(mockKeys[0].name)).toBeInTheDocument(); expect(activeKey.getByText(mockKeys[0].name)).toBeInTheDocument();
expect(activeKey.getByTestId('icon-tick')).toBeInTheDocument(); expect(activeKey.getByTestId('icon-tick')).toBeInTheDocument();
expect(screen.getByText(key1Alias)).toBeInTheDocument();
const inactiveKey = within(menu.getByTestId(/key-2+-mobile/)); const inactiveKey = within(menu.getByTestId(/key-2+-mobile/));
await userEvent.click(inactiveKey.getByText(mockKeys[1].name)); await userEvent.click(inactiveKey.getByText(mockKeys[1].name));

View File

@ -31,39 +31,27 @@ export const ProfileDialog = () => {
const pubKey = useProfileDialogStore((store) => store.pubKey); const pubKey = useProfileDialogStore((store) => store.pubKey);
const setOpen = useProfileDialogStore((store) => store.setOpen); const setOpen = useProfileDialogStore((store) => store.setOpen);
const { send, status, error, reset } = useSimpleTransaction({
onSuccess: () => {
refetch();
},
});
const profileEdge = data?.partiesProfilesConnection?.edges.find( const profileEdge = data?.partiesProfilesConnection?.edges.find(
(e) => e.node.partyId === pubKey (e) => e.node.partyId === pubKey
); );
const sendTx = (field: FormFields) => {
send({
updatePartyProfile: {
alias: field.alias,
metadata: [],
},
});
};
return ( return (
<Dialog <Dialog
open={open} open={open}
onChange={() => { onChange={() => {
setOpen(undefined); setOpen(undefined);
reset();
}} }}
title={t('Edit profile')} title={t('Edit profile')}
> >
<ProfileForm <ProfileFormContainer
profile={profileEdge?.node} profile={profileEdge?.node}
status={status} onSuccess={() => {
error={error} refetch();
onSubmit={sendTx}
setTimeout(() => {
setOpen(undefined);
}, 1000);
}}
/> />
</Dialog> </Dialog>
); );
@ -77,6 +65,32 @@ type Profile = NonNullable<
PartyProfilesQuery['partiesProfilesConnection'] PartyProfilesQuery['partiesProfilesConnection']
>['edges'][number]['node']; >['edges'][number]['node'];
const ProfileFormContainer = ({
profile,
onSuccess,
}: {
profile: Profile | undefined;
onSuccess: () => void;
}) => {
const { send, status, error } = useSimpleTransaction({ onSuccess });
const sendTx = (field: FormFields) => {
send({
updatePartyProfile: {
alias: field.alias,
metadata: [],
},
});
};
return (
<ProfileForm
profile={profile}
status={status}
error={error}
onSubmit={sendTx}
/>
);
};
const ProfileForm = ({ const ProfileForm = ({
profile, profile,
onSubmit, onSubmit,
@ -114,6 +128,14 @@ const ProfileForm = ({
const errorMessage = errors.alias?.message || error; const errorMessage = errors.alias?.message || error;
if (status === 'confirmed') {
return (
<p className="mt-2 mb-4 text-sm text-vega-green-600 dark:text-vega-green">
{t('Profile updated')}
</p>
);
}
return ( return (
<form onSubmit={handleSubmit(onSubmit)} className="mt-3"> <form onSubmit={handleSubmit(onSubmit)} className="mt-3">
<FormGroup label="Alias" labelFor="alias"> <FormGroup label="Alias" labelFor="alias">
@ -131,12 +153,6 @@ const ProfileForm = ({
</p> </p>
</InputError> </InputError>
)} )}
{status === 'confirmed' && (
<p className="mt-2 mb-4 text-sm text-success">
{t('Profile updated')}
</p>
)}
</FormGroup> </FormGroup>
<TradingButton <TradingButton
type="submit" type="submit"

View File

@ -94,6 +94,7 @@ export const VegaWalletConnectButton = ({
<KeypairRadioGroup <KeypairRadioGroup
pubKey={pubKey} pubKey={pubKey}
pubKeys={pubKeys} pubKeys={pubKeys}
activeKey={activeKey?.publicKey}
onSelect={selectPubKey} onSelect={selectPubKey}
/> />
<TradingDropdownSeparator /> <TradingDropdownSeparator />
@ -138,15 +139,18 @@ export const VegaWalletConnectButton = ({
const KeypairRadioGroup = ({ const KeypairRadioGroup = ({
pubKey, pubKey,
pubKeys, pubKeys,
activeKey,
onSelect, onSelect,
}: { }: {
pubKey: string | undefined; pubKey: string | undefined;
pubKeys: Key[]; pubKeys: Key[];
activeKey: string | undefined;
onSelect: (pubKey: string) => void; onSelect: (pubKey: string) => void;
}) => { }) => {
const { data } = usePartyProfilesQuery({ const { data } = usePartyProfilesQuery({
variables: { partyIds: pubKeys.map((pk) => pk.publicKey) }, variables: { partyIds: pubKeys.map((pk) => pk.publicKey) },
skip: pubKeys.length <= 0, skip: pubKeys.length <= 0,
fetchPolicy: 'cache-and-network',
}); });
return ( return (
@ -156,14 +160,27 @@ const KeypairRadioGroup = ({
(e) => e.node.partyId === pk.publicKey (e) => e.node.partyId === pk.publicKey
); );
return ( return (
<KeypairItem key={pk.publicKey} pk={pk} alias={profile?.node.alias} /> <KeypairItem
key={pk.publicKey}
pk={pk}
isActive={activeKey === pk.publicKey}
alias={profile?.node.alias}
/>
); );
})} })}
</TradingDropdownRadioGroup> </TradingDropdownRadioGroup>
); );
}; };
const KeypairItem = ({ pk, alias }: { pk: Key; alias: string | undefined }) => { const KeypairItem = ({
pk,
isActive,
alias,
}: {
pk: Key;
alias: string | undefined;
isActive: boolean;
}) => {
const t = useT(); const t = useT();
const [copied, setCopied] = useCopyTimeout(); const [copied, setCopied] = useCopyTimeout();
const setOpen = useProfileDialogStore((store) => store.setOpen); const setOpen = useProfileDialogStore((store) => store.setOpen);
@ -194,8 +211,13 @@ const KeypairItem = ({ pk, alias }: { pk: Key; alias: string | undefined }) => {
data-testid={`key-${pk.publicKey}`} data-testid={`key-${pk.publicKey}`}
> >
<Tooltip description={t('Public facing key alias. Click to edit')}> <Tooltip description={t('Public facing key alias. Click to edit')}>
<button data-testid="alias" onClick={() => setOpen(pk.publicKey)}> <button
data-testid="alias"
onClick={() => setOpen(pk.publicKey)}
className="flex items-center gap-1"
>
{alias ? alias : t('No alias')} {alias ? alias : t('No alias')}
{isActive && <VegaIcon name={VegaIconNames.EDIT} />}
</button> </button>
</Tooltip> </Tooltip>
</div> </div>

View File

@ -12,6 +12,8 @@ import CopyToClipboard from 'react-copy-to-clipboard';
import { ViewType, useSidebar } from '../sidebar'; import { ViewType, useSidebar } from '../sidebar';
import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id'; import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id';
import { useT } from '../../lib/use-t'; import { useT } from '../../lib/use-t';
import { usePartyProfilesQuery } from '../vega-wallet-connect-button/__generated__/PartyProfiles';
import { useProfileDialogStore } from '../../stores/profile-dialog-store';
export const VegaWalletMenu = ({ export const VegaWalletMenu = ({
setMenu, setMenu,
@ -23,6 +25,12 @@ export const VegaWalletMenu = ({
const currentRouteId = useGetCurrentRouteId(); const currentRouteId = useGetCurrentRouteId();
const setViews = useSidebar((store) => store.setViews); const setViews = useSidebar((store) => store.setViews);
const { data } = usePartyProfilesQuery({
variables: { partyIds: pubKeys.map((pk) => pk.publicKey) },
skip: pubKeys.length <= 0,
fetchPolicy: 'cache-and-network',
});
const activeKey = useMemo(() => { const activeKey = useMemo(() => {
return pubKeys?.find((pk) => pk.publicKey === pubKey); return pubKeys?.find((pk) => pk.publicKey === pubKey);
}, [pubKey, pubKeys]); }, [pubKey, pubKeys]);
@ -37,14 +45,21 @@ export const VegaWalletMenu = ({
return ( return (
<div> <div>
<div className="grow my-4" role="list"> <div className="grow my-4" role="list">
{(pubKeys || []).map((pk) => ( {(pubKeys || []).map((pk) => {
const profile = data?.partiesProfilesConnection?.edges.find(
(e) => e.node.partyId === pk.publicKey
);
return (
<KeypairListItem <KeypairListItem
key={pk.publicKey} key={pk.publicKey}
pk={pk} pk={pk}
isActive={activeKey?.publicKey === pk.publicKey} isActive={activeKey?.publicKey === pk.publicKey}
onSelectItem={onSelectItem} onSelectItem={onSelectItem}
alias={profile?.node.alias}
setMenu={setMenu}
/> />
))} );
})}
</div> </div>
<div className="flex flex-col gap-2 m-4"> <div className="flex flex-col gap-2 m-4">
@ -72,18 +87,23 @@ export const VegaWalletMenu = ({
const KeypairListItem = ({ const KeypairListItem = ({
pk, pk,
isActive, isActive,
alias,
onSelectItem, onSelectItem,
setMenu,
}: { }: {
pk: Key; pk: Key;
isActive: boolean; isActive: boolean;
alias: string | undefined;
onSelectItem: (pk: string) => void; onSelectItem: (pk: string) => void;
setMenu: (open: 'nav' | 'wallet' | null) => void;
}) => { }) => {
const t = useT(); const t = useT();
const [copied, setCopied] = useCopyTimeout(); const [copied, setCopied] = useCopyTimeout();
const setOpen = useProfileDialogStore((store) => store.setOpen);
return ( return (
<div <div
className="flex flex-col w-full ml-4 mr-2 mb-4" className="flex flex-col w-full px-4 mb-4"
data-testid={`key-${pk.publicKey}-mobile`} data-testid={`key-${pk.publicKey}-mobile`}
> >
<span className="flex gap-2 items-center mr-2"> <span className="flex gap-2 items-center mr-2">
@ -106,6 +126,24 @@ const KeypairListItem = ({
</CopyToClipboard> </CopyToClipboard>
{copied && <span className="text-xs">{t('Copied')}</span>} {copied && <span className="text-xs">{t('Copied')}</span>}
</span> </span>
<span
className="flex gap-2 items-center"
data-testid={`key-${pk.publicKey}`}
>
<span className="truncate">{alias ? alias : t('No alias')}</span>
{isActive && (
<button
data-testid="alias"
onClick={() => {
setOpen(pk.publicKey);
setMenu(null);
}}
className="flex items-center gap-1"
>
<VegaIcon name={VegaIconNames.EDIT} />
</button>
)}
</span>
</div> </div>
); );
}; };

View File

@ -186,7 +186,7 @@ def test_reward_history(
def test_staking_reward( def test_staking_reward(
setup_environment: Tuple[Page, str, str], setup_environment: Tuple[Page, str, str],
) -> None: ):
page, tDAI_market, tDAI_asset_id = setup_environment page, tDAI_market, tDAI_asset_id = setup_environment
expect(page.get_by_test_id("active-rewards-card")).to_have_count(2) expect(page.get_by_test_id("active-rewards-card")).to_have_count(2)
staking_reward_card = page.get_by_test_id("active-rewards-card").nth(1) staking_reward_card = page.get_by_test_id("active-rewards-card").nth(1)

View File

@ -39,6 +39,8 @@ const nextConfig = {
GIT_COMMIT: commitHash, GIT_COMMIT: commitHash,
GIT_TAG: tag, GIT_TAG: tag,
}, },
basePath: '/apps/vegas', // Set the base path
assetPrefix: '/apps/vegas', // Set the asset prefix
}; };
module.exports = SENTRY_AUTH_TOKEN module.exports = SENTRY_AUTH_TOKEN

View File

@ -4,11 +4,10 @@ export default function Document() {
return ( return (
<> <>
<Head> <Head>
{/* <meta
meta tags name="viewport"
- next advised against using _document for this, so they exist in our content="width=device-width, initial-scale=1.0, user-scalable=no"
- single page index.page.tsx />
*/}
{/* preload fonts */} {/* preload fonts */}
<link <link
@ -18,15 +17,38 @@ export default function Document() {
type="font/woff" type="font/woff"
/> />
<link
rel="preload"
href="/AlphaLyrae.woff2"
as="font"
type="font/woff2"
/>
{/* icons */} {/* icons */}
<link rel="icon" type="image/x-icon" href="/favicon.ico" /> <link rel="icon" type="image/x-icon" href="/favicon.ico" />
<link rel="apple-touch-icon" content="/favicon.ico" /> <link
rel="apple-touch-icon"
sizes="180x180"
href="/apple-touch-icon.png"
/>
<link
rel="icon"
type="image/png"
sizes="32x32"
href="/favicon-32x32.png"
/>
<link
rel="icon"
type="image/png"
sizes="16x16"
href="/favicon-16x16.png"
/>
{/* scripts */} {/* scripts */}
<script src="/theme-setter.js" type="text/javascript" async /> <script src="/theme-setter.js" type="text/javascript" async />
{/* manifest */} {/* manifest */}
<link rel="manifest" href="/apps/trading/public/manifest.json" /> <link rel="manifest" href="/manifest.json" />
</Head> </Head>
<Html> <Html>
<body <body

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 265 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 281 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -9,14 +9,14 @@
"background_color": "#ffffff", "background_color": "#ffffff",
"icons": [ "icons": [
{ {
"src": "favicon.ico", "src": "/android-chrome-192x192.png",
"sizes": "64x64 32x32 24x24 16x16", "sizes": "192x192",
"type": "image/x-icon" "type": "image/png"
}, },
{ {
"src": "cover.png", "src": "/android-chrome-512x512.png",
"type": "image/png", "sizes": "512x512",
"sizes": "192x192" "type": "image/png"
} }
] ]
} }

View File

@ -34,6 +34,21 @@
"options": { "options": {
"jestConfig": "libs/types/jest.config.ts" "jestConfig": "libs/types/jest.config.ts"
} }
},
"generate": {
"executor": "nx:run-commands",
"options": {
"commands": ["npx graphql-codegen --config=libs/types/codegen.yml"],
"parallel": false
}
},
"local-registry": {
"executor": "@nx/js:verdaccio",
"options": {
"port": 4873,
"config": ".verdaccio/config.yml",
"storage": "tmp/local-registry/storage"
}
} }
}, },
"tags": [] "tags": []

View File

@ -35,6 +35,14 @@
"options": { "options": {
"jestConfig": "libs/utils/jest.config.ts" "jestConfig": "libs/utils/jest.config.ts"
} }
},
"local-registry": {
"executor": "@nx/js:verdaccio",
"options": {
"port": 4873,
"config": ".verdaccio/config.yml",
"storage": "tmp/local-registry/storage"
}
} }
}, },
"tags": [] "tags": []

View File

@ -35,6 +35,14 @@
"options": { "options": {
"jestConfig": "libs/wallet/jest.config.ts" "jestConfig": "libs/wallet/jest.config.ts"
} }
},
"local-registry": {
"executor": "@nx/js:verdaccio",
"options": {
"port": 4873,
"config": ".verdaccio/config.yml",
"storage": "tmp/local-registry/storage"
}
} }
}, },
"tags": [] "tags": []

View File

@ -241,8 +241,5 @@
"graphql": "15.8.0", "graphql": "15.8.0",
"//": "workaround storybook issue: https://github.com/storybookjs/storybook/issues/21642", "//": "workaround storybook issue: https://github.com/storybookjs/storybook/issues/21642",
"@storybook/react-docgen-typescript-plugin": "1.0.6--canary.9.cd77847.0" "@storybook/react-docgen-typescript-plugin": "1.0.6--canary.9.cd77847.0"
},
"nx": {
"includedScripts": []
} }
} }

View File

@ -1,14 +0,0 @@
{
"name": "nx-monorepo",
"$schema": "node_modules/nx/schemas/project-schema.json",
"targets": {
"local-registry": {
"executor": "@nx/js:verdaccio",
"options": {
"port": 4873,
"config": ".verdaccio/config.yml",
"storage": "tmp/local-registry/storage"
}
}
}
}