fix(trading): party alias snags (#5947)

Co-authored-by: Dariusz Majcherczyk <dariusz.majcherczyk@gmail.com>
This commit is contained in:
Matthew Russell 2024-03-08 17:29:41 +00:00 committed by GitHub
parent 1d71a839b3
commit 1d721dc748
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 158 additions and 42 deletions

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}>
<MockedWalletProvider> <MockedProvider mocks={[partyProfilesMock]}>
<Navbar /> <MockedWalletProvider>
</MockedWalletProvider> <Navbar />
</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) => {
<KeypairListItem const profile = data?.partiesProfilesConnection?.edges.find(
key={pk.publicKey} (e) => e.node.partyId === pk.publicKey
pk={pk} );
isActive={activeKey?.publicKey === pk.publicKey} return (
onSelectItem={onSelectItem} <KeypairListItem
/> key={pk.publicKey}
))} pk={pk}
isActive={activeKey?.publicKey === pk.publicKey}
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)