feat(trading): add and show key aliases (#5819)
This commit is contained in:
parent
38d13085fb
commit
ad6f0c5798
1
apps/trading/components/profile-dialog/index.ts
Normal file
1
apps/trading/components/profile-dialog/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { ProfileDialog } from './profile-dialog';
|
150
apps/trading/components/profile-dialog/profile-dialog.tsx
Normal file
150
apps/trading/components/profile-dialog/profile-dialog.tsx
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
import {
|
||||||
|
Dialog,
|
||||||
|
FormGroup,
|
||||||
|
Input,
|
||||||
|
InputError,
|
||||||
|
Intent,
|
||||||
|
TradingButton,
|
||||||
|
} from '@vegaprotocol/ui-toolkit';
|
||||||
|
import { useProfileDialogStore } from '../../stores/profile-dialog-store';
|
||||||
|
import { useForm } from 'react-hook-form';
|
||||||
|
import { useT } from '../../lib/use-t';
|
||||||
|
import { useRequired } from '@vegaprotocol/utils';
|
||||||
|
import {
|
||||||
|
useSimpleTransaction,
|
||||||
|
type Status,
|
||||||
|
useVegaWallet,
|
||||||
|
} from '@vegaprotocol/wallet-react';
|
||||||
|
import {
|
||||||
|
usePartyProfilesQuery,
|
||||||
|
type PartyProfilesQuery,
|
||||||
|
} from '../vega-wallet-connect-button/__generated__/PartyProfiles';
|
||||||
|
|
||||||
|
export const ProfileDialog = () => {
|
||||||
|
const t = useT();
|
||||||
|
const { pubKeys } = useVegaWallet();
|
||||||
|
const { data, refetch } = usePartyProfilesQuery({
|
||||||
|
variables: { partyIds: pubKeys.map((pk) => pk.publicKey) },
|
||||||
|
skip: pubKeys.length <= 0,
|
||||||
|
});
|
||||||
|
const open = useProfileDialogStore((store) => store.open);
|
||||||
|
const pubKey = useProfileDialogStore((store) => store.pubKey);
|
||||||
|
const setOpen = useProfileDialogStore((store) => store.setOpen);
|
||||||
|
|
||||||
|
const { send, status, error, reset } = useSimpleTransaction({
|
||||||
|
onSuccess: () => {
|
||||||
|
refetch();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const profileEdge = data?.partiesProfilesConnection?.edges.find(
|
||||||
|
(e) => e.node.partyId === pubKey
|
||||||
|
);
|
||||||
|
|
||||||
|
const sendTx = (field: FormFields) => {
|
||||||
|
send({
|
||||||
|
updatePartyProfile: {
|
||||||
|
alias: field.alias,
|
||||||
|
metadata: [],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog
|
||||||
|
open={open}
|
||||||
|
onChange={() => {
|
||||||
|
setOpen(undefined);
|
||||||
|
reset();
|
||||||
|
}}
|
||||||
|
title={t('Edit profile')}
|
||||||
|
>
|
||||||
|
<ProfileForm
|
||||||
|
profile={profileEdge?.node}
|
||||||
|
status={status}
|
||||||
|
error={error}
|
||||||
|
onSubmit={sendTx}
|
||||||
|
/>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
interface FormFields {
|
||||||
|
alias: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
type Profile = NonNullable<
|
||||||
|
PartyProfilesQuery['partiesProfilesConnection']
|
||||||
|
>['edges'][number]['node'];
|
||||||
|
|
||||||
|
const ProfileForm = ({
|
||||||
|
profile,
|
||||||
|
onSubmit,
|
||||||
|
status,
|
||||||
|
error,
|
||||||
|
}: {
|
||||||
|
profile: Profile | undefined;
|
||||||
|
onSubmit: (fields: FormFields) => void;
|
||||||
|
status: Status;
|
||||||
|
error: string | undefined;
|
||||||
|
}) => {
|
||||||
|
const t = useT();
|
||||||
|
const required = useRequired();
|
||||||
|
const {
|
||||||
|
register,
|
||||||
|
handleSubmit,
|
||||||
|
formState: { errors },
|
||||||
|
} = useForm<FormFields>({
|
||||||
|
defaultValues: {
|
||||||
|
alias: profile?.alias,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const renderButtonText = () => {
|
||||||
|
if (status === 'requested') {
|
||||||
|
return t('Confirm in wallet...');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status === 'pending') {
|
||||||
|
return t('Confirming transaction...');
|
||||||
|
}
|
||||||
|
|
||||||
|
return t('Submit');
|
||||||
|
};
|
||||||
|
|
||||||
|
const errorMessage = errors.alias?.message || error;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form onSubmit={handleSubmit(onSubmit)} className="mt-3">
|
||||||
|
<FormGroup label="Alias" labelFor="alias">
|
||||||
|
<Input
|
||||||
|
{...register('alias', {
|
||||||
|
validate: {
|
||||||
|
required,
|
||||||
|
},
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
{errorMessage && (
|
||||||
|
<InputError>
|
||||||
|
<p className="break-words max-w-full first-letter:uppercase">
|
||||||
|
{errorMessage}
|
||||||
|
</p>
|
||||||
|
</InputError>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{status === 'confirmed' && (
|
||||||
|
<p className="mt-2 mb-4 text-sm text-success">
|
||||||
|
{t('Profile updated')}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</FormGroup>
|
||||||
|
<TradingButton
|
||||||
|
type="submit"
|
||||||
|
intent={Intent.Info}
|
||||||
|
disabled={status === 'requested' || status === 'pending'}
|
||||||
|
>
|
||||||
|
{renderButtonText()}
|
||||||
|
</TradingButton>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,14 @@
|
|||||||
|
query PartyProfiles($partyIds: [ID!]) {
|
||||||
|
partiesProfilesConnection(ids: $partyIds) {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
partyId
|
||||||
|
alias
|
||||||
|
metadata {
|
||||||
|
key
|
||||||
|
value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
57
apps/trading/components/vega-wallet-connect-button/__generated__/PartyProfiles.ts
generated
Normal file
57
apps/trading/components/vega-wallet-connect-button/__generated__/PartyProfiles.ts
generated
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import * as Types from '@vegaprotocol/types';
|
||||||
|
|
||||||
|
import { gql } from '@apollo/client';
|
||||||
|
import * as Apollo from '@apollo/client';
|
||||||
|
const defaultOptions = {} as const;
|
||||||
|
export type PartyProfilesQueryVariables = Types.Exact<{
|
||||||
|
partyIds?: Types.InputMaybe<Array<Types.Scalars['ID']> | Types.Scalars['ID']>;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
|
||||||
|
export type PartyProfilesQuery = { __typename?: 'Query', partiesProfilesConnection?: { __typename?: 'PartiesProfilesConnection', edges: Array<{ __typename?: 'PartyProfileEdge', node: { __typename?: 'PartyProfile', partyId: string, alias: string, metadata: Array<{ __typename?: 'Metadata', key: string, value: string }> } }> } | null };
|
||||||
|
|
||||||
|
|
||||||
|
export const PartyProfilesDocument = gql`
|
||||||
|
query PartyProfiles($partyIds: [ID!]) {
|
||||||
|
partiesProfilesConnection(ids: $partyIds) {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
partyId
|
||||||
|
alias
|
||||||
|
metadata {
|
||||||
|
key
|
||||||
|
value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __usePartyProfilesQuery__
|
||||||
|
*
|
||||||
|
* To run a query within a React component, call `usePartyProfilesQuery` and pass it any options that fit your needs.
|
||||||
|
* When your component renders, `usePartyProfilesQuery` returns an object from Apollo Client that contains loading, error, and data properties
|
||||||
|
* you can use to render your UI.
|
||||||
|
*
|
||||||
|
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const { data, loading, error } = usePartyProfilesQuery({
|
||||||
|
* variables: {
|
||||||
|
* partyIds: // value for 'partyIds'
|
||||||
|
* },
|
||||||
|
* });
|
||||||
|
*/
|
||||||
|
export function usePartyProfilesQuery(baseOptions?: Apollo.QueryHookOptions<PartyProfilesQuery, PartyProfilesQueryVariables>) {
|
||||||
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
|
return Apollo.useQuery<PartyProfilesQuery, PartyProfilesQueryVariables>(PartyProfilesDocument, options);
|
||||||
|
}
|
||||||
|
export function usePartyProfilesLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<PartyProfilesQuery, PartyProfilesQueryVariables>) {
|
||||||
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
|
return Apollo.useLazyQuery<PartyProfilesQuery, PartyProfilesQueryVariables>(PartyProfilesDocument, options);
|
||||||
|
}
|
||||||
|
export type PartyProfilesQueryHookResult = ReturnType<typeof usePartyProfilesQuery>;
|
||||||
|
export type PartyProfilesLazyQueryHookResult = ReturnType<typeof usePartyProfilesLazyQuery>;
|
||||||
|
export type PartyProfilesQueryResult = Apollo.QueryResult<PartyProfilesQuery, PartyProfilesQueryVariables>;
|
@ -1,21 +1,57 @@
|
|||||||
import { act, fireEvent, render, screen } from '@testing-library/react';
|
import { act, fireEvent, render, screen, within } from '@testing-library/react';
|
||||||
import { VegaWalletConnectButton } from './vega-wallet-connect-button';
|
import { VegaWalletConnectButton } from './vega-wallet-connect-button';
|
||||||
import { truncateByChars } from '@vegaprotocol/utils';
|
|
||||||
import userEvent from '@testing-library/user-event';
|
import userEvent from '@testing-library/user-event';
|
||||||
import {
|
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,
|
||||||
|
} from './__generated__/PartyProfiles';
|
||||||
|
|
||||||
jest.mock('../../lib/hooks/use-get-current-route-id', () => ({
|
jest.mock('../../lib/hooks/use-get-current-route-id', () => ({
|
||||||
useGetCurrentRouteId: jest.fn().mockReturnValue('current-route-id'),
|
useGetCurrentRouteId: jest.fn().mockReturnValue('current-route-id'),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
const key = { publicKey: '123456__123456', name: 'test' };
|
||||||
|
const key2 = { publicKey: 'abcdef__abcdef', name: 'test2' };
|
||||||
|
const keys = [key, key2];
|
||||||
|
const keyProfile = {
|
||||||
|
__typename: 'PartyProfile' as const,
|
||||||
|
partyId: key.publicKey,
|
||||||
|
alias: `${key.name} alias`,
|
||||||
|
metadata: [],
|
||||||
|
};
|
||||||
|
|
||||||
const renderComponent = (mockOnClick = jest.fn()) => {
|
const renderComponent = (mockOnClick = jest.fn()) => {
|
||||||
|
const partyProfilesMock: MockedResponse<PartyProfilesQuery> = {
|
||||||
|
request: {
|
||||||
|
query: PartyProfilesDocument,
|
||||||
|
variables: { partyIds: keys.map((k) => k.publicKey) },
|
||||||
|
},
|
||||||
|
result: {
|
||||||
|
data: {
|
||||||
|
partiesProfilesConnection: {
|
||||||
|
__typename: 'PartiesProfilesConnection',
|
||||||
|
edges: [
|
||||||
|
{
|
||||||
|
__typename: 'PartyProfileEdge',
|
||||||
|
node: keyProfile,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<MockedProvider mocks={[partyProfilesMock]}>
|
||||||
<MockedWalletProvider>
|
<MockedWalletProvider>
|
||||||
<VegaWalletConnectButton onClick={mockOnClick} />
|
<VegaWalletConnectButton onClick={mockOnClick} />
|
||||||
</MockedWalletProvider>
|
</MockedWalletProvider>
|
||||||
|
</MockedProvider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -43,10 +79,6 @@ describe('VegaWalletConnectButton', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should open dropdown and refresh keys when connected', async () => {
|
it('should open dropdown and refresh keys when connected', async () => {
|
||||||
const key = { publicKey: '123456__123456', name: 'test' };
|
|
||||||
const key2 = { publicKey: 'abcdef__abcdef', name: 'test2' };
|
|
||||||
const keys = [key, key2];
|
|
||||||
|
|
||||||
mockConfig.store.setState({
|
mockConfig.store.setState({
|
||||||
status: 'connected',
|
status: 'connected',
|
||||||
keys,
|
keys,
|
||||||
@ -61,14 +93,22 @@ describe('VegaWalletConnectButton', () => {
|
|||||||
|
|
||||||
expect(screen.queryByTestId('connect-vega-wallet')).not.toBeInTheDocument();
|
expect(screen.queryByTestId('connect-vega-wallet')).not.toBeInTheDocument();
|
||||||
const button = screen.getByTestId('manage-vega-wallet');
|
const button = screen.getByTestId('manage-vega-wallet');
|
||||||
expect(button).toHaveTextContent(truncateByChars(key.publicKey));
|
expect(button).toHaveTextContent(key.name);
|
||||||
|
|
||||||
fireEvent.click(button);
|
fireEvent.click(button);
|
||||||
|
|
||||||
expect(await screen.findByRole('menu')).toBeInTheDocument();
|
expect(await screen.findByRole('menu')).toBeInTheDocument();
|
||||||
expect(await screen.findAllByRole('menuitemradio')).toHaveLength(
|
const menuItems = await screen.findAllByRole('menuitemradio');
|
||||||
keys.length
|
expect(menuItems).toHaveLength(keys.length);
|
||||||
|
|
||||||
|
expect(within(menuItems[0]).getByTestId('alias')).toHaveTextContent(
|
||||||
|
keyProfile.alias
|
||||||
);
|
);
|
||||||
|
|
||||||
|
expect(within(menuItems[1]).getByTestId('alias')).toHaveTextContent(
|
||||||
|
'No alias'
|
||||||
|
);
|
||||||
|
|
||||||
expect(refreshKeys).toHaveBeenCalled();
|
expect(refreshKeys).toHaveBeenCalled();
|
||||||
|
|
||||||
fireEvent.click(screen.getByTestId(`key-${key2.publicKey}`));
|
fireEvent.click(screen.getByTestId(`key-${key2.publicKey}`));
|
||||||
|
@ -14,6 +14,7 @@ import {
|
|||||||
TradingDropdownItem,
|
TradingDropdownItem,
|
||||||
TradingDropdownRadioItem,
|
TradingDropdownRadioItem,
|
||||||
TradingDropdownItemIndicator,
|
TradingDropdownItemIndicator,
|
||||||
|
Tooltip,
|
||||||
} from '@vegaprotocol/ui-toolkit';
|
} from '@vegaprotocol/ui-toolkit';
|
||||||
import { isBrowserWalletInstalled, type Key } from '@vegaprotocol/wallet';
|
import { isBrowserWalletInstalled, type Key } from '@vegaprotocol/wallet';
|
||||||
import { useDialogStore, useVegaWallet } from '@vegaprotocol/wallet-react';
|
import { useDialogStore, useVegaWallet } from '@vegaprotocol/wallet-react';
|
||||||
@ -22,6 +23,8 @@ import classNames from 'classnames';
|
|||||||
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 './__generated__/PartyProfiles';
|
||||||
|
import { useProfileDialogStore } from '../../stores/profile-dialog-store';
|
||||||
|
|
||||||
export const VegaWalletConnectButton = ({
|
export const VegaWalletConnectButton = ({
|
||||||
intent = Intent.None,
|
intent = Intent.None,
|
||||||
@ -68,10 +71,10 @@ export const VegaWalletConnectButton = ({
|
|||||||
{activeKey ? (
|
{activeKey ? (
|
||||||
<>
|
<>
|
||||||
{activeKey && (
|
{activeKey && (
|
||||||
<span className="uppercase">{activeKey.name}</span>
|
<span className="uppercase">
|
||||||
|
{activeKey.name ? activeKey.name : t('Unnamed key')}
|
||||||
|
</span>
|
||||||
)}
|
)}
|
||||||
{' | '}
|
|
||||||
{truncateByChars(activeKey.publicKey)}
|
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>{'Select key'}</>
|
<>{'Select key'}</>
|
||||||
@ -88,20 +91,11 @@ export const VegaWalletConnectButton = ({
|
|||||||
onEscapeKeyDown={() => setDropdownOpen(false)}
|
onEscapeKeyDown={() => setDropdownOpen(false)}
|
||||||
>
|
>
|
||||||
<div className="min-w-[340px]" data-testid="keypair-list">
|
<div className="min-w-[340px]" data-testid="keypair-list">
|
||||||
<TradingDropdownRadioGroup
|
<KeypairRadioGroup
|
||||||
value={pubKey || undefined}
|
pubKey={pubKey}
|
||||||
onValueChange={(value) => {
|
pubKeys={pubKeys}
|
||||||
selectPubKey(value);
|
onSelect={selectPubKey}
|
||||||
}}
|
|
||||||
>
|
|
||||||
{pubKeys.map((pk) => (
|
|
||||||
<KeypairItem
|
|
||||||
key={pk.publicKey}
|
|
||||||
pk={pk}
|
|
||||||
active={pk.publicKey === pubKey}
|
|
||||||
/>
|
/>
|
||||||
))}
|
|
||||||
</TradingDropdownRadioGroup>
|
|
||||||
<TradingDropdownSeparator />
|
<TradingDropdownSeparator />
|
||||||
{!isReadOnly && (
|
{!isReadOnly && (
|
||||||
<TradingDropdownItem
|
<TradingDropdownItem
|
||||||
@ -141,28 +135,52 @@ export const VegaWalletConnectButton = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const KeypairItem = ({ pk, active }: { pk: Key; active: boolean }) => {
|
const KeypairRadioGroup = ({
|
||||||
|
pubKey,
|
||||||
|
pubKeys,
|
||||||
|
onSelect,
|
||||||
|
}: {
|
||||||
|
pubKey: string | undefined;
|
||||||
|
pubKeys: Key[];
|
||||||
|
onSelect: (pubKey: string) => void;
|
||||||
|
}) => {
|
||||||
|
const { data } = usePartyProfilesQuery({
|
||||||
|
variables: { partyIds: pubKeys.map((pk) => pk.publicKey) },
|
||||||
|
skip: pubKeys.length <= 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TradingDropdownRadioGroup value={pubKey} onValueChange={onSelect}>
|
||||||
|
{pubKeys.map((pk) => {
|
||||||
|
const profile = data?.partiesProfilesConnection?.edges.find(
|
||||||
|
(e) => e.node.partyId === pk.publicKey
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<KeypairItem key={pk.publicKey} pk={pk} alias={profile?.node.alias} />
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</TradingDropdownRadioGroup>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const KeypairItem = ({ pk, alias }: { pk: Key; alias: string | undefined }) => {
|
||||||
const t = useT();
|
const t = useT();
|
||||||
const [copied, setCopied] = useCopyTimeout();
|
const [copied, setCopied] = useCopyTimeout();
|
||||||
|
const setOpen = useProfileDialogStore((store) => store.setOpen);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TradingDropdownRadioItem value={pk.publicKey}>
|
<TradingDropdownRadioItem value={pk.publicKey}>
|
||||||
<div
|
<div>
|
||||||
className={classNames('flex-1 mr-2', {
|
<div className="flex items-center gap-2">
|
||||||
'text-default': active,
|
<span>{pk.name ? pk.name : t('Unnamed key')}</span>
|
||||||
'text-muted': !active,
|
|
||||||
})}
|
|
||||||
data-testid={`key-${pk.publicKey}`}
|
|
||||||
>
|
|
||||||
<span className={classNames('mr-2 uppercase')}>
|
|
||||||
{pk.name}
|
|
||||||
{' | '}
|
{' | '}
|
||||||
{truncateByChars(pk.publicKey)}
|
<span className="font-mono">
|
||||||
|
{truncateByChars(pk.publicKey, 3, 3)}
|
||||||
</span>
|
</span>
|
||||||
<span className="inline-flex items-center gap-1">
|
|
||||||
<CopyToClipboard text={pk.publicKey} onCopy={() => setCopied(true)}>
|
<CopyToClipboard text={pk.publicKey} onCopy={() => setCopied(true)}>
|
||||||
<button
|
<button
|
||||||
data-testid="copy-vega-public-key"
|
data-testid="copy-vega-public-key"
|
||||||
|
className="relative -top-px"
|
||||||
onClick={(e) => e.stopPropagation()}
|
onClick={(e) => e.stopPropagation()}
|
||||||
>
|
>
|
||||||
<span className="sr-only">{t('Copy')}</span>
|
<span className="sr-only">{t('Copy')}</span>
|
||||||
@ -170,7 +188,17 @@ const KeypairItem = ({ pk, active }: { pk: Key; active: boolean }) => {
|
|||||||
</button>
|
</button>
|
||||||
</CopyToClipboard>
|
</CopyToClipboard>
|
||||||
{copied && <span className="text-xs">{t('Copied')}</span>}
|
{copied && <span className="text-xs">{t('Copied')}</span>}
|
||||||
</span>
|
</div>
|
||||||
|
<div
|
||||||
|
className={classNames('flex-1 mr-2 text-secondary text-sm')}
|
||||||
|
data-testid={`key-${pk.publicKey}`}
|
||||||
|
>
|
||||||
|
<Tooltip description={t('Public facing key alias. Click to edit')}>
|
||||||
|
<button data-testid="alias" onClick={() => setOpen(pk.publicKey)}>
|
||||||
|
{alias ? alias : t('No alias')}
|
||||||
|
</button>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<TradingDropdownItemIndicator />
|
<TradingDropdownItemIndicator />
|
||||||
</TradingDropdownRadioItem>
|
</TradingDropdownRadioItem>
|
||||||
|
@ -8,6 +8,7 @@ import {
|
|||||||
} from '@vegaprotocol/web3';
|
} from '@vegaprotocol/web3';
|
||||||
import { WelcomeDialog } from '../components/welcome-dialog';
|
import { WelcomeDialog } from '../components/welcome-dialog';
|
||||||
import { VegaWalletConnectDialog } from '../components/vega-wallet-connect-dialog';
|
import { VegaWalletConnectDialog } from '../components/vega-wallet-connect-dialog';
|
||||||
|
import { ProfileDialog } from '../components/profile-dialog';
|
||||||
|
|
||||||
const DialogsContainer = () => {
|
const DialogsContainer = () => {
|
||||||
const { isOpen, id, trigger, setOpen } = useAssetDetailsDialogStore();
|
const { isOpen, id, trigger, setOpen } = useAssetDetailsDialogStore();
|
||||||
@ -24,6 +25,7 @@ const DialogsContainer = () => {
|
|||||||
<WelcomeDialog />
|
<WelcomeDialog />
|
||||||
<Web3ConnectUncontrolledDialog />
|
<Web3ConnectUncontrolledDialog />
|
||||||
<WithdrawalApprovalDialogContainer />
|
<WithdrawalApprovalDialogContainer />
|
||||||
|
<ProfileDialog />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
19
apps/trading/stores/profile-dialog-store.ts
Normal file
19
apps/trading/stores/profile-dialog-store.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { create } from 'zustand';
|
||||||
|
|
||||||
|
interface ProfileDialogStore {
|
||||||
|
open: boolean;
|
||||||
|
pubKey: string | undefined;
|
||||||
|
setOpen: (pubKey: string | undefined) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useProfileDialogStore = create<ProfileDialogStore>((set) => ({
|
||||||
|
open: false,
|
||||||
|
pubKey: undefined,
|
||||||
|
setOpen: (pubKey) => {
|
||||||
|
if (pubKey) {
|
||||||
|
set({ open: true, pubKey });
|
||||||
|
} else {
|
||||||
|
set({ open: false, pubKey: undefined });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}));
|
@ -86,6 +86,7 @@
|
|||||||
"Docs": "Docs",
|
"Docs": "Docs",
|
||||||
"Earn commission & stake rewards": "Earn commission & stake rewards",
|
"Earn commission & stake rewards": "Earn commission & stake rewards",
|
||||||
"Earned by me": "Earned by me",
|
"Earned by me": "Earned by me",
|
||||||
|
"Edit alias": "Edit alias",
|
||||||
"Eligible teams": "Eligible teams",
|
"Eligible teams": "Eligible teams",
|
||||||
"Enactment date reached and usual auction exit checks pass": "Enactment date reached and usual auction exit checks pass",
|
"Enactment date reached and usual auction exit checks pass": "Enactment date reached and usual auction exit checks pass",
|
||||||
"[empty]": "[empty]",
|
"[empty]": "[empty]",
|
||||||
@ -162,6 +163,7 @@
|
|||||||
"Joined": "Joined",
|
"Joined": "Joined",
|
||||||
"Joined at": "Joined at",
|
"Joined at": "Joined at",
|
||||||
"Joined epoch": "Joined epoch",
|
"Joined epoch": "Joined epoch",
|
||||||
|
"Key name": "Key name",
|
||||||
"gameCount_one": "Last game result",
|
"gameCount_one": "Last game result",
|
||||||
"gameCount_other": "Last {{count}} game results",
|
"gameCount_other": "Last {{count}} game results",
|
||||||
"Learn about providing liquidity": "Learn about providing liquidity",
|
"Learn about providing liquidity": "Learn about providing liquidity",
|
||||||
@ -194,6 +196,7 @@
|
|||||||
"My liquidity provision": "My liquidity provision",
|
"My liquidity provision": "My liquidity provision",
|
||||||
"My trading fees": "My trading fees",
|
"My trading fees": "My trading fees",
|
||||||
"Name": "Name",
|
"Name": "Name",
|
||||||
|
"No alias": "No alias",
|
||||||
"No closed orders": "No closed orders",
|
"No closed orders": "No closed orders",
|
||||||
"No data": "No data",
|
"No data": "No data",
|
||||||
"No deposits": "No deposits",
|
"No deposits": "No deposits",
|
||||||
@ -227,6 +230,7 @@
|
|||||||
"Not connected": "Not connected",
|
"Not connected": "Not connected",
|
||||||
"Number of epochs after distribution to delay vesting of rewards by": "Number of epochs after distribution to delay vesting of rewards by",
|
"Number of epochs after distribution to delay vesting of rewards by": "Number of epochs after distribution to delay vesting of rewards by",
|
||||||
"Number of traders": "Number of traders",
|
"Number of traders": "Number of traders",
|
||||||
|
"On-change alias": "On-change alias",
|
||||||
"Open": "Open",
|
"Open": "Open",
|
||||||
"Open a position": "Open a position",
|
"Open a position": "Open a position",
|
||||||
"Open markets": "Open markets",
|
"Open markets": "Open markets",
|
||||||
@ -249,6 +253,7 @@
|
|||||||
"Portfolio": "Portfolio",
|
"Portfolio": "Portfolio",
|
||||||
"Positions": "Positions",
|
"Positions": "Positions",
|
||||||
"Price": "Price",
|
"Price": "Price",
|
||||||
|
"Profile updated": "Profile updated",
|
||||||
"Program ends:": "Program ends:",
|
"Program ends:": "Program ends:",
|
||||||
"Propose a new market": "Propose a new market",
|
"Propose a new market": "Propose a new market",
|
||||||
"Proposed final price is {{price}} {{assetSymbol}}.": "Proposed final price is {{price}} {{assetSymbol}}.",
|
"Proposed final price is {{price}} {{assetSymbol}}.": "Proposed final price is {{price}} {{assetSymbol}}.",
|
||||||
@ -289,6 +294,7 @@
|
|||||||
"Search": "Search",
|
"Search": "Search",
|
||||||
"See all markets": "See all markets",
|
"See all markets": "See all markets",
|
||||||
"Select market": "Select market",
|
"Select market": "Select market",
|
||||||
|
"Set party alias": "Set party alias",
|
||||||
"Settings": "Settings",
|
"Settings": "Settings",
|
||||||
"Settlement asset": "Settlement asset",
|
"Settlement asset": "Settlement asset",
|
||||||
"Settlement date": "Settlement date",
|
"Settlement date": "Settlement date",
|
||||||
@ -311,6 +317,7 @@
|
|||||||
"Stop": "Stop",
|
"Stop": "Stop",
|
||||||
"Stop orders": "Stop orders",
|
"Stop orders": "Stop orders",
|
||||||
"Streak reward multiplier": "Streak reward multiplier",
|
"Streak reward multiplier": "Streak reward multiplier",
|
||||||
|
"Submit": "Submit",
|
||||||
"Successor of a market": "Successor of a market",
|
"Successor of a market": "Successor of a market",
|
||||||
"Successors to this market have been proposed": "Successors to this market have been proposed",
|
"Successors to this market have been proposed": "Successors to this market have been proposed",
|
||||||
"Supplied stake": "Supplied stake",
|
"Supplied stake": "Supplied stake",
|
||||||
@ -371,6 +378,7 @@
|
|||||||
"Staking rewards": "Staking rewards",
|
"Staking rewards": "Staking rewards",
|
||||||
"Unknown": "Unknown",
|
"Unknown": "Unknown",
|
||||||
"Unknown settlement date": "Unknown settlement date",
|
"Unknown settlement date": "Unknown settlement date",
|
||||||
|
"Unnamed key": "Unnamed key",
|
||||||
"Update team": "Update team",
|
"Update team": "Update team",
|
||||||
"URL": "URL",
|
"URL": "URL",
|
||||||
"Use a comma separated list to allow only specific public keys to join the team": "Use a comma separated list to allow only specific public keys to join the team",
|
"Use a comma separated list to allow only specific public keys to join the team": "Use a comma separated list to allow only specific public keys to join the team",
|
||||||
@ -407,8 +415,10 @@
|
|||||||
"You will no longer be able to hold a position on this market when it closes in {{duration}}.": "You will no longer be able to hold a position on this market when it closes in {{duration}}.",
|
"You will no longer be able to hold a position on this market when it closes in {{duration}}.": "You will no longer be able to hold a position on this market when it closes in {{duration}}.",
|
||||||
"Your code has been rejected": "Your code has been rejected",
|
"Your code has been rejected": "Your code has been rejected",
|
||||||
"Your identity is always anonymous on Vega": "Your identity is always anonymous on Vega",
|
"Your identity is always anonymous on Vega": "Your identity is always anonymous on Vega",
|
||||||
|
"Your key's private name, can be changed in your wallet": "Your key's private name, can be changed in your wallet",
|
||||||
"Your referral code": "Your referral code",
|
"Your referral code": "Your referral code",
|
||||||
"Your tier": "Your tier",
|
"Your tier": "Your tier",
|
||||||
|
"Your public alias, stored on chain": "Your public alias, stored on chain",
|
||||||
"checkOutProposalsAndVote": "Check out the terms of the proposals and vote:",
|
"checkOutProposalsAndVote": "Check out the terms of the proposals and vote:",
|
||||||
"checkOutProposalsAndVote_one": "Check out the terms of the proposal and vote:",
|
"checkOutProposalsAndVote_one": "Check out the terms of the proposal and vote:",
|
||||||
"checkOutProposalsAndVote_other": "Check out the terms of the proposals and vote:",
|
"checkOutProposalsAndVote_other": "Check out the terms of the proposals and vote:",
|
||||||
|
@ -33,6 +33,12 @@ export const useSimpleTransaction = (opts?: Options) => {
|
|||||||
const [result, setResult] = useState<Result>();
|
const [result, setResult] = useState<Result>();
|
||||||
const [error, setError] = useState<string>();
|
const [error, setError] = useState<string>();
|
||||||
|
|
||||||
|
const reset = () => {
|
||||||
|
setStatus('idle');
|
||||||
|
setResult(undefined);
|
||||||
|
setError(undefined);
|
||||||
|
};
|
||||||
|
|
||||||
const send = async (tx: Transaction) => {
|
const send = async (tx: Transaction) => {
|
||||||
if (!pubKey) {
|
if (!pubKey) {
|
||||||
throw new Error('no pubKey');
|
throw new Error('no pubKey');
|
||||||
@ -114,5 +120,6 @@ export const useSimpleTransaction = (opts?: Options) => {
|
|||||||
error,
|
error,
|
||||||
status,
|
status,
|
||||||
send,
|
send,
|
||||||
|
reset,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -492,6 +492,14 @@ export interface UpdateMarginMode {
|
|||||||
export interface UpdateMarginModeBody {
|
export interface UpdateMarginModeBody {
|
||||||
updateMarginMode: UpdateMarginMode;
|
updateMarginMode: UpdateMarginMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface UpdatePartyProfile {
|
||||||
|
updatePartyProfile: {
|
||||||
|
alias: string;
|
||||||
|
metadata: Array<{ key: string; value: string }>;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export type Transaction =
|
export type Transaction =
|
||||||
| UpdateMarginModeBody
|
| UpdateMarginModeBody
|
||||||
| StopOrdersSubmissionBody
|
| StopOrdersSubmissionBody
|
||||||
@ -510,7 +518,8 @@ export type Transaction =
|
|||||||
| ApplyReferralCode
|
| ApplyReferralCode
|
||||||
| JoinTeam
|
| JoinTeam
|
||||||
| CreateReferralSet
|
| CreateReferralSet
|
||||||
| UpdateReferralSet;
|
| UpdateReferralSet
|
||||||
|
| UpdatePartyProfile;
|
||||||
|
|
||||||
export interface TransactionResponse {
|
export interface TransactionResponse {
|
||||||
transactionHash: string;
|
transactionHash: string;
|
||||||
|
Loading…
Reference in New Issue
Block a user