feat(2211): download proposal forms data as json (#2521)
* feat(2211): view proposal forms data as json * feat(2211): removed the vega wallet barrier to viewing proposal forms * feat(2211): tweaked the json viewing to download the proposal form json, with a useful title (proposal title and readable datetime) * feat(2211): removed unwanted NX_SENTRY_DSN config from dev environments * feat(2211): unit test for download-json.ts * feat(2211): unit test for proposal-form-download-json.spec.tsx * feat(2211): simplified unit test for proposal-form-download-json.spec.tsx * feat(2211): removed unneeded unit test * feat(2211): revoked change that was causing test failures
This commit is contained in:
parent
863c288e0d
commit
c5b72e5a64
@ -6,4 +6,3 @@ NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/stagnet3-network.json
|
|||||||
NX_VEGA_EXPLORER_URL=https://stagnet3.explorer.vega.xyz
|
NX_VEGA_EXPLORER_URL=https://stagnet3.explorer.vega.xyz
|
||||||
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
|
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
|
||||||
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
|
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
|
||||||
NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40:87edc2605e544f888305d7fc4a9141bd@o286262.ingest.sentry.io/5882996
|
|
||||||
|
@ -9,4 +9,3 @@ NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
|
|||||||
NX_VEGA_EXPLORER_URL=https://explorer.fairground.wtf
|
NX_VEGA_EXPLORER_URL=https://explorer.fairground.wtf
|
||||||
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
|
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
|
||||||
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
|
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
|
||||||
NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40:87edc2605e544f888305d7fc4a9141bd@o286262.ingest.sentry.io/5882996
|
|
||||||
|
@ -159,8 +159,10 @@
|
|||||||
"Tokens are held in different <trancheLink>Tranches</trancheLink>. Each tranche has its own schedule for how the tokens are unlocked.": "Tokens are held in different <trancheLink>Tranches</trancheLink>. Each tranche has its own schedule for how the tokens are unlocked.",
|
"Tokens are held in different <trancheLink>Tranches</trancheLink>. Each tranche has its own schedule for how the tokens are unlocked.": "Tokens are held in different <trancheLink>Tranches</trancheLink>. Each tranche has its own schedule for how the tokens are unlocked.",
|
||||||
"proposals": "Proposals",
|
"proposals": "Proposals",
|
||||||
"proposal": "Proposal",
|
"proposal": "Proposal",
|
||||||
"submitting": "Submitting",
|
"submittingProposal": "Submitting proposal",
|
||||||
"submit": "Submit",
|
"submit": "Submit",
|
||||||
|
"submitProposal": "Submit proposal",
|
||||||
|
"connectWalletToSubmitProposal": "Connect your wallet to submit a proposal",
|
||||||
"proposedEnactment": "Proposed enactment",
|
"proposedEnactment": "Proposed enactment",
|
||||||
"Enacted": "Enacted",
|
"Enacted": "Enacted",
|
||||||
"enactedOn": "Enacted on",
|
"enactedOn": "Enacted on",
|
||||||
@ -729,5 +731,6 @@
|
|||||||
"homeRewardsIntro": "Track rewards you've earned for trading, liquidity provision, market creation, and staking.",
|
"homeRewardsIntro": "Track rewards you've earned for trading, liquidity provision, market creation, and staking.",
|
||||||
"homeRewardsButtonText": "See rewards",
|
"homeRewardsButtonText": "See rewards",
|
||||||
"homeVegaTokenIntro": "VEGA Token is a governance asset used to make and vote on proposals, and nominate validators.",
|
"homeVegaTokenIntro": "VEGA Token is a governance asset used to make and vote on proposals, and nominate validators.",
|
||||||
"homeVegaTokenButtonText": "Manage tokens"
|
"homeVegaTokenButtonText": "Manage tokens",
|
||||||
|
"downloadProposalJson": "Download proposal as JSON"
|
||||||
}
|
}
|
||||||
|
26
apps/token/src/lib/download-json.ts
Normal file
26
apps/token/src/lib/download-json.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
export const downloadJson = (jsonString: string, proposalTitle: string) => {
|
||||||
|
try {
|
||||||
|
const now = new Date();
|
||||||
|
const day = now.getDate().toString().padStart(2, '0');
|
||||||
|
const month = now.toLocaleString('en-US', { month: 'short' });
|
||||||
|
const year = now.getFullYear().toString();
|
||||||
|
const hours = now.getHours().toString().padStart(2, '0');
|
||||||
|
const minutes = now.getMinutes().toString().padStart(2, '0');
|
||||||
|
const seconds = now.getSeconds().toString().padStart(2, '0');
|
||||||
|
// e.g. "2023-Jan-03-23-59-59"
|
||||||
|
const formattedDateTime = `${day}-${month}-${year}-${hours}-${minutes}-${seconds}`;
|
||||||
|
|
||||||
|
const blob = new Blob([jsonString], { type: 'application/json' });
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
const a = document.createElement('a');
|
||||||
|
a.style.display = 'none';
|
||||||
|
a.href = url;
|
||||||
|
a.download = `${proposalTitle}-${formattedDateTime}.json`;
|
||||||
|
document.body.appendChild(a);
|
||||||
|
a.click();
|
||||||
|
window.URL.revokeObjectURL(url);
|
||||||
|
document.body.removeChild(a);
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
};
|
@ -5,3 +5,4 @@ export * from './proposal-form-terms';
|
|||||||
export * from './proposal-form-submit';
|
export * from './proposal-form-submit';
|
||||||
export * from './proposal-form-transaction-dialog';
|
export * from './proposal-form-transaction-dialog';
|
||||||
export * from './proposal-form-vote-and-enactment-deadline';
|
export * from './proposal-form-vote-and-enactment-deadline';
|
||||||
|
export * from './proposal-form-download-json';
|
||||||
|
@ -0,0 +1,12 @@
|
|||||||
|
import { fireEvent, render, screen } from '@testing-library/react';
|
||||||
|
import { ProposalFormDownloadJson } from './proposal-form-download-json';
|
||||||
|
|
||||||
|
describe('ProposalFormDownloadJson', () => {
|
||||||
|
it('calls the downloadJson method when the button is clicked', () => {
|
||||||
|
const downloadJson = jest.fn();
|
||||||
|
render(<ProposalFormDownloadJson downloadJson={downloadJson} />);
|
||||||
|
const button = screen.getByTestId('proposal-download-json');
|
||||||
|
fireEvent.click(button);
|
||||||
|
expect(downloadJson).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,19 @@
|
|||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { Button } from '@vegaprotocol/ui-toolkit';
|
||||||
|
|
||||||
|
interface ProposalFormDownloadJsonProps {
|
||||||
|
downloadJson: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ProposalFormDownloadJson = ({
|
||||||
|
downloadJson,
|
||||||
|
}: ProposalFormDownloadJsonProps) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
return (
|
||||||
|
<div className="mb-6">
|
||||||
|
<Button data-testid="proposal-download-json" onClick={downloadJson}>
|
||||||
|
{t('downloadProposalJson')}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,59 @@
|
|||||||
|
import { render, screen } from '@testing-library/react';
|
||||||
|
import { VegaWalletContext } from '@vegaprotocol/wallet';
|
||||||
|
import { AppStateProvider } from '../../../../contexts/app-state/app-state-provider';
|
||||||
|
import { ProposalFormSubmit } from './proposal-form-submit';
|
||||||
|
import type { VegaWalletContextShape } from '@vegaprotocol/wallet';
|
||||||
|
|
||||||
|
const renderComponent = (
|
||||||
|
context: VegaWalletContextShape,
|
||||||
|
isSubmitting: boolean
|
||||||
|
) => {
|
||||||
|
render(
|
||||||
|
<AppStateProvider>
|
||||||
|
<VegaWalletContext.Provider value={context}>
|
||||||
|
<ProposalFormSubmit isSubmitting={isSubmitting} />
|
||||||
|
</VegaWalletContext.Provider>
|
||||||
|
</AppStateProvider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('Proposal Form Submit', () => {
|
||||||
|
it('should display connection message and button if wallet not connected', () => {
|
||||||
|
renderComponent({ pubKey: null } as VegaWalletContextShape, false);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
screen.getByText('Connect your wallet to submit a proposal')
|
||||||
|
).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
screen.getByTestId('connect-to-vega-wallet-btn')
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display submit button if wallet is connected', () => {
|
||||||
|
const pubKey = { publicKey: '123456__123456', name: 'test' };
|
||||||
|
renderComponent(
|
||||||
|
{
|
||||||
|
pubKey: pubKey.publicKey,
|
||||||
|
pubKeys: [pubKey],
|
||||||
|
} as VegaWalletContextShape,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
expect(screen.getByTestId('proposal-submit')).toHaveTextContent(
|
||||||
|
'Submit proposal'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display submitting button text if wallet is connected and submitting', () => {
|
||||||
|
const pubKey = { publicKey: '123456__123456', name: 'test' };
|
||||||
|
renderComponent(
|
||||||
|
{
|
||||||
|
pubKey: pubKey.publicKey,
|
||||||
|
pubKeys: [pubKey],
|
||||||
|
} as VegaWalletContextShape,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
expect(screen.getByTestId('proposal-submit')).toHaveTextContent(
|
||||||
|
'Submitting proposal'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
@ -1,5 +1,7 @@
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Button } from '@vegaprotocol/ui-toolkit';
|
import { Button } from '@vegaprotocol/ui-toolkit';
|
||||||
|
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||||
|
import { VegaWalletContainer } from '../../../../components/vega-wallet-container';
|
||||||
|
|
||||||
interface ProposalFormSubmitProps {
|
interface ProposalFormSubmitProps {
|
||||||
isSubmitting: boolean;
|
isSubmitting: boolean;
|
||||||
@ -8,17 +10,25 @@ interface ProposalFormSubmitProps {
|
|||||||
export const ProposalFormSubmit = ({
|
export const ProposalFormSubmit = ({
|
||||||
isSubmitting,
|
isSubmitting,
|
||||||
}: ProposalFormSubmitProps) => {
|
}: ProposalFormSubmitProps) => {
|
||||||
|
const { pubKey } = useVegaWallet();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
return (
|
return (
|
||||||
<div className="mt-10 my-20">
|
<div className="mb-6">
|
||||||
<Button
|
<div className="mb-4 font-bold uppercase text-vega-orange">
|
||||||
variant="primary"
|
{!pubKey && t('connectWalletToSubmitProposal')}
|
||||||
type="submit"
|
</div>
|
||||||
data-testid="proposal-submit"
|
<VegaWalletContainer>
|
||||||
disabled={isSubmitting}
|
{() => (
|
||||||
>
|
<Button
|
||||||
{isSubmitting ? t('Submitting') : t('Submit')} {t('Proposal')}
|
variant="primary"
|
||||||
</Button>
|
type="submit"
|
||||||
|
data-testid="proposal-submit"
|
||||||
|
disabled={isSubmitting}
|
||||||
|
>
|
||||||
|
{isSubmitting ? t('submittingProposal') : t('submitProposal')}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</VegaWalletContainer>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -437,7 +437,7 @@ export function ProposalFormVoteAndEnactmentDeadline({
|
|||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
return (
|
return (
|
||||||
<>
|
<div className="mb-10">
|
||||||
<ProposalFormSubheader>
|
<ProposalFormSubheader>
|
||||||
{enactmentRegister && enactmentMinClose && enactmentMaxClose
|
{enactmentRegister && enactmentMinClose && enactmentMaxClose
|
||||||
? t('ProposalVoteAndEnactmentTitle')
|
? t('ProposalVoteAndEnactmentTitle')
|
||||||
@ -535,6 +535,6 @@ export function ProposalFormVoteAndEnactmentDeadline({
|
|||||||
maxEnactmentHours={maxEnactmentHours}
|
maxEnactmentHours={maxEnactmentHours}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -109,6 +109,7 @@ describe('Propose Freeform', () => {
|
|||||||
expect(screen.getByTestId('proposal-description')).toBeTruthy();
|
expect(screen.getByTestId('proposal-description')).toBeTruthy();
|
||||||
expect(screen.getByTestId('proposal-vote-deadline')).toBeTruthy();
|
expect(screen.getByTestId('proposal-vote-deadline')).toBeTruthy();
|
||||||
expect(screen.getByTestId('proposal-submit')).toBeTruthy();
|
expect(screen.getByTestId('proposal-submit')).toBeTruthy();
|
||||||
|
expect(screen.getByTestId('proposal-download-json')).toBeTruthy();
|
||||||
expect(screen.getByTestId('proposal-transaction-dialog')).toBeTruthy();
|
expect(screen.getByTestId('proposal-transaction-dialog')).toBeTruthy();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -12,18 +12,19 @@ import {
|
|||||||
ProposalFormSubmit,
|
ProposalFormSubmit,
|
||||||
ProposalFormTitle,
|
ProposalFormTitle,
|
||||||
ProposalFormTransactionDialog,
|
ProposalFormTransactionDialog,
|
||||||
|
ProposalFormDownloadJson,
|
||||||
ProposalFormVoteAndEnactmentDeadline,
|
ProposalFormVoteAndEnactmentDeadline,
|
||||||
} from '../../components/propose';
|
} from '../../components/propose';
|
||||||
import { ProposalMinRequirements } from '../../components/shared';
|
import { ProposalMinRequirements } from '../../components/shared';
|
||||||
import { AsyncRenderer, ExternalLink } from '@vegaprotocol/ui-toolkit';
|
import { AsyncRenderer, ExternalLink } from '@vegaprotocol/ui-toolkit';
|
||||||
import { Heading } from '../../../../components/heading';
|
import { Heading } from '../../../../components/heading';
|
||||||
import { VegaWalletContainer } from '../../../../components/vega-wallet-container';
|
|
||||||
import {
|
import {
|
||||||
createDocsLinks,
|
createDocsLinks,
|
||||||
NetworkParams,
|
NetworkParams,
|
||||||
useNetworkParams,
|
useNetworkParams,
|
||||||
} from '@vegaprotocol/react-helpers';
|
} from '@vegaprotocol/react-helpers';
|
||||||
import { ProposalUserAction } from '../../components/shared';
|
import { ProposalUserAction } from '../../components/shared';
|
||||||
|
import { downloadJson } from '../../../../lib/download-json';
|
||||||
|
|
||||||
export interface FreeformProposalFormFields {
|
export interface FreeformProposalFormFields {
|
||||||
proposalVoteDeadline: string;
|
proposalVoteDeadline: string;
|
||||||
@ -50,10 +51,11 @@ export const ProposeFreeform = () => {
|
|||||||
handleSubmit,
|
handleSubmit,
|
||||||
formState: { isSubmitting, errors },
|
formState: { isSubmitting, errors },
|
||||||
setValue,
|
setValue,
|
||||||
|
watch,
|
||||||
} = useForm<FreeformProposalFormFields>();
|
} = useForm<FreeformProposalFormFields>();
|
||||||
const { finalizedProposal, submit, Dialog } = useProposalSubmit();
|
const { finalizedProposal, submit, Dialog } = useProposalSubmit();
|
||||||
|
|
||||||
const onSubmit = async (fields: FreeformProposalFormFields) => {
|
const assembleProposal = (fields: FreeformProposalFormFields) => {
|
||||||
const isVoteDeadlineAtMinimum =
|
const isVoteDeadlineAtMinimum =
|
||||||
fields.proposalVoteDeadline ===
|
fields.proposalVoteDeadline ===
|
||||||
deadlineToRoundedHours(
|
deadlineToRoundedHours(
|
||||||
@ -66,7 +68,7 @@ export const ProposeFreeform = () => {
|
|||||||
params.governance_proposal_freeform_maxClose
|
params.governance_proposal_freeform_maxClose
|
||||||
).toString();
|
).toString();
|
||||||
|
|
||||||
await submit({
|
return {
|
||||||
rationale: {
|
rationale: {
|
||||||
title: fields.proposalTitle,
|
title: fields.proposalTitle,
|
||||||
description: fields.proposalDescription,
|
description: fields.proposalDescription,
|
||||||
@ -79,86 +81,101 @@ export const ProposeFreeform = () => {
|
|||||||
isVoteDeadlineAtMaximum
|
isVoteDeadlineAtMaximum
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
});
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const onSubmit = async (fields: FreeformProposalFormFields) => {
|
||||||
|
await submit(assembleProposal(fields));
|
||||||
|
};
|
||||||
|
|
||||||
|
const viewJson = () => {
|
||||||
|
const formData = watch();
|
||||||
|
downloadJson(
|
||||||
|
JSON.stringify(assembleProposal(formData)),
|
||||||
|
'vega-freeform-proposal'
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AsyncRenderer loading={loading} error={error} data={params}>
|
<AsyncRenderer
|
||||||
<Heading title={t('NewFreeformProposal')} />
|
loading={loading}
|
||||||
<VegaWalletContainer>
|
error={error}
|
||||||
{() => (
|
data={params}
|
||||||
<>
|
render={(params) => (
|
||||||
<ProposalMinRequirements
|
<>
|
||||||
minProposalBalance={
|
<Heading title={t('NewFreeformProposal')} />
|
||||||
params.governance_proposal_freeform_minProposerBalance
|
|
||||||
}
|
|
||||||
spamProtectionMin={params.spam_protection_proposal_min_tokens}
|
|
||||||
userAction={ProposalUserAction.CREATE}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{VEGA_DOCS_URL && (
|
<ProposalMinRequirements
|
||||||
<p className="text-sm" data-testid="proposal-docs-link">
|
minProposalBalance={
|
||||||
<span className="mr-1">{t('ProposalTermsText')}</span>
|
params.governance_proposal_freeform_minProposerBalance
|
||||||
<ExternalLink
|
}
|
||||||
href={`${
|
spamProtectionMin={params.spam_protection_proposal_min_tokens}
|
||||||
createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE
|
userAction={ProposalUserAction.CREATE}
|
||||||
}${DOCS_LINK}`}
|
/>
|
||||||
target="_blank"
|
|
||||||
>{`${
|
{VEGA_DOCS_URL && (
|
||||||
|
<p className="text-sm" data-testid="proposal-docs-link">
|
||||||
|
<span className="mr-1">{t('ProposalTermsText')}</span>
|
||||||
|
<ExternalLink
|
||||||
|
href={`${
|
||||||
createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE
|
createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE
|
||||||
}${DOCS_LINK}`}</ExternalLink>
|
}${DOCS_LINK}`}
|
||||||
</p>
|
target="_blank"
|
||||||
)}
|
>{`${
|
||||||
|
createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE
|
||||||
|
}${DOCS_LINK}`}</ExternalLink>
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
{VEGA_EXPLORER_URL && (
|
{VEGA_EXPLORER_URL && (
|
||||||
<p className="text-sm">
|
<p className="text-sm">
|
||||||
{t('MoreProposalsInfo')}{' '}
|
{t('MoreProposalsInfo')}{' '}
|
||||||
<ExternalLink
|
<ExternalLink
|
||||||
href={`${VEGA_EXPLORER_URL}/governance`}
|
href={`${VEGA_EXPLORER_URL}/governance`}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>{`${VEGA_EXPLORER_URL}/governance`}</ExternalLink>
|
>{`${VEGA_EXPLORER_URL}/governance`}</ExternalLink>
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div data-testid="freeform-proposal-form">
|
<div data-testid="freeform-proposal-form">
|
||||||
<form onSubmit={handleSubmit(onSubmit)}>
|
<form onSubmit={handleSubmit(onSubmit)}>
|
||||||
<ProposalFormSubheader>
|
<ProposalFormSubheader>
|
||||||
{t('ProposalRationale')}
|
{t('ProposalRationale')}
|
||||||
</ProposalFormSubheader>
|
</ProposalFormSubheader>
|
||||||
|
|
||||||
<ProposalFormTitle
|
<ProposalFormTitle
|
||||||
registerField={register('proposalTitle', {
|
registerField={register('proposalTitle', {
|
||||||
required: t('Required'),
|
required: t('Required'),
|
||||||
})}
|
})}
|
||||||
errorMessage={errors?.proposalTitle?.message}
|
errorMessage={errors?.proposalTitle?.message}
|
||||||
/>
|
/>
|
||||||
<ProposalFormDescription
|
<ProposalFormDescription
|
||||||
registerField={register('proposalDescription', {
|
registerField={register('proposalDescription', {
|
||||||
required: t('Required'),
|
required: t('Required'),
|
||||||
})}
|
})}
|
||||||
errorMessage={errors?.proposalDescription?.message}
|
errorMessage={errors?.proposalDescription?.message}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ProposalFormVoteAndEnactmentDeadline
|
<ProposalFormVoteAndEnactmentDeadline
|
||||||
onVoteMinMax={setValue}
|
onVoteMinMax={setValue}
|
||||||
voteRegister={register('proposalVoteDeadline', {
|
voteRegister={register('proposalVoteDeadline', {
|
||||||
required: t('Required'),
|
required: t('Required'),
|
||||||
})}
|
})}
|
||||||
voteErrorMessage={errors?.proposalVoteDeadline?.message}
|
voteErrorMessage={errors?.proposalVoteDeadline?.message}
|
||||||
voteMinClose={params.governance_proposal_freeform_minClose}
|
voteMinClose={params.governance_proposal_freeform_minClose}
|
||||||
voteMaxClose={params.governance_proposal_freeform_maxClose}
|
voteMaxClose={params.governance_proposal_freeform_maxClose}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ProposalFormSubmit isSubmitting={isSubmitting} />
|
<ProposalFormSubmit isSubmitting={isSubmitting} />
|
||||||
<ProposalFormTransactionDialog
|
<ProposalFormDownloadJson downloadJson={viewJson} />
|
||||||
finalizedProposal={finalizedProposal}
|
<ProposalFormTransactionDialog
|
||||||
TransactionDialog={Dialog}
|
finalizedProposal={finalizedProposal}
|
||||||
/>
|
TransactionDialog={Dialog}
|
||||||
</form>
|
/>
|
||||||
</div>
|
</form>
|
||||||
</>
|
</div>
|
||||||
)}
|
</>
|
||||||
</VegaWalletContainer>
|
)}
|
||||||
</AsyncRenderer>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -112,6 +112,7 @@ describe('Propose Network Parameter', () => {
|
|||||||
expect(screen.getByTestId('proposal-vote-deadline')).toBeTruthy();
|
expect(screen.getByTestId('proposal-vote-deadline')).toBeTruthy();
|
||||||
expect(screen.getByTestId('proposal-enactment-deadline')).toBeTruthy();
|
expect(screen.getByTestId('proposal-enactment-deadline')).toBeTruthy();
|
||||||
expect(screen.getByTestId('proposal-submit')).toBeTruthy();
|
expect(screen.getByTestId('proposal-submit')).toBeTruthy();
|
||||||
|
expect(screen.getByTestId('proposal-download-json')).toBeTruthy();
|
||||||
expect(screen.getByTestId('proposal-transaction-dialog')).toBeTruthy();
|
expect(screen.getByTestId('proposal-transaction-dialog')).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@ import {
|
|||||||
ProposalFormTitle,
|
ProposalFormTitle,
|
||||||
ProposalFormTransactionDialog,
|
ProposalFormTransactionDialog,
|
||||||
ProposalFormVoteAndEnactmentDeadline,
|
ProposalFormVoteAndEnactmentDeadline,
|
||||||
|
ProposalFormDownloadJson,
|
||||||
} from '../../components/propose';
|
} from '../../components/propose';
|
||||||
import { ProposalMinRequirements } from '../../components/shared';
|
import { ProposalMinRequirements } from '../../components/shared';
|
||||||
import {
|
import {
|
||||||
@ -33,8 +34,8 @@ import {
|
|||||||
TextArea,
|
TextArea,
|
||||||
} from '@vegaprotocol/ui-toolkit';
|
} from '@vegaprotocol/ui-toolkit';
|
||||||
import { Heading } from '../../../../components/heading';
|
import { Heading } from '../../../../components/heading';
|
||||||
import { VegaWalletContainer } from '../../../../components/vega-wallet-container';
|
|
||||||
import { ProposalUserAction } from '../../components/shared';
|
import { ProposalUserAction } from '../../components/shared';
|
||||||
|
import { downloadJson } from '../../../../lib/download-json';
|
||||||
|
|
||||||
interface SelectedNetworkParamCurrentValueProps {
|
interface SelectedNetworkParamCurrentValueProps {
|
||||||
value: string;
|
value: string;
|
||||||
@ -92,6 +93,7 @@ export const ProposeNetworkParameter = () => {
|
|||||||
handleSubmit,
|
handleSubmit,
|
||||||
formState: { isSubmitting, errors },
|
formState: { isSubmitting, errors },
|
||||||
setValue,
|
setValue,
|
||||||
|
watch,
|
||||||
} = useForm<NetworkParameterProposalFormFields>();
|
} = useForm<NetworkParameterProposalFormFields>();
|
||||||
const { finalizedProposal, submit, Dialog } = useProposalSubmit();
|
const { finalizedProposal, submit, Dialog } = useProposalSubmit();
|
||||||
|
|
||||||
@ -99,8 +101,8 @@ export const ProposeNetworkParameter = () => {
|
|||||||
? Object.entries(params).find(([key]) => key === selectedNetworkParam)
|
? Object.entries(params).find(([key]) => key === selectedNetworkParam)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
const onSubmit = async (fields: NetworkParameterProposalFormFields) => {
|
const assembleProposal = (fields: NetworkParameterProposalFormFields) => {
|
||||||
const acutalNetworkParamKey = fields.proposalNetworkParameterKey
|
const actualNetworkParamKey = fields.proposalNetworkParameterKey
|
||||||
.split('_')
|
.split('_')
|
||||||
.join('.');
|
.join('.');
|
||||||
|
|
||||||
@ -121,7 +123,7 @@ export const ProposeNetworkParameter = () => {
|
|||||||
params.governance_proposal_updateNetParam_maxEnact
|
params.governance_proposal_updateNetParam_maxEnact
|
||||||
);
|
);
|
||||||
|
|
||||||
await submit({
|
return {
|
||||||
rationale: {
|
rationale: {
|
||||||
title: fields.proposalTitle,
|
title: fields.proposalTitle,
|
||||||
description: fields.proposalDescription,
|
description: fields.proposalDescription,
|
||||||
@ -129,7 +131,7 @@ export const ProposeNetworkParameter = () => {
|
|||||||
terms: {
|
terms: {
|
||||||
updateNetworkParameter: {
|
updateNetworkParameter: {
|
||||||
changes: {
|
changes: {
|
||||||
key: acutalNetworkParamKey,
|
key: actualNetworkParamKey,
|
||||||
value: fields.proposalNetworkParameterValue,
|
value: fields.proposalNetworkParameterValue,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -144,7 +146,19 @@ export const ProposeNetworkParameter = () => {
|
|||||||
isEnactmentDeadlineAtMaximum
|
isEnactmentDeadlineAtMaximum
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
});
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const onSubmit = async (fields: NetworkParameterProposalFormFields) => {
|
||||||
|
await submit(assembleProposal(fields));
|
||||||
|
};
|
||||||
|
|
||||||
|
const viewJson = () => {
|
||||||
|
const formData = watch();
|
||||||
|
downloadJson(
|
||||||
|
JSON.stringify(assembleProposal(formData)),
|
||||||
|
'vega-network-param-proposal'
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -152,163 +166,161 @@ export const ProposeNetworkParameter = () => {
|
|||||||
loading={networkParamsLoading}
|
loading={networkParamsLoading}
|
||||||
error={networkParamsError}
|
error={networkParamsError}
|
||||||
data={params}
|
data={params}
|
||||||
>
|
render={(params) => (
|
||||||
<Heading title={t('NetworkParameterProposal')} />
|
<>
|
||||||
<VegaWalletContainer>
|
<Heading title={t('NetworkParameterProposal')} />
|
||||||
{() => (
|
<ProposalMinRequirements
|
||||||
<>
|
minProposalBalance={
|
||||||
<ProposalMinRequirements
|
params.governance_proposal_updateNetParam_minProposerBalance
|
||||||
minProposalBalance={
|
}
|
||||||
params.governance_proposal_updateNetParam_minProposerBalance
|
spamProtectionMin={params.spam_protection_proposal_min_tokens}
|
||||||
}
|
userAction={ProposalUserAction.CREATE}
|
||||||
spamProtectionMin={params.spam_protection_proposal_min_tokens}
|
/>
|
||||||
userAction={ProposalUserAction.CREATE}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{VEGA_DOCS_URL && (
|
{VEGA_DOCS_URL && (
|
||||||
<p className="text-sm" data-testid="proposal-docs-link">
|
<p className="text-sm" data-testid="proposal-docs-link">
|
||||||
<span className="mr-1">{t('ProposalTermsText')}</span>
|
<span className="mr-1">{t('ProposalTermsText')}</span>
|
||||||
<ExternalLink
|
<ExternalLink
|
||||||
href={`${
|
href={`${
|
||||||
createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE
|
|
||||||
}${DOCS_LINK}`}
|
|
||||||
target="_blank"
|
|
||||||
>{`${
|
|
||||||
createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE
|
createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE
|
||||||
}${DOCS_LINK}`}</ExternalLink>
|
}${DOCS_LINK}`}
|
||||||
</p>
|
target="_blank"
|
||||||
)}
|
>{`${
|
||||||
|
createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE
|
||||||
|
}${DOCS_LINK}`}</ExternalLink>
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
{VEGA_EXPLORER_URL && (
|
{VEGA_EXPLORER_URL && (
|
||||||
<p className="text-sm">
|
<p className="text-sm">
|
||||||
{t('MoreNetParamsInfo')}{' '}
|
{t('MoreNetParamsInfo')}{' '}
|
||||||
<ExternalLink
|
<ExternalLink
|
||||||
href={`${VEGA_EXPLORER_URL}/network-parameters`}
|
href={`${VEGA_EXPLORER_URL}/network-parameters`}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>{`${VEGA_EXPLORER_URL}/network-parameters`}</ExternalLink>
|
>{`${VEGA_EXPLORER_URL}/network-parameters`}</ExternalLink>
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div data-testid="network-parameter-proposal-form">
|
<div data-testid="network-parameter-proposal-form">
|
||||||
<form onSubmit={handleSubmit(onSubmit)}>
|
<form onSubmit={handleSubmit(onSubmit)}>
|
||||||
<ProposalFormSubheader>
|
<ProposalFormSubheader>
|
||||||
{t('ProposalRationale')}
|
{t('ProposalRationale')}
|
||||||
</ProposalFormSubheader>
|
</ProposalFormSubheader>
|
||||||
|
|
||||||
<ProposalFormTitle
|
<ProposalFormTitle
|
||||||
registerField={register('proposalTitle', {
|
registerField={register('proposalTitle', {
|
||||||
|
required: t('Required'),
|
||||||
|
})}
|
||||||
|
errorMessage={errors?.proposalTitle?.message}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ProposalFormDescription
|
||||||
|
registerField={register('proposalDescription', {
|
||||||
|
required: t('Required'),
|
||||||
|
})}
|
||||||
|
errorMessage={errors?.proposalDescription?.message}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ProposalFormSubheader>
|
||||||
|
{t('SelectAParameterToChange')}
|
||||||
|
</ProposalFormSubheader>
|
||||||
|
|
||||||
|
<FormGroup
|
||||||
|
label={t('SelectAParameterToChange')}
|
||||||
|
labelFor="proposal-parameter-key"
|
||||||
|
hideLabel={true}
|
||||||
|
>
|
||||||
|
<Select
|
||||||
|
data-testid="proposal-parameter-select"
|
||||||
|
id="proposal-parameter-key"
|
||||||
|
{...register('proposalNetworkParameterKey', {
|
||||||
required: t('Required'),
|
required: t('Required'),
|
||||||
})}
|
})}
|
||||||
errorMessage={errors?.proposalTitle?.message}
|
onChange={(e) => setSelectedNetworkParam(e.target.value)}
|
||||||
/>
|
value={selectedNetworkParam}
|
||||||
|
|
||||||
<ProposalFormDescription
|
|
||||||
registerField={register('proposalDescription', {
|
|
||||||
required: t('Required'),
|
|
||||||
})}
|
|
||||||
errorMessage={errors?.proposalDescription?.message}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<ProposalFormSubheader>
|
|
||||||
{t('SelectAParameterToChange')}
|
|
||||||
</ProposalFormSubheader>
|
|
||||||
|
|
||||||
<FormGroup
|
|
||||||
label={t('SelectAParameterToChange')}
|
|
||||||
labelFor="proposal-parameter-key"
|
|
||||||
hideLabel={true}
|
|
||||||
>
|
>
|
||||||
<Select
|
<option value="">{t('SelectParameter')}</option>
|
||||||
data-testid="proposal-parameter-select"
|
{Object.keys(params).map((key) => {
|
||||||
id="proposal-parameter-key"
|
const actualKey = key.split('_').join('.');
|
||||||
{...register('proposalNetworkParameterKey', {
|
return (
|
||||||
required: t('Required'),
|
<option key={key} value={key}>
|
||||||
})}
|
{actualKey}
|
||||||
onChange={(e) => setSelectedNetworkParam(e.target.value)}
|
</option>
|
||||||
value={selectedNetworkParam}
|
);
|
||||||
>
|
})}
|
||||||
<option value="">{t('SelectParameter')}</option>
|
</Select>
|
||||||
{Object.keys(params).map((key) => {
|
{errors?.proposalNetworkParameterKey?.message && (
|
||||||
const actualKey = key.split('_').join('.');
|
<InputError intent="danger">
|
||||||
return (
|
{errors?.proposalNetworkParameterKey?.message}
|
||||||
<option key={key} value={key}>
|
</InputError>
|
||||||
{actualKey}
|
|
||||||
</option>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Select>
|
|
||||||
{errors?.proposalNetworkParameterKey?.message && (
|
|
||||||
<InputError intent="danger">
|
|
||||||
{errors?.proposalNetworkParameterKey?.message}
|
|
||||||
</InputError>
|
|
||||||
)}
|
|
||||||
</FormGroup>
|
|
||||||
|
|
||||||
{selectedNetworkParam && (
|
|
||||||
<div className="mt-[-10px]">
|
|
||||||
{selectedParamEntry && (
|
|
||||||
<SelectedNetworkParamCurrentValue
|
|
||||||
value={selectedParamEntry[1]}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<FormGroup
|
|
||||||
label={t('NewProposedValue')}
|
|
||||||
labelFor="proposal-parameter-new-value"
|
|
||||||
>
|
|
||||||
<TextArea
|
|
||||||
data-testid="selected-proposal-param-new-value"
|
|
||||||
id="proposal-parameter-new-value"
|
|
||||||
{...register('proposalNetworkParameterValue', {
|
|
||||||
required: t('Required'),
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
{errors?.proposalNetworkParameterValue?.message && (
|
|
||||||
<InputError intent="danger">
|
|
||||||
{errors?.proposalNetworkParameterValue?.message}
|
|
||||||
</InputError>
|
|
||||||
)}
|
|
||||||
</FormGroup>
|
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
|
</FormGroup>
|
||||||
|
|
||||||
<ProposalFormVoteAndEnactmentDeadline
|
{selectedNetworkParam && (
|
||||||
onVoteMinMax={setValue}
|
<div className="mt-[-10px]">
|
||||||
voteRegister={register('proposalVoteDeadline', {
|
{selectedParamEntry && (
|
||||||
required: t('Required'),
|
<SelectedNetworkParamCurrentValue
|
||||||
})}
|
value={selectedParamEntry[1]}
|
||||||
voteErrorMessage={errors?.proposalVoteDeadline?.message}
|
/>
|
||||||
voteMinClose={
|
)}
|
||||||
params.governance_proposal_updateNetParam_minClose
|
|
||||||
}
|
|
||||||
voteMaxClose={
|
|
||||||
params.governance_proposal_updateNetParam_maxClose
|
|
||||||
}
|
|
||||||
onEnactMinMax={setValue}
|
|
||||||
enactmentRegister={register('proposalEnactmentDeadline', {
|
|
||||||
required: t('Required'),
|
|
||||||
})}
|
|
||||||
enactmentErrorMessage={
|
|
||||||
errors?.proposalEnactmentDeadline?.message
|
|
||||||
}
|
|
||||||
enactmentMinClose={
|
|
||||||
params.governance_proposal_updateNetParam_minEnact
|
|
||||||
}
|
|
||||||
enactmentMaxClose={
|
|
||||||
params.governance_proposal_updateNetParam_maxEnact
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<ProposalFormSubmit isSubmitting={isSubmitting} />
|
<FormGroup
|
||||||
<ProposalFormTransactionDialog
|
label={t('NewProposedValue')}
|
||||||
finalizedProposal={finalizedProposal}
|
labelFor="proposal-parameter-new-value"
|
||||||
TransactionDialog={Dialog}
|
>
|
||||||
/>
|
<TextArea
|
||||||
</form>
|
data-testid="selected-proposal-param-new-value"
|
||||||
</div>
|
id="proposal-parameter-new-value"
|
||||||
</>
|
{...register('proposalNetworkParameterValue', {
|
||||||
)}
|
required: t('Required'),
|
||||||
</VegaWalletContainer>
|
})}
|
||||||
</AsyncRenderer>
|
/>
|
||||||
|
{errors?.proposalNetworkParameterValue?.message && (
|
||||||
|
<InputError intent="danger">
|
||||||
|
{errors?.proposalNetworkParameterValue?.message}
|
||||||
|
</InputError>
|
||||||
|
)}
|
||||||
|
</FormGroup>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<ProposalFormVoteAndEnactmentDeadline
|
||||||
|
onVoteMinMax={setValue}
|
||||||
|
voteRegister={register('proposalVoteDeadline', {
|
||||||
|
required: t('Required'),
|
||||||
|
})}
|
||||||
|
voteErrorMessage={errors?.proposalVoteDeadline?.message}
|
||||||
|
voteMinClose={
|
||||||
|
params.governance_proposal_updateNetParam_minClose
|
||||||
|
}
|
||||||
|
voteMaxClose={
|
||||||
|
params.governance_proposal_updateNetParam_maxClose
|
||||||
|
}
|
||||||
|
onEnactMinMax={setValue}
|
||||||
|
enactmentRegister={register('proposalEnactmentDeadline', {
|
||||||
|
required: t('Required'),
|
||||||
|
})}
|
||||||
|
enactmentErrorMessage={
|
||||||
|
errors?.proposalEnactmentDeadline?.message
|
||||||
|
}
|
||||||
|
enactmentMinClose={
|
||||||
|
params.governance_proposal_updateNetParam_minEnact
|
||||||
|
}
|
||||||
|
enactmentMaxClose={
|
||||||
|
params.governance_proposal_updateNetParam_maxEnact
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ProposalFormSubmit isSubmitting={isSubmitting} />
|
||||||
|
<ProposalFormDownloadJson downloadJson={viewJson} />
|
||||||
|
<ProposalFormTransactionDialog
|
||||||
|
finalizedProposal={finalizedProposal}
|
||||||
|
TransactionDialog={Dialog}
|
||||||
|
/>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -110,6 +110,7 @@ describe('Propose New Asset', () => {
|
|||||||
expect(screen.getByTestId('proposal-validation-deadline')).toBeTruthy();
|
expect(screen.getByTestId('proposal-validation-deadline')).toBeTruthy();
|
||||||
expect(screen.getByTestId('proposal-enactment-deadline')).toBeTruthy();
|
expect(screen.getByTestId('proposal-enactment-deadline')).toBeTruthy();
|
||||||
expect(screen.getByTestId('proposal-submit')).toBeTruthy();
|
expect(screen.getByTestId('proposal-submit')).toBeTruthy();
|
||||||
|
expect(screen.getByTestId('proposal-download-json')).toBeTruthy();
|
||||||
expect(screen.getByTestId('proposal-transaction-dialog')).toBeTruthy();
|
expect(screen.getByTestId('proposal-transaction-dialog')).toBeTruthy();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -21,13 +21,14 @@ import {
|
|||||||
ProposalFormTerms,
|
ProposalFormTerms,
|
||||||
ProposalFormTitle,
|
ProposalFormTitle,
|
||||||
ProposalFormTransactionDialog,
|
ProposalFormTransactionDialog,
|
||||||
|
ProposalFormDownloadJson,
|
||||||
ProposalFormVoteAndEnactmentDeadline,
|
ProposalFormVoteAndEnactmentDeadline,
|
||||||
} from '../../components/propose';
|
} from '../../components/propose';
|
||||||
import { ProposalMinRequirements } from '../../components/shared';
|
import { ProposalMinRequirements } from '../../components/shared';
|
||||||
import { AsyncRenderer, ExternalLink } from '@vegaprotocol/ui-toolkit';
|
import { AsyncRenderer, ExternalLink } from '@vegaprotocol/ui-toolkit';
|
||||||
import { Heading } from '../../../../components/heading';
|
import { Heading } from '../../../../components/heading';
|
||||||
import { VegaWalletContainer } from '../../../../components/vega-wallet-container';
|
|
||||||
import { ProposalUserAction } from '../../components/shared';
|
import { ProposalUserAction } from '../../components/shared';
|
||||||
|
import { downloadJson } from '../../../../lib/download-json';
|
||||||
|
|
||||||
export interface NewAssetProposalFormFields {
|
export interface NewAssetProposalFormFields {
|
||||||
proposalVoteDeadline: string;
|
proposalVoteDeadline: string;
|
||||||
@ -62,10 +63,11 @@ export const ProposeNewAsset = () => {
|
|||||||
handleSubmit,
|
handleSubmit,
|
||||||
formState: { isSubmitting, errors },
|
formState: { isSubmitting, errors },
|
||||||
setValue,
|
setValue,
|
||||||
|
watch,
|
||||||
} = useForm<NewAssetProposalFormFields>();
|
} = useForm<NewAssetProposalFormFields>();
|
||||||
const { finalizedProposal, submit, Dialog } = useProposalSubmit();
|
const { finalizedProposal, submit, Dialog } = useProposalSubmit();
|
||||||
|
|
||||||
const onSubmit = async (fields: NewAssetProposalFormFields) => {
|
const assembleProposal = (fields: NewAssetProposalFormFields) => {
|
||||||
const isVoteDeadlineAtMinimum = doesValueEquateToParam(
|
const isVoteDeadlineAtMinimum = doesValueEquateToParam(
|
||||||
fields.proposalVoteDeadline,
|
fields.proposalVoteDeadline,
|
||||||
params.governance_proposal_asset_minClose
|
params.governance_proposal_asset_minClose
|
||||||
@ -87,7 +89,7 @@ export const ProposeNewAsset = () => {
|
|||||||
params.governance_proposal_asset_maxClose
|
params.governance_proposal_asset_maxClose
|
||||||
);
|
);
|
||||||
|
|
||||||
await submit({
|
return {
|
||||||
rationale: {
|
rationale: {
|
||||||
title: fields.proposalTitle,
|
title: fields.proposalTitle,
|
||||||
description: fields.proposalDescription,
|
description: fields.proposalDescription,
|
||||||
@ -111,7 +113,19 @@ export const ProposeNewAsset = () => {
|
|||||||
isValidationDeadlineAtMaximum
|
isValidationDeadlineAtMaximum
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
});
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const onSubmit = async (fields: NewAssetProposalFormFields) => {
|
||||||
|
await submit(assembleProposal(fields));
|
||||||
|
};
|
||||||
|
|
||||||
|
const viewJson = () => {
|
||||||
|
const formData = watch();
|
||||||
|
downloadJson(
|
||||||
|
JSON.stringify(assembleProposal(formData)),
|
||||||
|
'vega-new-asset-proposal'
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -119,112 +133,111 @@ export const ProposeNewAsset = () => {
|
|||||||
loading={networkParamsLoading}
|
loading={networkParamsLoading}
|
||||||
error={networkParamsError}
|
error={networkParamsError}
|
||||||
data={params}
|
data={params}
|
||||||
>
|
render={(params) => (
|
||||||
<Heading title={t('NewAssetProposal')} />
|
<>
|
||||||
<VegaWalletContainer>
|
<Heading title={t('NewAssetProposal')} />
|
||||||
{() => (
|
|
||||||
<>
|
|
||||||
<ProposalMinRequirements
|
|
||||||
minProposalBalance={
|
|
||||||
params.governance_proposal_asset_minProposerBalance
|
|
||||||
}
|
|
||||||
spamProtectionMin={params.spam_protection_proposal_min_tokens}
|
|
||||||
userAction={ProposalUserAction.CREATE}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{VEGA_DOCS_URL && (
|
<ProposalMinRequirements
|
||||||
<p className="text-sm" data-testid="proposal-docs-link">
|
minProposalBalance={
|
||||||
<span className="mr-1">{t('ProposalTermsText')}</span>
|
params.governance_proposal_asset_minProposerBalance
|
||||||
<ExternalLink
|
}
|
||||||
href={`${
|
spamProtectionMin={params.spam_protection_proposal_min_tokens}
|
||||||
createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE
|
userAction={ProposalUserAction.CREATE}
|
||||||
}${DOCS_LINK}`}
|
/>
|
||||||
target="_blank"
|
|
||||||
>{`${
|
{VEGA_DOCS_URL && (
|
||||||
|
<p className="text-sm" data-testid="proposal-docs-link">
|
||||||
|
<span className="mr-1">{t('ProposalTermsText')}</span>
|
||||||
|
<ExternalLink
|
||||||
|
href={`${
|
||||||
createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE
|
createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE
|
||||||
}${DOCS_LINK}`}</ExternalLink>
|
}${DOCS_LINK}`}
|
||||||
</p>
|
target="_blank"
|
||||||
)}
|
>{`${
|
||||||
|
createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE
|
||||||
|
}${DOCS_LINK}`}</ExternalLink>
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
{VEGA_EXPLORER_URL && (
|
{VEGA_EXPLORER_URL && (
|
||||||
<p className="text-sm">
|
<p className="text-sm">
|
||||||
{t('MoreAssetsInfo')}{' '}
|
{t('MoreAssetsInfo')}{' '}
|
||||||
<ExternalLink
|
<ExternalLink
|
||||||
href={`${VEGA_EXPLORER_URL}/assets`}
|
href={`${VEGA_EXPLORER_URL}/assets`}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>{`${VEGA_EXPLORER_URL}/assets`}</ExternalLink>
|
>{`${VEGA_EXPLORER_URL}/assets`}</ExternalLink>
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div data-testid="new-asset-proposal-form">
|
<div data-testid="new-asset-proposal-form">
|
||||||
<form onSubmit={handleSubmit(onSubmit)}>
|
<form onSubmit={handleSubmit(onSubmit)}>
|
||||||
<ProposalFormSubheader>
|
<ProposalFormSubheader>
|
||||||
{t('ProposalRationale')}
|
{t('ProposalRationale')}
|
||||||
</ProposalFormSubheader>
|
</ProposalFormSubheader>
|
||||||
|
|
||||||
<ProposalFormTitle
|
<ProposalFormTitle
|
||||||
registerField={register('proposalTitle', {
|
registerField={register('proposalTitle', {
|
||||||
required: t('Required'),
|
required: t('Required'),
|
||||||
})}
|
})}
|
||||||
errorMessage={errors?.proposalTitle?.message}
|
errorMessage={errors?.proposalTitle?.message}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ProposalFormDescription
|
<ProposalFormDescription
|
||||||
registerField={register('proposalDescription', {
|
registerField={register('proposalDescription', {
|
||||||
required: t('Required'),
|
required: t('Required'),
|
||||||
})}
|
})}
|
||||||
errorMessage={errors?.proposalDescription?.message}
|
errorMessage={errors?.proposalDescription?.message}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ProposalFormSubheader>{t('NewAsset')}</ProposalFormSubheader>
|
<ProposalFormSubheader>{t('NewAsset')}</ProposalFormSubheader>
|
||||||
|
|
||||||
<ProposalFormTerms
|
<ProposalFormTerms
|
||||||
registerField={register('proposalTerms', {
|
registerField={register('proposalTerms', {
|
||||||
required: t('Required'),
|
required: t('Required'),
|
||||||
validate: (value) => validateJson(value),
|
validate: (value) => validateJson(value),
|
||||||
})}
|
})}
|
||||||
labelOverride={'Terms.newAsset (JSON format)'}
|
labelOverride={'Terms.newAsset (JSON format)'}
|
||||||
errorMessage={errors?.proposalTerms?.message}
|
errorMessage={errors?.proposalTerms?.message}
|
||||||
docsLink={DOCS_LINK}
|
docsLink={DOCS_LINK}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ProposalFormVoteAndEnactmentDeadline
|
<ProposalFormVoteAndEnactmentDeadline
|
||||||
onVoteMinMax={setValue}
|
onVoteMinMax={setValue}
|
||||||
voteRegister={register('proposalVoteDeadline', {
|
voteRegister={register('proposalVoteDeadline', {
|
||||||
required: t('Required'),
|
required: t('Required'),
|
||||||
})}
|
})}
|
||||||
voteErrorMessage={errors?.proposalVoteDeadline?.message}
|
voteErrorMessage={errors?.proposalVoteDeadline?.message}
|
||||||
voteMinClose={params.governance_proposal_asset_minClose}
|
voteMinClose={params.governance_proposal_asset_minClose}
|
||||||
voteMaxClose={params.governance_proposal_asset_maxClose}
|
voteMaxClose={params.governance_proposal_asset_maxClose}
|
||||||
onEnactMinMax={setValue}
|
onEnactMinMax={setValue}
|
||||||
enactmentRegister={register('proposalEnactmentDeadline', {
|
enactmentRegister={register('proposalEnactmentDeadline', {
|
||||||
required: t('Required'),
|
required: t('Required'),
|
||||||
})}
|
})}
|
||||||
enactmentErrorMessage={
|
enactmentErrorMessage={
|
||||||
errors?.proposalEnactmentDeadline?.message
|
errors?.proposalEnactmentDeadline?.message
|
||||||
}
|
}
|
||||||
enactmentMinClose={params.governance_proposal_asset_minEnact}
|
enactmentMinClose={params.governance_proposal_asset_minEnact}
|
||||||
enactmentMaxClose={params.governance_proposal_asset_maxEnact}
|
enactmentMaxClose={params.governance_proposal_asset_maxEnact}
|
||||||
validationRequired={true}
|
validationRequired={true}
|
||||||
onValidationMinMax={setValue}
|
onValidationMinMax={setValue}
|
||||||
validationRegister={register('proposalValidationDeadline', {
|
validationRegister={register('proposalValidationDeadline', {
|
||||||
required: t('Required'),
|
required: t('Required'),
|
||||||
})}
|
})}
|
||||||
validationErrorMessage={
|
validationErrorMessage={
|
||||||
errors?.proposalValidationDeadline?.message
|
errors?.proposalValidationDeadline?.message
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ProposalFormSubmit isSubmitting={isSubmitting} />
|
<ProposalFormSubmit isSubmitting={isSubmitting} />
|
||||||
<ProposalFormTransactionDialog
|
<ProposalFormDownloadJson downloadJson={viewJson} />
|
||||||
finalizedProposal={finalizedProposal}
|
<ProposalFormTransactionDialog
|
||||||
TransactionDialog={Dialog}
|
finalizedProposal={finalizedProposal}
|
||||||
/>
|
TransactionDialog={Dialog}
|
||||||
</form>
|
/>
|
||||||
</div>
|
</form>
|
||||||
</>
|
</div>
|
||||||
)}
|
</>
|
||||||
</VegaWalletContainer>
|
)}
|
||||||
</AsyncRenderer>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -104,6 +104,7 @@ describe('Propose New Market', () => {
|
|||||||
expect(screen.getByTestId('proposal-vote-deadline')).toBeTruthy();
|
expect(screen.getByTestId('proposal-vote-deadline')).toBeTruthy();
|
||||||
expect(screen.getByTestId('proposal-enactment-deadline')).toBeTruthy();
|
expect(screen.getByTestId('proposal-enactment-deadline')).toBeTruthy();
|
||||||
expect(screen.getByTestId('proposal-submit')).toBeTruthy();
|
expect(screen.getByTestId('proposal-submit')).toBeTruthy();
|
||||||
|
expect(screen.getByTestId('proposal-download-json')).toBeTruthy();
|
||||||
expect(screen.getByTestId('proposal-transaction-dialog')).toBeTruthy();
|
expect(screen.getByTestId('proposal-transaction-dialog')).toBeTruthy();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -20,13 +20,14 @@ import {
|
|||||||
ProposalFormTerms,
|
ProposalFormTerms,
|
||||||
ProposalFormTitle,
|
ProposalFormTitle,
|
||||||
ProposalFormTransactionDialog,
|
ProposalFormTransactionDialog,
|
||||||
|
ProposalFormDownloadJson,
|
||||||
ProposalFormVoteAndEnactmentDeadline,
|
ProposalFormVoteAndEnactmentDeadline,
|
||||||
} from '../../components/propose';
|
} from '../../components/propose';
|
||||||
import { ProposalMinRequirements } from '../../components/shared';
|
import { ProposalMinRequirements } from '../../components/shared';
|
||||||
import { AsyncRenderer, ExternalLink } from '@vegaprotocol/ui-toolkit';
|
import { AsyncRenderer, ExternalLink } from '@vegaprotocol/ui-toolkit';
|
||||||
import { Heading } from '../../../../components/heading';
|
import { Heading } from '../../../../components/heading';
|
||||||
import { VegaWalletContainer } from '../../../../components/vega-wallet-container';
|
|
||||||
import { ProposalUserAction } from '../../components/shared';
|
import { ProposalUserAction } from '../../components/shared';
|
||||||
|
import { downloadJson } from '../../../../lib/download-json';
|
||||||
|
|
||||||
export interface NewMarketProposalFormFields {
|
export interface NewMarketProposalFormFields {
|
||||||
proposalVoteDeadline: string;
|
proposalVoteDeadline: string;
|
||||||
@ -60,10 +61,11 @@ export const ProposeNewMarket = () => {
|
|||||||
handleSubmit,
|
handleSubmit,
|
||||||
formState: { isSubmitting, errors },
|
formState: { isSubmitting, errors },
|
||||||
setValue,
|
setValue,
|
||||||
|
watch,
|
||||||
} = useForm<NewMarketProposalFormFields>();
|
} = useForm<NewMarketProposalFormFields>();
|
||||||
const { finalizedProposal, submit, Dialog } = useProposalSubmit();
|
const { finalizedProposal, submit, Dialog } = useProposalSubmit();
|
||||||
|
|
||||||
const onSubmit = async (fields: NewMarketProposalFormFields) => {
|
const assembleProposal = (fields: NewMarketProposalFormFields) => {
|
||||||
const isVoteDeadlineAtMinimum = doesValueEquateToParam(
|
const isVoteDeadlineAtMinimum = doesValueEquateToParam(
|
||||||
fields.proposalVoteDeadline,
|
fields.proposalVoteDeadline,
|
||||||
params.governance_proposal_market_minClose
|
params.governance_proposal_market_minClose
|
||||||
@ -81,7 +83,7 @@ export const ProposeNewMarket = () => {
|
|||||||
params.governance_proposal_market_maxEnact
|
params.governance_proposal_market_maxEnact
|
||||||
);
|
);
|
||||||
|
|
||||||
await submit({
|
return {
|
||||||
rationale: {
|
rationale: {
|
||||||
title: fields.proposalTitle,
|
title: fields.proposalTitle,
|
||||||
description: fields.proposalDescription,
|
description: fields.proposalDescription,
|
||||||
@ -101,7 +103,19 @@ export const ProposeNewMarket = () => {
|
|||||||
isEnactmentDeadlineAtMaximum
|
isEnactmentDeadlineAtMaximum
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
});
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const onSubmit = async (fields: NewMarketProposalFormFields) => {
|
||||||
|
await submit(assembleProposal(fields));
|
||||||
|
};
|
||||||
|
|
||||||
|
const viewJson = () => {
|
||||||
|
const formData = watch();
|
||||||
|
downloadJson(
|
||||||
|
JSON.stringify(assembleProposal(formData)),
|
||||||
|
'vega-new-market-proposal'
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -109,104 +123,103 @@ export const ProposeNewMarket = () => {
|
|||||||
loading={networkParamsLoading}
|
loading={networkParamsLoading}
|
||||||
error={networkParamsError}
|
error={networkParamsError}
|
||||||
data={params}
|
data={params}
|
||||||
>
|
render={(params) => (
|
||||||
<Heading title={t('NewMarketProposal')} />
|
<>
|
||||||
<VegaWalletContainer>
|
<Heading title={t('NewMarketProposal')} />
|
||||||
{() => (
|
|
||||||
<>
|
|
||||||
<ProposalMinRequirements
|
|
||||||
minProposalBalance={
|
|
||||||
params.governance_proposal_market_minProposerBalance
|
|
||||||
}
|
|
||||||
spamProtectionMin={params.spam_protection_proposal_min_tokens}
|
|
||||||
userAction={ProposalUserAction.CREATE}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{VEGA_DOCS_URL && (
|
<ProposalMinRequirements
|
||||||
<p className="text-sm" data-testid="proposal-docs-link">
|
minProposalBalance={
|
||||||
<span className="mr-1">{t('ProposalTermsText')}</span>
|
params.governance_proposal_market_minProposerBalance
|
||||||
<ExternalLink
|
}
|
||||||
href={`${
|
spamProtectionMin={params.spam_protection_proposal_min_tokens}
|
||||||
createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE
|
userAction={ProposalUserAction.CREATE}
|
||||||
}${DOCS_LINK}`}
|
/>
|
||||||
target="_blank"
|
|
||||||
>{`${
|
{VEGA_DOCS_URL && (
|
||||||
|
<p className="text-sm" data-testid="proposal-docs-link">
|
||||||
|
<span className="mr-1">{t('ProposalTermsText')}</span>
|
||||||
|
<ExternalLink
|
||||||
|
href={`${
|
||||||
createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE
|
createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE
|
||||||
}${DOCS_LINK}`}</ExternalLink>
|
}${DOCS_LINK}`}
|
||||||
</p>
|
target="_blank"
|
||||||
)}
|
>{`${
|
||||||
|
createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE
|
||||||
|
}${DOCS_LINK}`}</ExternalLink>
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
{VEGA_EXPLORER_URL && (
|
{VEGA_EXPLORER_URL && (
|
||||||
<p className="text-sm">
|
<p className="text-sm">
|
||||||
{t('MoreMarketsInfo')}{' '}
|
{t('MoreMarketsInfo')}{' '}
|
||||||
<ExternalLink
|
<ExternalLink
|
||||||
href={`${VEGA_EXPLORER_URL}/markets`}
|
href={`${VEGA_EXPLORER_URL}/markets`}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>{`${VEGA_EXPLORER_URL}/markets`}</ExternalLink>
|
>{`${VEGA_EXPLORER_URL}/markets`}</ExternalLink>
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div data-testid="new-market-proposal-form">
|
<div data-testid="new-market-proposal-form">
|
||||||
<form onSubmit={handleSubmit(onSubmit)}>
|
<form onSubmit={handleSubmit(onSubmit)}>
|
||||||
<ProposalFormSubheader>
|
<ProposalFormSubheader>
|
||||||
{t('ProposalRationale')}
|
{t('ProposalRationale')}
|
||||||
</ProposalFormSubheader>
|
</ProposalFormSubheader>
|
||||||
|
|
||||||
<ProposalFormTitle
|
<ProposalFormTitle
|
||||||
registerField={register('proposalTitle', {
|
registerField={register('proposalTitle', {
|
||||||
required: t('Required'),
|
required: t('Required'),
|
||||||
})}
|
})}
|
||||||
errorMessage={errors?.proposalTitle?.message}
|
errorMessage={errors?.proposalTitle?.message}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ProposalFormDescription
|
<ProposalFormDescription
|
||||||
registerField={register('proposalDescription', {
|
registerField={register('proposalDescription', {
|
||||||
required: t('Required'),
|
required: t('Required'),
|
||||||
})}
|
})}
|
||||||
errorMessage={errors?.proposalDescription?.message}
|
errorMessage={errors?.proposalDescription?.message}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ProposalFormSubheader>{t('NewMarket')}</ProposalFormSubheader>
|
<ProposalFormSubheader>{t('NewMarket')}</ProposalFormSubheader>
|
||||||
|
|
||||||
<ProposalFormTerms
|
<ProposalFormTerms
|
||||||
registerField={register('proposalTerms', {
|
registerField={register('proposalTerms', {
|
||||||
required: t('Required'),
|
required: t('Required'),
|
||||||
validate: (value) => validateJson(value),
|
validate: (value) => validateJson(value),
|
||||||
})}
|
})}
|
||||||
labelOverride={'Terms.newMarket (JSON format)'}
|
labelOverride={'Terms.newMarket (JSON format)'}
|
||||||
errorMessage={errors?.proposalTerms?.message}
|
errorMessage={errors?.proposalTerms?.message}
|
||||||
docsLink={DOCS_LINK}
|
docsLink={DOCS_LINK}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ProposalFormVoteAndEnactmentDeadline
|
<ProposalFormVoteAndEnactmentDeadline
|
||||||
onVoteMinMax={setValue}
|
onVoteMinMax={setValue}
|
||||||
voteRegister={register('proposalVoteDeadline', {
|
voteRegister={register('proposalVoteDeadline', {
|
||||||
required: t('Required'),
|
required: t('Required'),
|
||||||
})}
|
})}
|
||||||
voteErrorMessage={errors?.proposalVoteDeadline?.message}
|
voteErrorMessage={errors?.proposalVoteDeadline?.message}
|
||||||
voteMinClose={params.governance_proposal_market_minClose}
|
voteMinClose={params.governance_proposal_market_minClose}
|
||||||
voteMaxClose={params.governance_proposal_market_maxClose}
|
voteMaxClose={params.governance_proposal_market_maxClose}
|
||||||
onEnactMinMax={setValue}
|
onEnactMinMax={setValue}
|
||||||
enactmentRegister={register('proposalEnactmentDeadline', {
|
enactmentRegister={register('proposalEnactmentDeadline', {
|
||||||
required: t('Required'),
|
required: t('Required'),
|
||||||
})}
|
})}
|
||||||
enactmentErrorMessage={
|
enactmentErrorMessage={
|
||||||
errors?.proposalEnactmentDeadline?.message
|
errors?.proposalEnactmentDeadline?.message
|
||||||
}
|
}
|
||||||
enactmentMinClose={params.governance_proposal_market_minEnact}
|
enactmentMinClose={params.governance_proposal_market_minEnact}
|
||||||
enactmentMaxClose={params.governance_proposal_market_maxEnact}
|
enactmentMaxClose={params.governance_proposal_market_maxEnact}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ProposalFormSubmit isSubmitting={isSubmitting} />
|
<ProposalFormSubmit isSubmitting={isSubmitting} />
|
||||||
<ProposalFormTransactionDialog
|
<ProposalFormDownloadJson downloadJson={viewJson} />
|
||||||
finalizedProposal={finalizedProposal}
|
<ProposalFormTransactionDialog
|
||||||
TransactionDialog={Dialog}
|
finalizedProposal={finalizedProposal}
|
||||||
/>
|
TransactionDialog={Dialog}
|
||||||
</form>
|
/>
|
||||||
</div>
|
</form>
|
||||||
</>
|
</div>
|
||||||
)}
|
</>
|
||||||
</VegaWalletContainer>
|
)}
|
||||||
</AsyncRenderer>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -2,7 +2,6 @@ import { useForm } from 'react-hook-form';
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useEnvironment } from '@vegaprotocol/environment';
|
import { useEnvironment } from '@vegaprotocol/environment';
|
||||||
import { Heading } from '../../../../components/heading';
|
import { Heading } from '../../../../components/heading';
|
||||||
import { VegaWalletContainer } from '../../../../components/vega-wallet-container';
|
|
||||||
import {
|
import {
|
||||||
AsyncRenderer,
|
AsyncRenderer,
|
||||||
ExternalLink,
|
ExternalLink,
|
||||||
@ -20,8 +19,10 @@ import { useProposalSubmit } from '@vegaprotocol/governance';
|
|||||||
import {
|
import {
|
||||||
ProposalFormSubmit,
|
ProposalFormSubmit,
|
||||||
ProposalFormTransactionDialog,
|
ProposalFormTransactionDialog,
|
||||||
|
ProposalFormDownloadJson,
|
||||||
} from '../../components/propose';
|
} from '../../components/propose';
|
||||||
import { ProposalRawMinRequirements } from './proposal-raw-min-requirements';
|
import { ProposalRawMinRequirements } from './proposal-raw-min-requirements';
|
||||||
|
import { downloadJson } from '../../../../lib/download-json';
|
||||||
|
|
||||||
export interface RawProposalFormFields {
|
export interface RawProposalFormFields {
|
||||||
rawProposalData: string;
|
rawProposalData: string;
|
||||||
@ -48,6 +49,7 @@ export const ProposeRaw = () => {
|
|||||||
register,
|
register,
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
formState: { isSubmitting, errors },
|
formState: { isSubmitting, errors },
|
||||||
|
watch,
|
||||||
} = useForm<RawProposalFormFields>();
|
} = useForm<RawProposalFormFields>();
|
||||||
const { finalizedProposal, submit, Dialog } = useProposalSubmit();
|
const { finalizedProposal, submit, Dialog } = useProposalSubmit();
|
||||||
|
|
||||||
@ -57,88 +59,90 @@ export const ProposeRaw = () => {
|
|||||||
await submit(JSON.parse(fields.rawProposalData));
|
await submit(JSON.parse(fields.rawProposalData));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const viewJson = () => {
|
||||||
|
const formData = watch();
|
||||||
|
downloadJson(JSON.stringify(formData), 'vega-raw-proposal');
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AsyncRenderer
|
<AsyncRenderer
|
||||||
loading={networkParamsLoading}
|
loading={networkParamsLoading}
|
||||||
error={networkParamsError}
|
error={networkParamsError}
|
||||||
data={params}
|
data={params}
|
||||||
>
|
render={(params) => (
|
||||||
<Heading title={t('NewRawProposal')} />
|
<>
|
||||||
<VegaWalletContainer>
|
<Heading title={t('NewRawProposal')} />
|
||||||
{() => (
|
|
||||||
<>
|
|
||||||
<ProposalRawMinRequirements
|
|
||||||
assetMin={params.governance_proposal_asset_minProposerBalance}
|
|
||||||
updateAssetMin={
|
|
||||||
params.governance_proposal_updateAsset_minProposerBalance
|
|
||||||
}
|
|
||||||
marketMin={params.governance_proposal_market_minProposerBalance}
|
|
||||||
updateMarketMin={
|
|
||||||
params.governance_proposal_updateMarket_minProposerBalance
|
|
||||||
}
|
|
||||||
updateNetParamMin={
|
|
||||||
params.governance_proposal_updateNetParam_minProposerBalance
|
|
||||||
}
|
|
||||||
freeformMin={
|
|
||||||
params.governance_proposal_freeform_minProposerBalance
|
|
||||||
}
|
|
||||||
spamProtectionMin={params.spam_protection_proposal_min_tokens}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{VEGA_DOCS_URL && (
|
<ProposalRawMinRequirements
|
||||||
<p className="text-sm" data-testid="proposal-docs-link">
|
assetMin={params.governance_proposal_asset_minProposerBalance}
|
||||||
<span className="mr-1">{t('ProposalTermsText')}</span>
|
updateAssetMin={
|
||||||
<ExternalLink
|
params.governance_proposal_updateAsset_minProposerBalance
|
||||||
href={createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE}
|
}
|
||||||
target="_blank"
|
marketMin={params.governance_proposal_market_minProposerBalance}
|
||||||
>
|
updateMarketMin={
|
||||||
{createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE}
|
params.governance_proposal_updateMarket_minProposerBalance
|
||||||
</ExternalLink>
|
}
|
||||||
</p>
|
updateNetParamMin={
|
||||||
)}
|
params.governance_proposal_updateNetParam_minProposerBalance
|
||||||
|
}
|
||||||
|
freeformMin={params.governance_proposal_freeform_minProposerBalance}
|
||||||
|
spamProtectionMin={params.spam_protection_proposal_min_tokens}
|
||||||
|
/>
|
||||||
|
|
||||||
{VEGA_EXPLORER_URL && (
|
{VEGA_DOCS_URL && (
|
||||||
<p className="text-sm">
|
<p className="text-sm" data-testid="proposal-docs-link">
|
||||||
{t('MoreProposalsInfo')}{' '}
|
<span className="mr-1">{t('ProposalTermsText')}</span>
|
||||||
<ExternalLink
|
<ExternalLink
|
||||||
href={`${VEGA_EXPLORER_URL}/governance`}
|
href={createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>{`${VEGA_EXPLORER_URL}/governance`}</ExternalLink>
|
>
|
||||||
</p>
|
{createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE}
|
||||||
)}
|
</ExternalLink>
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
<div data-testid="raw-proposal-form">
|
{VEGA_EXPLORER_URL && (
|
||||||
<form onSubmit={handleSubmit(onSubmit)}>
|
<p className="text-sm">
|
||||||
<FormGroup
|
{t('MoreProposalsInfo')}{' '}
|
||||||
label="Make a proposal by submitting JSON"
|
<ExternalLink
|
||||||
labelFor="proposal-data"
|
href={`${VEGA_EXPLORER_URL}/governance`}
|
||||||
>
|
target="_blank"
|
||||||
<TextArea
|
>{`${VEGA_EXPLORER_URL}/governance`}</ExternalLink>
|
||||||
id="proposal-data"
|
</p>
|
||||||
className="min-h-[200px]"
|
)}
|
||||||
hasError={hasError}
|
|
||||||
data-testid="proposal-data"
|
<div data-testid="raw-proposal-form">
|
||||||
{...register('rawProposalData', {
|
<form onSubmit={handleSubmit(onSubmit)}>
|
||||||
required: t('Required'),
|
<FormGroup
|
||||||
validate: (value) => validateJson(value),
|
label="Make a proposal by submitting JSON"
|
||||||
})}
|
labelFor="proposal-data"
|
||||||
/>
|
>
|
||||||
{errors.rawProposalData?.message && (
|
<TextArea
|
||||||
<InputError intent="danger">
|
id="proposal-data"
|
||||||
{errors.rawProposalData?.message}
|
className="min-h-[200px]"
|
||||||
</InputError>
|
hasError={hasError}
|
||||||
)}
|
data-testid="proposal-data"
|
||||||
</FormGroup>
|
{...register('rawProposalData', {
|
||||||
<ProposalFormSubmit isSubmitting={isSubmitting} />
|
required: t('Required'),
|
||||||
<ProposalFormTransactionDialog
|
validate: (value) => validateJson(value),
|
||||||
finalizedProposal={finalizedProposal}
|
})}
|
||||||
TransactionDialog={Dialog}
|
|
||||||
/>
|
/>
|
||||||
</form>
|
{errors.rawProposalData?.message && (
|
||||||
</div>
|
<InputError intent="danger">
|
||||||
</>
|
{errors.rawProposalData?.message}
|
||||||
)}
|
</InputError>
|
||||||
</VegaWalletContainer>
|
)}
|
||||||
</AsyncRenderer>
|
</FormGroup>
|
||||||
|
<ProposalFormSubmit isSubmitting={isSubmitting} />
|
||||||
|
<ProposalFormDownloadJson downloadJson={viewJson} />
|
||||||
|
<ProposalFormTransactionDialog
|
||||||
|
finalizedProposal={finalizedProposal}
|
||||||
|
TransactionDialog={Dialog}
|
||||||
|
/>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -111,6 +111,7 @@ describe('Propose Update Asset', () => {
|
|||||||
expect(screen.getByTestId('proposal-vote-deadline')).toBeTruthy();
|
expect(screen.getByTestId('proposal-vote-deadline')).toBeTruthy();
|
||||||
expect(screen.getByTestId('proposal-enactment-deadline')).toBeTruthy();
|
expect(screen.getByTestId('proposal-enactment-deadline')).toBeTruthy();
|
||||||
expect(screen.getByTestId('proposal-submit')).toBeTruthy();
|
expect(screen.getByTestId('proposal-submit')).toBeTruthy();
|
||||||
|
expect(screen.getByTestId('proposal-download-json')).toBeTruthy();
|
||||||
expect(screen.getByTestId('proposal-transaction-dialog')).toBeTruthy();
|
expect(screen.getByTestId('proposal-transaction-dialog')).toBeTruthy();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -20,13 +20,14 @@ import {
|
|||||||
ProposalFormTerms,
|
ProposalFormTerms,
|
||||||
ProposalFormTitle,
|
ProposalFormTitle,
|
||||||
ProposalFormTransactionDialog,
|
ProposalFormTransactionDialog,
|
||||||
|
ProposalFormDownloadJson,
|
||||||
ProposalFormVoteAndEnactmentDeadline,
|
ProposalFormVoteAndEnactmentDeadline,
|
||||||
} from '../../components/propose';
|
} from '../../components/propose';
|
||||||
import { ProposalMinRequirements } from '../../components/shared';
|
import { ProposalMinRequirements } from '../../components/shared';
|
||||||
import { AsyncRenderer, ExternalLink } from '@vegaprotocol/ui-toolkit';
|
import { AsyncRenderer, ExternalLink } from '@vegaprotocol/ui-toolkit';
|
||||||
import { Heading } from '../../../../components/heading';
|
import { Heading } from '../../../../components/heading';
|
||||||
import { VegaWalletContainer } from '../../../../components/vega-wallet-container';
|
|
||||||
import { ProposalUserAction } from '../../components/shared';
|
import { ProposalUserAction } from '../../components/shared';
|
||||||
|
import { downloadJson } from '../../../../lib/download-json';
|
||||||
|
|
||||||
export interface UpdateAssetProposalFormFields {
|
export interface UpdateAssetProposalFormFields {
|
||||||
proposalVoteDeadline: string;
|
proposalVoteDeadline: string;
|
||||||
@ -60,10 +61,11 @@ export const ProposeUpdateAsset = () => {
|
|||||||
handleSubmit,
|
handleSubmit,
|
||||||
formState: { isSubmitting, errors },
|
formState: { isSubmitting, errors },
|
||||||
setValue,
|
setValue,
|
||||||
|
watch,
|
||||||
} = useForm<UpdateAssetProposalFormFields>();
|
} = useForm<UpdateAssetProposalFormFields>();
|
||||||
const { finalizedProposal, submit, Dialog } = useProposalSubmit();
|
const { finalizedProposal, submit, Dialog } = useProposalSubmit();
|
||||||
|
|
||||||
const onSubmit = async (fields: UpdateAssetProposalFormFields) => {
|
const assembleProposal = (fields: UpdateAssetProposalFormFields) => {
|
||||||
const isVoteDeadlineAtMinimum = doesValueEquateToParam(
|
const isVoteDeadlineAtMinimum = doesValueEquateToParam(
|
||||||
fields.proposalVoteDeadline,
|
fields.proposalVoteDeadline,
|
||||||
params.governance_proposal_updateAsset_minClose
|
params.governance_proposal_updateAsset_minClose
|
||||||
@ -81,7 +83,7 @@ export const ProposeUpdateAsset = () => {
|
|||||||
params.governance_proposal_updateAsset_maxEnact
|
params.governance_proposal_updateAsset_maxEnact
|
||||||
);
|
);
|
||||||
|
|
||||||
await submit({
|
return {
|
||||||
rationale: {
|
rationale: {
|
||||||
title: fields.proposalTitle,
|
title: fields.proposalTitle,
|
||||||
description: fields.proposalDescription,
|
description: fields.proposalDescription,
|
||||||
@ -101,7 +103,19 @@ export const ProposeUpdateAsset = () => {
|
|||||||
isEnactmentDeadlineAtMaximum
|
isEnactmentDeadlineAtMaximum
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
});
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const onSubmit = async (fields: UpdateAssetProposalFormFields) => {
|
||||||
|
await submit(assembleProposal(fields));
|
||||||
|
};
|
||||||
|
|
||||||
|
const viewJson = () => {
|
||||||
|
const formData = watch();
|
||||||
|
downloadJson(
|
||||||
|
JSON.stringify(assembleProposal(formData)),
|
||||||
|
'vega-update-asset-proposal'
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -109,110 +123,107 @@ export const ProposeUpdateAsset = () => {
|
|||||||
loading={networkParamsLoading}
|
loading={networkParamsLoading}
|
||||||
error={networkParamsError}
|
error={networkParamsError}
|
||||||
data={params}
|
data={params}
|
||||||
>
|
render={(params) => (
|
||||||
<Heading title={t('UpdateAssetProposal')} />
|
<>
|
||||||
<VegaWalletContainer>
|
<Heading title={t('UpdateAssetProposal')} />
|
||||||
{() => (
|
|
||||||
<>
|
|
||||||
<ProposalMinRequirements
|
|
||||||
minProposalBalance={
|
|
||||||
params.governance_proposal_updateAsset_minProposerBalance
|
|
||||||
}
|
|
||||||
spamProtectionMin={params.spam_protection_proposal_min_tokens}
|
|
||||||
userAction={ProposalUserAction.CREATE}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{VEGA_DOCS_URL && (
|
<ProposalMinRequirements
|
||||||
<p className="text-sm" data-testid="proposal-docs-link">
|
minProposalBalance={
|
||||||
<span className="mr-1">{t('ProposalTermsText')}</span>
|
params.governance_proposal_updateAsset_minProposerBalance
|
||||||
<ExternalLink
|
}
|
||||||
href={`${
|
spamProtectionMin={params.spam_protection_proposal_min_tokens}
|
||||||
createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE
|
userAction={ProposalUserAction.CREATE}
|
||||||
}${DOCS_LINK}`}
|
/>
|
||||||
target="_blank"
|
|
||||||
>{`${
|
{VEGA_DOCS_URL && (
|
||||||
|
<p className="text-sm" data-testid="proposal-docs-link">
|
||||||
|
<span className="mr-1">{t('ProposalTermsText')}</span>
|
||||||
|
<ExternalLink
|
||||||
|
href={`${
|
||||||
createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE
|
createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE
|
||||||
}${DOCS_LINK}`}</ExternalLink>
|
}${DOCS_LINK}`}
|
||||||
</p>
|
target="_blank"
|
||||||
)}
|
>{`${
|
||||||
|
createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE
|
||||||
|
}${DOCS_LINK}`}</ExternalLink>
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
{VEGA_EXPLORER_URL && (
|
{VEGA_EXPLORER_URL && (
|
||||||
<p className="text-sm">
|
<p className="text-sm">
|
||||||
{t('MoreAssetsInfo')}{' '}
|
{t('MoreAssetsInfo')}{' '}
|
||||||
<ExternalLink
|
<ExternalLink
|
||||||
href={`${VEGA_EXPLORER_URL}/assets`}
|
href={`${VEGA_EXPLORER_URL}/assets`}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>{`${VEGA_EXPLORER_URL}/assets`}</ExternalLink>
|
>{`${VEGA_EXPLORER_URL}/assets`}</ExternalLink>
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div data-testid="update-asset-proposal-form">
|
<div data-testid="update-asset-proposal-form">
|
||||||
<form onSubmit={handleSubmit(onSubmit)}>
|
<form onSubmit={handleSubmit(onSubmit)}>
|
||||||
<ProposalFormSubheader>
|
<ProposalFormSubheader>
|
||||||
{t('ProposalRationale')}
|
{t('ProposalRationale')}
|
||||||
</ProposalFormSubheader>
|
</ProposalFormSubheader>
|
||||||
|
|
||||||
<ProposalFormTitle
|
<ProposalFormTitle
|
||||||
registerField={register('proposalTitle', {
|
registerField={register('proposalTitle', {
|
||||||
required: t('Required'),
|
required: t('Required'),
|
||||||
})}
|
})}
|
||||||
errorMessage={errors?.proposalTitle?.message}
|
errorMessage={errors?.proposalTitle?.message}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ProposalFormDescription
|
<ProposalFormDescription
|
||||||
registerField={register('proposalDescription', {
|
registerField={register('proposalDescription', {
|
||||||
required: t('Required'),
|
required: t('Required'),
|
||||||
})}
|
})}
|
||||||
errorMessage={errors?.proposalDescription?.message}
|
errorMessage={errors?.proposalDescription?.message}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ProposalFormSubheader>
|
<ProposalFormSubheader>{t('UpdateAsset')}</ProposalFormSubheader>
|
||||||
{t('UpdateAsset')}
|
|
||||||
</ProposalFormSubheader>
|
|
||||||
|
|
||||||
<ProposalFormTerms
|
<ProposalFormTerms
|
||||||
registerField={register('proposalTerms', {
|
registerField={register('proposalTerms', {
|
||||||
required: t('Required'),
|
required: t('Required'),
|
||||||
validate: (value) => validateJson(value),
|
validate: (value) => validateJson(value),
|
||||||
})}
|
})}
|
||||||
labelOverride={'Terms.updateAsset (JSON format)'}
|
labelOverride={'Terms.updateAsset (JSON format)'}
|
||||||
errorMessage={errors?.proposalTerms?.message}
|
errorMessage={errors?.proposalTerms?.message}
|
||||||
docsLink={DOCS_LINK}
|
docsLink={DOCS_LINK}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ProposalFormVoteAndEnactmentDeadline
|
<ProposalFormVoteAndEnactmentDeadline
|
||||||
onVoteMinMax={setValue}
|
onVoteMinMax={setValue}
|
||||||
voteRegister={register('proposalVoteDeadline', {
|
voteRegister={register('proposalVoteDeadline', {
|
||||||
required: t('Required'),
|
required: t('Required'),
|
||||||
})}
|
})}
|
||||||
voteErrorMessage={errors?.proposalVoteDeadline?.message}
|
voteErrorMessage={errors?.proposalVoteDeadline?.message}
|
||||||
voteMinClose={params.governance_proposal_updateAsset_minClose}
|
voteMinClose={params.governance_proposal_updateAsset_minClose}
|
||||||
voteMaxClose={params.governance_proposal_updateAsset_maxClose}
|
voteMaxClose={params.governance_proposal_updateAsset_maxClose}
|
||||||
onEnactMinMax={setValue}
|
onEnactMinMax={setValue}
|
||||||
enactmentRegister={register('proposalEnactmentDeadline', {
|
enactmentRegister={register('proposalEnactmentDeadline', {
|
||||||
required: t('Required'),
|
required: t('Required'),
|
||||||
})}
|
})}
|
||||||
enactmentErrorMessage={
|
enactmentErrorMessage={
|
||||||
errors?.proposalEnactmentDeadline?.message
|
errors?.proposalEnactmentDeadline?.message
|
||||||
}
|
}
|
||||||
enactmentMinClose={
|
enactmentMinClose={
|
||||||
params.governance_proposal_updateAsset_minEnact
|
params.governance_proposal_updateAsset_minEnact
|
||||||
}
|
}
|
||||||
enactmentMaxClose={
|
enactmentMaxClose={
|
||||||
params.governance_proposal_updateAsset_maxEnact
|
params.governance_proposal_updateAsset_maxEnact
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ProposalFormSubmit isSubmitting={isSubmitting} />
|
<ProposalFormSubmit isSubmitting={isSubmitting} />
|
||||||
<ProposalFormTransactionDialog
|
<ProposalFormDownloadJson downloadJson={viewJson} />
|
||||||
finalizedProposal={finalizedProposal}
|
<ProposalFormTransactionDialog
|
||||||
TransactionDialog={Dialog}
|
finalizedProposal={finalizedProposal}
|
||||||
/>
|
TransactionDialog={Dialog}
|
||||||
</form>
|
/>
|
||||||
</div>
|
</form>
|
||||||
</>
|
</div>
|
||||||
)}
|
</>
|
||||||
</VegaWalletContainer>
|
)}
|
||||||
</AsyncRenderer>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -187,6 +187,7 @@ describe('Propose Update Market', () => {
|
|||||||
expect(screen.getByTestId('proposal-vote-deadline')).toBeTruthy();
|
expect(screen.getByTestId('proposal-vote-deadline')).toBeTruthy();
|
||||||
expect(screen.getByTestId('proposal-enactment-deadline')).toBeTruthy();
|
expect(screen.getByTestId('proposal-enactment-deadline')).toBeTruthy();
|
||||||
expect(screen.getByTestId('proposal-submit')).toBeTruthy();
|
expect(screen.getByTestId('proposal-submit')).toBeTruthy();
|
||||||
|
expect(screen.getByTestId('proposal-download-json')).toBeTruthy();
|
||||||
expect(screen.getByTestId('proposal-transaction-dialog')).toBeTruthy();
|
expect(screen.getByTestId('proposal-transaction-dialog')).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ import {
|
|||||||
ProposalFormTerms,
|
ProposalFormTerms,
|
||||||
ProposalFormTitle,
|
ProposalFormTitle,
|
||||||
ProposalFormTransactionDialog,
|
ProposalFormTransactionDialog,
|
||||||
|
ProposalFormDownloadJson,
|
||||||
ProposalFormVoteAndEnactmentDeadline,
|
ProposalFormVoteAndEnactmentDeadline,
|
||||||
} from '../../components/propose';
|
} from '../../components/propose';
|
||||||
import { ProposalMinRequirements } from '../../components/shared';
|
import { ProposalMinRequirements } from '../../components/shared';
|
||||||
@ -34,9 +35,9 @@ import {
|
|||||||
Select,
|
Select,
|
||||||
} from '@vegaprotocol/ui-toolkit';
|
} from '@vegaprotocol/ui-toolkit';
|
||||||
import { Heading } from '../../../../components/heading';
|
import { Heading } from '../../../../components/heading';
|
||||||
import { VegaWalletContainer } from '../../../../components/vega-wallet-container';
|
|
||||||
import { ProposalUserAction } from '../../components/shared';
|
import { ProposalUserAction } from '../../components/shared';
|
||||||
import { useProposalMarketsQueryQuery } from './__generated___/UpdateMarket';
|
import { useProposalMarketsQueryQuery } from './__generated___/UpdateMarket';
|
||||||
|
import { downloadJson } from '../../../../lib/download-json';
|
||||||
|
|
||||||
export interface UpdateMarketProposalFormFields {
|
export interface UpdateMarketProposalFormFields {
|
||||||
proposalVoteDeadline: string;
|
proposalVoteDeadline: string;
|
||||||
@ -101,10 +102,11 @@ export const ProposeUpdateMarket = () => {
|
|||||||
handleSubmit,
|
handleSubmit,
|
||||||
formState: { isSubmitting, errors },
|
formState: { isSubmitting, errors },
|
||||||
setValue,
|
setValue,
|
||||||
|
watch,
|
||||||
} = useForm<UpdateMarketProposalFormFields>();
|
} = useForm<UpdateMarketProposalFormFields>();
|
||||||
const { finalizedProposal, submit, Dialog } = useProposalSubmit();
|
const { finalizedProposal, submit, Dialog } = useProposalSubmit();
|
||||||
|
|
||||||
const onSubmit = async (fields: UpdateMarketProposalFormFields) => {
|
const assembleProposal = (fields: UpdateMarketProposalFormFields) => {
|
||||||
const isVoteDeadlineAtMinimum = doesValueEquateToParam(
|
const isVoteDeadlineAtMinimum = doesValueEquateToParam(
|
||||||
fields.proposalVoteDeadline,
|
fields.proposalVoteDeadline,
|
||||||
params.governance_proposal_updateMarket_minClose
|
params.governance_proposal_updateMarket_minClose
|
||||||
@ -122,7 +124,7 @@ export const ProposeUpdateMarket = () => {
|
|||||||
params.governance_proposal_updateMarket_maxEnact
|
params.governance_proposal_updateMarket_maxEnact
|
||||||
);
|
);
|
||||||
|
|
||||||
await submit({
|
return {
|
||||||
rationale: {
|
rationale: {
|
||||||
title: fields.proposalTitle,
|
title: fields.proposalTitle,
|
||||||
description: fields.proposalDescription,
|
description: fields.proposalDescription,
|
||||||
@ -145,176 +147,182 @@ export const ProposeUpdateMarket = () => {
|
|||||||
isEnactmentDeadlineAtMaximum
|
isEnactmentDeadlineAtMaximum
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
});
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const onSubmit = async (fields: UpdateMarketProposalFormFields) => {
|
||||||
|
await submit(assembleProposal(fields));
|
||||||
|
};
|
||||||
|
|
||||||
|
const viewJson = () => {
|
||||||
|
const formData = watch();
|
||||||
|
downloadJson(
|
||||||
|
JSON.stringify(assembleProposal(formData)),
|
||||||
|
'vega-update-market-proposal'
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AsyncRenderer
|
<AsyncRenderer
|
||||||
loading={networkParamsLoading && marketsLoading}
|
loading={networkParamsLoading && marketsLoading}
|
||||||
error={networkParamsError && marketsError}
|
error={networkParamsError && marketsError}
|
||||||
data={params && marketsData}
|
data={{ ...params, ...marketsData }}
|
||||||
>
|
render={(data) => (
|
||||||
<Heading title={t('UpdateMarketProposal')} />
|
<>
|
||||||
<VegaWalletContainer>
|
<Heading title={t('UpdateMarketProposal')} />
|
||||||
{() => (
|
<ProposalMinRequirements
|
||||||
<>
|
minProposalBalance={
|
||||||
<ProposalMinRequirements
|
data.governance_proposal_updateMarket_minProposerBalance
|
||||||
minProposalBalance={
|
}
|
||||||
params.governance_proposal_updateMarket_minProposerBalance
|
spamProtectionMin={data.spam_protection_proposal_min_tokens}
|
||||||
}
|
userAction={ProposalUserAction.CREATE}
|
||||||
spamProtectionMin={params.spam_protection_proposal_min_tokens}
|
/>
|
||||||
userAction={ProposalUserAction.CREATE}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{VEGA_DOCS_URL && (
|
{VEGA_DOCS_URL && (
|
||||||
<p className="text-sm" data-testid="proposal-docs-link">
|
<p className="text-sm" data-testid="proposal-docs-link">
|
||||||
<span className="mr-1">{t('ProposalTermsText')}</span>
|
<span className="mr-1">{t('ProposalTermsText')}</span>
|
||||||
<ExternalLink
|
<ExternalLink
|
||||||
href={`${
|
href={`${
|
||||||
createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE
|
|
||||||
}${DOCS_LINK}`}
|
|
||||||
target="_blank"
|
|
||||||
>{`${
|
|
||||||
createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE
|
createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE
|
||||||
}${DOCS_LINK}`}</ExternalLink>
|
}${DOCS_LINK}`}
|
||||||
</p>
|
target="_blank"
|
||||||
)}
|
>{`${
|
||||||
|
createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE
|
||||||
|
}${DOCS_LINK}`}</ExternalLink>
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
{VEGA_EXPLORER_URL && (
|
{VEGA_EXPLORER_URL && (
|
||||||
<p className="text-sm">
|
<p className="text-sm">
|
||||||
{t('MoreMarketsInfo')}{' '}
|
{t('MoreMarketsInfo')}{' '}
|
||||||
<ExternalLink
|
<ExternalLink
|
||||||
href={`${VEGA_EXPLORER_URL}/markets`}
|
href={`${VEGA_EXPLORER_URL}/markets`}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>{`${VEGA_EXPLORER_URL}/markets`}</ExternalLink>
|
>{`${VEGA_EXPLORER_URL}/markets`}</ExternalLink>
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div data-testid="update-market-proposal-form">
|
<div data-testid="update-market-proposal-form">
|
||||||
<form onSubmit={handleSubmit(onSubmit)}>
|
<form onSubmit={handleSubmit(onSubmit)}>
|
||||||
<ProposalFormSubheader>
|
<ProposalFormSubheader>
|
||||||
{t('ProposalRationale')}
|
{t('ProposalRationale')}
|
||||||
</ProposalFormSubheader>
|
</ProposalFormSubheader>
|
||||||
|
|
||||||
<ProposalFormTitle
|
<ProposalFormTitle
|
||||||
registerField={register('proposalTitle', {
|
registerField={register('proposalTitle', {
|
||||||
|
required: t('Required'),
|
||||||
|
})}
|
||||||
|
errorMessage={errors?.proposalTitle?.message}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ProposalFormDescription
|
||||||
|
registerField={register('proposalDescription', {
|
||||||
|
required: t('Required'),
|
||||||
|
})}
|
||||||
|
errorMessage={errors?.proposalDescription?.message}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ProposalFormSubheader>
|
||||||
|
{t('SelectAMarketToChange')}
|
||||||
|
</ProposalFormSubheader>
|
||||||
|
|
||||||
|
<FormGroup
|
||||||
|
label={t('SelectAMarketToChange')}
|
||||||
|
labelFor="proposal-market"
|
||||||
|
hideLabel={true}
|
||||||
|
>
|
||||||
|
<Select
|
||||||
|
data-testid="proposal-market-select"
|
||||||
|
id="proposal-market"
|
||||||
|
{...register('proposalMarketId', {
|
||||||
required: t('Required'),
|
required: t('Required'),
|
||||||
})}
|
})}
|
||||||
errorMessage={errors?.proposalTitle?.message}
|
onChange={(e) => setSelectedMarket(e.target.value)}
|
||||||
/>
|
|
||||||
|
|
||||||
<ProposalFormDescription
|
|
||||||
registerField={register('proposalDescription', {
|
|
||||||
required: t('Required'),
|
|
||||||
})}
|
|
||||||
errorMessage={errors?.proposalDescription?.message}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<ProposalFormSubheader>
|
|
||||||
{t('SelectAMarketToChange')}
|
|
||||||
</ProposalFormSubheader>
|
|
||||||
|
|
||||||
<FormGroup
|
|
||||||
label={t('SelectAMarketToChange')}
|
|
||||||
labelFor="proposal-market"
|
|
||||||
hideLabel={true}
|
|
||||||
>
|
>
|
||||||
<Select
|
<option value="">{t('SelectMarket')}</option>
|
||||||
data-testid="proposal-market-select"
|
{sortedMarkets.map((market) => (
|
||||||
id="proposal-market"
|
<option value={market.id} key={market.id}>
|
||||||
{...register('proposalMarketId', {
|
{market.tradableInstrument.instrument.name}
|
||||||
required: t('Required'),
|
</option>
|
||||||
})}
|
))}
|
||||||
onChange={(e) => setSelectedMarket(e.target.value)}
|
</Select>
|
||||||
>
|
{errors?.proposalMarketId?.message && (
|
||||||
<option value="">{t('SelectMarket')}</option>
|
<InputError intent="danger">
|
||||||
{sortedMarkets.map((market) => (
|
{errors?.proposalMarketId?.message}
|
||||||
<option value={market.id} key={market.id}>
|
</InputError>
|
||||||
{market.tradableInstrument.instrument.name}
|
|
||||||
</option>
|
|
||||||
))}
|
|
||||||
</Select>
|
|
||||||
{errors?.proposalMarketId?.message && (
|
|
||||||
<InputError intent="danger">
|
|
||||||
{errors?.proposalMarketId?.message}
|
|
||||||
</InputError>
|
|
||||||
)}
|
|
||||||
</FormGroup>
|
|
||||||
|
|
||||||
{selectedMarket && (
|
|
||||||
<div className="mt-[-20px] mb-6">
|
|
||||||
<KeyValueTable data-testid="update-market-details">
|
|
||||||
<KeyValueTableRow>
|
|
||||||
{t('MarketName')}
|
|
||||||
{
|
|
||||||
marketsData?.marketsConnection?.edges?.find(
|
|
||||||
({ node: market }) => market.id === selectedMarket
|
|
||||||
)?.node.tradableInstrument.instrument.name
|
|
||||||
}
|
|
||||||
</KeyValueTableRow>
|
|
||||||
<KeyValueTableRow>
|
|
||||||
{t('MarketCode')}
|
|
||||||
{
|
|
||||||
marketsData?.marketsConnection?.edges?.find(
|
|
||||||
({ node: market }) => market.id === selectedMarket
|
|
||||||
)?.node.tradableInstrument.instrument.code
|
|
||||||
}
|
|
||||||
</KeyValueTableRow>
|
|
||||||
<KeyValueTableRow>
|
|
||||||
{t('MarketId')}
|
|
||||||
{selectedMarket}
|
|
||||||
</KeyValueTableRow>
|
|
||||||
</KeyValueTable>
|
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
|
</FormGroup>
|
||||||
|
|
||||||
<ProposalFormTerms
|
{selectedMarket && (
|
||||||
registerField={register('proposalTerms', {
|
<div className="mt-[-20px] mb-6">
|
||||||
required: t('Required'),
|
<KeyValueTable data-testid="update-market-details">
|
||||||
validate: (value) => validateJson(value),
|
<KeyValueTableRow>
|
||||||
})}
|
{t('MarketName')}
|
||||||
labelOverride={t('ProposeUpdateMarketTerms')}
|
{
|
||||||
errorMessage={errors?.proposalTerms?.message}
|
data.marketsConnection?.edges?.find(
|
||||||
docsLink={DOCS_LINK}
|
({ node: market }) => market.id === selectedMarket
|
||||||
/>
|
)?.node.tradableInstrument.instrument.name
|
||||||
|
}
|
||||||
|
</KeyValueTableRow>
|
||||||
|
<KeyValueTableRow>
|
||||||
|
{t('MarketCode')}
|
||||||
|
{
|
||||||
|
data.marketsConnection?.edges?.find(
|
||||||
|
({ node: market }) => market.id === selectedMarket
|
||||||
|
)?.node.tradableInstrument.instrument.code
|
||||||
|
}
|
||||||
|
</KeyValueTableRow>
|
||||||
|
<KeyValueTableRow>
|
||||||
|
{t('MarketId')}
|
||||||
|
{selectedMarket}
|
||||||
|
</KeyValueTableRow>
|
||||||
|
</KeyValueTable>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<ProposalFormVoteAndEnactmentDeadline
|
<ProposalFormTerms
|
||||||
onVoteMinMax={setValue}
|
registerField={register('proposalTerms', {
|
||||||
voteRegister={register('proposalVoteDeadline', {
|
required: t('Required'),
|
||||||
required: t('Required'),
|
validate: (value) => validateJson(value),
|
||||||
})}
|
})}
|
||||||
voteErrorMessage={errors?.proposalVoteDeadline?.message}
|
labelOverride={t('ProposeUpdateMarketTerms')}
|
||||||
voteMinClose={
|
errorMessage={errors?.proposalTerms?.message}
|
||||||
params.governance_proposal_updateMarket_minClose
|
docsLink={DOCS_LINK}
|
||||||
}
|
/>
|
||||||
voteMaxClose={
|
|
||||||
params.governance_proposal_updateMarket_maxClose
|
|
||||||
}
|
|
||||||
onEnactMinMax={setValue}
|
|
||||||
enactmentRegister={register('proposalEnactmentDeadline', {
|
|
||||||
required: t('Required'),
|
|
||||||
})}
|
|
||||||
enactmentErrorMessage={
|
|
||||||
errors?.proposalEnactmentDeadline?.message
|
|
||||||
}
|
|
||||||
enactmentMinClose={
|
|
||||||
params.governance_proposal_updateMarket_minEnact
|
|
||||||
}
|
|
||||||
enactmentMaxClose={
|
|
||||||
params.governance_proposal_updateMarket_maxEnact
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<ProposalFormSubmit isSubmitting={isSubmitting} />
|
<ProposalFormVoteAndEnactmentDeadline
|
||||||
<ProposalFormTransactionDialog
|
onVoteMinMax={setValue}
|
||||||
finalizedProposal={finalizedProposal}
|
voteRegister={register('proposalVoteDeadline', {
|
||||||
TransactionDialog={Dialog}
|
required: t('Required'),
|
||||||
/>
|
})}
|
||||||
</form>
|
voteErrorMessage={errors?.proposalVoteDeadline?.message}
|
||||||
</div>
|
voteMinClose={data.governance_proposal_updateMarket_minClose}
|
||||||
</>
|
voteMaxClose={data.governance_proposal_updateMarket_maxClose}
|
||||||
)}
|
onEnactMinMax={setValue}
|
||||||
</VegaWalletContainer>
|
enactmentRegister={register('proposalEnactmentDeadline', {
|
||||||
</AsyncRenderer>
|
required: t('Required'),
|
||||||
|
})}
|
||||||
|
enactmentErrorMessage={
|
||||||
|
errors?.proposalEnactmentDeadline?.message
|
||||||
|
}
|
||||||
|
enactmentMinClose={
|
||||||
|
data.governance_proposal_updateMarket_minEnact
|
||||||
|
}
|
||||||
|
enactmentMaxClose={
|
||||||
|
data.governance_proposal_updateMarket_maxEnact
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ProposalFormSubmit isSubmitting={isSubmitting} />
|
||||||
|
<ProposalFormDownloadJson downloadJson={viewJson} />
|
||||||
|
<ProposalFormTransactionDialog
|
||||||
|
finalizedProposal={finalizedProposal}
|
||||||
|
TransactionDialog={Dialog}
|
||||||
|
/>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user