From e851e52591fe6d1411393eb906f9fecb7ea8c4ae Mon Sep 17 00:00:00 2001 From: corn-potage Date: Tue, 1 Nov 2022 18:23:40 -0700 Subject: [PATCH 1/6] sidebar WIP --- src/renderer/App.tsx | 4 +- src/renderer/Generics/redesign/utils.ts | 1 - .../Presentational/Sidebar/Sidebar.tsx | 64 +++++++++++++++++-- 3 files changed, 61 insertions(+), 8 deletions(-) diff --git a/src/renderer/App.tsx b/src/renderer/App.tsx index ee0a4a106..a6b3e2aee 100644 --- a/src/renderer/App.tsx +++ b/src/renderer/App.tsx @@ -13,6 +13,7 @@ import LeftSideBar from './LeftSideBar'; import NodeScreen from './NodeScreen'; import DataRefresher from './DataRefresher'; import electron from './electronGlobal'; +import Sidebar from './Presentational/Sidebar/Sidebar'; Sentry.init({ dsn: electron.SENTRY_DSN, @@ -53,7 +54,8 @@ const MainScreen = () => { flex: 1, }} > - + {/* */} +
{ let syncStatus = null; switch (true) { - // TODO: revisit this.. feels off or unnecessary // find worst cases first case status.updating: syncStatus = SYNC_STATUS.UPDATING; diff --git a/src/renderer/Presentational/Sidebar/Sidebar.tsx b/src/renderer/Presentational/Sidebar/Sidebar.tsx index 2157cdf2c..ad7cf6d4b 100644 --- a/src/renderer/Presentational/Sidebar/Sidebar.tsx +++ b/src/renderer/Presentational/Sidebar/Sidebar.tsx @@ -1,3 +1,11 @@ +import { NodeId } from 'common/node'; +import { useEffect } from 'react'; +import { + selectSelectedNodeId, + selectUserNodes, + updateSelectedNodeId, +} from 'renderer/state/node'; +import { useAppDispatch, useAppSelector } from 'renderer/state/hooks'; import { Banner } from '../../Generics/redesign/Banner/Banner'; import { SidebarNodeItem } from '../../Generics/redesign/SidebarNodeItem/SidebarNodeItem'; import { SidebarLinkItem } from '../../Generics/redesign/SidebarLinkItem/SidebarLinkItem'; @@ -66,6 +74,36 @@ const itemListData = [ ]; const Sidebar = ({ offline }: SidebarProps) => { + const sSelectedNodeId = useAppSelector(selectSelectedNodeId); + const sUserNodes = useAppSelector(selectUserNodes); + const dispatch = useAppDispatch(); + + // Default selected node to be the first node + useEffect(() => { + if ( + !sSelectedNodeId && + sUserNodes && + Array.isArray(sUserNodes?.nodeIds) && + sUserNodes.nodeIds.length > 0 + ) { + dispatch(updateSelectedNodeId(sUserNodes.nodeIds[0])); + } + }, [sSelectedNodeId, sUserNodes, dispatch]); + + const nodeListObject = { nodeService: [], validator: [], singleClients: [] }; + sUserNodes?.nodeIds.forEach((nodeId: NodeId) => { + const node = sUserNodes.nodes[nodeId]; + // TODO: add validator logic here eventually + if ( + node.spec.category === 'L1/ExecutionClient' || + node.spec.category === 'L1/ConsensusClient/BeaconNode' + ) { + nodeListObject.nodeService.push(node); + } else { + nodeListObject.singleClients.push(node); + } + }); + return (
{offline && ( @@ -77,14 +115,28 @@ const Sidebar = ({ offline }: SidebarProps) => {
- {nodeListData.map((item) => { + {nodeListObject.nodeService.length === 2 && ( + { + dispatch(updateSelectedNodeId(nodeListObject.nodeService[1].id)); + }} + /> + )} + {nodeListObject.singleClients.map((nodeId: NodeId) => { + const item = sUserNodes.nodes[nodeId]; + const { spec, status } = item; return ( ); })} From f21ed4ce8172001523bb2913b85dca59e8d53b94 Mon Sep 17 00:00:00 2001 From: jgresham Date: Thu, 3 Nov 2022 11:41:32 -0500 Subject: [PATCH 2/6] feat(wip): new sidebar rendering. remove legacy css. functionality not all working --- src/renderer/AddNode/AddNodeRedesign.tsx | 2 +- src/renderer/App.tsx | 10 ++- src/renderer/Footer/Monitoring.tsx | 2 +- .../Generics/redesign/NodeIcon/NodeIcon.tsx | 10 ++- .../SidebarNodeItem/SidebarNodeItem.tsx | 2 +- .../SidebarNodeItem/sideBarNodeItem.css.ts | 2 +- .../Presentational/Sidebar/Sidebar.tsx | 75 +++++++++++++------ .../Presentational/Sidebar/sidebar.css.ts | 2 +- 8 files changed, 72 insertions(+), 33 deletions(-) diff --git a/src/renderer/AddNode/AddNodeRedesign.tsx b/src/renderer/AddNode/AddNodeRedesign.tsx index 5cdbb8aa6..7ef62d9a6 100644 --- a/src/renderer/AddNode/AddNodeRedesign.tsx +++ b/src/renderer/AddNode/AddNodeRedesign.tsx @@ -22,7 +22,7 @@ const AddNode = () => { -
+
{ const dispatch = useAppDispatch(); + const [isDarkTheme, setIsDarkTheme] = useState(false); // const isStartOnLogin = await electron.getStoreValue('isStartOnLogin'); // console.log('isStartOnLogin: ', isStartOnLogin); @@ -39,6 +41,8 @@ const MainScreen = () => { return (
{ />

-
+
{/* { {statusComponent}
- Node icon + Node icon
); diff --git a/src/renderer/Generics/redesign/SidebarNodeItem/SidebarNodeItem.tsx b/src/renderer/Generics/redesign/SidebarNodeItem/SidebarNodeItem.tsx index 52773c5f3..e2f30947b 100644 --- a/src/renderer/Generics/redesign/SidebarNodeItem/SidebarNodeItem.tsx +++ b/src/renderer/Generics/redesign/SidebarNodeItem/SidebarNodeItem.tsx @@ -28,7 +28,7 @@ export interface SidebarNodeItemProps { /** * Which icon? */ - iconId: NodeIconId; + iconId: NodeIconId | string; /** * What's the status? */ diff --git a/src/renderer/Generics/redesign/SidebarNodeItem/sideBarNodeItem.css.ts b/src/renderer/Generics/redesign/SidebarNodeItem/sideBarNodeItem.css.ts index 93d5e2bcc..575717477 100644 --- a/src/renderer/Generics/redesign/SidebarNodeItem/sideBarNodeItem.css.ts +++ b/src/renderer/Generics/redesign/SidebarNodeItem/sideBarNodeItem.css.ts @@ -29,7 +29,7 @@ export const textContainer = style({ alignItems: 'flex-start', padding: '0px', gap: '2px', - width: '172px', + // width: '172px', height: '32px', flex: 'none', order: '1', diff --git a/src/renderer/Presentational/Sidebar/Sidebar.tsx b/src/renderer/Presentational/Sidebar/Sidebar.tsx index f395254c7..977b50caa 100644 --- a/src/renderer/Presentational/Sidebar/Sidebar.tsx +++ b/src/renderer/Presentational/Sidebar/Sidebar.tsx @@ -1,5 +1,5 @@ -import { NodeId } from 'common/node'; -import { useEffect } from 'react'; +import { NodeId, NodeStatus } from 'common/node'; +import { useCallback, useEffect } from 'react'; import { selectSelectedNodeId, selectUserNodes, @@ -83,6 +83,25 @@ const itemListData: { iconId: IconId; label: string; count?: number }[] = [ }, ]; +const NODE_SIDEBAR_STATUS_MAP: Record = { + created: 'stopped', + initializing: 'sync', + [NodeStatus.checkingForUpdates]: 'sync', + downloading: 'sync', + downloaded: 'sync', + [NodeStatus.errorDownloading]: 'error', + extracting: 'sync', + [NodeStatus.readyToStart]: 'stopped', + starting: 'sync', + running: 'healthy', + stopping: 'healthy', + stopped: 'stopped', + [NodeStatus.errorRunning]: 'error', + [NodeStatus.errorStarting]: 'error', + [NodeStatus.errorStopping]: 'error', + unknown: 'error', +}; + const Sidebar = ({ offline }: SidebarProps) => { const sSelectedNodeId = useAppSelector(selectSelectedNodeId); const sUserNodes = useAppSelector(selectUserNodes); @@ -100,19 +119,26 @@ const Sidebar = ({ offline }: SidebarProps) => { } }, [sSelectedNodeId, sUserNodes, dispatch]); - const nodeListObject = { nodeService: [], validator: [], singleClients: [] }; - sUserNodes?.nodeIds.forEach((nodeId: NodeId) => { - const node = sUserNodes.nodes[nodeId]; - // TODO: add validator logic here eventually - if ( - node.spec.category === 'L1/ExecutionClient' || - node.spec.category === 'L1/ConsensusClient/BeaconNode' - ) { - nodeListObject.nodeService.push(node); - } else { - nodeListObject.singleClients.push(node); + // const nodeListObject = { nodeService: [], validator: [], singleClients: [] }; + // sUserNodes?.nodeIds.forEach((nodeId: NodeId) => { + // const node = sUserNodes.nodes[nodeId]; + // // TODO: add validator logic here eventually + // if ( + // node.spec.category === 'L1/ExecutionClient' || + // node.spec.category === 'L1/ConsensusClient/BeaconNode' + // ) { + // nodeListObject.nodeService.push(node); + // } else { + // nodeListObject.singleClients.push(node); + // } + // }); + + const onClickLinkItem = useCallback((linkItemId) => { + console.log('sidebar link item clicked: ', linkItemId); + if (linkItemId === 'add') { + // open add node dialog } - }); + }, []); return (
@@ -125,7 +151,7 @@ const Sidebar = ({ offline }: SidebarProps) => {
- {nodeListObject.nodeService.length === 2 && ( + {/* {nodeListObject.nodeService.length === 2 && ( { dispatch(updateSelectedNodeId(nodeListObject.nodeService[1].id)); }} /> - )} - {nodeListObject.singleClients.map((nodeId: NodeId) => { - const item = sUserNodes.nodes[nodeId]; - const { spec, status } = item; + )} */} + {sUserNodes?.nodeIds.map((nodeId: NodeId) => { + const node = sUserNodes.nodes[nodeId]; + const { spec, status } = node; + const sidebarStatus = NODE_SIDEBAR_STATUS_MAP[status]; return ( dispatch(updateSelectedNodeId(node.id))} /> ); })} @@ -155,9 +184,11 @@ const Sidebar = ({ offline }: SidebarProps) => { {itemListData.map((item) => { return ( onClickLinkItem(item.iconId)} /> ); })} diff --git a/src/renderer/Presentational/Sidebar/sidebar.css.ts b/src/renderer/Presentational/Sidebar/sidebar.css.ts index 58487d609..3807245b8 100644 --- a/src/renderer/Presentational/Sidebar/sidebar.css.ts +++ b/src/renderer/Presentational/Sidebar/sidebar.css.ts @@ -30,7 +30,7 @@ export const titleItem = style({ }); export const nodeList = style({ - overflowY: 'scroll', + overflowY: 'auto', order: '2', alignSelf: 'stretch', flexGrow: '1', From fb32ff44ba43092bb22e13cb71e47d42de9222a2 Mon Sep 17 00:00:00 2001 From: jgresham Date: Thu, 3 Nov 2022 12:27:14 -0500 Subject: [PATCH 3/6] feat: add node from new sidebar. remove some old code --- src/renderer/AddNode/AddNode.tsx | 202 ------------------ src/renderer/AddNode/AddNodeRedesign.tsx | 45 ---- src/renderer/AddNode/ConfirmAddNode.tsx | 62 ------ src/renderer/AddNode/ConfirmRemoveNode.tsx | 2 +- src/renderer/App.tsx | 2 +- src/renderer/Footer/MenuDrawer.tsx | 3 +- src/renderer/Footer/Monitoring.tsx | 4 - .../Generics/redesign/Modal/Modal.tsx | 12 +- src/renderer/InfoIconButton.tsx | 2 +- src/renderer/LeftSideBar.tsx | 107 ---------- src/renderer/Modal.tsx | 74 ------- .../Presentational/Sidebar/Sidebar.tsx | 103 +++++---- 12 files changed, 68 insertions(+), 550 deletions(-) delete mode 100644 src/renderer/AddNode/AddNode.tsx delete mode 100644 src/renderer/AddNode/AddNodeRedesign.tsx delete mode 100644 src/renderer/AddNode/ConfirmAddNode.tsx delete mode 100644 src/renderer/LeftSideBar.tsx delete mode 100644 src/renderer/Modal.tsx diff --git a/src/renderer/AddNode/AddNode.tsx b/src/renderer/AddNode/AddNode.tsx deleted file mode 100644 index 60c69098b..000000000 --- a/src/renderer/AddNode/AddNode.tsx +++ /dev/null @@ -1,202 +0,0 @@ -import { BsPlusSquareDotted } from 'react-icons/bs'; -import { useEffect, useState } from 'react'; -import { useTranslation } from 'react-i18next'; - -import IconButton from '../IconButton'; -import { Modal } from '../Modal'; -import NodeCard from './NodeCard'; -import ConfirmAddNode from './ConfirmAddNode'; -import { NodeSpecification } from '../../common/nodeSpec'; -// import { DopeButton } from '../DivButton'; -import electron from '../electronGlobal'; -import { categorizeNodeLibrary } from '../utils'; - -const AddNode = () => { - const { t } = useTranslation(); - const [sIsModalOpenAddNode, setIsModalOpenAddNode] = useState(); - const [sIsModalOpenConfirmAddNode, setIsModalOpenConfirmAddNode] = - useState(false); - const [sSelectedNodeSpecification, setSelectedNodeSpecification] = - useState(); - const [sExecutionClientLibrary, setExecutionClientLibrary] = useState< - NodeSpecification[] - >([]); - const [sBeaconNodeLibrary, setBeaconNodeLibrary] = useState< - NodeSpecification[] - >([]); - // const [sLayer2ClientLibrary, setLayer2ClientLibrary] = useState< - // NodeSpecification[] - // >([]); - const [sOtherNodeLibrary, setOtherNodeLibrary] = useState< - NodeSpecification[] - >([]); - - useEffect(() => { - const fetchNodeLibrary = async () => { - const nodeLibrary = await electron.getNodeLibrary(); - console.log('nodeLibrary', nodeLibrary); - const categorized = categorizeNodeLibrary(nodeLibrary); - console.log('nodeLibrary categorized', categorized); - setExecutionClientLibrary(categorized.ExecutionClient); - setBeaconNodeLibrary(categorized.BeaconNode); - // setLayer2ClientLibrary(categorized.L2); - setOtherNodeLibrary(categorized.Other); - // set exec, beacons, and layer 2s - }; - fetchNodeLibrary(); - }, []); - - const onNodeSelected = (nodeSpec: NodeSpecification) => { - // set selected node - setSelectedNodeSpecification(nodeSpec); - // open confirm add modal - setIsModalOpenConfirmAddNode(true); - }; - - const onConfirmAddNode = () => { - // close both modals - setIsModalOpenConfirmAddNode(false); - setIsModalOpenAddNode(false); - }; - - const onClickAddNodeButton = async () => { - setIsModalOpenAddNode(true); - }; - - return ( -
- {t('Add Node')} - - - - - setIsModalOpenAddNode(false)} - > -
-

Ethereum Node (Execution client)

- - {sExecutionClientLibrary ? ( -
- {/* - onNodeSelected( - Math.floor(Math.random() * 2) === 0 ? 'besu' : 'nethermind' - ) - } - > - - Minority Client - - */} - {sExecutionClientLibrary.map((nodeSpec: NodeSpecification) => { - return ( - onNodeSelected(nodeSpec)} - /> - ); - })} -
- ) : ( - Unable to load node library - )} -
-
-

Ethereum Beacon Node (Consensus client)

- {sBeaconNodeLibrary ? ( -
- {/* dispatch(updateSelectedNodeId(node.id))} - > - - Minority Client - - */} - {sBeaconNodeLibrary.map((nodeSpec: NodeSpecification) => { - return ( - onNodeSelected(nodeSpec)} - /> - ); - })} -
- ) : ( - Unable to load beacon node library - )} -
- {/*
-

Ethereum Layer 2

- {sLayer2ClientLibrary ? ( -
- {sLayer2ClientLibrary.map((nodeSpec: NodeSpecification) => { - return ( - onNodeSelected(nodeSpec)} - /> - ); - })} -
- ) : ( - Unable to load layer 2 node library - )} -
*/} - {sOtherNodeLibrary.length > 0 && ( -
-

Other

-
- {sOtherNodeLibrary.map((nodeSpec: NodeSpecification) => { - return ( - onNodeSelected(nodeSpec)} - /> - ); - })} -
-
- )} -
- - setIsModalOpenConfirmAddNode(false)} - nodeSpec={sSelectedNodeSpecification} - /> -
- ); -}; -export default AddNode; diff --git a/src/renderer/AddNode/AddNodeRedesign.tsx b/src/renderer/AddNode/AddNodeRedesign.tsx deleted file mode 100644 index 7ef62d9a6..000000000 --- a/src/renderer/AddNode/AddNodeRedesign.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import { BsPlusSquareDotted } from 'react-icons/bs'; -import { useState } from 'react'; -import { useTranslation } from 'react-i18next'; - -import IconButton from '../IconButton'; -import { Modal } from '../Generics/redesign/Modal/Modal'; -import AddNodeStepper from '../Presentational/AddNodeStepper/AddNodeStepper'; -// todo: remove when new ui/ux redesign is further along -import { darkTheme } from '../Generics/redesign/theme.css'; - -const AddNode = () => { - const { t } = useTranslation(); - const [sIsModalOpenAddNode, setIsModalOpenAddNode] = useState(); - - const onClickAddNodeButton = async () => { - setIsModalOpenAddNode(true); - }; - - return ( -
- {t('Add Node')} - - - -
- setIsModalOpenAddNode(false)} - isFullScreen - > - { - console.log(newValue); - if (newValue === 'done' || newValue === 'cancel') { - setIsModalOpenAddNode(false); - } - }} - /> - -
-
- ); -}; -export default AddNode; diff --git a/src/renderer/AddNode/ConfirmAddNode.tsx b/src/renderer/AddNode/ConfirmAddNode.tsx deleted file mode 100644 index 83d703a40..000000000 --- a/src/renderer/AddNode/ConfirmAddNode.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import { useTranslation } from 'react-i18next'; - -import { updateSelectedNodeId } from '../state/node'; -import { NodeSpecification } from '../../common/nodeSpec'; -import electron from '../electronGlobal'; -import { Modal } from '../Modal'; -import { useAppDispatch } from '../state/hooks'; - -type Props = { - isOpen: boolean; - onConfirm: () => void; - onCancel: () => void; - // eslint-disable-next-line react/require-default-props - nodeSpec?: NodeSpecification; -}; - -const ConfirmAddNode = (props: Props) => { - const { t } = useTranslation(); - const dispatch = useAppDispatch(); - const { isOpen, onConfirm, onCancel, nodeSpec } = props; - if (!nodeSpec) { - return <>; - } - - const onConfirmAddSpecificNode = async () => { - const node = await electron.addNode(nodeSpec); - - console.log('addNode returned node: ', node); - dispatch(updateSelectedNodeId(node.id)); - onConfirm(); - }; - - const { iconUrl, displayName, category } = nodeSpec; - return ( - -
- {displayName} -
- {displayName} -
- {category} -
-
{t('nodeNotStartedYet')}
-
- -   - -
-
- ); -}; -export default ConfirmAddNode; diff --git a/src/renderer/AddNode/ConfirmRemoveNode.tsx b/src/renderer/AddNode/ConfirmRemoveNode.tsx index ac9a5d7b0..88fd16b2d 100644 --- a/src/renderer/AddNode/ConfirmRemoveNode.tsx +++ b/src/renderer/AddNode/ConfirmRemoveNode.tsx @@ -3,7 +3,7 @@ import { MdDelete } from 'react-icons/md'; import { useTranslation } from 'react-i18next'; import electron from '../electronGlobal'; -import { Modal } from '../Modal'; +import { Modal } from '../Generics/redesign/Modal/Modal'; import Node from '../../common/node'; type Props = { diff --git a/src/renderer/App.tsx b/src/renderer/App.tsx index 7fad6cb80..5aa722501 100644 --- a/src/renderer/App.tsx +++ b/src/renderer/App.tsx @@ -23,7 +23,7 @@ Sentry.init({ const MainScreen = () => { const dispatch = useAppDispatch(); - const [isDarkTheme, setIsDarkTheme] = useState(false); + const [isDarkTheme] = useState(false); // const isStartOnLogin = await electron.getStoreValue('isStartOnLogin'); // console.log('isStartOnLogin: ', isStartOnLogin); diff --git a/src/renderer/Footer/MenuDrawer.tsx b/src/renderer/Footer/MenuDrawer.tsx index bf8637fd5..9982289ff 100644 --- a/src/renderer/Footer/MenuDrawer.tsx +++ b/src/renderer/Footer/MenuDrawer.tsx @@ -3,11 +3,12 @@ import React from 'react'; import styled from 'styled-components'; import IconButton from '../IconButton'; -import { LEFT_SIDEBAR_WIDTH } from '../LeftSideBar'; + import { HEADER_HEIGHT } from '../Header'; // eslint-disable-next-line import/no-cycle // import { FOOTER_HEIGHT } from './Footer'; +const LEFT_SIDEBAR_WIDTH = 100; const FOOTER_HEIGHT = 64; const MenuDrawerStyled = styled.div` diff --git a/src/renderer/Footer/Monitoring.tsx b/src/renderer/Footer/Monitoring.tsx index 41d8b456b..6353dca10 100644 --- a/src/renderer/Footer/Monitoring.tsx +++ b/src/renderer/Footer/Monitoring.tsx @@ -7,8 +7,6 @@ import { useAppSelector } from '../state/hooks'; import { selectNumFreeDiskGB, selectSelectedNode } from '../state/node'; // import { Checklist } from '../Generics/redesign/Checklist/Checklist'; -// todo: remove when new ui/ux redesign is further along -import { darkTheme, lightTheme } from '../Generics/redesign/theme.css'; import { SystemMonitor } from '../Generics/redesign/SystemMonitor/SystemMonitor'; type Props = { @@ -110,8 +108,6 @@ const Monitoring = ({ isOpen, onClickCloseButton }: Props) => { } }, [isOpen]); - console.log('monitoring lightTheme: ', lightTheme); - return (

{title}

- - - +
{children}
diff --git a/src/renderer/InfoIconButton.tsx b/src/renderer/InfoIconButton.tsx index ea7c8b0cf..8cc054574 100644 --- a/src/renderer/InfoIconButton.tsx +++ b/src/renderer/InfoIconButton.tsx @@ -2,7 +2,7 @@ import { useState } from 'react'; import { MdInfoOutline } from 'react-icons/md'; import styled from 'styled-components'; -import { Modal } from './Modal'; +import { Modal } from './Generics/redesign/Modal/Modal'; const InfoButton = styled.button` background: transparent; diff --git a/src/renderer/LeftSideBar.tsx b/src/renderer/LeftSideBar.tsx deleted file mode 100644 index c283130aa..000000000 --- a/src/renderer/LeftSideBar.tsx +++ /dev/null @@ -1,107 +0,0 @@ -import { useEffect } from 'react'; - -import { NodeId } from '../common/node'; -import AddNode from './AddNode/AddNodeRedesign'; -import DivButton from './DivButton'; -import { useAppDispatch, useAppSelector } from './state/hooks'; -import { - selectSelectedNodeId, - selectUserNodes, - updateSelectedNodeId, -} from './state/node'; - -export const LEFT_SIDEBAR_WIDTH = 120; - -const LeftSideBar = () => { - const sSelectedNodeId = useAppSelector(selectSelectedNodeId); - const sUserNodes = useAppSelector(selectUserNodes); - const dispatch = useAppDispatch(); - - // Default selected node to be the first node - useEffect(() => { - if ( - !sSelectedNodeId && - sUserNodes && - Array.isArray(sUserNodes?.nodeIds) && - sUserNodes.nodeIds.length > 0 - ) { - dispatch(updateSelectedNodeId(sUserNodes.nodeIds[0])); - } - }, [sSelectedNodeId, sUserNodes, dispatch]); - - return ( -
-
- - {/* {qGetNodes.error && <>Oh no, there was an error getting nodes} - {qGetNodes.isLoading && <>Loading nodes...} */} - {sUserNodes?.nodeIds ? ( - <> - {sUserNodes.nodeIds.map((nodeId: NodeId) => { - const node = sUserNodes.nodes[nodeId]; - let statusColor = node.status === 'running' ? 'green' : 'black'; - if (node.status.includes('error')) { - statusColor = 'red'; - } else if (node.status.includes('stopped')) { - statusColor = 'grey'; - } - const isSelectedNode = sSelectedNodeId === node.id; - return ( - dispatch(updateSelectedNodeId(node.id))} - > -
- {node.spec.displayName} -
- - - {node.spec.displayName} - -
- -
-
- ); - })} - - ) : ( - <>No nodes {JSON.stringify(sUserNodes)} - )} -
-
- ); -}; -export default LeftSideBar; diff --git a/src/renderer/Modal.tsx b/src/renderer/Modal.tsx deleted file mode 100644 index 8e779d31a..000000000 --- a/src/renderer/Modal.tsx +++ /dev/null @@ -1,74 +0,0 @@ -import styled from 'styled-components'; -import { CgCloseO } from 'react-icons/cg'; - -import IconButton from './IconButton'; - -const ModalBackdrop = styled.div` - display: none; /* Hidden by default */ - position: fixed; /* Stay in place */ - z-index: 1; /* Sit on top */ - // padding-top: 100px; /* Location of the box */ - left: 0; - top: 0; - width: 100%; /* Full width */ - height: 100%; /* Full height */ - overflow: auto; /* Enable scroll if needed */ - background-color: rgb(0, 0, 0); /* Fallback color */ - background-color: rgba(0, 0, 0, 0.8); /* Black w/ opacity */ -`; - -const ModalContent = styled.div` - // background-color: #fefefe; - max-height: 95vh; - background-color: #d3d3d3; - padding: 20px; - padding-top: 0px; - border: 1px solid #888; - width: 80%; - top: 50%; - left: 50%; - position: fixed; - transform: translate(-50%, -50%); - color: black; - - a { - color: inherit; - } -`; - -type Props = { - children: React.ReactNode; - isOpen: boolean | undefined; - onClickCloseButton: () => void; - title: string; -}; - -export const Modal = ({ - children, - isOpen, - onClickCloseButton, - title, -}: Props) => { - return ( - - -
-

{title}

- - - -
-
{children}
-
-
- ); -}; diff --git a/src/renderer/Presentational/Sidebar/Sidebar.tsx b/src/renderer/Presentational/Sidebar/Sidebar.tsx index 977b50caa..f83a51141 100644 --- a/src/renderer/Presentational/Sidebar/Sidebar.tsx +++ b/src/renderer/Presentational/Sidebar/Sidebar.tsx @@ -1,11 +1,11 @@ -import { NodeId, NodeStatus } from 'common/node'; -import { useCallback, useEffect } from 'react'; +import { useCallback, useEffect, useState } from 'react'; +import { useAppDispatch, useAppSelector } from '../../state/hooks'; import { selectSelectedNodeId, selectUserNodes, updateSelectedNodeId, -} from 'renderer/state/node'; -import { useAppDispatch, useAppSelector } from 'renderer/state/hooks'; +} from '../../state/node'; +import { NodeId, NodeStatus } from '../../../common/node'; import { Banner } from '../../Generics/redesign/Banner/Banner'; import { SidebarNodeItem, @@ -21,7 +21,9 @@ import { titleItem, } from './sidebar.css'; import { IconId } from '../../assets/images/icons'; -import { NodeIconId } from '../../assets/images/nodeIcons'; +// import { NodeIconId } from '../../assets/images/nodeIcons'; +import { Modal } from '../../Generics/redesign/Modal/Modal'; +import AddNodeStepper from '../AddNodeStepper/AddNodeStepper'; export interface SidebarProps { /** @@ -30,43 +32,43 @@ export interface SidebarProps { offline: boolean; } -const nodeListData: { - iconId: NodeIconId; - title: string; - info: string; - status: SidebarNodeStatus; -}[] = [ - { - iconId: 'ethereum', - title: 'Ethereum', - info: 'Mainnet', - status: 'healthy', - }, - { - iconId: 'zkSync', - title: 'zkSync', - info: 'Rinkeby', - status: 'sync', - }, - { - iconId: 'arbitrum', - title: 'Arbitrum Nitro', - info: 'Testnet', - status: 'healthy', - }, - { - iconId: 'starknet', - title: 'Starknet', - info: 'Testnet', - status: 'error', - }, - { - iconId: 'livepeer', - title: 'Livepeer Orchestrator', - info: 'Testnet', - status: 'warning', - }, -]; +// const nodeListData: { +// iconId: NodeIconId; +// title: string; +// info: string; +// status: SidebarNodeStatus; +// }[] = [ +// { +// iconId: 'ethereum', +// title: 'Ethereum', +// info: 'Mainnet', +// status: 'healthy', +// }, +// { +// iconId: 'zkSync', +// title: 'zkSync', +// info: 'Rinkeby', +// status: 'sync', +// }, +// { +// iconId: 'arbitrum', +// title: 'Arbitrum Nitro', +// info: 'Testnet', +// status: 'healthy', +// }, +// { +// iconId: 'starknet', +// title: 'Starknet', +// info: 'Testnet', +// status: 'error', +// }, +// { +// iconId: 'livepeer', +// title: 'Livepeer Orchestrator', +// info: 'Testnet', +// status: 'warning', +// }, +// ]; const itemListData: { iconId: IconId; label: string; count?: number }[] = [ { @@ -106,6 +108,7 @@ const Sidebar = ({ offline }: SidebarProps) => { const sSelectedNodeId = useAppSelector(selectSelectedNodeId); const sUserNodes = useAppSelector(selectUserNodes); const dispatch = useAppDispatch(); + const [sIsModalOpenAddNode, setIsModalOpenAddNode] = useState(); // Default selected node to be the first node useEffect(() => { @@ -137,6 +140,7 @@ const Sidebar = ({ offline }: SidebarProps) => { console.log('sidebar link item clicked: ', linkItemId); if (linkItemId === 'add') { // open add node dialog + setIsModalOpenAddNode(true); } }, []); @@ -193,6 +197,21 @@ const Sidebar = ({ offline }: SidebarProps) => { ); })}
+ setIsModalOpenAddNode(false)} + isFullScreen + > + { + console.log(newValue); + if (newValue === 'done' || newValue === 'cancel') { + setIsModalOpenAddNode(false); + } + }} + /> +
); }; From d4a78f6b75cfe151fda0980528899032134943ba Mon Sep 17 00:00:00 2001 From: jgresham Date: Thu, 3 Nov 2022 14:48:42 -0500 Subject: [PATCH 4/6] feat: remove window top bar. add custom draggable area. remove old header. --- src/main/main.ts | 2 ++ src/renderer/App.tsx | 5 +++-- .../Presentational/Sidebar/sidebar.css.ts | 1 + src/renderer/app.css.ts | 17 +++++++++++++++++ src/renderer/{App.css => reset.css} | 12 +++++++----- 5 files changed, 30 insertions(+), 7 deletions(-) create mode 100644 src/renderer/app.css.ts rename src/renderer/{App.css => reset.css} (93%) diff --git a/src/main/main.ts b/src/main/main.ts index cc69df772..8638202eb 100644 --- a/src/main/main.ts +++ b/src/main/main.ts @@ -86,6 +86,8 @@ const createWindow = async () => { }; mainWindow = new BrowserWindow({ + titleBarOverlay: true, + titleBarStyle: 'hiddenInset', show: false, width: 1200, height: 820, diff --git a/src/renderer/App.tsx b/src/renderer/App.tsx index 5aa722501..ad749fbd3 100644 --- a/src/renderer/App.tsx +++ b/src/renderer/App.tsx @@ -3,7 +3,7 @@ import { MemoryRouter as Router, Routes, Route } from 'react-router-dom'; import * as Sentry from '@sentry/electron/renderer'; import './Generics/redesign/globalStyle.css'; -// import './App.css'; +import './reset.css'; import { useAppDispatch } from './state/hooks'; import Header from './Header'; import Footer from './Footer/Footer'; @@ -15,6 +15,7 @@ import DataRefresher from './DataRefresher'; import electron from './electronGlobal'; import Sidebar from './Presentational/Sidebar/Sidebar'; import { darkTheme, lightTheme } from './Generics/redesign/theme.css'; +import { dragWindowContainer } from './app.css'; Sentry.init({ dsn: electron.SENTRY_DSN, @@ -50,7 +51,7 @@ const MainScreen = () => { height: '100vh', }} > -
+
Date: Thu, 3 Nov 2022 14:49:01 -0500 Subject: [PATCH 5/6] feat: remove window top bar. add custom draggable area. remove old header. --- src/renderer/App.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/renderer/App.tsx b/src/renderer/App.tsx index ad749fbd3..37ca235a0 100644 --- a/src/renderer/App.tsx +++ b/src/renderer/App.tsx @@ -5,7 +5,6 @@ import * as Sentry from '@sentry/electron/renderer'; import './Generics/redesign/globalStyle.css'; import './reset.css'; import { useAppDispatch } from './state/hooks'; -import Header from './Header'; import Footer from './Footer/Footer'; import Warnings from './Warnings'; import { initialize as initializeIpcListeners } from './ipc'; From 1d97cf8f14ef2ab64f08ea47c087f7d03a782f26 Mon Sep 17 00:00:00 2001 From: jgresham Date: Thu, 3 Nov 2022 16:12:22 -0500 Subject: [PATCH 6/6] wip: define single content props. parse selected node to single content. missing lots of func. --- src/renderer/App.tsx | 2 - .../redesign/HeaderMetrics/HeaderMetrics.tsx | 6 +- .../redesign/MetricTypes/MetricTypes.tsx | 28 +-- .../redesign/MetricTypes/metricTypes.css.ts | 2 +- src/renderer/Generics/redesign/consts.ts | 20 +-- src/renderer/NodeScreen.tsx | 155 ++++++++++++++-- .../ContentMultipleClients.tsx | 5 +- .../ContentSingleClient.tsx | 35 +++- src/renderer/Warnings.tsx | 168 ------------------ src/stories/Generic/Header.stories.tsx | 2 +- src/stories/Generic/HeaderMetrics.stories.tsx | 2 +- .../ContentMultipleClients.stories.tsx | 4 +- .../ContentSingleClient.stories.tsx | 46 ++++- 13 files changed, 253 insertions(+), 222 deletions(-) delete mode 100644 src/renderer/Warnings.tsx diff --git a/src/renderer/App.tsx b/src/renderer/App.tsx index 37ca235a0..49998be9a 100644 --- a/src/renderer/App.tsx +++ b/src/renderer/App.tsx @@ -6,7 +6,6 @@ import './Generics/redesign/globalStyle.css'; import './reset.css'; import { useAppDispatch } from './state/hooks'; import Footer from './Footer/Footer'; -import Warnings from './Warnings'; import { initialize as initializeIpcListeners } from './ipc'; // import LeftSideBar from './LeftSideBar'; import NodeScreen from './NodeScreen'; @@ -71,7 +70,6 @@ const MainScreen = () => { }} > -
diff --git a/src/renderer/Generics/redesign/HeaderMetrics/HeaderMetrics.tsx b/src/renderer/Generics/redesign/HeaderMetrics/HeaderMetrics.tsx index cc586b4b6..64e21cefe 100644 --- a/src/renderer/Generics/redesign/HeaderMetrics/HeaderMetrics.tsx +++ b/src/renderer/Generics/redesign/HeaderMetrics/HeaderMetrics.tsx @@ -17,14 +17,14 @@ export const HeaderMetrics = (props: NodeOverviewProps) => { client: MetricStats[]; validator: MetricStats[]; } = { - altruistic: ['status', 'currentSlot', 'cpuLoad', 'diskUsage'], - client: ['status', getSlotOrBlockMetricType, 'peers', 'diskUsage'], + altruistic: ['status', 'currentSlot', 'cpuLoad', 'diskUsageGBs'], + client: ['status', getSlotOrBlockMetricType, 'peers', 'diskUsageGBs'], validator: ['status', 'stake', 'rewards', 'balance'], }; const assignedMetric = metricTypeArray[type]; return (
- {assignedMetric.map((metric, index) => { + {assignedMetric?.map((metric, index) => { let statsValue; if (metric === 'status') { statsValue = getSyncStatus(status); diff --git a/src/renderer/Generics/redesign/MetricTypes/MetricTypes.tsx b/src/renderer/Generics/redesign/MetricTypes/MetricTypes.tsx index fe2f23afa..9d3554dbf 100644 --- a/src/renderer/Generics/redesign/MetricTypes/MetricTypes.tsx +++ b/src/renderer/Generics/redesign/MetricTypes/MetricTypes.tsx @@ -24,7 +24,7 @@ export type MetricStats = | 'currentBlock' | 'peers' | 'cpuLoad' - | 'diskUsage' + | 'diskUsageGBs' | 'balance' | 'stake' | 'rewards'; @@ -121,6 +121,7 @@ export const MetricTypes = ({ labelText = 'Current slot'; break; case 'peers': + iconId = 'peers'; titleText = '16'; labelText = 'Peers connected'; break; @@ -129,17 +130,22 @@ export const MetricTypes = ({ titleText = `${statsValue}%`; labelText = 'CPU load'; break; - case 'diskUsage': - if (typeof statsValue === 'number' && statsValue >= 1000000) { - titleText = `${statsValue / 1000000} TB`; - } else if ( - typeof statsValue === 'number' && - statsValue <= 999999 && - statsValue >= 1000 - ) { - titleText = `${statsValue / 1000} GB`; + case 'diskUsageGBs': + // if (typeof statsValue === 'number' && statsValue >= 1000000) { + // titleText = `${statsValue / 1000000} TB`; + // } else if ( + // typeof statsValue === 'number' && + // statsValue <= 999999 && + // statsValue >= 1000 + // ) { + // titleText = `${statsValue / 1000} GB`; + // } else { + // titleText = `${statsValue} MB`; + // } + if (typeof statsValue === 'number') { + titleText = `${statsValue.toFixed(2)} GB`; } else { - titleText = `${statsValue} MB`; + titleText = `${statsValue} GB`; } iconId = 'disks'; labelText = 'Disk usage'; diff --git a/src/renderer/Generics/redesign/MetricTypes/metricTypes.css.ts b/src/renderer/Generics/redesign/MetricTypes/metricTypes.css.ts index 03267863f..e405efeb0 100644 --- a/src/renderer/Generics/redesign/MetricTypes/metricTypes.css.ts +++ b/src/renderer/Generics/redesign/MetricTypes/metricTypes.css.ts @@ -61,7 +61,7 @@ const redPulse = keyframes({ }); export const statusStyle = style({ - zIndex: 1, + // zIndex: 1, animationDuration: '2s', animationIterationCount: 'infinite', animationTimingFunction: 'linear', diff --git a/src/renderer/Generics/redesign/consts.ts b/src/renderer/Generics/redesign/consts.ts index 54d98ee22..426e9e241 100644 --- a/src/renderer/Generics/redesign/consts.ts +++ b/src/renderer/Generics/redesign/consts.ts @@ -25,22 +25,22 @@ export interface ClientStatsProps { highestSlot?: number; peers?: number; cpuLoad?: number; - diskUsage?: number; + diskUsageGBs?: number; rewards?: number; balance?: number; stake?: number; } export interface ClientStatusProps { - updating: boolean; - initialized: boolean; // initial initialization is done - synchronized: boolean; // constantly updated from checking current / height slot or block - lowPeerCount: boolean; - updateAvailable: boolean; - blocksBehind: boolean; - noConnection: boolean; - stopped: boolean; - error: boolean; + updating?: boolean; + initialized?: boolean; // initial initialization is done + synchronized?: boolean; // constantly updated from checking current / height slot or block + lowPeerCount?: boolean; + updateAvailable?: boolean; + blocksBehind?: boolean; + noConnection?: boolean; + stopped?: boolean; + error?: boolean; } export interface SyncStatusProps { diff --git a/src/renderer/NodeScreen.tsx b/src/renderer/NodeScreen.tsx index 0d2dfda65..a5af0ed50 100644 --- a/src/renderer/NodeScreen.tsx +++ b/src/renderer/NodeScreen.tsx @@ -1,14 +1,23 @@ import { FaPlayCircle, FaPauseCircle } from 'react-icons/fa'; import { useTranslation } from 'react-i18next'; +import { useEffect, useState } from 'react'; import { NodeStatus } from '../common/node'; import electron from './electronGlobal'; -import InstallDocker from './Docker/InstallDocker'; // import { useGetNodesQuery } from './state/nodeService'; import { useAppSelector } from './state/hooks'; -import { selectSelectedNode } from './state/node'; -import { useGetNodeVersionQuery } from './state/services'; -import { useGetIsDockerInstalledQuery } from './state/settingsService'; +import { selectIsAvailableForPolling, selectSelectedNode } from './state/node'; +import { + useGetExecutionIsSyncingQuery, + useGetExecutionLatestBlockQuery, + useGetExecutionPeersQuery, + useGetNodeVersionQuery, +} from './state/services'; +import { useGetNetworkConnectedQuery } from './state/network'; +import ContentSingleClient, { + SingleNodeContent, +} from './Presentational/ContentSingleClient/ContentSingleClient'; +import { hexToDecimal } from './utils'; const NodeScreen = () => { const { t } = useTranslation(); @@ -16,9 +25,109 @@ const NodeScreen = () => { const qNodeVersion = useGetNodeVersionQuery( selectedNode?.spec.rpcTranslation ); - const qIsDockerInstalled = useGetIsDockerInstalledQuery(); - // const isDisabled = true; - const isDockerInstalled = qIsDockerInstalled?.data; + const [sIsSyncing, setIsSyncing] = useState(); + const [sSyncPercent, setSyncPercent] = useState(''); + const [sPeers, setPeers] = useState(); + const [sLatestBlockNumber, setLatestBlockNumber] = useState(); + const sIsAvailableForPolling = useAppSelector(selectIsAvailableForPolling); + const pollingInterval = sIsAvailableForPolling ? 15000 : 0; + const qExeuctionIsSyncing = useGetExecutionIsSyncingQuery( + selectedNode?.spec.rpcTranslation, + { + pollingInterval, + } + ); + // const isSelectedNode = selectedNode !== undefined; + // const peersPolling = isSelectedNode ? pollingInterval : 0; + const qExecutionPeers = useGetExecutionPeersQuery( + selectedNode?.spec.rpcTranslation, + { + pollingInterval, + } + ); + const qLatestBlock = useGetExecutionLatestBlockQuery( + selectedNode?.spec.rpcTranslation, + { + pollingInterval, + } + ); + const qNetwork = useGetNetworkConnectedQuery(null, { + // Only polls network connection if there are exactly 0 peers + pollingInterval: typeof sPeers === 'number' && sPeers === 0 ? 30000 : 0, + }); + + const diskUsed = + selectedNode?.runtime?.usage?.diskGBs?.toPrecision(2) ?? undefined; + // eslint-disable-next-line eqeqeq + const isHttpEnabled = + selectedNode?.config?.configValuesMap?.http && + ['Enabled', 'enabled', 'true', true, 1].includes( + selectedNode?.config?.configValuesMap?.http + ); + // todo: http apis + + useEffect(() => { + if (!sIsAvailableForPolling) { + // clear all node data when it becomes unavailable to get + setSyncPercent(''); + setIsSyncing(undefined); + setPeers(undefined); + setLatestBlockNumber(undefined); + } + }, [sIsAvailableForPolling]); + + useEffect(() => { + console.log('qExeuctionIsSyncing: ', qExeuctionIsSyncing); + if (qExeuctionIsSyncing.isError) { + setSyncPercent(''); + setIsSyncing(undefined); + return; + } + const syncingData = qExeuctionIsSyncing.data; + if (typeof syncingData === 'object') { + setSyncPercent(syncingData.syncPercent); + setIsSyncing(syncingData.isSyncing); + } + // else if (syncingData === false) { + // // light client geth, it is done syncing if data is false + // setSyncPercent(''); + // setIsSyncing(false); + // } + else { + setSyncPercent(''); + setIsSyncing(undefined); + } + }, [qExeuctionIsSyncing]); + + useEffect(() => { + if (qExecutionPeers.isError) { + setPeers(undefined); + return; + } + if (typeof qExecutionPeers.data === 'string') { + setPeers(qExecutionPeers.data); + } else if (typeof qExecutionPeers.data === 'number') { + setPeers(qExecutionPeers.data.toString()); + } else { + setPeers(undefined); + } + }, [qExecutionPeers]); + + useEffect(() => { + if (qLatestBlock.isError) { + setLatestBlockNumber(undefined); + return; + } + if ( + qLatestBlock?.data?.number && + typeof qLatestBlock.data.number === 'string' + ) { + const latestBlockNum = hexToDecimal(qLatestBlock.data.number); + setLatestBlockNumber(latestBlockNum); + } else { + setLatestBlockNumber(undefined); + } + }, [qLatestBlock]); // useEffect(() => { // qNodeInfo.refetch(); // }, [selectedNode]); @@ -34,17 +143,33 @@ const NodeScreen = () => { // }); if (!selectedNode) { // if docker is not installed, show prompt - if (!isDockerInstalled) { - if (qIsDockerInstalled.isLoading) { - return <>Loading...; - } - return ; - } - return
No node selected
; + // eslint-disable-next-line react/jsx-curly-brace-presence + return

{'Get started! "Add a node"!'}

; } const { status, spec } = selectedNode; - const { category, displayName } = spec; + // todo: get node type, single or multi-service + // parse node details from selectedNode => SingleNodeContent + // todo: add stop/start ability? + const nodeContent: SingleNodeContent = { + nodeId: selectedNode.id, + name: spec.specId.replace('-beacon', ''), + type: 'client', + version: qNodeVersion?.currentData, + info: spec.category, + status: { + stopped: status === 'stopped', + error: status.includes('error'), + sychronized: !sIsSyncing && parseFloat(sSyncPercent) > 99.9, + }, + stats: { + peers: sPeers, + currentBlock: sLatestBlockNumber, + diskUsageGBs: diskUsed ? parseFloat(diskUsed) : undefined, + }, + }; + console.log('passing content to NodeScreen: ', nodeContent); + return ; return (
diff --git a/src/renderer/Presentational/ContentMultipleClients/ContentMultipleClients.tsx b/src/renderer/Presentational/ContentMultipleClients/ContentMultipleClients.tsx index 87637b852..14b246d25 100644 --- a/src/renderer/Presentational/ContentMultipleClients/ContentMultipleClients.tsx +++ b/src/renderer/Presentational/ContentMultipleClients/ContentMultipleClients.tsx @@ -127,8 +127,9 @@ const ContentMultipleClients = (props: { highestSlot: clClient?.stats.highestSlot, cpuLoad: (clClient?.stats.cpuLoad || 0) + (elClient?.stats.cpuLoad || 0), - diskUsage: - (clClient?.stats.diskUsage || 0) + (elClient?.stats.diskUsage || 0), + diskUsageGBs: + (clClient?.stats.diskUsageGBs || 0) + + (elClient?.stats.diskUsageGBs || 0), }, }; return nodeOverview; diff --git a/src/renderer/Presentational/ContentSingleClient/ContentSingleClient.tsx b/src/renderer/Presentational/ContentSingleClient/ContentSingleClient.tsx index 0abb0495f..225b46e34 100644 --- a/src/renderer/Presentational/ContentSingleClient/ContentSingleClient.tsx +++ b/src/renderer/Presentational/ContentSingleClient/ContentSingleClient.tsx @@ -30,11 +30,40 @@ const client = { currentBlock: 1000, highestBlock: 2000, cpuLoad: 20, - diskUsage: 600, // in MB? + diskUsageGBs: 600, // in MB? }, }; -const ContentSingleClient = () => { +export type SingleNodeContent = { + nodeId: string; + name: string; // lowercase for supported node icons + version?: string; + type?: string; + nodeType?: 'execution' | 'consensus' | string; + info?: string; + network?: string; + iconUrl?: string; + status?: { + updating?: boolean; + sychronized?: boolean; + initialized?: boolean; + lowPeerCount?: boolean; + updateAvailable?: boolean; + blocksBehind?: boolean; + noConnection?: boolean; + stopped?: boolean; + error?: boolean; + }; + stats?: { + peers?: number; + currentBlock?: number; + highestBlock?: number; + cpuLoad?: number; + diskUsageGBs?: number; // in MB? + }; +}; + +const ContentSingleClient = (props: SingleNodeContent) => { /* TODO: maybe a "provider" wrapper/manager to fetch data and handle states */ // TODO: refactor this out so that it can be shared with multiple, single, and validator? @@ -50,7 +79,7 @@ const ContentSingleClient = () => { }; }; - const nodeOverview = getNodeOverview(); + const nodeOverview = props; // TODO: retrieve initial data for all pages diff --git a/src/renderer/Warnings.tsx b/src/renderer/Warnings.tsx deleted file mode 100644 index 9466705cc..000000000 --- a/src/renderer/Warnings.tsx +++ /dev/null @@ -1,168 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ -import { useEffect, useState } from 'react'; -import { CgCloseO } from 'react-icons/cg'; -import { ImWarning } from 'react-icons/im'; - -import electron from './electronGlobal'; -import IconButton from './IconButton'; -import { useAppDispatch } from './state/hooks'; -import { updateSystemNumFreeDiskGB } from './state/node'; - -const Warnings = () => { - const dispatch = useAppDispatch(); - // const sGethDiskUsed = useAppSelector(selectNumGethDiskUsedGB); - // const sFreeDisk = useAppSelector(selectNumFreeDiskGB); - - const [sIsOpen, setIsOpen] = useState(false); - const [sHasBeenClosed, setHasBeenClosed] = useState(false); - const [sWarnings, setWarnings] = useState(); - const [sStorageWarning] = useState(); - - const getSystemWarnings = async () => { - const warnings = await electron.checkSystemHardware(); - setWarnings(warnings); - }; - - // useEffect(() => { - // const updateGethDiskUsed = async () => { - // // todo: fix warnings for multi-client - // const gethDiskUsed = await electron.getGethDiskUsed(); - // if (gethDiskUsed) { - // dispatch(updateNodeNumGethDiskUsedGB(gethDiskUsed)); - // } - // }; - // updateGethDiskUsed(); - // const intveral = setInterval(updateGethDiskUsed, 30000); - // return () => clearInterval(intveral); - // }, [dispatch]); - - useEffect(() => { - const updateFreeDisk = async () => { - const freeDisk = await electron.getSystemFreeDiskSpace(); - if (freeDisk) { - dispatch(updateSystemNumFreeDiskGB(freeDisk)); - } - }; - updateFreeDisk(); - const intveral = setInterval(updateFreeDisk, 30000); - return () => clearInterval(intveral); - }, [dispatch]); - - // useEffect(() => { - // if (sFreeDisk !== undefined && sGethDiskUsed !== undefined) { - // if (sNodeConfig?.syncMode === 'light') { - // if (sFreeDisk < 2) { - // setStorageWarning(true); - // } else { - // setStorageWarning(false); - // } - // } else { - // // eslint-disable-next-line no-lonely-if - // if (sGethDiskUsed + sFreeDisk > 1000) { - // setStorageWarning(false); - // } else { - // setStorageWarning(true); - // } - // } - // } - // }, [sGethDiskUsed, sFreeDisk, sStorageWarning, sNodeConfig]); - - useEffect(() => { - // don't show the warning if it has already been closed - if (sHasBeenClosed) { - return; - } - if ((sWarnings && sWarnings.length > 0) || sStorageWarning) { - setIsOpen(true); - } else { - setIsOpen(false); - } - }, [sHasBeenClosed, sWarnings, sStorageWarning]); - - useEffect(() => { - getSystemWarnings(); - }, []); - - return ( -
- - - -
- {sWarnings?.map((warning) => { - return ( -
- - {warning} -
- ); - })} - {/* {sStorageWarning && ( -
- {sNodeConfig?.syncMode === 'light' ? ( - - - At least 2GB of storage is required to run an Ethereum light - client. Your computer does not have enough free SSD storage - space. - - ) : ( - - - At least 1 TB of storage is required to run an Ethereum Node. - Your computer does not have enough free SSD storage space. - - )} -
- )} */} - {((sWarnings && sWarnings.length > 0) || sStorageWarning) && ( -
- - Please visit ethereum.org to see computer hardware requirements at{' '} - - ethereum.org/run-a-node - - -
- - Or consider using light client mode available in Settings > - Node Configuration{' '} - - geth.ethereum.org/docs/interface/les - - -
- )} -
- - { - setIsOpen(false); - setHasBeenClosed(true); - }} - style={{ paddingRight: 0, paddingTop: 0 }} - > - - - -
- ); -}; -export default Warnings; diff --git a/src/stories/Generic/Header.stories.tsx b/src/stories/Generic/Header.stories.tsx index c9826c8db..9053adf9c 100644 --- a/src/stories/Generic/Header.stories.tsx +++ b/src/stories/Generic/Header.stories.tsx @@ -31,6 +31,6 @@ Primary.args = { currentSlot: 90, highestSlot: 190, cpuLoad: 90, - diskUsage: 10000, + diskUsageGBs: 10000, }, }; diff --git a/src/stories/Generic/HeaderMetrics.stories.tsx b/src/stories/Generic/HeaderMetrics.stories.tsx index 2d6b820dc..bf8d29bf3 100644 --- a/src/stories/Generic/HeaderMetrics.stories.tsx +++ b/src/stories/Generic/HeaderMetrics.stories.tsx @@ -33,6 +33,6 @@ Primary.args = { currentSlot: 90, highestSlot: 190, cpuLoad: 90, - diskUsage: 10000 + diskUsageGBs: 10000 }, }; diff --git a/src/stories/Presentational/ContentMultipleClients.stories.tsx b/src/stories/Presentational/ContentMultipleClients.stories.tsx index 254cf190f..f77ac58e6 100644 --- a/src/stories/Presentational/ContentMultipleClients.stories.tsx +++ b/src/stories/Presentational/ContentMultipleClients.stories.tsx @@ -40,7 +40,7 @@ Primary.args = { highestSlot: highestSlot, peers: 20, cpuLoad: 20, - diskUsage: 600, // in MB? + diskUsageGBs: 0.600, }, }, { @@ -64,7 +64,7 @@ Primary.args = { highestBlock: highestBlock, peers: 16, cpuLoad: 82, - diskUsage: 5000, + diskUsageGBs: 5.000, }, }, ], diff --git a/src/stories/Presentational/ContentSingleClient.stories.tsx b/src/stories/Presentational/ContentSingleClient.stories.tsx index 747272c34..3b399288e 100644 --- a/src/stories/Presentational/ContentSingleClient.stories.tsx +++ b/src/stories/Presentational/ContentSingleClient.stories.tsx @@ -8,9 +8,49 @@ export default { argTypes: {}, } as ComponentMeta; -const Template: ComponentStory = () => ( - +const Template: ComponentStory = (args) => ( + ); export const Primary = Template.bind({}); -Primary.args = {}; +Primary.args = { + nodeId: "1f916ffa-b5e8-421e-a9b2-622efc3e8223", + name: 'geth', + version: 'v10', + type: 'client', + nodeType: 'execution', + status: { + updating: false, + sychronized: true, + initialized: false, + lowPeerCount: false, + updateAvailable: false, + blocksBehind: true, + noConnection: false, + stopped: false, + error: false, + }, + stats: { + peers: 15, + currentBlock: 1000, + highestBlock: 2000, + cpuLoad: 20, + diskUsageGBs: 600, // in MB? + }, +}; + +export const LimitedData = Template.bind({}); +LimitedData.args = { + "nodeId": "1f916ffa-b5e8-421e-a9b2-622efc3e8223", + "name": "nethermind", + "type": 'client', + "nodeType": "L1/ExecutionClient", + "network": "Ethereum mainnet", + "status": { + "stopped": true, + "error": false + }, + "stats": { + "diskUsageGBs": 5.6 + } +};