Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7ad32c2c96 | ||
|
|
c31a1d57cf | ||
|
|
50208ae222 |
@@ -10,7 +10,7 @@ on:
|
||||
inputs:
|
||||
console-test-branch:
|
||||
type: choice
|
||||
description: 'main: v0.73.13, develop: v0.74.0'
|
||||
description: 'main: v0.73.5, develop: v0.73.5'
|
||||
options:
|
||||
- main
|
||||
- develop
|
||||
|
||||
@@ -64,9 +64,7 @@ export const ProposalSummary = ({
|
||||
return (
|
||||
<div className="w-auto max-w-lg border-2 border-solid border-vega-light-100 dark:border-vega-dark-200 p-5">
|
||||
{id && <ProposalStatusIcon id={id} />}
|
||||
{rationale?.title && (
|
||||
<h1 className="text-xl pb-1 break-all">{rationale.title}</h1>
|
||||
)}
|
||||
{rationale?.title && <h1 className="text-xl pb-1">{rationale.title}</h1>}
|
||||
{rationale?.description && (
|
||||
<div className="pt-2 text-sm leading-tight">
|
||||
<ReactMarkdown
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
query ExplorerTransferStatus($id: ID!) {
|
||||
transfer(id: $id) {
|
||||
transfer {
|
||||
reference
|
||||
timestamp
|
||||
status
|
||||
reason
|
||||
fromAccountType
|
||||
from
|
||||
to
|
||||
toAccountType
|
||||
asset {
|
||||
id
|
||||
}
|
||||
amount
|
||||
}
|
||||
}
|
||||
}
|
||||
-61
@@ -1,61 +0,0 @@
|
||||
import * as Types from '@vegaprotocol/types';
|
||||
|
||||
import { gql } from '@apollo/client';
|
||||
import * as Apollo from '@apollo/client';
|
||||
const defaultOptions = {} as const;
|
||||
export type ExplorerTransferStatusQueryVariables = Types.Exact<{
|
||||
id: Types.Scalars['ID'];
|
||||
}>;
|
||||
|
||||
|
||||
export type ExplorerTransferStatusQuery = { __typename?: 'Query', transfer?: { __typename?: 'TransferNode', transfer: { __typename?: 'Transfer', reference?: string | null, timestamp: any, status: Types.TransferStatus, reason?: string | null, fromAccountType: Types.AccountType, from: string, to: string, toAccountType: Types.AccountType, amount: string, asset?: { __typename?: 'Asset', id: string } | null } } | null };
|
||||
|
||||
|
||||
export const ExplorerTransferStatusDocument = gql`
|
||||
query ExplorerTransferStatus($id: ID!) {
|
||||
transfer(id: $id) {
|
||||
transfer {
|
||||
reference
|
||||
timestamp
|
||||
status
|
||||
reason
|
||||
fromAccountType
|
||||
from
|
||||
to
|
||||
toAccountType
|
||||
asset {
|
||||
id
|
||||
}
|
||||
amount
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* __useExplorerTransferStatusQuery__
|
||||
*
|
||||
* To run a query within a React component, call `useExplorerTransferStatusQuery` and pass it any options that fit your needs.
|
||||
* When your component renders, `useExplorerTransferStatusQuery` 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 } = useExplorerTransferStatusQuery({
|
||||
* variables: {
|
||||
* id: // value for 'id'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useExplorerTransferStatusQuery(baseOptions: Apollo.QueryHookOptions<ExplorerTransferStatusQuery, ExplorerTransferStatusQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useQuery<ExplorerTransferStatusQuery, ExplorerTransferStatusQueryVariables>(ExplorerTransferStatusDocument, options);
|
||||
}
|
||||
export function useExplorerTransferStatusLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<ExplorerTransferStatusQuery, ExplorerTransferStatusQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useLazyQuery<ExplorerTransferStatusQuery, ExplorerTransferStatusQueryVariables>(ExplorerTransferStatusDocument, options);
|
||||
}
|
||||
export type ExplorerTransferStatusQueryHookResult = ReturnType<typeof useExplorerTransferStatusQuery>;
|
||||
export type ExplorerTransferStatusLazyQueryHookResult = ReturnType<typeof useExplorerTransferStatusLazyQuery>;
|
||||
export type ExplorerTransferStatusQueryResult = Apollo.QueryResult<ExplorerTransferStatusQuery, ExplorerTransferStatusQueryVariables>;
|
||||
+2
-2
@@ -111,7 +111,7 @@ export function TransferParticipants({
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 16 9"
|
||||
className="fill-white dark:fill-black"
|
||||
className="fill-vega-light-100 dark:fill-black"
|
||||
>
|
||||
<path d="M0,0L8,9l8,-9Z" />
|
||||
</svg>
|
||||
@@ -120,7 +120,7 @@ export function TransferParticipants({
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 16 9"
|
||||
className="fill-vega-light-200 dark:fill-vega-dark-200"
|
||||
className="fill-vega-light-100 dark:fill-vega-dark-200"
|
||||
>
|
||||
<path d="M0,0L8,9l8,-9Z" />
|
||||
</svg>
|
||||
|
||||
+52
-178
@@ -1,223 +1,97 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { AssetLink, MarketLink } from '../../../../links';
|
||||
import { headerClasses, wrapperClasses } from '../transfer-details';
|
||||
import type { components } from '../../../../../../types/explorer';
|
||||
import type { Recurring } from '../transfer-details';
|
||||
import {
|
||||
DispatchMetricLabels,
|
||||
DistributionStrategy,
|
||||
} from '@vegaprotocol/types';
|
||||
import { VegaIcon, VegaIconNames } from '@vegaprotocol/ui-toolkit';
|
||||
import { formatNumber } from '@vegaprotocol/utils';
|
||||
import { DispatchMetricLabels } from '@vegaprotocol/types';
|
||||
|
||||
export type Metric = components['schemas']['vegaDispatchMetric'];
|
||||
export type Strategy = components['schemas']['vegaDispatchStrategy'];
|
||||
|
||||
export const wrapperClasses = 'border pv-2 w-full flex-auto basis-full';
|
||||
export const headerClasses =
|
||||
'bg-solid bg-vega-light-150 dark:bg-vega-dark-150 text-center text-xl py-2 font-alpha calt';
|
||||
|
||||
const metricLabels: Record<Metric, string> = {
|
||||
DISPATCH_METRIC_UNSPECIFIED: 'Unknown metric',
|
||||
...DispatchMetricLabels,
|
||||
};
|
||||
|
||||
// Maps the two (non-null) values of entityScope to the icon that represents it
|
||||
const entityScopeIcons: Record<
|
||||
string,
|
||||
typeof VegaIconNames[keyof typeof VegaIconNames]
|
||||
> = {
|
||||
ENTITY_SCOPE_INDIVIDUALS: VegaIconNames.MAN,
|
||||
ENTITY_SCOPE_TEAMS: VegaIconNames.TEAM,
|
||||
};
|
||||
|
||||
const distributionStrategyLabel: Record<DistributionStrategy, string> = {
|
||||
[DistributionStrategy.DISTRIBUTION_STRATEGY_PRO_RATA]: 'Pro Rata',
|
||||
[DistributionStrategy.DISTRIBUTION_STRATEGY_RANK]: 'Ranked',
|
||||
};
|
||||
|
||||
interface TransferRewardsProps {
|
||||
recurring: Recurring;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders recurring transfers/game details in a way that is, perhaps, easy to understand
|
||||
* Renderer for a transfer. These can vary quite
|
||||
* widely, essentially every field can be null.
|
||||
*
|
||||
* @param transfer A recurring transfer object
|
||||
*/
|
||||
export function TransferRewards({ recurring }: TransferRewardsProps) {
|
||||
const metric =
|
||||
recurring?.dispatchStrategy?.metric || 'DISPATCH_METRIC_UNSPECIFIED';
|
||||
|
||||
if (!recurring || !recurring.dispatchStrategy) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Destructure to make things a bit more readable
|
||||
const {
|
||||
entityScope,
|
||||
individualScope,
|
||||
teamScope,
|
||||
distributionStrategy,
|
||||
lockPeriod,
|
||||
markets,
|
||||
stakingRequirement,
|
||||
windowLength,
|
||||
notionalTimeWeightedAveragePositionRequirement,
|
||||
rankTable,
|
||||
nTopPerformers,
|
||||
} = recurring.dispatchStrategy;
|
||||
|
||||
return (
|
||||
<div className={wrapperClasses}>
|
||||
<h2 className={headerClasses}>{getRewardTitle(entityScope)}</h2>
|
||||
<ul className="relative block rounded-lg py-6 text-left p-6">
|
||||
{entityScope && entityScopeIcons[entityScope] ? (
|
||||
<h2 className={headerClasses}>{t('Reward metrics')}</h2>
|
||||
<ul className="relative block rounded-lg py-6 text-center p-6">
|
||||
{recurring.dispatchStrategy.assetForMetric ? (
|
||||
<li>
|
||||
<strong>{t('Scope')}</strong>:{' '}
|
||||
<VegaIcon name={entityScopeIcons[entityScope]} />
|
||||
|
||||
{individualScope ? individualScopeLabels[individualScope] : null}
|
||||
{getScopeLabel(entityScope, teamScope)}
|
||||
<strong>{t('Asset')}</strong>:{' '}
|
||||
<AssetLink assetId={recurring.dispatchStrategy.assetForMetric} />
|
||||
</li>
|
||||
) : null}
|
||||
{recurring.dispatchStrategy &&
|
||||
recurring.dispatchStrategy.assetForMetric && (
|
||||
<li>
|
||||
<strong>{t('Asset for metric')}</strong>:{' '}
|
||||
<AssetLink assetId={recurring.dispatchStrategy.assetForMetric} />
|
||||
</li>
|
||||
)}
|
||||
{recurring.dispatchStrategy.metric &&
|
||||
metricLabels[recurring.dispatchStrategy.metric] && (
|
||||
<li>
|
||||
<strong>{t('Metric')}</strong>:{' '}
|
||||
{metricLabels[recurring.dispatchStrategy.metric]}
|
||||
</li>
|
||||
)}
|
||||
{lockPeriod && (
|
||||
<li>
|
||||
<strong>{t('Reward lock')}</strong>:
|
||||
{recurring.dispatchStrategy.lockPeriod}{' '}
|
||||
{recurring.dispatchStrategy.lockPeriod === '1'
|
||||
? t('epoch')
|
||||
: t('epochs')}
|
||||
</li>
|
||||
)}
|
||||
|
||||
{markets && markets.length > 0 ? (
|
||||
<li>
|
||||
<strong>{t('Metric')}</strong>: {metricLabels[metric]}
|
||||
</li>
|
||||
{recurring.dispatchStrategy.markets &&
|
||||
recurring.dispatchStrategy.markets.length > 0 ? (
|
||||
<li>
|
||||
<strong>{t('Markets in scope')}</strong>:
|
||||
<ul className="inline-block ml-1">
|
||||
{markets.map((m) => (
|
||||
<li key={m} className="inline-block mr-2">
|
||||
<ul>
|
||||
{recurring.dispatchStrategy.markets.map((m) => (
|
||||
<li key={m}>
|
||||
<MarketLink id={m} />
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</li>
|
||||
) : null}
|
||||
|
||||
{stakingRequirement && stakingRequirement !== '0' ? (
|
||||
<li>
|
||||
<strong>{t('Staking requirement')}</strong>: {stakingRequirement}
|
||||
</li>
|
||||
) : null}
|
||||
|
||||
{windowLength && windowLength !== '0' ? (
|
||||
<li>
|
||||
<strong>{t('Window length')}</strong>:{' '}
|
||||
{recurring.dispatchStrategy.windowLength}{' '}
|
||||
{recurring.dispatchStrategy.windowLength === '1'
|
||||
? t('epoch')
|
||||
: t('epochs')}
|
||||
</li>
|
||||
) : null}
|
||||
|
||||
{notionalTimeWeightedAveragePositionRequirement &&
|
||||
notionalTimeWeightedAveragePositionRequirement !== '' ? (
|
||||
<li>
|
||||
<strong>{t('Notional TWAP')}</strong>:{' '}
|
||||
{notionalTimeWeightedAveragePositionRequirement}
|
||||
</li>
|
||||
) : null}
|
||||
|
||||
{nTopPerformers && (
|
||||
<li>
|
||||
<strong>{t('Elligible team members:')}</strong> top{' '}
|
||||
{`${formatNumber(Number(nTopPerformers) * 100, 0)}%`}
|
||||
</li>
|
||||
)}
|
||||
|
||||
{distributionStrategy &&
|
||||
distributionStrategy !== 'DISTRIBUTION_STRATEGY_UNSPECIFIED' && (
|
||||
<li>
|
||||
<strong>{t('Distribution strategy')}</strong>:{' '}
|
||||
{distributionStrategyLabel[distributionStrategy]}
|
||||
</li>
|
||||
)}
|
||||
<li>
|
||||
<strong>{t('Factor')}</strong>: {recurring.factor}
|
||||
</li>
|
||||
</ul>
|
||||
<div className="px-6 pt-1 pb-5">
|
||||
{rankTable && rankTable.length > 0 ? (
|
||||
<table className="border-collapse border border-gray-400 ">
|
||||
<thead>
|
||||
<tr>
|
||||
<th className="border border-gray-300 bg-gray-300 px-3">
|
||||
<strong>{t('Start rank')}</strong>
|
||||
</th>
|
||||
<th className="border border-gray-300 bg-gray-300 px-3">
|
||||
<strong>{t('Share of reward pool')}</strong>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{rankTable.map((row, i) => {
|
||||
return (
|
||||
<tr key={`rank-${i}`}>
|
||||
<td className="border border-slate-300 text-center">
|
||||
{row.startRank}
|
||||
</td>
|
||||
<td className="border border-slate-300 text-center">
|
||||
{row.shareRatio}
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function getScopeLabel(
|
||||
scope: components['schemas']['vegaEntityScope'] | undefined,
|
||||
teamScope: readonly string[] | undefined
|
||||
): string {
|
||||
if (scope === 'ENTITY_SCOPE_TEAMS') {
|
||||
if (teamScope && teamScope.length !== 0) {
|
||||
return ` ${teamScope.length} teams`;
|
||||
} else {
|
||||
return t('All teams');
|
||||
}
|
||||
} else if (scope === 'ENTITY_SCOPE_INDIVIDUALS') {
|
||||
return t('Individuals');
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
export function getRewardTitle(
|
||||
scope?: components['schemas']['vegaEntityScope']
|
||||
) {
|
||||
if (scope === 'ENTITY_SCOPE_TEAMS') {
|
||||
return t('Game');
|
||||
}
|
||||
return t('Reward metrics');
|
||||
interface TransferRecurringStrategyProps {
|
||||
strategy: Strategy;
|
||||
}
|
||||
|
||||
const individualScopeLabels: Record<
|
||||
components['schemas']['vegaIndividualScope'],
|
||||
string
|
||||
> = {
|
||||
// Unspecified and All are not rendered
|
||||
INDIVIDUAL_SCOPE_UNSPECIFIED: '',
|
||||
INDIVIDUAL_SCOPE_ALL: '',
|
||||
INDIVIDUAL_SCOPE_IN_TEAM: '(in team)',
|
||||
INDIVIDUAL_SCOPE_NOT_IN_TEAM: '(not in team)',
|
||||
};
|
||||
/**
|
||||
* Simple renderer for a dispatch strategy in a recurring transfer
|
||||
*
|
||||
* @param strategy Dispatch strategy object
|
||||
*/
|
||||
export function TransferRecurringStrategy({
|
||||
strategy,
|
||||
}: TransferRecurringStrategyProps) {
|
||||
if (!strategy) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{strategy.assetForMetric ? (
|
||||
<li>
|
||||
<strong>{t('Asset for metric')}</strong>:{' '}
|
||||
<AssetLink assetId={strategy.assetForMetric} />
|
||||
</li>
|
||||
) : null}
|
||||
<li>
|
||||
<strong>{t('Metric')}</strong>: {strategy.metric}
|
||||
</li>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { headerClasses, wrapperClasses } from '../transfer-details';
|
||||
import { Icon, Loader } from '@vegaprotocol/ui-toolkit';
|
||||
import type { IconName } from '@vegaprotocol/ui-toolkit';
|
||||
import type { ApolloError } from '@apollo/client';
|
||||
import { TransferStatus, TransferStatusMapping } from '@vegaprotocol/types';
|
||||
import { IconNames } from '@blueprintjs/icons';
|
||||
|
||||
interface TransferStatusProps {
|
||||
status: TransferStatus | undefined;
|
||||
error: ApolloError | undefined;
|
||||
loading: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renderer for a transfer. These can vary quite
|
||||
* widely, essentially every field can be null.
|
||||
*
|
||||
* @param transfer A recurring transfer object
|
||||
*/
|
||||
export function TransferStatusView({ status, loading }: TransferStatusProps) {
|
||||
if (!status) {
|
||||
status = TransferStatus.STATUS_PENDING;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={wrapperClasses}>
|
||||
<h2 className={headerClasses}>{t('Status')}</h2>
|
||||
<div className="relative block rounded-lg py-6 text-center p-6">
|
||||
{loading ? (
|
||||
<div className="leading-10 mt-12">
|
||||
<Loader size={'small'} />
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<p className="leading-10 my-2">
|
||||
<Icon
|
||||
name={getIconForStatus(status)}
|
||||
className={getColourForStatus(status)}
|
||||
/>
|
||||
</p>
|
||||
<p className="leading-10 my-2">{TransferStatusMapping[status]}</p>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple mapping from status to icon name
|
||||
* @param status TransferStatus
|
||||
* @returns IconName
|
||||
*/
|
||||
export function getIconForStatus(status: TransferStatus): IconName {
|
||||
switch (status) {
|
||||
case TransferStatus.STATUS_PENDING:
|
||||
return IconNames.TIME;
|
||||
case TransferStatus.STATUS_DONE:
|
||||
return IconNames.TICK;
|
||||
case TransferStatus.STATUS_REJECTED:
|
||||
return IconNames.CROSS;
|
||||
default:
|
||||
return IconNames.TIME;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple mapping from status to colour
|
||||
* @param status TransferStatus
|
||||
* @returns string Tailwind classname
|
||||
*/
|
||||
export function getColourForStatus(status: TransferStatus): string {
|
||||
switch (status) {
|
||||
case TransferStatus.STATUS_PENDING:
|
||||
return 'text-yellow-500';
|
||||
case TransferStatus.STATUS_DONE:
|
||||
return 'text-green-500';
|
||||
case TransferStatus.STATUS_REJECTED:
|
||||
return 'text-red-500';
|
||||
default:
|
||||
return 'text-yellow-500';
|
||||
}
|
||||
}
|
||||
@@ -2,15 +2,12 @@ import type { components } from '../../../../../types/explorer';
|
||||
import { TransferRepeat } from './blocks/transfer-repeat';
|
||||
import { TransferRewards } from './blocks/transfer-rewards';
|
||||
import { TransferParticipants } from './blocks/transfer-participants';
|
||||
import { useExplorerTransferStatusQuery } from './__generated__/Transfer';
|
||||
import { TransferStatusView } from './blocks/transfer-status';
|
||||
import { TransferStatus } from '@vegaprotocol/types';
|
||||
|
||||
export type Recurring = components['schemas']['commandsv1RecurringTransfer'];
|
||||
export type Metric = components['schemas']['vegaDispatchMetric'];
|
||||
|
||||
export const wrapperClasses =
|
||||
'border border-vega-light-150 dark:border-vega-dark-200 pv-2 w-full sm:w-1/3 basis-1/3';
|
||||
'border border-vega-light-150 dark:border-vega-dark-200 rounded-md pv-2 mb-5 w-full sm:w-1/4 min-w-[200px] ';
|
||||
export const headerClasses =
|
||||
'bg-solid bg-vega-light-150 dark:bg-vega-dark-150 border-vega-light-150 text-center text-xl py-2 font-alpha calt';
|
||||
|
||||
@@ -19,7 +16,6 @@ export type Transfer = components['schemas']['commandsv1Transfer'];
|
||||
interface TransferDetailsProps {
|
||||
transfer: Transfer;
|
||||
from: string;
|
||||
id: string;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -28,24 +24,13 @@ interface TransferDetailsProps {
|
||||
*
|
||||
* @param transfer A recurring transfer object
|
||||
*/
|
||||
export function TransferDetails({ transfer, from, id }: TransferDetailsProps) {
|
||||
export function TransferDetails({ transfer, from }: TransferDetailsProps) {
|
||||
const recurring = transfer.recurring;
|
||||
|
||||
// Currently all this is passed in to TransferStatus, but the extra details
|
||||
// may be useful in the future.
|
||||
const { data, error, loading } = useExplorerTransferStatusQuery({
|
||||
variables: { id },
|
||||
});
|
||||
|
||||
const status = error
|
||||
? TransferStatus.STATUS_REJECTED
|
||||
: data?.transfer?.transfer.status;
|
||||
|
||||
return (
|
||||
<div className="flex flex-wrap">
|
||||
<div className="flex gap-5 flex-wrap">
|
||||
<TransferParticipants from={from} transfer={transfer} />
|
||||
{recurring ? <TransferRepeat recurring={transfer.recurring} /> : null}
|
||||
<TransferStatusView status={status} error={error} loading={loading} />
|
||||
{recurring && recurring.dispatchStrategy ? (
|
||||
<TransferRewards recurring={transfer.recurring} />
|
||||
) : null}
|
||||
|
||||
@@ -1,172 +0,0 @@
|
||||
import {
|
||||
getScopeLabel,
|
||||
getRewardTitle,
|
||||
TransferRewards,
|
||||
} from './blocks/transfer-rewards';
|
||||
import { render } from '@testing-library/react';
|
||||
import type { components } from '../../../../../types/explorer';
|
||||
import type { Recurring } from './transfer-details';
|
||||
import {
|
||||
DispatchMetric,
|
||||
DistributionStrategy,
|
||||
EntityScope,
|
||||
IndividualScope,
|
||||
} from '@vegaprotocol/types';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
|
||||
describe('getScopeLabel', () => {
|
||||
it('should return the correct label for ENTITY_SCOPE_TEAMS with teamScope', () => {
|
||||
const scope = 'ENTITY_SCOPE_TEAMS';
|
||||
const teamScope = ['team1', 'team2', 'team3'];
|
||||
const expectedLabel = ' 3 teams';
|
||||
|
||||
const result = getScopeLabel(scope, teamScope);
|
||||
|
||||
expect(result).toEqual(expectedLabel);
|
||||
});
|
||||
|
||||
it('should return the correct label for ENTITY_SCOPE_TEAMS without teamScope', () => {
|
||||
const scope = 'ENTITY_SCOPE_TEAMS';
|
||||
const teamScope = undefined;
|
||||
const expectedLabel = 'All teams';
|
||||
|
||||
const result = getScopeLabel(scope, teamScope);
|
||||
|
||||
expect(result).toEqual(expectedLabel);
|
||||
});
|
||||
|
||||
it('should return the correct label for ENTITY_SCOPE_INDIVIDUALS', () => {
|
||||
const scope = 'ENTITY_SCOPE_INDIVIDUALS';
|
||||
const teamScope = undefined;
|
||||
const expectedLabel = 'Individuals';
|
||||
|
||||
const result = getScopeLabel(scope, teamScope);
|
||||
|
||||
expect(result).toEqual(expectedLabel);
|
||||
});
|
||||
|
||||
it('should return an empty string for unknown scope', () => {
|
||||
const scope = 'UNKNOWN_SCOPE';
|
||||
const teamScope = undefined;
|
||||
const expectedLabel = '';
|
||||
|
||||
const result = getScopeLabel(
|
||||
scope as unknown as components['schemas']['vegaEntityScope'],
|
||||
teamScope
|
||||
);
|
||||
|
||||
expect(result).toEqual(expectedLabel);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getRewardTitle', () => {
|
||||
it('should return the correct title for ENTITY_SCOPE_TEAMS', () => {
|
||||
const scope = 'ENTITY_SCOPE_TEAMS';
|
||||
const expectedTitle = 'Game';
|
||||
|
||||
const result = getRewardTitle(scope);
|
||||
|
||||
expect(result).toEqual(expectedTitle);
|
||||
});
|
||||
|
||||
it('should return the correct title for other scopes', () => {
|
||||
const scope = 'ENTITY_SCOPE_INDIVIDUALS';
|
||||
const expectedTitle = 'Reward metrics';
|
||||
|
||||
const result = getRewardTitle(scope);
|
||||
|
||||
expect(result).toEqual(expectedTitle);
|
||||
});
|
||||
});
|
||||
|
||||
describe('TransferRewards', () => {
|
||||
it('should render nothing if recurring dispatchStrategy is not provided', () => {
|
||||
const { container } = render(
|
||||
<TransferRewards recurring={null as unknown as Recurring} />
|
||||
);
|
||||
expect(container.firstChild).toBeNull();
|
||||
});
|
||||
|
||||
it('should render nothing if recurring.dispatchStrategy is not provided', () => {
|
||||
const { container } = render(
|
||||
<TransferRewards recurring={{} as unknown as Recurring} />
|
||||
);
|
||||
expect(container.firstChild).toBeNull();
|
||||
});
|
||||
|
||||
it('should render the reward details correctly', () => {
|
||||
const recurring = {
|
||||
dispatchStrategy: {
|
||||
metric: DispatchMetric.DISPATCH_METRIC_AVERAGE_POSITION,
|
||||
assetForMetric: '123',
|
||||
entityScope: EntityScope.ENTITY_SCOPE_TEAMS,
|
||||
individualScope: IndividualScope.INDIVIDUAL_SCOPE_IN_TEAM,
|
||||
teamScope: [],
|
||||
distributionStrategy:
|
||||
DistributionStrategy.DISTRIBUTION_STRATEGY_PRO_RATA,
|
||||
lockPeriod: 'lockPeriod',
|
||||
markets: ['market1', 'market2'],
|
||||
stakingRequirement: '1',
|
||||
windowLength: 'windowLength',
|
||||
notionalTimeWeightedAveragePositionRequirement:
|
||||
'notionalTimeWeightedAveragePositionRequirement',
|
||||
rankTable: [
|
||||
{ startRank: 1, shareRatio: 0.2 },
|
||||
{ startRank: 2, shareRatio: 0.3 },
|
||||
],
|
||||
nTopPerformers: 'nTopPerformers',
|
||||
},
|
||||
};
|
||||
|
||||
const { getByText } = render(
|
||||
<MemoryRouter>
|
||||
<MockedProvider>
|
||||
<TransferRewards recurring={recurring} />
|
||||
</MockedProvider>
|
||||
</MemoryRouter>
|
||||
);
|
||||
|
||||
expect(getByText('Game')).toBeInTheDocument();
|
||||
expect(getByText('Scope')).toBeInTheDocument();
|
||||
expect(getByText('Asset for metric')).toBeInTheDocument();
|
||||
expect(getByText('Metric')).toBeInTheDocument();
|
||||
expect(getByText('Reward lock')).toBeInTheDocument();
|
||||
expect(getByText('Markets in scope')).toBeInTheDocument();
|
||||
expect(getByText('Staking requirement')).toBeInTheDocument();
|
||||
expect(getByText('Window length')).toBeInTheDocument();
|
||||
expect(getByText('Notional TWAP')).toBeInTheDocument();
|
||||
expect(getByText('Elligible team members:')).toBeInTheDocument();
|
||||
expect(getByText('Distribution strategy')).toBeInTheDocument();
|
||||
expect(getByText('Start rank')).toBeInTheDocument();
|
||||
expect(getByText('Share of reward pool')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should not render a rank table if recurring.dispatchStrategy.rankTable is not provided', () => {
|
||||
const recurring = {
|
||||
dispatchStrategy: {
|
||||
entityScope: EntityScope.ENTITY_SCOPE_INDIVIDUALS,
|
||||
individualScope: IndividualScope.INDIVIDUAL_SCOPE_ALL,
|
||||
teamScope: ['team1', 'team2', 'team3'],
|
||||
distributionStrategy:
|
||||
DistributionStrategy.DISTRIBUTION_STRATEGY_PRO_RATA,
|
||||
lockPeriod: 'lockPeriod',
|
||||
markets: ['market1', 'market2'],
|
||||
stakingRequirement: 'stakingRequirement',
|
||||
windowLength: 'windowLength',
|
||||
notionalTimeWeightedAveragePositionRequirement:
|
||||
'notionalTimeWeightedAveragePositionRequirement',
|
||||
nTopPerformers: 'nTopPerformers',
|
||||
},
|
||||
};
|
||||
|
||||
const { container } = render(
|
||||
<MemoryRouter>
|
||||
<MockedProvider>
|
||||
<TransferRewards recurring={recurring} />
|
||||
</MockedProvider>
|
||||
</MemoryRouter>
|
||||
);
|
||||
expect(container.querySelector('table')).toBeNull();
|
||||
});
|
||||
});
|
||||
@@ -12,8 +12,6 @@ import { ProposalSignatureBundleNewAsset } from './proposal/signature-bundle-new
|
||||
import { ProposalSignatureBundleUpdateAsset } from './proposal/signature-bundle-update';
|
||||
import { MarketLink } from '../../links';
|
||||
import { formatNumber } from '@vegaprotocol/utils';
|
||||
import { TransferDetails } from './transfer/transfer-details';
|
||||
import { proposalToTransfer } from '../lib/proposal-to-transfer';
|
||||
|
||||
export type Proposal = components['schemas']['v1ProposalSubmission'];
|
||||
export type ProposalTerms = components['schemas']['vegaProposalTerms'];
|
||||
@@ -106,12 +104,6 @@ export const TxProposal = ({ txData, pubKey, blockData }: TxProposalProps) => {
|
||||
? ProposalSignatureBundleNewAsset
|
||||
: ProposalSignatureBundleUpdateAsset;
|
||||
|
||||
let transfer, from;
|
||||
if (proposal.terms?.newTransfer?.changes) {
|
||||
transfer = proposalToTransfer(proposal.terms?.newTransfer.changes);
|
||||
from = proposal.terms.newTransfer.changes.source;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<TableWithTbody className="mb-8" allowWrap={true}>
|
||||
@@ -157,26 +149,14 @@ export const TxProposal = ({ txData, pubKey, blockData }: TxProposalProps) => {
|
||||
</>
|
||||
) : null}
|
||||
</TableWithTbody>
|
||||
|
||||
<ProposalSummary
|
||||
id={deterministicId}
|
||||
rationale={proposal.rationale}
|
||||
terms={proposal?.terms}
|
||||
/>
|
||||
|
||||
{proposalRequiresSignatureBundle(proposal) && (
|
||||
<SignatureBundleComponent id={deterministicId} tx={tx} />
|
||||
)}
|
||||
|
||||
{transfer && (
|
||||
<div className="mt-8">
|
||||
<TransferDetails
|
||||
transfer={transfer}
|
||||
from={from || ''}
|
||||
id={deterministicId}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -13,7 +13,6 @@ import {
|
||||
SPECIAL_CASE_NETWORK_ID,
|
||||
} from '../../links/party-link/party-link';
|
||||
import { txSignatureToDeterministicId } from '../lib/deterministic-ids';
|
||||
import Hash from '../../links/hash';
|
||||
|
||||
type Transfer = components['schemas']['commandsv1Transfer'];
|
||||
|
||||
@@ -61,7 +60,7 @@ export const TxDetailsTransfer = ({
|
||||
}
|
||||
|
||||
const from = txData.submitter;
|
||||
const id = txSignatureToDeterministicId(txData.signature.value);
|
||||
|
||||
return (
|
||||
<>
|
||||
<TableWithTbody className="mb-8" allowWrap={true}>
|
||||
@@ -72,7 +71,7 @@ export const TxDetailsTransfer = ({
|
||||
<TableRow modifier="bordered" data-testid="id">
|
||||
<TableCell {...sharedHeaderProps}>{t('Transfer ID')}</TableCell>
|
||||
<TableCell>
|
||||
<Hash text={id} />
|
||||
{txSignatureToDeterministicId(txData.signature.value)}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TxDetailsShared
|
||||
@@ -106,7 +105,7 @@ export const TxDetailsTransfer = ({
|
||||
</TableRow>
|
||||
) : null}
|
||||
</TableWithTbody>
|
||||
<TransferDetails from={from} transfer={transfer} id={id} />
|
||||
<TransferDetails from={from} transfer={transfer} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
import type { components } from '../../../../types/explorer';
|
||||
|
||||
type TransferProposal = components['schemas']['vegaNewTransferConfiguration'];
|
||||
type ActualTransfer = components['schemas']['commandsv1Transfer'];
|
||||
|
||||
/**
|
||||
* Converts a governance proposal for a transfer in to a transfer command that the
|
||||
* TransferDetails component can then render. The types are very similar, but do not
|
||||
* map precisely to each other due to some missing fields and some different field
|
||||
* names.
|
||||
*
|
||||
* @param proposal Governance proposal for a transfer
|
||||
* @returns transfer a Transfer object as if it had been submitted
|
||||
*/
|
||||
export function proposalToTransfer(proposal: TransferProposal): ActualTransfer {
|
||||
return {
|
||||
amount: proposal.amount,
|
||||
asset: proposal.asset,
|
||||
// On a transfer, 'from' is determined by the submitter, so there is no 'from' field
|
||||
// fromAccountType does exist and is just named differently on the proposal
|
||||
fromAccountType: proposal.sourceType,
|
||||
oneOff: proposal.oneOff,
|
||||
recurring: proposal.recurring,
|
||||
// There is no reference applied on governance initiated transfers
|
||||
reference: '',
|
||||
to: proposal.destination,
|
||||
toAccountType: proposal.destinationType,
|
||||
};
|
||||
}
|
||||
-10
@@ -241,16 +241,6 @@ describe('generateEpochAssetRewardsList', () => {
|
||||
amount: '5',
|
||||
},
|
||||
},
|
||||
{
|
||||
// This should not be included in the result
|
||||
node: {
|
||||
epoch: 2,
|
||||
assetId: '3',
|
||||
decimals: 18,
|
||||
rewardType: AccountType.ACCOUNT_TYPE_REWARD_RETURN_VOLATILITY,
|
||||
amount: '5',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
epoch: {
|
||||
|
||||
-6
@@ -83,12 +83,6 @@ export const generateEpochTotalRewardsList = ({
|
||||
(Number(rewardItem?.amount) || 0) + Number(reward.amount)
|
||||
).toString();
|
||||
|
||||
// only RowAccountTypes are relevant for this table, others should
|
||||
// be discarded
|
||||
if (!Object.keys(RowAccountTypes).includes(reward.rewardType)) {
|
||||
return acc;
|
||||
}
|
||||
|
||||
rewards?.set(reward.rewardType, {
|
||||
rewardType: reward.rewardType,
|
||||
amount,
|
||||
|
||||
@@ -5,7 +5,10 @@ import { useTranslation } from 'react-i18next';
|
||||
import { useAppState } from '../../../contexts/app-state/app-state-context';
|
||||
import type { BigNumber } from '../../../lib/bignumber';
|
||||
import type { UndelegateSubmissionBody } from '@vegaprotocol/wallet';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import {
|
||||
UndelegateSubmissionMethod,
|
||||
useVegaWallet,
|
||||
} from '@vegaprotocol/wallet';
|
||||
import { removeDecimal } from '@vegaprotocol/utils';
|
||||
|
||||
interface PendingStakeProps {
|
||||
@@ -38,7 +41,7 @@ export const PendingStake = ({
|
||||
undelegateSubmission: {
|
||||
nodeId,
|
||||
amount: removeDecimal(pendingAmount.toString(), appState.decimals),
|
||||
method: 'METHOD_NOW',
|
||||
method: UndelegateSubmissionMethod.METHOD_NOW,
|
||||
},
|
||||
};
|
||||
await sendTx(pubKey, command);
|
||||
|
||||
@@ -28,12 +28,16 @@ import {
|
||||
NetworkParams,
|
||||
} from '@vegaprotocol/network-parameters';
|
||||
import { useBalances } from '../../../lib/balances/balances-store';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import { SubHeading } from '../../../components/heading';
|
||||
import type {
|
||||
DelegateSubmissionBody,
|
||||
UndelegateSubmissionBody,
|
||||
import {
|
||||
UndelegateSubmissionMethod,
|
||||
useVegaWallet,
|
||||
type DelegateSubmissionBody,
|
||||
type UndelegateSubmissionBody,
|
||||
} from '@vegaprotocol/wallet';
|
||||
|
||||
import { SubHeading } from '../../../components/heading';
|
||||
import type {} from '@vegaprotocol/wallet';
|
||||
|
||||
import Routes from '../../routes';
|
||||
|
||||
export enum FormState {
|
||||
@@ -128,8 +132,8 @@ export const StakingForm = ({
|
||||
amount: removeDecimal(amount, appState.decimals),
|
||||
method:
|
||||
removeType === RemoveType.Now
|
||||
? 'METHOD_NOW'
|
||||
: 'METHOD_AT_END_OF_EPOCH',
|
||||
? UndelegateSubmissionMethod.METHOD_NOW
|
||||
: UndelegateSubmissionMethod.METHOD_AT_END_OF_EPOCH,
|
||||
},
|
||||
};
|
||||
try {
|
||||
|
||||
@@ -3,8 +3,8 @@ import { ErrorBoundary } from '@sentry/react';
|
||||
import { CompetitionsHeader } from '../../components/competitions/competitions-header';
|
||||
import { Intent, Loader, TradingButton } from '@vegaprotocol/ui-toolkit';
|
||||
|
||||
import { useGameCards } from '../../lib/hooks/use-game-cards';
|
||||
import { useCurrentEpochInfoQuery } from '../../lib/hooks/__generated__/Epoch';
|
||||
import { useGames } from '../../lib/hooks/use-games';
|
||||
import { useCurrentEpochInfoQuery } from '../referrals/hooks/__generated__/Epoch';
|
||||
import { Link, useNavigate } from 'react-router-dom';
|
||||
import { Links } from '../../lib/links';
|
||||
import {
|
||||
@@ -28,7 +28,7 @@ export const CompetitionsHome = () => {
|
||||
const { data: epochData } = useCurrentEpochInfoQuery();
|
||||
const currentEpoch = Number(epochData?.epoch.id);
|
||||
|
||||
const { data: gamesData, loading: gamesLoading } = useGameCards({
|
||||
const { data: gamesData, loading: gamesLoading } = useGames({
|
||||
onlyActive: true,
|
||||
currentEpoch,
|
||||
});
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
type TeamStats as ITeamStats,
|
||||
type Team as TeamType,
|
||||
type Member,
|
||||
type TeamGame,
|
||||
} from '../../lib/hooks/use-team';
|
||||
import { DApp, EXPLORER_PARTIES, useLinks } from '@vegaprotocol/environment';
|
||||
import { TeamAvatar } from '../../components/competitions/team-avatar';
|
||||
@@ -22,11 +23,6 @@ import { LayoutWithGradient } from '../../components/layouts-inner';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import { JoinTeam } from './join-team';
|
||||
import { UpdateTeamButton } from './update-team-button';
|
||||
import {
|
||||
type TeamGame,
|
||||
useGames,
|
||||
areTeamGames,
|
||||
} from '../../lib/hooks/use-games';
|
||||
|
||||
export const CompetitionsTeam = () => {
|
||||
const t = useT();
|
||||
@@ -42,12 +38,8 @@ export const CompetitionsTeam = () => {
|
||||
const TeamPageContainer = ({ teamId }: { teamId: string | undefined }) => {
|
||||
const t = useT();
|
||||
const { pubKey } = useVegaWallet();
|
||||
const { data, team, partyTeam, stats, members, loading, refetch } = useTeam(
|
||||
teamId,
|
||||
pubKey || undefined
|
||||
);
|
||||
|
||||
const { data: games, loading: gamesLoading } = useGames(teamId);
|
||||
const { data, team, partyTeam, stats, members, games, loading, refetch } =
|
||||
useTeam(teamId, pubKey || undefined);
|
||||
|
||||
// only show spinner on first load so when users join teams its smoother
|
||||
if (!data && loading) {
|
||||
@@ -72,8 +64,7 @@ const TeamPageContainer = ({ teamId }: { teamId: string | undefined }) => {
|
||||
partyTeam={partyTeam}
|
||||
stats={stats}
|
||||
members={members}
|
||||
games={areTeamGames(games) ? games : undefined}
|
||||
gamesLoading={gamesLoading}
|
||||
games={games}
|
||||
refetch={refetch}
|
||||
/>
|
||||
);
|
||||
@@ -85,7 +76,6 @@ const TeamPage = ({
|
||||
stats,
|
||||
members,
|
||||
games,
|
||||
gamesLoading,
|
||||
refetch,
|
||||
}: {
|
||||
team: TeamType;
|
||||
@@ -93,7 +83,6 @@ const TeamPage = ({
|
||||
stats?: ITeamStats;
|
||||
members?: Member[];
|
||||
games?: TeamGame[];
|
||||
gamesLoading?: boolean;
|
||||
refetch: () => void;
|
||||
}) => {
|
||||
const t = useT();
|
||||
@@ -124,11 +113,7 @@ const TeamPage = ({
|
||||
onClick={() => setShowGames(true)}
|
||||
data-testid="games-toggle"
|
||||
>
|
||||
{t('Results {{games}}', {
|
||||
replace: {
|
||||
games: gamesLoading ? '' : games ? `(${games.length})` : '(0)',
|
||||
},
|
||||
})}
|
||||
{t('Games ({{count}})', { count: games ? games.length : 0 })}
|
||||
</ToggleButton>
|
||||
<ToggleButton
|
||||
active={!showGames}
|
||||
@@ -140,35 +125,17 @@ const TeamPage = ({
|
||||
})}
|
||||
</ToggleButton>
|
||||
</div>
|
||||
{showGames ? (
|
||||
<Games games={games} gamesLoading={gamesLoading} />
|
||||
) : (
|
||||
<Members members={members} />
|
||||
)}
|
||||
{showGames ? <Games games={games} /> : <Members members={members} />}
|
||||
</section>
|
||||
</LayoutWithGradient>
|
||||
);
|
||||
};
|
||||
|
||||
const Games = ({
|
||||
games,
|
||||
gamesLoading,
|
||||
}: {
|
||||
games?: TeamGame[];
|
||||
gamesLoading?: boolean;
|
||||
}) => {
|
||||
const Games = ({ games }: { games?: TeamGame[] }) => {
|
||||
const t = useT();
|
||||
|
||||
if (gamesLoading) {
|
||||
return (
|
||||
<div className="w-[15px]">
|
||||
<Loader size="small" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (!games?.length) {
|
||||
return <p>{t('No game results available')}</p>;
|
||||
return <p>{t('No games')}</p>;
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -46,7 +46,7 @@ const prepareTransaction = (
|
||||
createReferralSet: {
|
||||
isTeam: true,
|
||||
team: {
|
||||
name: fields.name.trim(),
|
||||
name: fields.name,
|
||||
teamUrl: fields.url,
|
||||
avatarUrl: fields.avatarUrl,
|
||||
closed: fields.private,
|
||||
@@ -62,7 +62,7 @@ const prepareTransaction = (
|
||||
id: fields.id,
|
||||
isTeam: true,
|
||||
team: {
|
||||
name: fields.name.trim(),
|
||||
name: fields.name,
|
||||
teamUrl: fields.url,
|
||||
avatarUrl: fields.avatarUrl,
|
||||
closed: fields.private,
|
||||
@@ -116,17 +116,7 @@ export const TeamForm = ({
|
||||
<input type="hidden" {...register('id')} />
|
||||
<TradingFormGroup label={t('Team name')} labelFor="name">
|
||||
<TradingInput
|
||||
{...register('name', {
|
||||
required: t('Required'),
|
||||
validate: {
|
||||
notEmpty: (value) => {
|
||||
if (/^\s*$/.test(value)) {
|
||||
return t('Team name cannot be empty');
|
||||
}
|
||||
return true;
|
||||
},
|
||||
},
|
||||
})}
|
||||
{...register('name', { required: t('Required') })}
|
||||
data-testid="team-name-input"
|
||||
/>
|
||||
{errors.name?.message && (
|
||||
|
||||
@@ -1,20 +1,27 @@
|
||||
import { TinyScroll } from '@vegaprotocol/ui-toolkit';
|
||||
import { useEffect } from 'react';
|
||||
import { titlefy } from '@vegaprotocol/utils';
|
||||
import { ErrorBoundary } from '../../components/error-boundary';
|
||||
import { FeesContainer } from '../../components/fees-container';
|
||||
import { useT } from '../../lib/use-t';
|
||||
import { usePageTitle } from '../../lib/hooks/use-page-title';
|
||||
import { usePageTitleStore } from '../../stores';
|
||||
|
||||
export const Fees = () => {
|
||||
const t = useT();
|
||||
const title = t('Fees');
|
||||
usePageTitle(title);
|
||||
const { updateTitle } = usePageTitleStore((store) => ({
|
||||
updateTitle: store.updateTitle,
|
||||
}));
|
||||
|
||||
useEffect(() => {
|
||||
updateTitle(titlefy([title]));
|
||||
}, [updateTitle, title]);
|
||||
|
||||
return (
|
||||
<ErrorBoundary feature="fees">
|
||||
<TinyScroll className="p-4 max-h-full overflow-auto">
|
||||
<h1 className="md:px-4 pb-4 text-2xl">{title}</h1>
|
||||
<div className="container p-4 mx-auto">
|
||||
<h1 className="px-4 pb-4 text-2xl">{title}</h1>
|
||||
<FeesContainer />
|
||||
</TinyScroll>
|
||||
</div>
|
||||
</ErrorBoundary>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -56,6 +56,7 @@ export const MarketHeaderStats = ({ market }: MarketHeaderStatsProps) => {
|
||||
<Last24hPriceChange
|
||||
marketId={market.id}
|
||||
decimalPlaces={market.decimalPlaces}
|
||||
fallback={<span>-</span>}
|
||||
/>
|
||||
</HeaderStat>
|
||||
<HeaderStat heading={t('Volume (24h)')} testId="market-volume">
|
||||
|
||||
@@ -72,14 +72,7 @@ export const TradePanels = ({ market, pinnedAsset }: TradePanelsProps) => {
|
||||
<div className="h-full flex flex-col lg:grid grid-rows-[min-content_min-content_1fr_min-content]">
|
||||
<div className="flex flex-col w-full overflow-hidden">
|
||||
<div className="flex flex-nowrap overflow-x-auto max-w-full border-t border-default">
|
||||
{[
|
||||
'chart',
|
||||
'orderbook',
|
||||
'trades',
|
||||
'liquidity',
|
||||
'fundingPayments',
|
||||
'funding',
|
||||
]
|
||||
{['chart', 'orderbook', 'trades', 'liquidity', 'fundingPayments']
|
||||
// filter to control available views for the current market
|
||||
// e.g. only perpetuals should get the funding views
|
||||
.filter((_key) => {
|
||||
@@ -170,12 +163,9 @@ const ViewButton = ({
|
||||
onClick: () => void;
|
||||
}) => {
|
||||
const label = useViewLabel(view);
|
||||
const className = classNames(
|
||||
'py-2 px-4 capitalize text-sm whitespace-nowrap',
|
||||
{
|
||||
'bg-vega-clight-500 dark:bg-vega-cdark-500': isActive,
|
||||
}
|
||||
);
|
||||
const className = classNames('py-2 px-4 min-w-[100px] capitalize text-sm', {
|
||||
'bg-vega-clight-500 dark:bg-vega-cdark-500': isActive,
|
||||
});
|
||||
|
||||
return (
|
||||
<button data-testid={view} onClick={onClick} className={className}>
|
||||
@@ -191,8 +181,8 @@ const useViewLabel = (view: TradingView) => {
|
||||
chart: t('Chart'),
|
||||
depth: t('Depth'),
|
||||
liquidity: t('Liquidity'),
|
||||
funding: t('Funding history'),
|
||||
fundingPayments: t('Funding payments'),
|
||||
funding: t('Funding'),
|
||||
fundingPayments: t('Funding'),
|
||||
orderbook: t('Orderbook'),
|
||||
trades: t('Trades'),
|
||||
positions: t('Positions'),
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import { titlefy } from '@vegaprotocol/utils';
|
||||
import {
|
||||
LocalStoragePersistTabs as Tabs,
|
||||
Tab,
|
||||
@@ -5,6 +7,7 @@ import {
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { OpenMarkets } from './open-markets';
|
||||
import { Proposed } from './proposed';
|
||||
import { usePageTitleStore } from '../../stores';
|
||||
import { Closed } from './closed';
|
||||
import {
|
||||
DApp,
|
||||
@@ -14,14 +17,19 @@ import {
|
||||
import { useT } from '../../lib/use-t';
|
||||
import { ErrorBoundary } from '../../components/error-boundary';
|
||||
import { MarketsSettings } from './markets-settings';
|
||||
import { usePageTitle } from '../../lib/hooks/use-page-title';
|
||||
|
||||
export const MarketsPage = () => {
|
||||
const t = useT();
|
||||
const { updateTitle } = usePageTitleStore((store) => ({
|
||||
updateTitle: store.updateTitle,
|
||||
}));
|
||||
|
||||
const governanceLink = useLinks(DApp.Governance);
|
||||
const externalLink = governanceLink(TOKEN_NEW_MARKET_PROPOSAL);
|
||||
|
||||
usePageTitle(t('Markets'));
|
||||
useEffect(() => {
|
||||
updateTitle(titlefy([t('Markets')]));
|
||||
}, [updateTitle, t]);
|
||||
|
||||
return (
|
||||
<div className="h-full pt-0.5 pb-3 px-1.5">
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { useEffect } from 'react';
|
||||
import type { ReactNode } from 'react';
|
||||
import { LayoutPriority } from 'allotment';
|
||||
import { titlefy } from '@vegaprotocol/utils';
|
||||
import { useIncompleteWithdrawals } from '@vegaprotocol/withdraws';
|
||||
import { Tab, LocalStoragePersistTabs as Tabs } from '@vegaprotocol/ui-toolkit';
|
||||
import { usePageTitleStore } from '../../stores';
|
||||
import {
|
||||
AccountsContainer,
|
||||
AccountsSettings,
|
||||
@@ -39,7 +41,6 @@ import { WithdrawalsMenu } from '../../components/withdrawals-menu';
|
||||
import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id';
|
||||
import { useT } from '../../lib/use-t';
|
||||
import { ErrorBoundary } from '../../components/error-boundary';
|
||||
import { usePageTitle } from '../../lib/hooks/use-page-title';
|
||||
|
||||
const WithdrawalsIndicator = () => {
|
||||
const { ready } = useIncompleteWithdrawals();
|
||||
@@ -68,7 +69,14 @@ const SidebarViewInitializer = () => {
|
||||
|
||||
export const Portfolio = () => {
|
||||
const t = useT();
|
||||
usePageTitle(t('Portfolio'));
|
||||
|
||||
const { updateTitle } = usePageTitleStore((store) => ({
|
||||
updateTitle: store.updateTitle,
|
||||
}));
|
||||
|
||||
useEffect(() => {
|
||||
updateTitle(titlefy([t('Portfolio')]));
|
||||
}, [updateTitle, t]);
|
||||
|
||||
const [sizes, handleOnLayoutChange] = usePaneLayout({ id: 'portfolio' });
|
||||
const wrapperClasses = 'p-0.5 h-full max-h-full flex flex-col';
|
||||
|
||||
@@ -11,7 +11,7 @@ import { useEffect } from 'react';
|
||||
import { useT } from '../../../lib/use-t';
|
||||
import { matchPath, useLocation, useNavigate } from 'react-router-dom';
|
||||
import { Routes } from '../../../lib/links';
|
||||
import { useCurrentEpochInfoQuery } from '../../../lib/hooks/__generated__/Epoch';
|
||||
import { useCurrentEpochInfoQuery } from './__generated__/Epoch';
|
||||
|
||||
const REFETCH_INTERVAL = 60 * 60 * 1000; // 1h
|
||||
const NON_ELIGIBLE_REFERRAL_SET_TOAST_ID = 'non-eligible-referral-set';
|
||||
|
||||
@@ -34,10 +34,9 @@ import {
|
||||
} from './hooks/use-referral';
|
||||
import { ApplyCodeForm, ApplyCodeFormContainer } from './apply-code-form';
|
||||
import { useReferralProgram } from './hooks/use-referral-program';
|
||||
import { useCurrentEpochInfoQuery } from '../../lib/hooks/__generated__/Epoch';
|
||||
import { useCurrentEpochInfoQuery } from './hooks/__generated__/Epoch';
|
||||
import { QUSDTooltip } from './qusd-tooltip';
|
||||
import { CodeTile, StatTile, Tile } from './tile';
|
||||
import { areTeamGames, useGames } from '../../lib/hooks/use-games';
|
||||
|
||||
export const ReferralStatistics = () => {
|
||||
const { pubKey } = useVegaWallet();
|
||||
@@ -577,8 +576,7 @@ export const RefereesTable = ({
|
||||
};
|
||||
|
||||
const Team = ({ teamId }: { teamId?: string }) => {
|
||||
const { team, members } = useTeam(teamId);
|
||||
const { data: games } = useGames(teamId);
|
||||
const { team, games, members } = useTeam(teamId);
|
||||
|
||||
if (!team) return null;
|
||||
|
||||
@@ -587,10 +585,7 @@ const Team = ({ teamId }: { teamId?: string }) => {
|
||||
<TeamAvatar teamId={team.teamId} imgUrl={team.avatarUrl} />
|
||||
<div className="flex flex-col items-start gap-1 lg:gap-3">
|
||||
<h1 className="calt text-2xl lg:text-3xl xl:text-5xl">{team.name}</h1>
|
||||
<TeamStats
|
||||
members={members}
|
||||
games={areTeamGames(games) ? games : undefined}
|
||||
/>
|
||||
<TeamStats members={members} games={games} />
|
||||
</div>
|
||||
</Tile>
|
||||
);
|
||||
|
||||
@@ -1,18 +1,24 @@
|
||||
import { TinyScroll } from '@vegaprotocol/ui-toolkit';
|
||||
import { useEffect } from 'react';
|
||||
import { titlefy } from '@vegaprotocol/utils';
|
||||
import { useT } from '../../lib/use-t';
|
||||
import { RewardsContainer } from '../../components/rewards-container';
|
||||
import { usePageTitleStore } from '../../stores';
|
||||
import { ErrorBoundary } from '../../components/error-boundary';
|
||||
import { usePageTitle } from '../../lib/hooks/use-page-title';
|
||||
import { TinyScroll } from '@vegaprotocol/ui-toolkit';
|
||||
|
||||
export const Rewards = () => {
|
||||
const t = useT();
|
||||
const title = t('Rewards');
|
||||
usePageTitle(title);
|
||||
|
||||
const { updateTitle } = usePageTitleStore((store) => ({
|
||||
updateTitle: store.updateTitle,
|
||||
}));
|
||||
useEffect(() => {
|
||||
updateTitle(titlefy([title]));
|
||||
}, [updateTitle, title]);
|
||||
return (
|
||||
<ErrorBoundary feature="rewards">
|
||||
<TinyScroll className="p-4 max-h-full overflow-auto">
|
||||
<h1 className="md:px-4 pb-4 text-2xl">{title}</h1>
|
||||
<h1 className="px-4 pb-4 text-2xl">{title}</h1>
|
||||
<RewardsContainer />
|
||||
</TinyScroll>
|
||||
</ErrorBoundary>
|
||||
|
||||
@@ -153,8 +153,5 @@ const cacheConfig: InMemoryCacheConfig = {
|
||||
OrderUpdate: {
|
||||
keyFields: false,
|
||||
},
|
||||
Game: {
|
||||
keyFields: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -56,10 +56,7 @@ export const CompetitionsLeaderboard = ({
|
||||
className="hover:underline"
|
||||
to={Links.COMPETITIONS_TEAM(td.teamId)}
|
||||
>
|
||||
{
|
||||
// Its possible for a tx to be submitted with an empty space as team name
|
||||
td.name.trim() !== '' ? td.name : t('[empty]')
|
||||
}
|
||||
{td.name}
|
||||
</Link>
|
||||
),
|
||||
earned: num(td.totalQuantumRewards),
|
||||
|
||||
@@ -68,7 +68,6 @@ export const GamesContainer = ({
|
||||
transferNode={game}
|
||||
currentEpoch={currentEpoch}
|
||||
kind={transfer.kind}
|
||||
allMarkets={markets || undefined}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { type TeamStats } from '../../lib/hooks/use-team';
|
||||
import { type TeamGame, type TeamStats } from '../../lib/hooks/use-team';
|
||||
import { type TeamsFieldsFragment } from '../../lib/hooks/__generated__/Teams';
|
||||
import { TeamAvatar, getFallbackAvatar } from './team-avatar';
|
||||
import { FavoriteGame, Stat } from './team-stats';
|
||||
@@ -13,7 +13,6 @@ import { take } from 'lodash';
|
||||
import { DispatchMetricLabels } from '@vegaprotocol/types';
|
||||
import classNames from 'classnames';
|
||||
import { UpdateTeamButton } from '../../client-pages/competitions/update-team-button';
|
||||
import { type TeamGame } from '../../lib/hooks/use-games';
|
||||
|
||||
export const TeamCard = ({
|
||||
rank,
|
||||
|
||||
@@ -11,11 +11,11 @@ import { formatNumberRounded } from '@vegaprotocol/utils';
|
||||
import {
|
||||
type TeamStats as ITeamStats,
|
||||
type Member,
|
||||
type TeamGame,
|
||||
} from '../../lib/hooks/use-team';
|
||||
import { useT } from '../../lib/use-t';
|
||||
import { DispatchMetricLabels, type DispatchMetric } from '@vegaprotocol/types';
|
||||
import classNames from 'classnames';
|
||||
import { type TeamGame } from '../../lib/hooks/use-games';
|
||||
|
||||
export const TeamStats = ({
|
||||
stats,
|
||||
|
||||
@@ -29,35 +29,28 @@ export const MobileMarketHeader = () => {
|
||||
if (!marketId) return null;
|
||||
|
||||
return (
|
||||
<div className="pl-3 pr-2 grid grid-cols-2 h-10 bg-vega-clight-700 dark:bg-vega-cdark-700">
|
||||
<div className="pl-3 pr-2 flex justify-between gap-2 h-10 bg-vega-clight-700 dark:bg-vega-cdark-700">
|
||||
<FullScreenPopover
|
||||
open={openMarket}
|
||||
onOpenChange={(x) => {
|
||||
setOpenMarket(x);
|
||||
}}
|
||||
trigger={
|
||||
<button
|
||||
data-testid="popover-trigger"
|
||||
className="min-w-0 flex gap-1 items-center"
|
||||
>
|
||||
<h1 className="whitespace-nowrap overflow-hidden text-ellipsis items-center">
|
||||
<span className="">
|
||||
{data
|
||||
? data.tradableInstrument.instrument.code
|
||||
: t('Select market')}
|
||||
</span>
|
||||
</h1>
|
||||
<VegaIcon
|
||||
name={VegaIconNames.CHEVRON_DOWN}
|
||||
size={16}
|
||||
<h1 className="flex gap-1 sm:gap-2 md:gap-4 items-center text-base leading-3 md:text-lg whitespace-nowrap">
|
||||
{data
|
||||
? data.tradableInstrument.instrument.code
|
||||
: t('Select market')}
|
||||
<span
|
||||
className={classNames(
|
||||
'origin-center transition-transform ease-in-out duration-300 flex',
|
||||
'transition-transform ease-in-out duration-300 flex',
|
||||
{
|
||||
'rotate-180': openMarket,
|
||||
}
|
||||
)}
|
||||
/>
|
||||
</button>
|
||||
>
|
||||
<VegaIcon name={VegaIconNames.CHEVRON_DOWN} size={16} />
|
||||
</span>
|
||||
</h1>
|
||||
}
|
||||
>
|
||||
<MarketSelector
|
||||
@@ -71,40 +64,34 @@ export const MobileMarketHeader = () => {
|
||||
setOpenPrice(x);
|
||||
}}
|
||||
trigger={
|
||||
<button
|
||||
data-testid="popover-trigger"
|
||||
className="min-w-0 flex gap-2 items-center justify-end"
|
||||
>
|
||||
<span className="flex gap-2 items-end md:text-md whitespace-nowrap leading-3">
|
||||
{data && (
|
||||
<>
|
||||
<span className="min-w-0 flex flex-col items-end gap-0">
|
||||
<span className="text-sm">
|
||||
<MarketMarkPrice
|
||||
marketId={data.id}
|
||||
decimalPlaces={data.decimalPlaces}
|
||||
/>
|
||||
</span>
|
||||
<span className="text-xs">
|
||||
<Last24hPriceChange
|
||||
marketId={data.id}
|
||||
decimalPlaces={data.decimalPlaces}
|
||||
fallback={<span />} // dont render anything so price is vertically centered
|
||||
/>
|
||||
</span>
|
||||
<span className="text-xs">
|
||||
<Last24hPriceChange
|
||||
marketId={data.id}
|
||||
decimalPlaces={data.decimalPlaces}
|
||||
/>
|
||||
</span>
|
||||
<span className="flex items-center gap-1">
|
||||
<MarketMarkPrice
|
||||
marketId={data.id}
|
||||
decimalPlaces={data.decimalPlaces}
|
||||
/>
|
||||
<VegaIcon
|
||||
name={VegaIconNames.CHEVRON_DOWN}
|
||||
size={16}
|
||||
className={classNames(
|
||||
'transition-transform ease-in-out duration-300',
|
||||
{
|
||||
'rotate-180': openPrice,
|
||||
}
|
||||
)}
|
||||
/>
|
||||
</span>
|
||||
<VegaIcon
|
||||
name={VegaIconNames.CHEVRON_DOWN}
|
||||
size={16}
|
||||
className={classNames(
|
||||
'min-w-0 transition-transform ease-in-out duration-300',
|
||||
{
|
||||
'rotate-180': openPrice,
|
||||
}
|
||||
)}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
</span>
|
||||
}
|
||||
>
|
||||
{data && (
|
||||
@@ -117,11 +104,11 @@ export const MobileMarketHeader = () => {
|
||||
);
|
||||
};
|
||||
|
||||
interface PopoverProps extends PopoverPrimitive.PopoverProps {
|
||||
export interface PopoverProps extends PopoverPrimitive.PopoverProps {
|
||||
trigger: React.ReactNode | string;
|
||||
}
|
||||
|
||||
const FullScreenPopover = ({
|
||||
export const FullScreenPopover = ({
|
||||
trigger,
|
||||
children,
|
||||
open,
|
||||
@@ -129,7 +116,7 @@ const FullScreenPopover = ({
|
||||
}: PopoverProps) => {
|
||||
return (
|
||||
<PopoverPrimitive.Root open={open} onOpenChange={onOpenChange}>
|
||||
<PopoverPrimitive.Trigger asChild={true}>
|
||||
<PopoverPrimitive.Trigger data-testid="popover-trigger">
|
||||
{trigger}
|
||||
</PopoverPrimitive.Trigger>
|
||||
<PopoverPrimitive.Portal>
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
CONSOLE_IMAGE_NAME=vegaprotocol/trading:latest
|
||||
VEGA_VERSION=v0.74.1
|
||||
VEGA_VERSION=v0.74.0-preview.10
|
||||
LOCAL_SERVER=false
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
CONSOLE_IMAGE_NAME=vegaprotocol/trading:develop
|
||||
VEGA_VERSION=v0.74.1
|
||||
VEGA_VERSION=v0.74.0-preview.6
|
||||
LOCAL_SERVER=false
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
CONSOLE_IMAGE_NAME=vegaprotocol/trading:main
|
||||
VEGA_VERSION=v0.73.13
|
||||
VEGA_VERSION=v0.73.10
|
||||
LOCAL_SERVER=false
|
||||
Generated
+1
-1
@@ -1161,7 +1161,7 @@ profile = ["pytest-profiling", "snakeviz"]
|
||||
type = "git"
|
||||
url = "https://github.com/vegaprotocol/vega-market-sim.git/"
|
||||
reference = "HEAD"
|
||||
resolved_reference = "a8afded34874a01cfd1bb771052aa12a062960b9"
|
||||
resolved_reference = "026976549c21e59f6f9c48f06ab15a210c5a5bf3"
|
||||
|
||||
[[package]]
|
||||
name = "websocket-client"
|
||||
|
||||
@@ -15,8 +15,7 @@ deal_ticket_deposit_dialog_button = "deal-ticket-deposit-dialog-button"
|
||||
@pytest.fixture(scope="module")
|
||||
def vega(request):
|
||||
with init_vega(request) as vega_instance:
|
||||
request.addfinalizer(lambda: cleanup_container(
|
||||
vega_instance)) # Register the cleanup function
|
||||
request.addfinalizer(lambda: cleanup_container(vega_instance)) # Register the cleanup function
|
||||
yield vega_instance
|
||||
|
||||
|
||||
@@ -25,7 +24,6 @@ def continuous_market(vega):
|
||||
return setup_continuous_market(vega)
|
||||
|
||||
|
||||
@pytest.mark.skip("tbd - issue only on the sim, should work in vega 0.74.0")
|
||||
@pytest.mark.usefixtures("auth", "risk_accepted")
|
||||
def test_should_display_info_and_button_for_deposit(continuous_market, page: Page):
|
||||
page.goto(f"/#/markets/{continuous_market}")
|
||||
|
||||
@@ -35,9 +35,9 @@ def test_market_lifecycle(proposed_market, vega: VegaServiceNull, page: Page):
|
||||
# 6002-MDET-003
|
||||
expect(page.get_by_test_id("market-price")).to_have_text("Mark Price0.00")
|
||||
# 6002-MDET-004
|
||||
expect(page.get_by_test_id("market-change")).to_have_text("Change (24h)-")
|
||||
expect(page.get_by_test_id("market-change")).to_have_text("Change (24h)0.00%0.00")
|
||||
# 6002-MDET-005
|
||||
expect(page.get_by_test_id("market-volume")).to_have_text("Volume (24h)-")
|
||||
expect(page.get_by_test_id("market-volume")).to_have_text("Volume (24h)- (- BTC)")
|
||||
# 6002-MDET-008
|
||||
expect(page.get_by_test_id("market-settlement-asset")).to_have_text(
|
||||
"Settlement assettDAI"
|
||||
|
||||
@@ -4,7 +4,7 @@ from playwright.sync_api import Page, expect
|
||||
from vega_sim.null_service import VegaServiceNull
|
||||
from vega_sim.service import MarketStateUpdateType
|
||||
from datetime import datetime, timedelta
|
||||
from conftest import init_vega, cleanup_container
|
||||
from conftest import init_vega
|
||||
from actions.utils import change_keys
|
||||
from actions.vega import submit_multiple_orders
|
||||
from fixtures.market import setup_perps_market
|
||||
@@ -17,9 +17,8 @@ col_amount = '[col-id="amount"]'
|
||||
class TestPerpetuals:
|
||||
@pytest.fixture(scope="class")
|
||||
def vega(self, request):
|
||||
with init_vega(request) as vega_instance:
|
||||
request.addfinalizer(lambda: cleanup_container(vega_instance)) # Register the cleanup function
|
||||
yield vega_instance
|
||||
with init_vega(request) as vega:
|
||||
yield vega
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def perps_market(self, vega: VegaServiceNull):
|
||||
|
||||
@@ -129,8 +129,7 @@ def setup_teams_and_games(vega: VegaServiceNull):
|
||||
)
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
# this recurring transfer has been commented out as there appears to be a bug where individual rewards earned are showing on the teams page
|
||||
""" vega.recurring_transfer(
|
||||
vega.recurring_transfer(
|
||||
from_key_name=PARTY_C.name,
|
||||
from_account_type=vega_protos.vega.ACCOUNT_TYPE_GENERAL,
|
||||
to_account_type=vega_protos.vega.ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES,
|
||||
@@ -144,7 +143,7 @@ def setup_teams_and_games(vega: VegaServiceNull):
|
||||
amount=100,
|
||||
factor=1.0,
|
||||
window_length=15
|
||||
) """
|
||||
)
|
||||
next_epoch(vega)
|
||||
print(f"[EPOCH: {vega.statistics().epoch_seq}] starting order activity")
|
||||
|
||||
@@ -213,17 +212,15 @@ def create_team(vega: VegaServiceNull):
|
||||
|
||||
|
||||
def test_team_page_games_table(team_page: Page):
|
||||
team_page.pause()
|
||||
team_page.get_by_test_id("games-toggle").click()
|
||||
expect(team_page.get_by_test_id("games-toggle")).to_have_text("Results (10)")
|
||||
expect(team_page.get_by_test_id("rank-0")).to_have_text("1")
|
||||
expect(team_page.get_by_test_id("games-toggle")).to_have_text("Games (1)")
|
||||
expect(team_page.get_by_test_id("rank-0")).to_have_text("2")
|
||||
expect(team_page.get_by_test_id("epoch-0")).to_have_text("19")
|
||||
expect(team_page.get_by_test_id("type-0")
|
||||
).to_have_text("Price maker fees paid")
|
||||
#TODO skipped as the amount is wrong
|
||||
#expect(team_page.get_by_test_id("amount-0")).to_have_text("74") # 50,000,000 on 74.1
|
||||
expect(team_page.get_by_test_id("amount-0")).to_have_text("74")
|
||||
expect(team_page.get_by_test_id("participatingTeams-0")).to_have_text("2")
|
||||
expect(team_page.get_by_test_id("participatingMembers-0")).to_have_text("3")
|
||||
expect(team_page.get_by_test_id("participatingMembers-0")).to_have_text("4")
|
||||
|
||||
|
||||
def test_team_page_members_table(team_page: Page):
|
||||
@@ -240,12 +237,12 @@ def test_team_page_headline(team_page: Page, setup_teams_and_games):
|
||||
expect(team_page.get_by_test_id("team-name")).to_have_text(team_name)
|
||||
expect(team_page.get_by_test_id("members-count-stat")).to_have_text("4")
|
||||
|
||||
expect(team_page.get_by_test_id("total-games-stat")).to_have_text("2")
|
||||
expect(team_page.get_by_test_id("total-games-stat")).to_have_text("1")
|
||||
|
||||
# TODO this still seems wrong as its always 0
|
||||
expect(team_page.get_by_test_id("total-volume-stat")).to_have_text("0")
|
||||
|
||||
expect(team_page.get_by_test_id("rewards-paid-stat")).to_have_text("1.2k")
|
||||
expect(team_page.get_by_test_id("rewards-paid-stat")).to_have_text("78")
|
||||
|
||||
|
||||
def test_switch_teams(team_page: Page, vega: VegaServiceNull):
|
||||
@@ -262,7 +259,6 @@ def test_switch_teams(team_page: Page, vega: VegaServiceNull):
|
||||
def test_leaderboard(competitions_page: Page, setup_teams_and_games):
|
||||
team_name = setup_teams_and_games["team_name"]
|
||||
competitions_page.reload()
|
||||
competitions_page.pause()
|
||||
expect(
|
||||
competitions_page.get_by_test_id("rank-0").locator(".text-yellow-300")
|
||||
).to_have_count(1)
|
||||
@@ -270,15 +266,15 @@ def test_leaderboard(competitions_page: Page, setup_teams_and_games):
|
||||
competitions_page.get_by_test_id(
|
||||
"rank-1").locator(".text-vega-clight-500")
|
||||
).to_have_count(1)
|
||||
expect(competitions_page.get_by_test_id("team-0")).to_have_text(team_name)
|
||||
expect(competitions_page.get_by_test_id("team-1")).to_have_text(team_name)
|
||||
expect(competitions_page.get_by_test_id("status-1")).to_have_text("Open")
|
||||
|
||||
# FIXME: the numbers are different we need to clarify this with the backend
|
||||
# expect(competitions_page.get_by_test_id("earned-1")).to_have_text("160")
|
||||
expect(competitions_page.get_by_test_id("games-1")).to_have_text("2")
|
||||
expect(competitions_page.get_by_test_id("games-1")).to_have_text("1")
|
||||
|
||||
# TODO still odd that this is 0
|
||||
expect(competitions_page.get_by_test_id("volume-0")).to_have_text("0")
|
||||
expect(competitions_page.get_by_test_id("volume-0")).to_have_text("-")
|
||||
|
||||
|
||||
def test_game_card(competitions_page: Page):
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
fragment TeamEntity on TeamGameEntity {
|
||||
rank
|
||||
volume
|
||||
rewardMetric
|
||||
rewardEarned
|
||||
totalRewardsEarned
|
||||
team {
|
||||
teamId
|
||||
membersParticipating {
|
||||
individual
|
||||
rank
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fragment GameFields on Game {
|
||||
id
|
||||
epoch
|
||||
numberOfParticipants
|
||||
entities {
|
||||
... on TeamGameEntity {
|
||||
...TeamEntity
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
query Games($epochFrom: Int) {
|
||||
games(epochFrom: $epochFrom, entityScope: ENTITY_SCOPE_TEAMS) {
|
||||
edges {
|
||||
node {
|
||||
...GameFields
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,28 @@ fragment TeamRefereeFields on TeamReferee {
|
||||
joinedAtEpoch
|
||||
}
|
||||
|
||||
fragment TeamEntity on TeamGameEntity {
|
||||
rank
|
||||
volume
|
||||
rewardMetric
|
||||
rewardEarned
|
||||
totalRewardsEarned
|
||||
team {
|
||||
teamId
|
||||
}
|
||||
}
|
||||
|
||||
fragment TeamGameFields on Game {
|
||||
id
|
||||
epoch
|
||||
numberOfParticipants
|
||||
entities {
|
||||
... on TeamGameEntity {
|
||||
...TeamEntity
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fragment TeamMemberStatsFields on TeamMemberStatistics {
|
||||
partyId
|
||||
totalQuantumVolume
|
||||
@@ -65,6 +87,13 @@ query Team($teamId: ID!, $partyId: ID, $aggregationEpochs: Int) {
|
||||
}
|
||||
}
|
||||
}
|
||||
games(entityScope: ENTITY_SCOPE_TEAMS) {
|
||||
edges {
|
||||
node {
|
||||
...TeamGameFields
|
||||
}
|
||||
}
|
||||
}
|
||||
teamMembersStatistics(
|
||||
teamId: $teamId
|
||||
aggregationEpochs: $aggregationEpochs
|
||||
|
||||
-83
@@ -1,83 +0,0 @@
|
||||
import * as Types from '@vegaprotocol/types';
|
||||
|
||||
import { gql } from '@apollo/client';
|
||||
import * as Apollo from '@apollo/client';
|
||||
const defaultOptions = {} as const;
|
||||
export type TeamEntityFragment = { __typename?: 'TeamGameEntity', rank: number, volume: string, rewardMetric: Types.DispatchMetric, rewardEarned: string, totalRewardsEarned: string, team: { __typename?: 'TeamParticipation', teamId: string, membersParticipating: Array<{ __typename?: 'IndividualGameEntity', individual: string, rank: number }> } };
|
||||
|
||||
export type GameFieldsFragment = { __typename?: 'Game', id: string, epoch: number, numberOfParticipants: number, entities: Array<{ __typename?: 'IndividualGameEntity' } | { __typename?: 'TeamGameEntity', rank: number, volume: string, rewardMetric: Types.DispatchMetric, rewardEarned: string, totalRewardsEarned: string, team: { __typename?: 'TeamParticipation', teamId: string, membersParticipating: Array<{ __typename?: 'IndividualGameEntity', individual: string, rank: number }> } }> };
|
||||
|
||||
export type GamesQueryVariables = Types.Exact<{
|
||||
epochFrom?: Types.InputMaybe<Types.Scalars['Int']>;
|
||||
}>;
|
||||
|
||||
|
||||
export type GamesQuery = { __typename?: 'Query', games: { __typename?: 'GamesConnection', edges?: Array<{ __typename?: 'GameEdge', node: { __typename?: 'Game', id: string, epoch: number, numberOfParticipants: number, entities: Array<{ __typename?: 'IndividualGameEntity' } | { __typename?: 'TeamGameEntity', rank: number, volume: string, rewardMetric: Types.DispatchMetric, rewardEarned: string, totalRewardsEarned: string, team: { __typename?: 'TeamParticipation', teamId: string, membersParticipating: Array<{ __typename?: 'IndividualGameEntity', individual: string, rank: number }> } }> } } | null> | null } };
|
||||
|
||||
export const TeamEntityFragmentDoc = gql`
|
||||
fragment TeamEntity on TeamGameEntity {
|
||||
rank
|
||||
volume
|
||||
rewardMetric
|
||||
rewardEarned
|
||||
totalRewardsEarned
|
||||
team {
|
||||
teamId
|
||||
membersParticipating {
|
||||
individual
|
||||
rank
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
export const GameFieldsFragmentDoc = gql`
|
||||
fragment GameFields on Game {
|
||||
id
|
||||
epoch
|
||||
numberOfParticipants
|
||||
entities {
|
||||
... on TeamGameEntity {
|
||||
...TeamEntity
|
||||
}
|
||||
}
|
||||
}
|
||||
${TeamEntityFragmentDoc}`;
|
||||
export const GamesDocument = gql`
|
||||
query Games($epochFrom: Int) {
|
||||
games(epochFrom: $epochFrom, entityScope: ENTITY_SCOPE_TEAMS) {
|
||||
edges {
|
||||
node {
|
||||
...GameFields
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
${GameFieldsFragmentDoc}`;
|
||||
|
||||
/**
|
||||
* __useGamesQuery__
|
||||
*
|
||||
* To run a query within a React component, call `useGamesQuery` and pass it any options that fit your needs.
|
||||
* When your component renders, `useGamesQuery` 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 } = useGamesQuery({
|
||||
* variables: {
|
||||
* epochFrom: // value for 'epochFrom'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useGamesQuery(baseOptions?: Apollo.QueryHookOptions<GamesQuery, GamesQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useQuery<GamesQuery, GamesQueryVariables>(GamesDocument, options);
|
||||
}
|
||||
export function useGamesLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<GamesQuery, GamesQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useLazyQuery<GamesQuery, GamesQueryVariables>(GamesDocument, options);
|
||||
}
|
||||
export type GamesQueryHookResult = ReturnType<typeof useGamesQuery>;
|
||||
export type GamesLazyQueryHookResult = ReturnType<typeof useGamesLazyQuery>;
|
||||
export type GamesQueryResult = Apollo.QueryResult<GamesQuery, GamesQueryVariables>;
|
||||
+37
-1
@@ -9,6 +9,10 @@ export type TeamStatsFieldsFragment = { __typename?: 'TeamStatistics', teamId: s
|
||||
|
||||
export type TeamRefereeFieldsFragment = { __typename?: 'TeamReferee', teamId: string, referee: string, joinedAt: any, joinedAtEpoch: number };
|
||||
|
||||
export type TeamEntityFragment = { __typename?: 'TeamGameEntity', rank: number, volume: string, rewardMetric: Types.DispatchMetric, rewardEarned: string, totalRewardsEarned: string, team: { __typename?: 'TeamParticipation', teamId: string } };
|
||||
|
||||
export type TeamGameFieldsFragment = { __typename?: 'Game', id: string, epoch: number, numberOfParticipants: number, entities: Array<{ __typename?: 'IndividualGameEntity' } | { __typename?: 'TeamGameEntity', rank: number, volume: string, rewardMetric: Types.DispatchMetric, rewardEarned: string, totalRewardsEarned: string, team: { __typename?: 'TeamParticipation', teamId: string } }> };
|
||||
|
||||
export type TeamMemberStatsFieldsFragment = { __typename?: 'TeamMemberStatistics', partyId: string, totalQuantumVolume: string, totalQuantumRewards: string, totalGamesPlayed: number };
|
||||
|
||||
export type TeamQueryVariables = Types.Exact<{
|
||||
@@ -18,7 +22,7 @@ export type TeamQueryVariables = Types.Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type TeamQuery = { __typename?: 'Query', teams?: { __typename?: 'TeamConnection', edges: Array<{ __typename?: 'TeamEdge', node: { __typename?: 'Team', teamId: string, referrer: string, name: string, teamUrl: string, avatarUrl: string, createdAt: any, createdAtEpoch: number, closed: boolean, allowList: Array<string> } }> } | null, partyTeams?: { __typename?: 'TeamConnection', edges: Array<{ __typename?: 'TeamEdge', node: { __typename?: 'Team', teamId: string, referrer: string, name: string, teamUrl: string, avatarUrl: string, createdAt: any, createdAtEpoch: number, closed: boolean, allowList: Array<string> } }> } | null, teamsStatistics?: { __typename?: 'TeamsStatisticsConnection', edges: Array<{ __typename?: 'TeamStatisticsEdge', node: { __typename?: 'TeamStatistics', teamId: string, totalQuantumVolume: string, totalQuantumRewards: string, totalGamesPlayed: number, gamesPlayed: Array<string>, quantumRewards: Array<{ __typename?: 'QuantumRewardsPerEpoch', epoch: number, totalQuantumRewards: string }> } }> } | null, teamReferees?: { __typename?: 'TeamRefereeConnection', edges: Array<{ __typename?: 'TeamRefereeEdge', node: { __typename?: 'TeamReferee', teamId: string, referee: string, joinedAt: any, joinedAtEpoch: number } }> } | null, teamMembersStatistics?: { __typename?: 'TeamMembersStatisticsConnection', edges: Array<{ __typename?: 'TeamMemberStatisticsEdge', node: { __typename?: 'TeamMemberStatistics', partyId: string, totalQuantumVolume: string, totalQuantumRewards: string, totalGamesPlayed: number } }> } | null };
|
||||
export type TeamQuery = { __typename?: 'Query', teams?: { __typename?: 'TeamConnection', edges: Array<{ __typename?: 'TeamEdge', node: { __typename?: 'Team', teamId: string, referrer: string, name: string, teamUrl: string, avatarUrl: string, createdAt: any, createdAtEpoch: number, closed: boolean, allowList: Array<string> } }> } | null, partyTeams?: { __typename?: 'TeamConnection', edges: Array<{ __typename?: 'TeamEdge', node: { __typename?: 'Team', teamId: string, referrer: string, name: string, teamUrl: string, avatarUrl: string, createdAt: any, createdAtEpoch: number, closed: boolean, allowList: Array<string> } }> } | null, teamsStatistics?: { __typename?: 'TeamsStatisticsConnection', edges: Array<{ __typename?: 'TeamStatisticsEdge', node: { __typename?: 'TeamStatistics', teamId: string, totalQuantumVolume: string, totalQuantumRewards: string, totalGamesPlayed: number, gamesPlayed: Array<string>, quantumRewards: Array<{ __typename?: 'QuantumRewardsPerEpoch', epoch: number, totalQuantumRewards: string }> } }> } | null, teamReferees?: { __typename?: 'TeamRefereeConnection', edges: Array<{ __typename?: 'TeamRefereeEdge', node: { __typename?: 'TeamReferee', teamId: string, referee: string, joinedAt: any, joinedAtEpoch: number } }> } | null, games: { __typename?: 'GamesConnection', edges?: Array<{ __typename?: 'GameEdge', node: { __typename?: 'Game', id: string, epoch: number, numberOfParticipants: number, entities: Array<{ __typename?: 'IndividualGameEntity' } | { __typename?: 'TeamGameEntity', rank: number, volume: string, rewardMetric: Types.DispatchMetric, rewardEarned: string, totalRewardsEarned: string, team: { __typename?: 'TeamParticipation', teamId: string } }> } } | null> | null }, teamMembersStatistics?: { __typename?: 'TeamMembersStatisticsConnection', edges: Array<{ __typename?: 'TeamMemberStatisticsEdge', node: { __typename?: 'TeamMemberStatistics', partyId: string, totalQuantumVolume: string, totalQuantumRewards: string, totalGamesPlayed: number } }> } | null };
|
||||
|
||||
export const TeamFieldsFragmentDoc = gql`
|
||||
fragment TeamFields on Team {
|
||||
@@ -54,6 +58,30 @@ export const TeamRefereeFieldsFragmentDoc = gql`
|
||||
joinedAtEpoch
|
||||
}
|
||||
`;
|
||||
export const TeamEntityFragmentDoc = gql`
|
||||
fragment TeamEntity on TeamGameEntity {
|
||||
rank
|
||||
volume
|
||||
rewardMetric
|
||||
rewardEarned
|
||||
totalRewardsEarned
|
||||
team {
|
||||
teamId
|
||||
}
|
||||
}
|
||||
`;
|
||||
export const TeamGameFieldsFragmentDoc = gql`
|
||||
fragment TeamGameFields on Game {
|
||||
id
|
||||
epoch
|
||||
numberOfParticipants
|
||||
entities {
|
||||
... on TeamGameEntity {
|
||||
...TeamEntity
|
||||
}
|
||||
}
|
||||
}
|
||||
${TeamEntityFragmentDoc}`;
|
||||
export const TeamMemberStatsFieldsFragmentDoc = gql`
|
||||
fragment TeamMemberStatsFields on TeamMemberStatistics {
|
||||
partyId
|
||||
@@ -92,6 +120,13 @@ export const TeamDocument = gql`
|
||||
}
|
||||
}
|
||||
}
|
||||
games(entityScope: ENTITY_SCOPE_TEAMS) {
|
||||
edges {
|
||||
node {
|
||||
...TeamGameFields
|
||||
}
|
||||
}
|
||||
}
|
||||
teamMembersStatistics(teamId: $teamId, aggregationEpochs: $aggregationEpochs) {
|
||||
edges {
|
||||
node {
|
||||
@@ -103,6 +138,7 @@ export const TeamDocument = gql`
|
||||
${TeamFieldsFragmentDoc}
|
||||
${TeamStatsFieldsFragmentDoc}
|
||||
${TeamRefereeFieldsFragmentDoc}
|
||||
${TeamGameFieldsFragmentDoc}
|
||||
${TeamMemberStatsFieldsFragmentDoc}`;
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
import compact from 'lodash/compact';
|
||||
import { useActiveRewardsQuery } from '../../components/rewards-container/__generated__/Rewards';
|
||||
import { isActiveReward } from '../../components/rewards-container/active-rewards';
|
||||
import {
|
||||
EntityScope,
|
||||
IndividualScope,
|
||||
type TransferNode,
|
||||
} from '@vegaprotocol/types';
|
||||
|
||||
const isScopedToTeams = (node: TransferNode) =>
|
||||
node.transfer.kind.__typename === 'RecurringTransfer' &&
|
||||
// scoped to teams
|
||||
(node.transfer.kind.dispatchStrategy?.entityScope ===
|
||||
EntityScope.ENTITY_SCOPE_TEAMS ||
|
||||
// or to individuals
|
||||
(node.transfer.kind.dispatchStrategy?.entityScope ===
|
||||
EntityScope.ENTITY_SCOPE_INDIVIDUALS &&
|
||||
// but they have to be in a team
|
||||
node.transfer.kind.dispatchStrategy.individualScope ===
|
||||
IndividualScope.INDIVIDUAL_SCOPE_IN_TEAM));
|
||||
|
||||
export const useGameCards = ({
|
||||
currentEpoch,
|
||||
onlyActive,
|
||||
}: {
|
||||
currentEpoch: number;
|
||||
onlyActive: boolean;
|
||||
}) => {
|
||||
const { data, loading, error } = useActiveRewardsQuery({
|
||||
variables: {
|
||||
isReward: true,
|
||||
},
|
||||
fetchPolicy: 'cache-and-network',
|
||||
});
|
||||
|
||||
const games = compact(data?.transfersConnection?.edges?.map((n) => n?.node))
|
||||
.map((n) => n as TransferNode)
|
||||
.filter((node) => {
|
||||
const active = onlyActive ? isActiveReward(node, currentEpoch) : true;
|
||||
return active && isScopedToTeams(node);
|
||||
});
|
||||
|
||||
return {
|
||||
data: games,
|
||||
loading,
|
||||
error,
|
||||
};
|
||||
};
|
||||
@@ -1,80 +1,48 @@
|
||||
import compact from 'lodash/compact';
|
||||
import { useActiveRewardsQuery } from '../../components/rewards-container/__generated__/Rewards';
|
||||
import { isActiveReward } from '../../components/rewards-container/active-rewards';
|
||||
import {
|
||||
useGamesQuery,
|
||||
type GameFieldsFragment,
|
||||
type TeamEntityFragment,
|
||||
} from './__generated__/Games';
|
||||
import orderBy from 'lodash/orderBy';
|
||||
import { removePaginationWrapper } from '@vegaprotocol/utils';
|
||||
import { useCurrentEpochInfoQuery } from './__generated__/Epoch';
|
||||
import { type ApolloError } from '@apollo/client';
|
||||
EntityScope,
|
||||
IndividualScope,
|
||||
type TransferNode,
|
||||
} from '@vegaprotocol/types';
|
||||
|
||||
const TAKE_EPOCHS = 30; // TODO: should this be DEFAULT_AGGREGATION_EPOCHS?
|
||||
const isScopedToTeams = (node: TransferNode) =>
|
||||
node.transfer.kind.__typename === 'RecurringTransfer' &&
|
||||
// scoped to teams
|
||||
(node.transfer.kind.dispatchStrategy?.entityScope ===
|
||||
EntityScope.ENTITY_SCOPE_TEAMS ||
|
||||
// or to individuals
|
||||
(node.transfer.kind.dispatchStrategy?.entityScope ===
|
||||
EntityScope.ENTITY_SCOPE_INDIVIDUALS &&
|
||||
// but they have to be in a team
|
||||
node.transfer.kind.dispatchStrategy.individualScope ===
|
||||
IndividualScope.INDIVIDUAL_SCOPE_IN_TEAM));
|
||||
|
||||
const findTeam = (entities: GameFieldsFragment['entities'], teamId: string) => {
|
||||
const team = entities.find(
|
||||
(ent) => ent.__typename === 'TeamGameEntity' && ent.team.teamId === teamId
|
||||
);
|
||||
if (team?.__typename === 'TeamGameEntity') return team; // drops __typename === 'IndividualGameEntity' from team object
|
||||
return undefined;
|
||||
};
|
||||
|
||||
export type Game = GameFieldsFragment & {
|
||||
/** The team entity data accessible only if scoped to particular team. */
|
||||
team?: TeamEntityFragment;
|
||||
};
|
||||
export type TeamGame = Game & { team: NonNullable<Game['team']> };
|
||||
|
||||
const isTeamGame = (game: Game): game is TeamGame => game.team !== undefined;
|
||||
export const areTeamGames = (games?: Game[]): games is TeamGame[] =>
|
||||
Boolean(games && games.filter((g) => isTeamGame(g)).length > 0);
|
||||
|
||||
type GamesData = {
|
||||
data?: Game[];
|
||||
loading: boolean;
|
||||
error?: ApolloError;
|
||||
};
|
||||
|
||||
export const useGames = (teamId?: string, epochFrom?: number): GamesData => {
|
||||
const {
|
||||
data: epochData,
|
||||
loading: epochLoading,
|
||||
error: epochError,
|
||||
} = useCurrentEpochInfoQuery({
|
||||
skip: Boolean(epochFrom),
|
||||
});
|
||||
|
||||
let from = epochFrom;
|
||||
if (!from && epochData) {
|
||||
from = Number(epochData.epoch.id) - TAKE_EPOCHS;
|
||||
if (from < 1) from = 1; // make sure it's not negative
|
||||
}
|
||||
|
||||
const { data, loading, error } = useGamesQuery({
|
||||
export const useGames = ({
|
||||
currentEpoch,
|
||||
onlyActive,
|
||||
}: {
|
||||
currentEpoch: number;
|
||||
onlyActive: boolean;
|
||||
}) => {
|
||||
const { data, loading, error } = useActiveRewardsQuery({
|
||||
variables: {
|
||||
epochFrom: from,
|
||||
isReward: true,
|
||||
},
|
||||
skip: !from,
|
||||
fetchPolicy: 'cache-and-network',
|
||||
context: { isEnlargedTimeout: true },
|
||||
});
|
||||
|
||||
const allGames = removePaginationWrapper(data?.games.edges);
|
||||
const allOrScoped = allGames
|
||||
.map((g) => ({
|
||||
...g,
|
||||
team: teamId ? findTeam(g.entities, teamId) : undefined,
|
||||
}))
|
||||
.filter((g) => {
|
||||
// passthrough if not scoped to particular team
|
||||
if (!teamId) return true;
|
||||
return isTeamGame(g);
|
||||
const games = compact(data?.transfersConnection?.edges?.map((n) => n?.node))
|
||||
.map((n) => n as TransferNode)
|
||||
.filter((node) => {
|
||||
const active = onlyActive ? isActiveReward(node, currentEpoch) : true;
|
||||
return active && isScopedToTeams(node);
|
||||
});
|
||||
|
||||
const games = orderBy(allOrScoped, 'epoch', 'desc');
|
||||
|
||||
return {
|
||||
data: games,
|
||||
loading: loading || epochLoading,
|
||||
error: error || epochError,
|
||||
loading,
|
||||
error,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -4,7 +4,6 @@ import first from 'lodash/first';
|
||||
import { useTeamsQuery } from './__generated__/Teams';
|
||||
import { useTeam } from './use-team';
|
||||
import { useTeams } from './use-teams';
|
||||
import { areTeamGames, useGames } from './use-games';
|
||||
|
||||
export const useMyTeam = () => {
|
||||
const { pubKey } = useVegaWallet();
|
||||
@@ -20,8 +19,7 @@ export const useMyTeam = () => {
|
||||
|
||||
const team = first(compact(maybeMyTeam?.teams?.edges.map((n) => n.node)));
|
||||
const rank = teams.findIndex((t) => t.teamId === team?.teamId) + 1;
|
||||
const { stats } = useTeam(team?.teamId);
|
||||
const { data: games } = useGames(team?.teamId);
|
||||
const { games, stats } = useTeam(team?.teamId);
|
||||
|
||||
return { team, stats, games: areTeamGames(games) ? games : undefined, rank };
|
||||
return { team, stats, games, rank };
|
||||
};
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
import compact from 'lodash/compact';
|
||||
import orderBy from 'lodash/orderBy';
|
||||
import {
|
||||
useTeamQuery,
|
||||
type TeamFieldsFragment,
|
||||
type TeamStatsFieldsFragment,
|
||||
type TeamRefereeFieldsFragment,
|
||||
type TeamEntityFragment,
|
||||
type TeamMemberStatsFieldsFragment,
|
||||
} from './__generated__/Team';
|
||||
import { DEFAULT_AGGREGATION_EPOCHS } from './use-teams';
|
||||
@@ -15,6 +18,8 @@ export type Member = TeamRefereeFieldsFragment & {
|
||||
totalQuantumVolume: string;
|
||||
totalQuantumRewards: string;
|
||||
};
|
||||
export type TeamEntity = TeamEntityFragment;
|
||||
export type TeamGame = ReturnType<typeof useTeam>['games'][number];
|
||||
export type MemberStats = TeamMemberStatsFieldsFragment;
|
||||
|
||||
export const useTeam = (teamId?: string, partyId?: string) => {
|
||||
@@ -75,11 +80,33 @@ export const useTeam = (teamId?: string, partyId?: string) => {
|
||||
});
|
||||
}
|
||||
|
||||
// Find games where the current team participated in
|
||||
const gamesWithTeam = compact(data?.games.edges).map((edge) => {
|
||||
const team = edge.node.entities.find((e) => {
|
||||
if (e.__typename !== 'TeamGameEntity') return false;
|
||||
if (e.team.teamId !== teamId) return false;
|
||||
return true;
|
||||
});
|
||||
|
||||
if (!team) return null;
|
||||
|
||||
return {
|
||||
id: edge.node.id,
|
||||
epoch: edge.node.epoch,
|
||||
numberOfParticipants: edge.node.numberOfParticipants,
|
||||
entities: edge.node.entities,
|
||||
team: team as TeamEntity, // TS can't infer that all the game entities are teams
|
||||
};
|
||||
});
|
||||
|
||||
const games = orderBy(compact(gamesWithTeam), 'epoch', 'desc');
|
||||
|
||||
return {
|
||||
...queryResult,
|
||||
stats: teamStatsEdge?.node,
|
||||
team,
|
||||
members,
|
||||
games,
|
||||
partyTeam,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -3,19 +3,10 @@ import { useMemo } from 'react';
|
||||
import { useTeamsQuery } from './__generated__/Teams';
|
||||
import { useTeamsStatisticsQuery } from './__generated__/TeamsStatistics';
|
||||
import compact from 'lodash/compact';
|
||||
import { type TeamStatsFieldsFragment } from './__generated__/Team';
|
||||
|
||||
// 192
|
||||
export const DEFAULT_AGGREGATION_EPOCHS = 192;
|
||||
|
||||
const EMPTY_STATS: Partial<TeamStatsFieldsFragment> = {
|
||||
totalQuantumVolume: '0',
|
||||
totalQuantumRewards: '0',
|
||||
totalGamesPlayed: 0,
|
||||
gamesPlayed: [],
|
||||
quantumRewards: [],
|
||||
};
|
||||
|
||||
export const useTeams = (aggregationEpochs = DEFAULT_AGGREGATION_EPOCHS) => {
|
||||
const {
|
||||
data: teamsData,
|
||||
@@ -42,7 +33,7 @@ export const useTeams = (aggregationEpochs = DEFAULT_AGGREGATION_EPOCHS) => {
|
||||
const data = useMemo(() => {
|
||||
const data = teams.map((t) => ({
|
||||
...t,
|
||||
...(stats.find((s) => s.teamId === t.teamId) || EMPTY_STATS),
|
||||
...stats.find((s) => s.teamId === t.teamId),
|
||||
}));
|
||||
|
||||
return orderBy(data, (d) => Number(d.totalQuantumRewards || 0), 'desc').map(
|
||||
|
||||
@@ -48,8 +48,5 @@ export const DEFAULT_CACHE_CONFIG: InMemoryCacheConfig = {
|
||||
statistics: {
|
||||
keyFields: false,
|
||||
},
|
||||
Game: {
|
||||
keyFields: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
type FirstDataRenderedEvent,
|
||||
type SortChangedEvent,
|
||||
type GridReadyEvent,
|
||||
type GridApi,
|
||||
GridApi,
|
||||
} from 'ag-grid-community';
|
||||
import { useCallback, useEffect, useRef } from 'react';
|
||||
|
||||
|
||||
@@ -281,7 +281,7 @@ export const DealTicket = ({
|
||||
marginFactor: margin?.marginFactor || '1',
|
||||
marginMode:
|
||||
margin?.marginMode || Schema.MarginMode.MARGIN_MODE_CROSS_MARGIN,
|
||||
includeRequiredPositionMarginInAvailableCollateral: true,
|
||||
includeCollateralIncreaseInAvailableCollateral: true,
|
||||
},
|
||||
!normalizedOrder ||
|
||||
(normalizedOrder.type !== Schema.OrderType.TYPE_MARKET &&
|
||||
|
||||
@@ -89,7 +89,7 @@ export const MarginChange = ({
|
||||
openVolume,
|
||||
marketId,
|
||||
orderMarginAccountBalance: orderMarginAccountBalance || '0',
|
||||
includeRequiredPositionMarginInAvailableCollateral: true,
|
||||
includeCollateralIncreaseInAvailableCollateral: true,
|
||||
orders,
|
||||
},
|
||||
skip
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"{{liquidityPriceRange}} of mid price": "{{liquidityPriceRange}} of mid price",
|
||||
"{{probability}} probability price bounds": "{{probability}} probability price bounds",
|
||||
"24 hour change is unavailable at this time. The price change in the last 120 hours is:": "24 hour change is unavailable at this time. The price change in the last 120 hours is:",
|
||||
"24 hour change is unavailable at this time. The volume change in the last 120 hours is {{candleVolumeValue}} for a total of {{candleVolumePrice}} {{quoteUnit}}": "24 hour change is unavailable at this time. The volume change in the last 120 hours is {{candleVolumeValue}} for a total of {{candleVolumePrice}} {{quoteUnit}}",
|
||||
"24 hour change is unavailable at this time. The volume change in the last 120 hours is {{candleVolumeValue}}": "24 hour change is unavailable at this time. The volume change in the last 120 hours is {{candleVolumeValue}}",
|
||||
"A concept derived from traditional markets. It is a calculated value for the ‘current market price’ on a market.": "A concept derived from traditional markets. It is a calculated value for the ‘current market price’ on a market.",
|
||||
"A number that will be calculated by an appropriate stochastic risk model, dependent on the type of risk model used and its parameters.": "A number that will be calculated by an appropriate stochastic risk model, dependent on the type of risk model used and its parameters.",
|
||||
"A sliding penalty for how much an LP bond is slashed if an LP fails to reach the minimum SLA. This is a network parameter.": "A sliding penalty for how much an LP bond is slashed if an LP fails to reach the minimum SLA. This is a network parameter.",
|
||||
@@ -49,9 +49,6 @@
|
||||
"Market": "Market",
|
||||
"Market data": "Market data",
|
||||
"Market governance": "Market governance",
|
||||
"Market has not been active for 24 hours. The price change between {{start}} and {{end}} is:": "Market has not been active for 24 hours. The price change between {{start}} and {{end}} is:",
|
||||
"Market has not been active for 24 hours. The volume traded between {{start}} and {{end}} is:": "Market has not been active for 24 hours. The volume traded between {{start}} and {{end}} is:",
|
||||
"Market has not been active for 24 hours. The volume traded between {{start}} and {{end}} is {{candleVolumeValue}} for a total of {{candleVolumePrice}} {{quoteUnit}}": "Market has not been active for 24 hours. The volume traded between {{start}} and {{end}} is {{candleVolumeValue}} for a total of {{candleVolumePrice}} {{quoteUnit}}",
|
||||
"Market ID": "Market ID",
|
||||
"Market price": "Market price",
|
||||
"Market specification": "Market specification",
|
||||
|
||||
@@ -90,7 +90,6 @@
|
||||
"Earned by me": "Earned by me",
|
||||
"Eligible teams": "Eligible teams",
|
||||
"Enactment date reached and usual auction exit checks pass": "Enactment date reached and usual auction exit checks pass",
|
||||
"[empty]": "[empty]",
|
||||
"Ends in": "Ends in",
|
||||
"Entity scope": "Entity scope",
|
||||
"{{entity}} scope": "{{entity}} scope",
|
||||
@@ -123,7 +122,6 @@
|
||||
"Funding rate": "Funding rate",
|
||||
"Futures": "Futures",
|
||||
"Games ({{count}})": "Games ({{count}})",
|
||||
"Results ({{count}})": "Results ({{count}})",
|
||||
"Generate a referral code to share with your friends and start earning commission.": "Generate a referral code to share with your friends and start earning commission.",
|
||||
"Generate code": "Generate code",
|
||||
"Get rewards for providing liquidity.": "Get rewards for providing liquidity.",
|
||||
@@ -200,7 +198,6 @@
|
||||
"No funding history data": "No funding history data",
|
||||
"No future markets.": "No future markets.",
|
||||
"No games": "No games",
|
||||
"No game results available": "No game results available",
|
||||
"No ledger entries to export": "No ledger entries to export",
|
||||
"No market": "No market",
|
||||
"No markets": "No markets",
|
||||
@@ -320,7 +317,6 @@
|
||||
"Target stake": "Target stake",
|
||||
"Team": "Team",
|
||||
"Team name": "Team name",
|
||||
"Team name cannot be empty": "Team name cannot be empty",
|
||||
"Team creation transaction successful": "Team creation transaction successful",
|
||||
"Team joined": "Team joined",
|
||||
"Team switch successful. You will switch team at the end of the epoch.": "Team switch successful. You will switch team at the end of the epoch.",
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { type ReactNode } from 'react';
|
||||
import {
|
||||
addDecimalsFormatNumber,
|
||||
formatNumberPercentage,
|
||||
getDateTimeFormat,
|
||||
isNumeric,
|
||||
priceChange,
|
||||
priceChangePercentage,
|
||||
} from '@vegaprotocol/utils';
|
||||
@@ -15,57 +14,29 @@ import { useT } from '../../use-t';
|
||||
|
||||
interface Props {
|
||||
marketId?: string;
|
||||
decimalPlaces: number;
|
||||
fallback?: ReactNode;
|
||||
decimalPlaces?: number;
|
||||
initialValue?: string[];
|
||||
isHeader?: boolean;
|
||||
noUpdate?: boolean;
|
||||
// render prop for no price change
|
||||
fallback?: React.ReactNode;
|
||||
}
|
||||
|
||||
export const Last24hPriceChange = ({
|
||||
marketId,
|
||||
decimalPlaces,
|
||||
initialValue,
|
||||
fallback,
|
||||
}: Props) => {
|
||||
const t = useT();
|
||||
const { oneDayCandles, fiveDaysCandles, error } = useCandles({
|
||||
const { oneDayCandles, error, fiveDaysCandles } = useCandles({
|
||||
marketId,
|
||||
});
|
||||
|
||||
const nonIdeal = fallback || <span>{'-'}</span>;
|
||||
|
||||
if (error || !oneDayCandles || !fiveDaysCandles) {
|
||||
return nonIdeal;
|
||||
}
|
||||
|
||||
if (fiveDaysCandles.length < 24) {
|
||||
return (
|
||||
<Tooltip
|
||||
description={
|
||||
<span className="justify-start">
|
||||
{t(
|
||||
'Market has not been active for 24 hours. The price change between {{start}} and {{end}} is:',
|
||||
{
|
||||
start: getDateTimeFormat().format(
|
||||
new Date(fiveDaysCandles[0].periodStart)
|
||||
),
|
||||
end: getDateTimeFormat().format(
|
||||
new Date(
|
||||
fiveDaysCandles[fiveDaysCandles.length - 1].periodStart
|
||||
)
|
||||
),
|
||||
}
|
||||
)}
|
||||
<PriceChangeCell
|
||||
candles={fiveDaysCandles.map((c) => c.close) || []}
|
||||
decimalPlaces={decimalPlaces}
|
||||
/>
|
||||
</span>
|
||||
}
|
||||
>
|
||||
<span>{nonIdeal}</span>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
||||
if (oneDayCandles.length < 24) {
|
||||
if (
|
||||
fiveDaysCandles &&
|
||||
fiveDaysCandles.length > 0 &&
|
||||
(!oneDayCandles || oneDayCandles?.length === 0)
|
||||
) {
|
||||
return (
|
||||
<Tooltip
|
||||
description={
|
||||
@@ -80,12 +51,16 @@ export const Last24hPriceChange = ({
|
||||
</span>
|
||||
}
|
||||
>
|
||||
<span>{nonIdeal}</span>
|
||||
<span>{fallback}</span>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
||||
const candles = oneDayCandles?.map((c) => c.close) || [];
|
||||
if (error || !isNumeric(decimalPlaces)) {
|
||||
return <span>{fallback}</span>;
|
||||
}
|
||||
|
||||
const candles = oneDayCandles?.map((c) => c.close) || initialValue || [];
|
||||
const change = priceChange(candles);
|
||||
const changePercentage = priceChangePercentage(candles);
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ import { calcCandleVolume, calcCandleVolumePrice } from '../../market-utils';
|
||||
import {
|
||||
addDecimalsFormatNumber,
|
||||
formatNumber,
|
||||
getDateTimeFormat,
|
||||
isNumeric,
|
||||
} from '@vegaprotocol/utils';
|
||||
import { Tooltip } from '@vegaprotocol/ui-toolkit';
|
||||
@@ -27,17 +26,15 @@ export const Last24hVolume = ({
|
||||
quoteUnit,
|
||||
}: Props) => {
|
||||
const t = useT();
|
||||
const { oneDayCandles, fiveDaysCandles, error } = useCandles({
|
||||
const { oneDayCandles, fiveDaysCandles } = useCandles({
|
||||
marketId,
|
||||
});
|
||||
|
||||
const nonIdeal = <span>{'-'}</span>;
|
||||
|
||||
if (error || !oneDayCandles || !fiveDaysCandles) {
|
||||
return nonIdeal;
|
||||
}
|
||||
|
||||
if (fiveDaysCandles.length < 24) {
|
||||
if (
|
||||
fiveDaysCandles &&
|
||||
fiveDaysCandles.length > 0 &&
|
||||
(!oneDayCandles || oneDayCandles?.length === 0)
|
||||
) {
|
||||
const candleVolume = calcCandleVolume(fiveDaysCandles);
|
||||
const candleVolumePrice = calcCandleVolumePrice(
|
||||
fiveDaysCandles,
|
||||
@@ -58,59 +55,14 @@ export const Last24hVolume = ({
|
||||
<div>
|
||||
<span className="flex flex-col">
|
||||
{t(
|
||||
'Market has not been active for 24 hours. The volume traded between {{start}} and {{end}} is {{candleVolumeValue}} for a total of {{candleVolumePrice}} {{quoteUnit}}',
|
||||
{
|
||||
start: getDateTimeFormat().format(
|
||||
new Date(fiveDaysCandles[0].periodStart)
|
||||
),
|
||||
end: getDateTimeFormat().format(
|
||||
new Date(
|
||||
fiveDaysCandles[fiveDaysCandles.length - 1].periodStart
|
||||
)
|
||||
),
|
||||
candleVolumeValue,
|
||||
candleVolumePrice,
|
||||
quoteUnit,
|
||||
}
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<span>{nonIdeal}</span>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
||||
if (oneDayCandles.length < 24) {
|
||||
const candleVolume = calcCandleVolume(fiveDaysCandles);
|
||||
const candleVolumePrice = calcCandleVolumePrice(
|
||||
fiveDaysCandles,
|
||||
marketDecimals,
|
||||
positionDecimalPlaces
|
||||
);
|
||||
const candleVolumeValue =
|
||||
candleVolume && isNumeric(positionDecimalPlaces)
|
||||
? addDecimalsFormatNumber(
|
||||
candleVolume,
|
||||
positionDecimalPlaces,
|
||||
formatDecimals
|
||||
)
|
||||
: '-';
|
||||
return (
|
||||
<Tooltip
|
||||
description={
|
||||
<div>
|
||||
<span className="flex flex-col">
|
||||
{t(
|
||||
'24 hour change is unavailable at this time. The volume change in the last 120 hours is {{candleVolumeValue}} for a total of ({{candleVolumePrice}} {{quoteUnit}})',
|
||||
'24 hour change is unavailable at this time. The volume change in the last 120 hours is {{candleVolumeValue}} ({{candleVolumePrice}} {{quoteUnit}})',
|
||||
{ candleVolumeValue, candleVolumePrice, quoteUnit }
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<span>{nonIdeal}</span>
|
||||
<span>-</span>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ const mockData = [
|
||||
periodStart: today.toISOString(),
|
||||
__typename: 'Candle',
|
||||
},
|
||||
null,
|
||||
{
|
||||
high: '6309988',
|
||||
low: '6296335',
|
||||
|
||||
@@ -18,12 +18,7 @@ export const useCandles = ({ marketId }: { marketId?: string }) => {
|
||||
skip: !marketId,
|
||||
});
|
||||
|
||||
const fiveDaysCandles = data?.filter((c) => {
|
||||
if (c.open === '' || c.close === '' || c.high === '' || c.close === '') {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
const fiveDaysCandles = data?.filter(Boolean);
|
||||
|
||||
const oneDayCandles = fiveDaysCandles?.filter((candle) =>
|
||||
isCandleLessThan24hOld(candle, yesterday)
|
||||
|
||||
@@ -48,7 +48,7 @@ query EstimatePosition(
|
||||
$orderMarginAccountBalance: String!
|
||||
$marginMode: MarginMode!
|
||||
$marginFactor: String
|
||||
$includeRequiredPositionMarginInAvailableCollateral: Boolean
|
||||
$includeCollateralIncreaseInAvailableCollateral: Boolean
|
||||
) {
|
||||
estimatePosition(
|
||||
marketId: $marketId
|
||||
@@ -60,7 +60,7 @@ query EstimatePosition(
|
||||
orderMarginAccountBalance: $orderMarginAccountBalance
|
||||
marginMode: $marginMode
|
||||
marginFactor: $marginFactor
|
||||
includeRequiredPositionMarginInAvailableCollateral: $includeRequiredPositionMarginInAvailableCollateral
|
||||
includeCollateralIncreaseInAvailableCollateral: $includeCollateralIncreaseInAvailableCollateral
|
||||
# Everywhere in the codebase we expect price values of the underlying to have the right
|
||||
# number of digits for formatting with market.decimalPlaces. By default the estimatePosition
|
||||
# query will return a full value requiring formatting using asset.decimals. For consistency
|
||||
|
||||
+4
-4
@@ -29,7 +29,7 @@ export type EstimatePositionQueryVariables = Types.Exact<{
|
||||
orderMarginAccountBalance: Types.Scalars['String'];
|
||||
marginMode: Types.MarginMode;
|
||||
marginFactor?: Types.InputMaybe<Types.Scalars['String']>;
|
||||
includeRequiredPositionMarginInAvailableCollateral?: Types.InputMaybe<Types.Scalars['Boolean']>;
|
||||
includeCollateralIncreaseInAvailableCollateral?: Types.InputMaybe<Types.Scalars['Boolean']>;
|
||||
}>;
|
||||
|
||||
|
||||
@@ -130,7 +130,7 @@ export function usePositionsSubscriptionSubscription(baseOptions: Apollo.Subscri
|
||||
export type PositionsSubscriptionSubscriptionHookResult = ReturnType<typeof usePositionsSubscriptionSubscription>;
|
||||
export type PositionsSubscriptionSubscriptionResult = Apollo.SubscriptionResult<PositionsSubscriptionSubscription>;
|
||||
export const EstimatePositionDocument = gql`
|
||||
query EstimatePosition($marketId: ID!, $openVolume: String!, $averageEntryPrice: String!, $orders: [OrderInfo!], $marginAccountBalance: String!, $generalAccountBalance: String!, $orderMarginAccountBalance: String!, $marginMode: MarginMode!, $marginFactor: String, $includeRequiredPositionMarginInAvailableCollateral: Boolean) {
|
||||
query EstimatePosition($marketId: ID!, $openVolume: String!, $averageEntryPrice: String!, $orders: [OrderInfo!], $marginAccountBalance: String!, $generalAccountBalance: String!, $orderMarginAccountBalance: String!, $marginMode: MarginMode!, $marginFactor: String, $includeCollateralIncreaseInAvailableCollateral: Boolean) {
|
||||
estimatePosition(
|
||||
marketId: $marketId
|
||||
openVolume: $openVolume
|
||||
@@ -141,7 +141,7 @@ export const EstimatePositionDocument = gql`
|
||||
orderMarginAccountBalance: $orderMarginAccountBalance
|
||||
marginMode: $marginMode
|
||||
marginFactor: $marginFactor
|
||||
includeRequiredPositionMarginInAvailableCollateral: $includeRequiredPositionMarginInAvailableCollateral
|
||||
includeCollateralIncreaseInAvailableCollateral: $includeCollateralIncreaseInAvailableCollateral
|
||||
scaleLiquidationPriceToMarketDecimals: true
|
||||
) {
|
||||
collateralIncreaseEstimate {
|
||||
@@ -185,7 +185,7 @@ export const EstimatePositionDocument = gql`
|
||||
* orderMarginAccountBalance: // value for 'orderMarginAccountBalance'
|
||||
* marginMode: // value for 'marginMode'
|
||||
* marginFactor: // value for 'marginFactor'
|
||||
* includeRequiredPositionMarginInAvailableCollateral: // value for 'includeRequiredPositionMarginInAvailableCollateral'
|
||||
* includeCollateralIncreaseInAvailableCollateral: // value for 'includeCollateralIncreaseInAvailableCollateral'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useState, useCallback } from 'react';
|
||||
import {
|
||||
OpenVolumeData,
|
||||
openVolumeDataProvider,
|
||||
type OpenVolumeData,
|
||||
} from './positions-data-providers';
|
||||
import { useDataProvider } from '@vegaprotocol/data-provider';
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
ExternalLink,
|
||||
Intent,
|
||||
NotificationBanner,
|
||||
SHORT,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import type { StoredNextProtocolUpgradeData } from '../lib';
|
||||
import {
|
||||
@@ -69,7 +70,7 @@ export const ProtocolUpgradeInProgressNotification = () => {
|
||||
if (!upgradeInProgress) return null;
|
||||
|
||||
return (
|
||||
<NotificationBanner intent={Intent.Danger}>
|
||||
<NotificationBanner intent={Intent.Danger} className={SHORT}>
|
||||
<div className="uppercase">
|
||||
{t('The network is being upgraded to {{vegaReleaseTag}}', {
|
||||
vegaReleaseTag,
|
||||
|
||||
Generated
+1
-1
@@ -5067,7 +5067,7 @@ export type QueryestimateOrderArgs = {
|
||||
export type QueryestimatePositionArgs = {
|
||||
averageEntryPrice: Scalars['String'];
|
||||
generalAccountBalance: Scalars['String'];
|
||||
includeRequiredPositionMarginInAvailableCollateral?: InputMaybe<Scalars['Boolean']>;
|
||||
includeCollateralIncreaseInAvailableCollateral?: InputMaybe<Scalars['Boolean']>;
|
||||
marginAccountBalance: Scalars['String'];
|
||||
marginFactor?: InputMaybe<Scalars['String']>;
|
||||
marginMode: MarginMode;
|
||||
|
||||
@@ -4,6 +4,8 @@ import { Intent } from '../../utils/intent';
|
||||
import { Icon, VegaIcon, VegaIconNames } from '../icon';
|
||||
import type { HTMLAttributes } from 'react';
|
||||
|
||||
export const SHORT = '!px-1 !py-1 min-h-fit';
|
||||
|
||||
interface NotificationBannerProps {
|
||||
intent?: Intent;
|
||||
children?: React.ReactNode;
|
||||
@@ -21,7 +23,7 @@ export const NotificationBanner = ({
|
||||
return (
|
||||
<div
|
||||
className={classNames(
|
||||
'flex items-center border-b pl-3 pr-2',
|
||||
'flex items-center border-b px-2',
|
||||
'text-xs leading-tight font-normal',
|
||||
{
|
||||
'bg-vega-light-100 dark:bg-vega-dark-100 ': intent === Intent.None,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { NotificationBanner } from '../notification-banner';
|
||||
import { NotificationBanner, SHORT } from '../notification-banner';
|
||||
import { Intent } from '../../utils/intent';
|
||||
import { TradingButton } from '../trading-button';
|
||||
import { useT } from '../../use-t';
|
||||
@@ -23,7 +23,7 @@ export const ViewingAsBanner = ({
|
||||
}: ViewingAsBannerProps) => {
|
||||
const t = useT();
|
||||
return (
|
||||
<NotificationBanner>
|
||||
<NotificationBanner intent={Intent.None} className={SHORT}>
|
||||
<div className="flex items-baseline justify-between">
|
||||
<span data-testid="view-banner">
|
||||
{t('Viewing as Vega user: {{pubKey}}', {
|
||||
|
||||
@@ -41,7 +41,7 @@ const ethereumRequest = <T>(args: RequestArguments): Promise<T> => {
|
||||
|
||||
export const LOCAL_SNAP_ID = 'local:http://localhost:8080';
|
||||
export const DEFAULT_SNAP_ID = 'npm:@vegaprotocol/snap';
|
||||
export const DEFAULT_SNAP_VERSION = '1.0.1';
|
||||
export const DEFAULT_SNAP_VERSION = '0.3.1';
|
||||
|
||||
type GetSnapsResponse = Record<string, Snap>;
|
||||
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import { WalletClientError } from '@vegaprotocol/wallet-client';
|
||||
import type * as Schema from '@vegaprotocol/types';
|
||||
import type { PeggedReference } from '@vegaprotocol/types';
|
||||
import {
|
||||
vegaMarginMode,
|
||||
v1UndelegateSubmissionMethod,
|
||||
} from '@vegaprotocol/rest-clients/dist/trading-data';
|
||||
|
||||
export interface LiquidityProvisionSubmission {
|
||||
liquidityProvisionSubmission: LiquidityProvisionBody;
|
||||
@@ -32,7 +36,7 @@ export interface UndelegateSubmissionBody {
|
||||
undelegateSubmission: {
|
||||
nodeId: string;
|
||||
amount: string;
|
||||
method: 'METHOD_NOW' | 'METHOD_AT_END_OF_EPOCH';
|
||||
method: v1UndelegateSubmissionMethod;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -472,13 +476,12 @@ export type UpdateReferralSet = {
|
||||
};
|
||||
};
|
||||
|
||||
export enum MarginMode {
|
||||
MARGIN_MODE_CROSS_MARGIN = 1,
|
||||
MARGIN_MODE_ISOLATED_MARGIN,
|
||||
}
|
||||
export { vegaMarginMode as MarginMode };
|
||||
export { v1UndelegateSubmissionMethod as UndelegateSubmissionMethod };
|
||||
|
||||
export interface UpdateMarginMode {
|
||||
marketId: string;
|
||||
mode: MarginMode;
|
||||
mode: vegaMarginMode;
|
||||
marginFactor?: string;
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
"@sentry/nextjs": "^6.19.3",
|
||||
"@sentry/react": "^6.19.2",
|
||||
"@sentry/tracing": "^6.19.2",
|
||||
"@vegaprotocol/rest-clients": "^0.0.5",
|
||||
"@vegaprotocol/wallet-client": "0.1.9",
|
||||
"@walletconnect/ethereum-provider": "^2.6.0",
|
||||
"@web3-react/coinbase-wallet": "8.1.2-beta.0",
|
||||
|
||||
@@ -7808,6 +7808,11 @@
|
||||
"@typescript-eslint/types" "6.11.0"
|
||||
eslint-visitor-keys "^3.4.1"
|
||||
|
||||
"@vegaprotocol/rest-clients@^0.0.5":
|
||||
version "0.0.5"
|
||||
resolved "https://registry.yarnpkg.com/@vegaprotocol/rest-clients/-/rest-clients-0.0.5.tgz#b75f14fc549e8d170518e973435f2b91ec19f553"
|
||||
integrity sha512-UTsGJKrzMsXHkuAmRxEA3ei9GEGFKwIHPdVl2DHlRMQRnP39atSu4IZsP6kK2HqLgJi8QiEZCyIkXQk+jrNRDA==
|
||||
|
||||
"@vegaprotocol/wallet-client@0.1.9":
|
||||
version "0.1.9"
|
||||
resolved "https://registry.yarnpkg.com/@vegaprotocol/wallet-client/-/wallet-client-0.1.9.tgz#8c6a71c8b2222b3de5d73cade8fc6db57e332de9"
|
||||
|
||||
Reference in New Issue
Block a user