mirror of
https://github.com/haveno-dex/haveno-ui.git
synced 2025-06-20 12:24:11 -04:00
feat: Account > Node Settings screen
This commit is contained in:
parent
ba4b634aaa
commit
bc6ed842d5
17 changed files with 556 additions and 39 deletions
|
@ -39,6 +39,10 @@ export enum LangKeys {
|
||||||
AccountNodeFieldDeamonFlags = "account.nodeSecurity.deamonFlags",
|
AccountNodeFieldDeamonFlags = "account.nodeSecurity.deamonFlags",
|
||||||
AccountNodeFieldPort = "account.nodeSecurity.port",
|
AccountNodeFieldPort = "account.nodeSecurity.port",
|
||||||
AccountNodeStopDeamon = "account.nodeSecurity.stopDeamon",
|
AccountNodeStopDeamon = "account.nodeSecurity.stopDeamon",
|
||||||
|
AccountNodeStartDeamon = "account.nodeSecurity.startDeamon",
|
||||||
|
AccountNodeLocalSaveNotification = "account.nodeSecurity.saveNotification",
|
||||||
|
AccountNodeDeamonStoppedNotif = "account.nodeSecurity.stoppedNotification",
|
||||||
|
AccountNodeDeamonStartedNotif = "account.nodeSecurity.startedNotification",
|
||||||
AccountSettingsAddNode = "account.settings.addNewNode",
|
AccountSettingsAddNode = "account.settings.addNewNode",
|
||||||
AccountSettingsCurrent = "account.settings.current",
|
AccountSettingsCurrent = "account.settings.current",
|
||||||
AccountSecurityFieldPassword = "account.security.field.password",
|
AccountSecurityFieldPassword = "account.security.field.password",
|
||||||
|
|
|
@ -43,6 +43,11 @@ const LangPackEN: { [key in LangKeys]: string } = {
|
||||||
[LangKeys.AccountNodeFieldPort]: "Port",
|
[LangKeys.AccountNodeFieldPort]: "Port",
|
||||||
[LangKeys.AccountNodeFieldDeamonFlags]: "Deamon startup flags",
|
[LangKeys.AccountNodeFieldDeamonFlags]: "Deamon startup flags",
|
||||||
[LangKeys.AccountNodeStopDeamon]: "Stop deamon",
|
[LangKeys.AccountNodeStopDeamon]: "Stop deamon",
|
||||||
|
[LangKeys.AccountNodeStartDeamon]: "Start deamon",
|
||||||
|
[LangKeys.AccountNodeLocalSaveNotification]:
|
||||||
|
"Local node settings updated successfully",
|
||||||
|
[LangKeys.AccountNodeDeamonStoppedNotif]: "Deamon stopped successfully",
|
||||||
|
[LangKeys.AccountNodeDeamonStartedNotif]: "Deamon started successfully",
|
||||||
[LangKeys.AccountSettingsAddNode]: "Add a new node",
|
[LangKeys.AccountSettingsAddNode]: "Add a new node",
|
||||||
[LangKeys.AccountSettingsCurrent]: "Current",
|
[LangKeys.AccountSettingsCurrent]: "Current",
|
||||||
[LangKeys.AccountSecurityFieldPassword]: "Update account password",
|
[LangKeys.AccountSecurityFieldPassword]: "Update account password",
|
||||||
|
|
|
@ -44,6 +44,11 @@ const LangPackES: { [key in LangKeys]: string } = {
|
||||||
[LangKeys.AccountNodeFieldPort]: "Puerto",
|
[LangKeys.AccountNodeFieldPort]: "Puerto",
|
||||||
[LangKeys.AccountNodeFieldDeamonFlags]: "Indicadores de inicio de daemon",
|
[LangKeys.AccountNodeFieldDeamonFlags]: "Indicadores de inicio de daemon",
|
||||||
[LangKeys.AccountNodeStopDeamon]: "Detener demonio",
|
[LangKeys.AccountNodeStopDeamon]: "Detener demonio",
|
||||||
|
[LangKeys.AccountNodeStartDeamon]: "Comienzo demonio",
|
||||||
|
[LangKeys.AccountNodeLocalSaveNotification]:
|
||||||
|
"La configuración del nodo local se actualizó correctamente.",
|
||||||
|
[LangKeys.AccountNodeDeamonStoppedNotif]: "Daemon se detuvo con éxito",
|
||||||
|
[LangKeys.AccountNodeDeamonStartedNotif]: "Daemon se inició con éxito",
|
||||||
[LangKeys.AccountSettingsAddNode]: "Agregar un nuevo nodo",
|
[LangKeys.AccountSettingsAddNode]: "Agregar un nuevo nodo",
|
||||||
[LangKeys.AccountSettingsCurrent]: "Actual",
|
[LangKeys.AccountSettingsCurrent]: "Actual",
|
||||||
[LangKeys.AccountSecurityFieldPassword]: "Clave",
|
[LangKeys.AccountSecurityFieldPassword]: "Clave",
|
||||||
|
|
|
@ -18,6 +18,10 @@ export enum QueryKeys {
|
||||||
HavenoVersion = "Haveno.Version",
|
HavenoVersion = "Haveno.Version",
|
||||||
Balances = "Haveno.Balances",
|
Balances = "Haveno.Balances",
|
||||||
PaymentAccounts = "Haveno.PaymentAccounts",
|
PaymentAccounts = "Haveno.PaymentAccounts",
|
||||||
|
MoneroNodeSettings = "Haveno.MoneroNodeSettings",
|
||||||
|
MoneroNodeIsRunning = "Haveno.MoneroNodeIsRunning",
|
||||||
|
MoneroRemoteNodes = "Haveno.MoneroRemoteNodes",
|
||||||
|
|
||||||
SyncStatus = "Haveno.SyncStatus",
|
SyncStatus = "Haveno.SyncStatus",
|
||||||
|
|
||||||
StorageAccountInfo = "Storage.AccountInfo",
|
StorageAccountInfo = "Storage.AccountInfo",
|
||||||
|
|
27
packages/renderer/src/hooks/haveno/useIsMoneroNodeRunning.ts
Normal file
27
packages/renderer/src/hooks/haveno/useIsMoneroNodeRunning.ts
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
// =============================================================================
|
||||||
|
// Copyright 2022 Haveno
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
import { useQuery } from "react-query";
|
||||||
|
import { QueryKeys } from "@constants/query-keys";
|
||||||
|
import { useHavenoClient } from "./useHavenoClient";
|
||||||
|
|
||||||
|
export function useIsMoneroNodeRunning() {
|
||||||
|
const client = useHavenoClient();
|
||||||
|
|
||||||
|
return useQuery<boolean, Error>(QueryKeys.MoneroNodeIsRunning, () =>
|
||||||
|
client.isMoneroNodeRunning()
|
||||||
|
);
|
||||||
|
}
|
31
packages/renderer/src/hooks/haveno/useMoneroNodeSettings.ts
Normal file
31
packages/renderer/src/hooks/haveno/useMoneroNodeSettings.ts
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
// =============================================================================
|
||||||
|
// Copyright 2022 Haveno
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
import { QueryKeys } from "@constants/query-keys";
|
||||||
|
import type { MoneroNodeSettings } from "haveno-ts";
|
||||||
|
import { useQuery } from "react-query";
|
||||||
|
import { useHavenoClient } from "./useHavenoClient";
|
||||||
|
|
||||||
|
export function useMoneroNodeSettings() {
|
||||||
|
const client = useHavenoClient();
|
||||||
|
|
||||||
|
return useQuery<MoneroNodeSettings | undefined, Error>(
|
||||||
|
QueryKeys.MoneroNodeSettings,
|
||||||
|
async () => {
|
||||||
|
return client.getMoneroNodeSettings();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
39
packages/renderer/src/hooks/haveno/useMoneroRemoteNodes.ts
Normal file
39
packages/renderer/src/hooks/haveno/useMoneroRemoteNodes.ts
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
// =============================================================================
|
||||||
|
// Copyright 2022 Haveno
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
import { useQuery } from "react-query";
|
||||||
|
import { QueryKeys } from "@constants/query-keys";
|
||||||
|
// import { useHavenoClient } from "./useHavenoClient";
|
||||||
|
|
||||||
|
interface MoneroRemoteNodes {
|
||||||
|
title: string;
|
||||||
|
isActive: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useMoneroRemoteNodes() {
|
||||||
|
// const client = useHavenoClient();
|
||||||
|
|
||||||
|
return useQuery<MoneroRemoteNodes[], Error>(
|
||||||
|
QueryKeys.MoneroRemoteNodes,
|
||||||
|
async () => {
|
||||||
|
return Promise.resolve([
|
||||||
|
{ title: "node.moneroworldcom:18089", isActive: true },
|
||||||
|
{ title: "node.xmr.pt:18081", isActive: true },
|
||||||
|
{ title: "node.monero.net:18081", isActive: true },
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
// =============================================================================
|
||||||
|
// Copyright 2022 Haveno
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
import { useMutation, useQueryClient } from "react-query";
|
||||||
|
import { QueryKeys } from "@constants/query-keys";
|
||||||
|
import { useHavenoClient } from "./useHavenoClient";
|
||||||
|
|
||||||
|
interface SetMeneroNodeSettingsVariables {
|
||||||
|
blockchainPath?: string;
|
||||||
|
bootstrapUrl?: string;
|
||||||
|
startupFlags?: Array<string>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useSetMoneroNodeSettings() {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
const client = useHavenoClient();
|
||||||
|
|
||||||
|
return useMutation(
|
||||||
|
async (data: SetMeneroNodeSettingsVariables) => {
|
||||||
|
const nodeSettings = await client.getMoneroNodeSettings();
|
||||||
|
|
||||||
|
data.blockchainPath &&
|
||||||
|
nodeSettings?.setBlockchainPath(data.blockchainPath);
|
||||||
|
data.startupFlags && nodeSettings?.setStartupFlagsList(data.startupFlags);
|
||||||
|
data.bootstrapUrl && nodeSettings?.setBootstrapUrl(data.bootstrapUrl);
|
||||||
|
},
|
||||||
|
{
|
||||||
|
onSuccess: () => {
|
||||||
|
queryClient.invalidateQueries(QueryKeys.MoneroNodeSettings);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
34
packages/renderer/src/hooks/haveno/useStartMoneroNode.ts
Normal file
34
packages/renderer/src/hooks/haveno/useStartMoneroNode.ts
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
// =============================================================================
|
||||||
|
// Copyright 2022 Haveno
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
import { QueryKeys } from "@constants/query-keys";
|
||||||
|
import type { MoneroNodeSettings } from "haveno-ts";
|
||||||
|
import { useMutation, useQueryClient } from "react-query";
|
||||||
|
import { useHavenoClient } from "./useHavenoClient";
|
||||||
|
|
||||||
|
export function useStartMoneroNode() {
|
||||||
|
const client = useHavenoClient();
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation<void, Error, MoneroNodeSettings>(
|
||||||
|
(data: MoneroNodeSettings) => client.startMoneroNode(data),
|
||||||
|
{
|
||||||
|
onSuccess: () => {
|
||||||
|
queryClient.invalidateQueries(QueryKeys.MoneroNodeIsRunning);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
30
packages/renderer/src/hooks/haveno/useStopMoneroNode.ts
Normal file
30
packages/renderer/src/hooks/haveno/useStopMoneroNode.ts
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
// =============================================================================
|
||||||
|
// Copyright 2022 Haveno
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
import { QueryKeys } from "@constants/query-keys";
|
||||||
|
import { useMutation, useQueryClient } from "react-query";
|
||||||
|
import { useHavenoClient } from "./useHavenoClient";
|
||||||
|
|
||||||
|
export function useStopMoneroNode() {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
const client = useHavenoClient();
|
||||||
|
|
||||||
|
return useMutation(() => client.stopMoneroNode(), {
|
||||||
|
onSuccess: () => {
|
||||||
|
queryClient.invalidateQueries(QueryKeys.MoneroNodeIsRunning);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
|
@ -14,28 +14,70 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
||||||
import { Box, Stack, Grid, createStyles } from "@mantine/core";
|
import { Box, Stack, Grid, Group } from "@mantine/core";
|
||||||
import { useForm } from "@mantine/form";
|
import { joiResolver, useForm } from "@mantine/form";
|
||||||
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
import { showNotification } from "@mantine/notifications";
|
||||||
import { Button } from "@atoms/Buttons";
|
import { Button } from "@atoms/Buttons";
|
||||||
import { FormattedMessage } from "react-intl";
|
|
||||||
import { LangKeys } from "@constants/lang";
|
import { LangKeys } from "@constants/lang";
|
||||||
import { TextInput } from "@atoms/TextInput";
|
import { TextInput } from "@atoms/TextInput";
|
||||||
|
import { useMoneroNodeSettings } from "@hooks/haveno/useMoneroNodeSettings";
|
||||||
|
import { useSetMoneroNodeSettings } from "@hooks/haveno/useSetMoneroNodeSettings";
|
||||||
|
import { NodeLocalStopDeamon } from "./NodeLocalStopDeamon";
|
||||||
|
import type { NodeLocalFormValues } from "./_hooks";
|
||||||
|
import { useNodeLocalFormValidation } from "./_hooks";
|
||||||
|
import { transformSettingsRequestToForm } from "./_utils";
|
||||||
|
|
||||||
export function NodeLocalForm() {
|
export function NodeLocalForm() {
|
||||||
const form = useForm({
|
const { data: nodeSettings } = useMoneroNodeSettings();
|
||||||
|
const { mutateAsync: updateNodeSettings } = useSetMoneroNodeSettings();
|
||||||
|
const intl = useIntl();
|
||||||
|
|
||||||
|
const validation = useNodeLocalFormValidation();
|
||||||
|
|
||||||
|
const form = useForm<NodeLocalFormValues>({
|
||||||
initialValues: {
|
initialValues: {
|
||||||
blockchainLocation: "",
|
blockchainLocation: "",
|
||||||
startupFlags: "",
|
startupFlags: "",
|
||||||
deamonAddress: "",
|
deamonAddress: "",
|
||||||
port: "",
|
port: "",
|
||||||
|
...(nodeSettings
|
||||||
|
? transformSettingsRequestToForm(nodeSettings.toObject())
|
||||||
|
: {}),
|
||||||
},
|
},
|
||||||
|
validate: joiResolver(validation),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const handleFormSubmit = (values: NodeLocalFormValues) => {
|
||||||
|
updateNodeSettings({
|
||||||
|
blockchainPath: values.blockchainLocation,
|
||||||
|
startupFlags: values.startupFlags.split(", "),
|
||||||
|
bootstrapUrl: `${values.deamonAddress}:${values.port}`,
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
showNotification({
|
||||||
|
color: "green",
|
||||||
|
message: intl.formatMessage({
|
||||||
|
id: LangKeys.AccountNodeLocalSaveNotification,
|
||||||
|
defaultMessage: "Local node settings updated successfully",
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.dir(err);
|
||||||
|
showNotification({
|
||||||
|
color: "red",
|
||||||
|
message: err.message,
|
||||||
|
title: "Something went wrong",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
<NodeLocalStopDeamon />
|
<NodeLocalStopDeamon />
|
||||||
|
|
||||||
<form onSubmit={form.onSubmit((values) => console.log(values))}>
|
<form onSubmit={form.onSubmit(handleFormSubmit)}>
|
||||||
<Stack spacing="lg">
|
<Stack spacing="lg">
|
||||||
<TextInput
|
<TextInput
|
||||||
id="blockchainLocation"
|
id="blockchainLocation"
|
||||||
|
@ -48,7 +90,7 @@ export function NodeLocalForm() {
|
||||||
{...form.getInputProps("blockchainLocation")}
|
{...form.getInputProps("blockchainLocation")}
|
||||||
/>
|
/>
|
||||||
<TextInput
|
<TextInput
|
||||||
id="deamonFlags"
|
id="startupFlags"
|
||||||
label={
|
label={
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id={LangKeys.AccountNodeFieldDeamonFlags}
|
id={LangKeys.AccountNodeFieldDeamonFlags}
|
||||||
|
@ -67,6 +109,7 @@ export function NodeLocalForm() {
|
||||||
defaultMessage="Deamon Address"
|
defaultMessage="Deamon Address"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
|
required
|
||||||
{...form.getInputProps("deamonAddress")}
|
{...form.getInputProps("deamonAddress")}
|
||||||
/>
|
/>
|
||||||
</Grid.Col>
|
</Grid.Col>
|
||||||
|
@ -79,33 +122,19 @@ export function NodeLocalForm() {
|
||||||
defaultMessage="Port"
|
defaultMessage="Port"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
|
required
|
||||||
{...form.getInputProps("port")}
|
{...form.getInputProps("port")}
|
||||||
/>
|
/>
|
||||||
</Grid.Col>
|
</Grid.Col>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
|
<Group position="right" mt="md">
|
||||||
|
<Button size="md" type="submit">
|
||||||
|
<FormattedMessage id={LangKeys.Save} defaultMessage="Save" />
|
||||||
|
</Button>
|
||||||
|
</Group>
|
||||||
</Stack>
|
</Stack>
|
||||||
</form>
|
</form>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function NodeLocalStopDeamon() {
|
|
||||||
const { classes } = useStyles();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={classes.actions}>
|
|
||||||
<Button flavor="neutral">
|
|
||||||
<FormattedMessage
|
|
||||||
id={LangKeys.AccountNodeStopDeamon}
|
|
||||||
defaultMessage="Stop deamon"
|
|
||||||
/>
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const useStyles = createStyles((theme) => ({
|
|
||||||
actions: {
|
|
||||||
marginBottom: theme.spacing.xl,
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
|
@ -0,0 +1,112 @@
|
||||||
|
// =============================================================================
|
||||||
|
// Copyright 2022 Haveno
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
import { createStyles } from "@mantine/core";
|
||||||
|
import { showNotification } from "@mantine/notifications";
|
||||||
|
import { Button } from "@atoms/Buttons";
|
||||||
|
import { LangKeys } from "@constants/lang";
|
||||||
|
import { useMoneroNodeSettings } from "@hooks/haveno/useMoneroNodeSettings";
|
||||||
|
import { useStopMoneroNode } from "@hooks/haveno/useStopMoneroNode";
|
||||||
|
import { useIsMoneroNodeRunning } from "@hooks/haveno/useIsMoneroNodeRunning";
|
||||||
|
import { useStartMoneroNode } from "@hooks/haveno/useStartMoneroNode";
|
||||||
|
|
||||||
|
export function NodeLocalStopDeamon() {
|
||||||
|
const { classes } = useStyles();
|
||||||
|
const intl = useIntl();
|
||||||
|
|
||||||
|
const { mutateAsync: stopMoneroNode } = useStopMoneroNode();
|
||||||
|
const { data: isMoneroNodeRunning } = useIsMoneroNodeRunning();
|
||||||
|
const { mutateAsync: startMoneroNode } = useStartMoneroNode();
|
||||||
|
const { isLoading: isNodeSettingsLoading, data: nodeSettings } =
|
||||||
|
useMoneroNodeSettings();
|
||||||
|
|
||||||
|
// handle the stop button click.
|
||||||
|
const handleStopBtnClick = () => {
|
||||||
|
stopMoneroNode()
|
||||||
|
.then(() => {
|
||||||
|
showNotification({
|
||||||
|
color: "green",
|
||||||
|
message: intl.formatMessage({
|
||||||
|
id: LangKeys.AccountNodeDeamonStoppedNotif,
|
||||||
|
defaultMessage: "Deamon stopped successfully",
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.dir(err);
|
||||||
|
showNotification({
|
||||||
|
color: "red",
|
||||||
|
message: err.message,
|
||||||
|
title: "Something went wrong",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
// Handle the start button click.
|
||||||
|
const handleStartBtnClick = () => {
|
||||||
|
if (!nodeSettings) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
startMoneroNode(nodeSettings)
|
||||||
|
.then(() => {
|
||||||
|
showNotification({
|
||||||
|
color: "green",
|
||||||
|
message: intl.formatMessage({
|
||||||
|
id: LangKeys.AccountNodeDeamonStartedNotif,
|
||||||
|
defaultMessage: "Deamon started successfully",
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.dir(err);
|
||||||
|
showNotification({
|
||||||
|
color: "red",
|
||||||
|
message: err.message,
|
||||||
|
title: "Something went wrong",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classes.actions}>
|
||||||
|
{isMoneroNodeRunning ? (
|
||||||
|
<Button flavor="neutral" onClick={handleStopBtnClick}>
|
||||||
|
<FormattedMessage
|
||||||
|
id={LangKeys.AccountNodeStopDeamon}
|
||||||
|
defaultMessage="Stop deamon"
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
) : (
|
||||||
|
<Button
|
||||||
|
flavor="neutral"
|
||||||
|
onClick={handleStartBtnClick}
|
||||||
|
disabled={Boolean(isNodeSettingsLoading || !nodeSettings)}
|
||||||
|
>
|
||||||
|
<FormattedMessage
|
||||||
|
id={LangKeys.AccountNodeStopDeamon}
|
||||||
|
defaultMessage="Start deamon"
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const useStyles = createStyles((theme) => ({
|
||||||
|
actions: {
|
||||||
|
marginBottom: theme.spacing.xl,
|
||||||
|
},
|
||||||
|
}));
|
|
@ -15,23 +15,26 @@
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
||||||
import { Stack, createStyles, Group } from "@mantine/core";
|
import { Stack, createStyles, Group } from "@mantine/core";
|
||||||
|
import { FormattedMessage } from "react-intl";
|
||||||
import { Button } from "@atoms/Buttons";
|
import { Button } from "@atoms/Buttons";
|
||||||
import { NodeStatus, NodeStatusType } from "@atoms/NodeStatus";
|
import { NodeStatus, NodeStatusType } from "@atoms/NodeStatus";
|
||||||
import { FormattedMessage } from "react-intl";
|
|
||||||
import { LangKeys } from "@constants/lang";
|
import { LangKeys } from "@constants/lang";
|
||||||
|
import { useMoneroRemoteNodes } from "@hooks/haveno/useMoneroRemoteNodes";
|
||||||
|
|
||||||
export function NodeRemoteStatus() {
|
export function NodeRemoteStatus() {
|
||||||
|
const { data: remoteNodes } = useMoneroRemoteNodes();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack>
|
<Stack>
|
||||||
|
{remoteNodes?.map((node) => (
|
||||||
<NodeStatus
|
<NodeStatus
|
||||||
title="node.moneroworldcom:18089"
|
key={node.title}
|
||||||
status={NodeStatusType.Active}
|
title={node.title}
|
||||||
/>
|
status={
|
||||||
<NodeStatus title="node.xmr.pt:18081" status={NodeStatusType.Inactive} />
|
node.isActive ? NodeStatusType.Active : NodeStatusType.Inactive
|
||||||
<NodeStatus
|
}
|
||||||
title="node.monero.net:18081"
|
|
||||||
status={NodeStatusType.Active}
|
|
||||||
/>
|
/>
|
||||||
|
))}
|
||||||
<AddNewNodeButton />
|
<AddNewNodeButton />
|
||||||
|
|
||||||
<Group position="right" mt="sm">
|
<Group position="right" mt="sm">
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
// =============================================================================
|
||||||
|
// Copyright 2022 Haveno
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
import type { ReactNode } from "react";
|
||||||
|
import { BodyText } from "@atoms/Typography";
|
||||||
|
import { useMoneroNodeSettings } from "@hooks/haveno/useMoneroNodeSettings";
|
||||||
|
import { useIsMoneroNodeRunning } from "@hooks/haveno/useIsMoneroNodeRunning";
|
||||||
|
import { useMoneroRemoteNodes } from "@hooks/haveno/useMoneroRemoteNodes";
|
||||||
|
|
||||||
|
interface NodeSettingsBootProps {
|
||||||
|
children: ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function LocalNodeSettingsBoot({ children }: NodeSettingsBootProps) {
|
||||||
|
const { isLoading: isNodeSettingsLoading } = useMoneroNodeSettings();
|
||||||
|
const { isLoading: isMoneroNodeIsLoading } = useIsMoneroNodeRunning();
|
||||||
|
|
||||||
|
return isNodeSettingsLoading || isMoneroNodeIsLoading ? (
|
||||||
|
<BodyText>Loading settings...</BodyText>
|
||||||
|
) : (
|
||||||
|
<>{children}</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RemoteNodeSettingsBootProps {
|
||||||
|
children: ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function RemoteNodeSettingsBoot({
|
||||||
|
children,
|
||||||
|
}: RemoteNodeSettingsBootProps) {
|
||||||
|
const { isLoading: isMoneroRemoteLoading } = useMoneroRemoteNodes();
|
||||||
|
|
||||||
|
return isMoneroRemoteLoading ? (
|
||||||
|
<BodyText>Loading settings...</BodyText>
|
||||||
|
) : (
|
||||||
|
<>{children}</>
|
||||||
|
);
|
||||||
|
}
|
|
@ -22,6 +22,10 @@ import { ReactComponent as CloudIcon } from "@assets/setting-cloud.svg";
|
||||||
import { ReactComponent as ServerIcon } from "@assets/setting-server.svg";
|
import { ReactComponent as ServerIcon } from "@assets/setting-server.svg";
|
||||||
import { NodeLocalForm } from "./NodeLocalForm";
|
import { NodeLocalForm } from "./NodeLocalForm";
|
||||||
import { NodeRemoteStatus } from "./NodeRemoteStatus";
|
import { NodeRemoteStatus } from "./NodeRemoteStatus";
|
||||||
|
import {
|
||||||
|
LocalNodeSettingsBoot,
|
||||||
|
RemoteNodeSettingsBoot,
|
||||||
|
} from "./NodeSettingsBoot";
|
||||||
|
|
||||||
export function NodeSettingsSwitch() {
|
export function NodeSettingsSwitch() {
|
||||||
const { classes } = useStyles();
|
const { classes } = useStyles();
|
||||||
|
@ -43,7 +47,9 @@ export function NodeSettingsSwitch() {
|
||||||
}
|
}
|
||||||
icon={<ServerIcon width={32} height={62} />}
|
icon={<ServerIcon width={32} height={62} />}
|
||||||
>
|
>
|
||||||
|
<LocalNodeSettingsBoot>
|
||||||
<NodeLocalForm />
|
<NodeLocalForm />
|
||||||
|
</LocalNodeSettingsBoot>
|
||||||
</NodeConnectSwitch.Method>
|
</NodeConnectSwitch.Method>
|
||||||
|
|
||||||
<NodeConnectSwitch.Method
|
<NodeConnectSwitch.Method
|
||||||
|
@ -56,7 +62,9 @@ export function NodeSettingsSwitch() {
|
||||||
}
|
}
|
||||||
icon={<CloudIcon width={58} height={54} />}
|
icon={<CloudIcon width={58} height={54} />}
|
||||||
>
|
>
|
||||||
|
<RemoteNodeSettingsBoot>
|
||||||
<NodeRemoteStatus />
|
<NodeRemoteStatus />
|
||||||
|
</RemoteNodeSettingsBoot>
|
||||||
</NodeConnectSwitch.Method>
|
</NodeConnectSwitch.Method>
|
||||||
</NodeConnectSwitch>
|
</NodeConnectSwitch>
|
||||||
);
|
);
|
||||||
|
|
33
packages/renderer/src/pages/Account/NodeSettings/_hooks.ts
Normal file
33
packages/renderer/src/pages/Account/NodeSettings/_hooks.ts
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
// =============================================================================
|
||||||
|
// Copyright 2022 Haveno
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
import * as Joi from "joi";
|
||||||
|
|
||||||
|
export interface NodeLocalFormValues {
|
||||||
|
blockchainLocation: string;
|
||||||
|
startupFlags: string;
|
||||||
|
deamonAddress: string;
|
||||||
|
port: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useNodeLocalFormValidation() {
|
||||||
|
return Joi.object<NodeLocalFormValues>({
|
||||||
|
blockchainLocation: Joi.string().empty("").uri({ relativeOnly: true }),
|
||||||
|
startupFlags: Joi.string().empty(""),
|
||||||
|
deamonAddress: Joi.string().uri({ allowRelative: false }),
|
||||||
|
port: Joi.number().port(),
|
||||||
|
});
|
||||||
|
}
|
55
packages/renderer/src/pages/Account/NodeSettings/_utils.ts
Normal file
55
packages/renderer/src/pages/Account/NodeSettings/_utils.ts
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
// =============================================================================
|
||||||
|
// Copyright 2022 Haveno
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
import type { MoneroNodeSettings } from "haveno-ts";
|
||||||
|
import type { NodeLocalFormValues } from "./_hooks";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transformes the settings request values to form.
|
||||||
|
* @param {MoneroNodeSettings.AsObject} nodeSettings
|
||||||
|
* @returns {NodeLocalFormValues}
|
||||||
|
*/
|
||||||
|
export function transformSettingsRequestToForm(
|
||||||
|
nodeSettings: MoneroNodeSettings.AsObject
|
||||||
|
): NodeLocalFormValues {
|
||||||
|
return {
|
||||||
|
blockchainLocation: nodeSettings?.blockchainPath || "",
|
||||||
|
startupFlags: nodeSettings?.startupFlagsList.join(", ") || "",
|
||||||
|
deamonAddress: transfromBootstrapUrl(nodeSettings?.bootstrapUrl || ""),
|
||||||
|
port: transformPort(nodeSettings?.bootstrapUrl || ""),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function transformPort(urlAsString: string) {
|
||||||
|
try {
|
||||||
|
const url = new URL(urlAsString);
|
||||||
|
return url.port;
|
||||||
|
} catch {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function transfromBootstrapUrl(urlAsString: string) {
|
||||||
|
try {
|
||||||
|
const url = new URL(urlAsString);
|
||||||
|
|
||||||
|
// Remove the port from url.
|
||||||
|
url.port = "";
|
||||||
|
return url.href;
|
||||||
|
} catch {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue