allow nym node config updates (#5066)
This commit is contained in:
@@ -3,7 +3,7 @@ import { CurrencyDenom } from '@nymproject/types';
|
||||
import { TBondNymNodeArgs, TBondMixNodeArgs } from 'src/types';
|
||||
|
||||
const defaultNymNodeValues: TBondNymNodeArgs['nymnode'] = {
|
||||
identity_key: 'H6rXWgsW89QsVyaNSS3qBe9zZFLhBS6Gn3YRkGFSoFW9',
|
||||
identity_key: '',
|
||||
custom_http_port: null,
|
||||
host: '1.1.1.1',
|
||||
};
|
||||
|
||||
@@ -1,31 +1,12 @@
|
||||
import React from 'react';
|
||||
import * as yup from 'yup';
|
||||
import * as Yup from 'yup';
|
||||
import { Stack, TextField, FormControlLabel, Checkbox } from '@mui/material';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { IdentityKeyFormField } from '@nymproject/react/mixnodes/IdentityKeyFormField';
|
||||
import { yupResolver } from '@hookform/resolvers/yup';
|
||||
import { isValidHostname, validateRawPort } from 'src/utils';
|
||||
import { SimpleModal } from 'src/components/Modals/SimpleModal';
|
||||
import { useFormContext } from './FormContext';
|
||||
|
||||
const yupValidationSchema = yup.object().shape({
|
||||
identity_key: yup.string().required('Identity key is required'),
|
||||
host: yup
|
||||
.string()
|
||||
.required('A host is required')
|
||||
.test('no-whitespace', 'Host cannot contain whitespace', (value) => !/\s/.test(value || ''))
|
||||
.test('valid-host', 'A valid host is required', (value) => (value ? isValidHostname(value) : false)),
|
||||
|
||||
custom_http_port: yup
|
||||
.number()
|
||||
.nullable()
|
||||
.test('valid-http', 'A valid http port is required', (value) => {
|
||||
if (value === null) {
|
||||
return true;
|
||||
}
|
||||
return value ? validateRawPort(value) : false;
|
||||
}),
|
||||
});
|
||||
import { settingsValidationSchema } from './settingsValidationSchema';
|
||||
|
||||
type NymNodeDataProps = {
|
||||
onClose: () => void;
|
||||
@@ -34,6 +15,11 @@ type NymNodeDataProps = {
|
||||
step: number;
|
||||
};
|
||||
|
||||
const validationSchema = Yup.object().shape({
|
||||
identity_key: Yup.string().required('Identity key is required'),
|
||||
...settingsValidationSchema.fields,
|
||||
});
|
||||
|
||||
const NymNodeData = ({ onClose, onNext, step }: NymNodeDataProps) => {
|
||||
const { setNymNodeData, nymNodeData } = useFormContext();
|
||||
const {
|
||||
@@ -44,7 +30,7 @@ const NymNodeData = ({ onClose, onNext, step }: NymNodeDataProps) => {
|
||||
} = useForm({
|
||||
mode: 'all',
|
||||
defaultValues: nymNodeData,
|
||||
resolver: yupResolver(yupValidationSchema),
|
||||
resolver: yupResolver(validationSchema),
|
||||
});
|
||||
|
||||
const [showAdvancedOptions, setShowAdvancedOptions] = React.useState(false);
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
import { isValidHostname, validateRawPort } from 'src/utils';
|
||||
import * as Yup from 'yup';
|
||||
|
||||
const settingsValidationSchema = Yup.object().shape({
|
||||
host: Yup.string()
|
||||
.required('A host is required')
|
||||
.test('no-whitespace', 'Host cannot contain whitespace', (value) => !/\s/.test(value || ''))
|
||||
.test('valid-host', 'A valid host is required', (value) => (value ? isValidHostname(value) : false)),
|
||||
|
||||
custom_http_port: Yup.number()
|
||||
.nullable()
|
||||
.test('valid-http', 'A valid http port is required', (value) => {
|
||||
if (value === null) {
|
||||
return true;
|
||||
}
|
||||
return value ? validateRawPort(value) : false;
|
||||
}),
|
||||
});
|
||||
|
||||
export { settingsValidationSchema };
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
migrateLegacyMixnode as migrateLegacyMixnodeReq,
|
||||
migrateLegacyGateway as migrateLegacyGatewayReq,
|
||||
bondNymNode,
|
||||
updateNymNodeConfig as updateNymNodeConfigReq,
|
||||
} from '../requests';
|
||||
|
||||
export type TBondedNode = TBondedMixnode | TBondedGateway | TBondedNymNode;
|
||||
@@ -34,6 +35,10 @@ export type TBondingContext = {
|
||||
unbond: (fee?: FeeDetails) => Promise<TransactionExecuteResult | undefined>;
|
||||
bond: (args: TBondNymNodeArgs) => Promise<TransactionExecuteResult | undefined>;
|
||||
updateBondAmount: (data: TUpdateBondArgs) => Promise<TransactionExecuteResult | undefined>;
|
||||
updateNymNodeConfig: (data: {
|
||||
host: string;
|
||||
custom_http_port: number | null;
|
||||
}) => Promise<TransactionExecuteResult | undefined>;
|
||||
redeemRewards: (fee?: FeeDetails) => Promise<TransactionExecuteResult | undefined>;
|
||||
generateNymNodeMsgPayload: (data: TNymNodeSignatureArgs) => Promise<string | undefined>;
|
||||
migrateVestedMixnode: () => Promise<TransactionExecuteResult | undefined>;
|
||||
@@ -52,6 +57,9 @@ export const BondingContext = createContext<TBondingContext>({
|
||||
updateBondAmount: async () => {
|
||||
throw new Error('Not implemented');
|
||||
},
|
||||
updateNymNodeConfig: async () => {
|
||||
throw new Error('Not implemented');
|
||||
},
|
||||
redeemRewards: async () => {
|
||||
throw new Error('Not implemented');
|
||||
},
|
||||
@@ -140,6 +148,23 @@ export const BondingContextProvider: FCWithChildren = ({ children }): JSX.Elemen
|
||||
return tx;
|
||||
};
|
||||
|
||||
const updateNymNodeConfig = async (data: { host: string; custom_http_port: number | null }) => {
|
||||
let tx;
|
||||
setIsLoading(true);
|
||||
try {
|
||||
tx = await updateNymNodeConfigReq(data);
|
||||
if (clientDetails?.client_address) {
|
||||
await getNodeDetails(clientDetails?.client_address);
|
||||
}
|
||||
} catch (e) {
|
||||
Console.warn(e);
|
||||
setError(`an error occurred: ${e}`);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
return tx;
|
||||
};
|
||||
|
||||
const redeemRewards = async (fee?: FeeDetails) => {
|
||||
let tx;
|
||||
setIsLoading(true);
|
||||
@@ -225,6 +250,7 @@ export const BondingContextProvider: FCWithChildren = ({ children }): JSX.Elemen
|
||||
refresh,
|
||||
redeemRewards,
|
||||
updateBondAmount,
|
||||
updateNymNodeConfig,
|
||||
generateNymNodeMsgPayload,
|
||||
migrateVestedMixnode,
|
||||
migrateLegacyNode,
|
||||
|
||||
@@ -149,6 +149,14 @@ export const MockBondingContextProvider = ({
|
||||
return TxResultMock;
|
||||
};
|
||||
|
||||
const updateNymNodeConfig = async (): Promise<TransactionExecuteResult> => {
|
||||
setIsLoading(true);
|
||||
await mockSleep(SLEEP_MS);
|
||||
triggerStateUpdate();
|
||||
setIsLoading(false);
|
||||
return TxResultMock;
|
||||
};
|
||||
|
||||
const redeemRewards = async (): Promise<TransactionExecuteResult | undefined> => {
|
||||
setIsLoading(true);
|
||||
await mockSleep(SLEEP_MS);
|
||||
@@ -212,6 +220,7 @@ export const MockBondingContextProvider = ({
|
||||
isVestingAccount: false,
|
||||
migrateVestedMixnode: async () => undefined,
|
||||
migrateLegacyNode: async () => undefined,
|
||||
updateNymNodeConfig,
|
||||
}),
|
||||
[isLoading, error, bondedMixnode, bondedGateway, trigger, fee],
|
||||
);
|
||||
|
||||
+20
-24
@@ -3,22 +3,21 @@ import { useForm } from 'react-hook-form';
|
||||
import { yupResolver } from '@hookform/resolvers/yup';
|
||||
import { Box, Button, Divider, Grid, Stack, TextField, Typography } from '@mui/material';
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import { updateNymNodeConfig } from 'src/requests';
|
||||
import { SimpleModal } from 'src/components/Modals/SimpleModal';
|
||||
import { bondedInfoParametersValidationSchema } from 'src/components/Bonding/forms/legacyForms/mixnodeValidationSchema';
|
||||
import { Console } from 'src/utils/console';
|
||||
import { Alert } from 'src/components/Alert';
|
||||
import { ConfirmTx } from 'src/components/ConfirmTX';
|
||||
import { useGetFee } from 'src/hooks/useGetFee';
|
||||
import { LoadingModal } from 'src/components/Modals/LoadingModal';
|
||||
import { BalanceWarning } from 'src/components/FeeWarning';
|
||||
import { AppContext } from 'src/context';
|
||||
import { AppContext, useBondingContext } from 'src/context';
|
||||
import { TBondedNymNode } from 'src/requests/nymNodeDetails';
|
||||
import { settingsValidationSchema } from 'src/components/Bonding/forms/nym-node/settingsValidationSchema';
|
||||
|
||||
export const GeneralNymNodeSettings = ({ bondedNode }: { bondedNode: TBondedNymNode }) => {
|
||||
const [openConfirmationModal, setOpenConfirmationModal] = useState<boolean>(false);
|
||||
const { fee, resetFeeState } = useGetFee();
|
||||
const { userBalance } = useContext(AppContext);
|
||||
const { updateNymNodeConfig } = useBondingContext();
|
||||
|
||||
const theme = useTheme();
|
||||
|
||||
@@ -27,28 +26,26 @@ export const GeneralNymNodeSettings = ({ bondedNode }: { bondedNode: TBondedNymN
|
||||
handleSubmit,
|
||||
formState: { errors, isSubmitting, isDirty, isValid },
|
||||
} = useForm({
|
||||
resolver: yupResolver(bondedInfoParametersValidationSchema),
|
||||
resolver: yupResolver(settingsValidationSchema),
|
||||
mode: 'onChange',
|
||||
defaultValues: {
|
||||
host: bondedNode.host,
|
||||
customHttpPort: bondedNode.customHttpPort,
|
||||
custom_http_port: bondedNode.customHttpPort,
|
||||
},
|
||||
});
|
||||
|
||||
const onSubmit = async (data: { host?: string; customHttpPort?: number | null }) => {
|
||||
const onSubmit = async ({ host, custom_http_port }: { host: string; custom_http_port: number | null }) => {
|
||||
resetFeeState();
|
||||
const { host, customHttpPort } = data;
|
||||
if (host && customHttpPort) {
|
||||
|
||||
try {
|
||||
const NymNodeConfigParams = {
|
||||
host,
|
||||
custom_http_port: customHttpPort,
|
||||
custom_http_port,
|
||||
};
|
||||
try {
|
||||
await updateNymNodeConfig(NymNodeConfigParams);
|
||||
setOpenConfirmationModal(true);
|
||||
} catch (error) {
|
||||
Console.error(error);
|
||||
}
|
||||
await updateNymNodeConfig(NymNodeConfigParams);
|
||||
setOpenConfirmationModal(true);
|
||||
} catch (error) {
|
||||
Console.error(error);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -59,7 +56,7 @@ export const GeneralNymNodeSettings = ({ bondedNode }: { bondedNode: TBondedNymN
|
||||
open
|
||||
header="Update node settings"
|
||||
fee={fee}
|
||||
onConfirm={handleSubmit((d) => onSubmit(d))}
|
||||
onConfirm={handleSubmit(onSubmit)}
|
||||
onPrev={resetFeeState}
|
||||
onClose={resetFeeState}
|
||||
>
|
||||
@@ -70,7 +67,6 @@ export const GeneralNymNodeSettings = ({ bondedNode }: { bondedNode: TBondedNymN
|
||||
)}
|
||||
</ConfirmTx>
|
||||
)}
|
||||
{isSubmitting && <LoadingModal />}
|
||||
<Alert
|
||||
title={
|
||||
<Stack>
|
||||
@@ -93,12 +89,12 @@ export const GeneralNymNodeSettings = ({ bondedNode }: { bondedNode: TBondedNymN
|
||||
<Grid spacing={3} item container alignItems="center" xs={12} md={6}>
|
||||
<Grid item width={1}>
|
||||
<TextField
|
||||
{...register('customHttpPort')}
|
||||
name="customHttpPort"
|
||||
{...register('custom_http_port')}
|
||||
name="custom_http_port"
|
||||
label="Custom HTTP port"
|
||||
fullWidth
|
||||
error={!!errors.customHttpPort}
|
||||
helperText={errors.customHttpPort?.message}
|
||||
error={!!errors.custom_http_port}
|
||||
helperText={errors.custom_http_port?.message}
|
||||
InputLabelProps={{ shrink: true }}
|
||||
/>
|
||||
</Grid>
|
||||
@@ -134,7 +130,7 @@ export const GeneralNymNodeSettings = ({ bondedNode }: { bondedNode: TBondedNymN
|
||||
size="large"
|
||||
variant="contained"
|
||||
disabled={isSubmitting || !isDirty || !isValid}
|
||||
onClick={handleSubmit(() => undefined)}
|
||||
onClick={handleSubmit(onSubmit)}
|
||||
sx={{ m: 3, mr: 0 }}
|
||||
fullWidth
|
||||
>
|
||||
@@ -152,7 +148,7 @@ export const GeneralNymNodeSettings = ({ bondedNode }: { bondedNode: TBondedNymN
|
||||
hideCloseIcon
|
||||
displayInfoIcon
|
||||
onOk={async () => {
|
||||
await setOpenConfirmationModal(false);
|
||||
setOpenConfirmationModal(false);
|
||||
}}
|
||||
buttonFullWidth
|
||||
sx={{
|
||||
|
||||
@@ -86,7 +86,7 @@ export type TNodeDescription = {
|
||||
|
||||
export type TNodeConfigUpdateArgs = {
|
||||
host: string;
|
||||
custom_http_port: number;
|
||||
custom_http_port: number | null;
|
||||
};
|
||||
|
||||
export type TDelegateArgs = {
|
||||
|
||||
Reference in New Issue
Block a user