dispatch(setSelected(pubKey))}
- className={selected ? 'bg-lightblue' : ''}
+ className={`transition duration-50 bg-opacity-20 hover:bg-opacity-30 hover:bg-primary-light ${
+ selected ? 'bg-primary-light' : ''
+ }`}
>
- pinAccount(pubKey, pinned)}>
+ | pinAccount(pubKey, pinned)} align="center">
-
+ {pinned ? : }
|
-
- {accountMeta?.privatekey ? (
-
- ) : (
- ''
- )}
+
+ {accountMeta?.privatekey ? : ''}
|
diff --git a/src/renderer/components/ProgramChangeView.tsx b/src/renderer/components/ProgramChangeView.tsx
index 0cb41cdb..c7951eaa 100644
--- a/src/renderer/components/ProgramChangeView.tsx
+++ b/src/renderer/components/ProgramChangeView.tsx
@@ -1,49 +1,36 @@
-import {
- faFilter,
- faSpinner,
- faSortDesc,
- faUnsorted,
-} from '@fortawesome/free-solid-svg-icons';
-import * as faRegular from '@fortawesome/free-regular-svg-icons';
-
+import { faSpinner } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { useEffect, useRef, useState } from 'react';
-import { Dropdown, DropdownButton, Button } from 'react-bootstrap';
-import ButtonGroup from 'react-bootstrap/ButtonGroup';
-import ButtonToolbar from 'react-bootstrap/ButtonToolbar';
-import Table from 'react-bootstrap/Table';
-import { toast } from 'react-toastify';
-import EdiText from 'react-editext';
-
-import OutsideClickHandler from 'react-outside-click-handler';
-
import { useWallet } from '@solana/wallet-adapter-react';
+import { useEffect, useState } from 'react';
+import { Button } from 'react-bootstrap';
+import { toast } from 'react-toastify';
+import { css } from 'vite-plugin-inline-css-modules';
import {
- setSelected,
accountsActions,
selectAccountsListState,
-} from 'renderer/data/SelectedAccountsList/selectedAccountsState';
-import { useInterval, useAppSelector, useAppDispatch } from '../hooks';
-import {
- selectValidatorNetworkState,
- NetStatus,
-} from '../data/ValidatorNetwork/validatorNetworkState';
+ setSelected,
+} from '@/data/SelectedAccountsList/selectedAccountsState';
+import { logger } from '@/common/globals';
+import createNewAccount from '../data/accounts/account';
+import { AccountInfo } from '../data/accounts/accountInfo';
import {
BASE58_PUBKEY_REGEX,
GetTopAccounts,
} from '../data/accounts/getAccount';
-import { AccountInfo } from '../data/accounts/accountInfo';
-
-import { ProgramChange } from './ProgramChange';
import {
- unsubscribeProgramChanges,
subscribeProgramChanges,
+ unsubscribeProgramChanges,
} from '../data/accounts/programChanges';
-import createNewAccount from '../data/accounts/account';
-import WatchAccountButton from './WatchAccountButton';
+import {
+ NetStatus,
+ selectValidatorNetworkState,
+} from '../data/ValidatorNetwork/validatorNetworkState';
+import { useAppDispatch, useAppSelector, useInterval } from '../hooks';
+import Chip from './base/Chip';
+import EditableText from './base/EditableText';
import InlinePK from './InlinePK';
-
-const logger = window.electron.log;
+import { ProgramChange } from './ProgramChange';
+import WatchAccountButton from './WatchAccountButton';
export const MAX_PROGRAM_CHANGES_DISPLAYED = 20;
export enum KnownProgramID {
@@ -56,6 +43,19 @@ interface PinnedAccountMap {
[pubKey: string]: boolean;
}
+const classes = css`
+ .account-view {
+ @apply w-full h-full border-collapse overflow-auto text-xs;
+ & th:not(:global(.text-center)) {
+ @apply text-left;
+ }
+
+ & th svg {
+ @apply inline-block;
+ }
+ }
+`;
+
function ProgramChangeView() {
const dispatch = useAppDispatch();
const { net, status } = useAppSelector(selectValidatorNetworkState);
@@ -137,8 +137,6 @@ function ProgramChangeView() {
}, 666);
const uniqueAccounts = displayList.length;
- const [filterDropdownShow, setFilterDropdownShow] = useState(false);
- const filterProgramIDRef = useRef({} as HTMLInputElement);
const [programID, setProgramID] = useState(
KnownProgramID.SystemProgram
@@ -159,169 +157,140 @@ function ProgramChangeView() {
}, [net, programID, status]);
if (status !== NetStatus.Running) {
- return network not available ;
+ return (
+
+
+
+
+ Network Not Available
+
+
+ );
}
- const changeFilterDropdownTitle = (
- <>
-
- Filter
- >
- );
+ const SortIcon: React.FC<{
+ sortColumn: SortColumn;
+ target: SortColumn;
+ }> = ({ sortColumn: column, target }) => {
+ return column === target ? (
+
+ ) : (
+
+ );
+ };
return (
-
+
+
+ Program Account Changes
+ (Validator Slot {validatorSlot})
+
-
- Program Account Changes:
- (Validator Slot {validatorSlot})
-
+
+
+
-
-
-
- setFilterDropdownShow(false)}
- display="inline"
+
+ Filter Programs
+
+ {Object.entries(KnownProgramID).map(([name, value]) => (
+ setProgramID(value)}
+ active={programID === value}
>
- {
- setFilterDropdownShow(false);
- if (s) setProgramID(s as KnownProgramID);
- }}
- onClick={() => {
- if (!filterDropdownShow) {
- setFilterDropdownShow(true);
- } else {
- setFilterDropdownShow(false);
- }
- }}
- className="ms-2 d-inline"
- variant="light"
- show={filterDropdownShow}
- >
-
-
- Program ID
-
-
-
- System Program
-
-
- Token Program
-
-
- Serum DEX V3
-
-
- {
- const pastedID = val;
- if (pastedID.match(BASE58_PUBKEY_REGEX)) {
- unsubscribeProgramChanges(net, programID);
- subscribeProgramChanges(
- net,
- programID,
- setValidatorSlot
- );
- setProgramID(pastedID);
- } else {
- toast.warn(`Invalid program ID: ${pastedID}`);
- }
- filterProgramIDRef.current.value = 'Custom';
- filterProgramIDRef.current.blur();
- setFilterDropdownShow(false);
- }}
- />
-
-
-
-
-
-
-
+ ))}
+
+
+
+
+
+
+ Program:
+ {
+ const pastedID = val;
+ if (pastedID.match(BASE58_PUBKEY_REGEX)) {
+ unsubscribeProgramChanges(net, programID);
+ subscribeProgramChanges(net, programID, setValidatorSlot);
+ setProgramID(pastedID);
+ } else {
+ toast.warn(`Invalid program ID: ${pastedID}`);
+ }
}}
- >
- Create Account
-
-
-
-
-
-
-
-
- Program:
- {programID}
+ />
+
+
{`${uniqueAccounts} account${uniqueAccounts > 1 ? 's' : ''}`}
-
-
-
-
+
+
+
+
{displayList.length > 0 ? (
-
-
-
-
+
+
+
+
{' '}
-
+
|
Address |
setSortColumn(SortColumn.MaxDelta)}>
Max Δ{' '}
-
|
setSortColumn(SortColumn.Sol)}>
SOL{' '}
-
+
|
setSortColumn(SortColumn.Count)}>
Count{' '}
-
+
|
+
+
{displayList
.slice(0, MAX_PROGRAM_CHANGES_DISPLAYED)
.map((pubKey: string) => {
@@ -337,7 +306,7 @@ function ProgramChangeView() {
);
})}
-
+ |
) : (
diff --git a/src/renderer/components/TransferSolButton.tsx b/src/renderer/components/TransferSolButton.tsx
index 0d134b2f..be20f6db 100644
--- a/src/renderer/components/TransferSolButton.tsx
+++ b/src/renderer/components/TransferSolButton.tsx
@@ -1,12 +1,11 @@
-import { useState, useEffect } from 'react';
-import OverlayTrigger from 'react-bootstrap/OverlayTrigger';
-import Popover from 'react-bootstrap/Popover';
+import { useConnection, useWallet } from '@solana/wallet-adapter-react';
+import { useEffect, useState } from 'react';
+import { Col, Row } from 'react-bootstrap';
import Button from 'react-bootstrap/Button';
import Form from 'react-bootstrap/Form';
-import { Row, Col } from 'react-bootstrap';
+import OverlayTrigger from 'react-bootstrap/OverlayTrigger';
+import Popover from 'react-bootstrap/Popover';
import { toast } from 'react-toastify';
-
-import { useConnection, useWallet } from '@solana/wallet-adapter-react';
import { sendSolFromSelectedWallet } from '../data/accounts/account';
function TransferSolPopover(props: { pubKey: string | undefined }) {
@@ -152,7 +151,9 @@ function TransferSolButton(props: { pubKey: string | undefined }) {
overlay={TransferSolPopover({ pubKey })}
rootClose
>
-
+
);
}
diff --git a/src/renderer/components/WatchAccountButton.tsx b/src/renderer/components/WatchAccountButton.tsx
index 9929e103..036ac265 100644
--- a/src/renderer/components/WatchAccountButton.tsx
+++ b/src/renderer/components/WatchAccountButton.tsx
@@ -1,10 +1,9 @@
-import { useState, useEffect } from 'react';
-
-import OverlayTrigger from 'react-bootstrap/OverlayTrigger';
-import Popover from 'react-bootstrap/Popover';
+import { useEffect, useState } from 'react';
+import { Col, Row } from 'react-bootstrap';
import Button from 'react-bootstrap/Button';
import Form from 'react-bootstrap/Form';
-import { Row, Col } from 'react-bootstrap';
+import OverlayTrigger from 'react-bootstrap/OverlayTrigger';
+import Popover from 'react-bootstrap/Popover';
function WatchAcountPopover(props: {
pinAccount: (pk: string, b: boolean) => void;
@@ -72,7 +71,9 @@ function WatchAccountButton(props: {
overlay={WatchAcountPopover({ pinAccount })}
rootClose
>
-
+
);
}
diff --git a/src/renderer/components/base/Chip.tsx b/src/renderer/components/base/Chip.tsx
new file mode 100644
index 00000000..1b56c4b5
--- /dev/null
+++ b/src/renderer/components/base/Chip.tsx
@@ -0,0 +1,32 @@
+import { css } from 'vite-plugin-inline-css-modules';
+
+const classes = css`
+ .chip {
+ @apply bg-surface-100 border-2 border-surface-300/50 w-min p-1 px-2 rounded-full select-none cursor-pointer bg-opacity-10 transition duration-100 hover:bg-surface-300 whitespace-nowrap;
+
+ &.active {
+ @apply bg-primary-base;
+ }
+ }
+`;
+
+const Chip: React.FC<
+ React.DetailedHTMLProps<
+ React.ButtonHTMLAttributes ,
+ HTMLButtonElement
+ > & {
+ active?: boolean;
+ }
+> = ({ children, active, ...rest }) => {
+ return (
+
+ );
+};
+
+export default Chip;
diff --git a/src/renderer/components/base/EditableText.tsx b/src/renderer/components/base/EditableText.tsx
new file mode 100644
index 00000000..277c97dd
--- /dev/null
+++ b/src/renderer/components/base/EditableText.tsx
@@ -0,0 +1,70 @@
+import { KeyboardEvent, useEffect, useRef, useState } from 'react';
+import IconButton from './IconButton';
+
+const EditableText: React.FC<
+ {
+ value: string;
+ onSave: (value: string) => void;
+ } & React.InputHTMLAttributes
+> = ({ value, onSave, ...rest }) => {
+ const [editingValue, setEditingValue] = useState(
+ undefined
+ );
+ const [editing, setEditing] = useState(false);
+ const input = useRef(null);
+
+ useEffect(() => {
+ input.current?.focus();
+ }, [editing]);
+
+ const save = () => {
+ onSave(editingValue || value);
+ setEditing(false);
+ };
+
+ const onKeyDown = (ev: KeyboardEvent) => {
+ switch (ev.key) {
+ case 'Enter':
+ save();
+ break;
+ case 'Escape':
+ setEditing(false);
+ break;
+ default:
+ break;
+ }
+ };
+
+ if (editing) {
+ return (
+
+ setEditingValue(ev.currentTarget.value)}
+ value={editingValue || value}
+ ref={input}
+ onKeyDown={onKeyDown}
+ />
+
+
+
+
+ setEditing(false)} dense>
+
+
+
+
+ );
+ }
+ return (
+
+ {value || 'Unset'}
+ setEditing(true)}>
+
+
+
+ );
+};
+
+export default EditableText;
diff --git a/src/renderer/components/base/IconButton.tsx b/src/renderer/components/base/IconButton.tsx
new file mode 100644
index 00000000..93777076
--- /dev/null
+++ b/src/renderer/components/base/IconButton.tsx
@@ -0,0 +1,37 @@
+import classNames from 'classnames';
+import { css } from 'vite-plugin-inline-css-modules';
+
+const classes = css`
+ .btn {
+ @apply p-3 hover:bg-contrast/20 active:bg-contrast/30 rounded-full transition duration-100;
+
+ &.dense {
+ @apply p-1;
+ }
+ }
+`;
+
+const IconButton: React.FC<
+ {
+ dense?: boolean;
+ } & React.DetailedHTMLProps<
+ React.ButtonHTMLAttributes,
+ HTMLButtonElement
+ >
+> = ({ children, className, dense, ...rest }) => {
+ return (
+
+ );
+};
+
+export default IconButton;
diff --git a/src/renderer/data/Config/configState.ts b/src/renderer/data/Config/configState.ts
index 4c1b003a..88f50147 100644
--- a/src/renderer/data/Config/configState.ts
+++ b/src/renderer/data/Config/configState.ts
@@ -1,14 +1,12 @@
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
-import { ConfigMap } from 'types/types';
import { useEffect } from 'react';
+import { logger } from '@/common/globals';
+import { ConfigMap } from '../../../../release/dist/main/types/types';
import { useAppDispatch, useAppSelector } from '../../hooks';
-
// https://redux.js.org/usage/usage-with-typescript#define-slice-state-and-action-types
// eslint-disable-next-line import/no-cycle
import { RootState } from '../../store';
-const logger = window.electron.log;
-
export enum ConfigKey {
AnalyticsEnabled = 'analytics_enabled',
}
diff --git a/src/renderer/data/ValidatorNetwork/ValidatorNetwork.tsx b/src/renderer/data/ValidatorNetwork/ValidatorNetwork.tsx
index 9cdc5c07..21e679b8 100644
--- a/src/renderer/data/ValidatorNetwork/ValidatorNetwork.tsx
+++ b/src/renderer/data/ValidatorNetwork/ValidatorNetwork.tsx
@@ -1,24 +1,18 @@
import * as sol from '@solana/web3.js';
-
import { useEffect } from 'react';
-
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import DropdownButton from 'react-bootstrap/DropdownButton';
import Dropdown from 'react-bootstrap/Dropdown';
-import { faNetworkWired, faCircle } from '@fortawesome/free-solid-svg-icons';
-
-import { useInterval, useAppSelector, useAppDispatch } from '../../hooks';
+import DropdownButton from 'react-bootstrap/DropdownButton';
+import { logger } from '@/common/globals';
+import { useAppDispatch, useAppSelector, useInterval } from '../../hooks';
import {
Net,
- netToURL,
NetStatus,
+ netToURL,
+ selectValidatorNetworkState,
setNet,
setState,
- selectValidatorNetworkState,
} from './validatorNetworkState';
-const logger = window.electron.log;
-
const validatorState = async (net: Net): Promise => {
let solConn: sol.Connection;
@@ -67,22 +61,21 @@ function ValidatorNetwork() {
};
let statusText = validator.status as string;
- let statusClass = 'text-danger';
+ let statusClass = 'text-red-500';
if (validator.status === NetStatus.Running) {
statusText = 'Available';
- statusClass = 'text-solgreen';
+ statusClass = 'text-green-500';
}
const statusDisplay = (
-
-
- {statusText}
-
+ <>
+
+ {statusText}
+ >
);
const netDropdownTitle = (
<>
- {' '}
- {net}
+ {net}
{statusDisplay}
>
);
@@ -90,10 +83,8 @@ function ValidatorNetwork() {
return (
diff --git a/src/renderer/data/accounts/account.ts b/src/renderer/data/accounts/account.ts
index 65e8da9a..658769ad 100644
--- a/src/renderer/data/accounts/account.ts
+++ b/src/renderer/data/accounts/account.ts
@@ -1,19 +1,16 @@
-import * as sol from '@solana/web3.js';
-
+import { AnyAction, Dispatch, ThunkDispatch } from '@reduxjs/toolkit';
import { WalletContextState } from '@solana/wallet-adapter-react';
-
-import { ThunkDispatch, AnyAction, Dispatch } from '@reduxjs/toolkit';
-import { AccountsState, reloadFromMain } from './accountState';
+import * as sol from '@solana/web3.js';
+import { logger } from '@/common/globals';
+import { NewKeyPairInfo } from '../../../types/types';
+import { ConfigState, setConfigValue } from '../Config/configState';
+import { SelectedAccountsList } from '../SelectedAccountsList/selectedAccountsState';
import {
Net,
netToURL,
ValidatorState,
} from '../ValidatorNetwork/validatorNetworkState';
-import { ConfigState, setConfigValue } from '../Config/configState';
-import { SelectedAccountsList } from '../SelectedAccountsList/selectedAccountsState';
-import { NewKeyPairInfo } from '../../../types/types';
-
-const logger = window.electron.log;
+import { AccountsState, reloadFromMain } from './accountState';
export async function airdropSol(net: Net, toKey: string, solAmount: string) {
const to = new sol.PublicKey(toKey);
diff --git a/src/renderer/data/accounts/accountState.ts b/src/renderer/data/accounts/accountState.ts
index e5869490..52093cf2 100644
--- a/src/renderer/data/accounts/accountState.ts
+++ b/src/renderer/data/accounts/accountState.ts
@@ -1,14 +1,12 @@
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
-import { useEffect } from 'react';
import * as sol from '@solana/web3.js';
+import { useEffect } from 'react';
+import { logger } from '@/common/globals';
import { useAppDispatch, useAppSelector } from '../../hooks';
-
// https://redux.js.org/usage/usage-with-typescript#define-slice-state-and-action-types
// eslint-disable-next-line import/no-cycle
import { RootState } from '../../store';
-const logger = window.electron.log;
-
export interface AccountMetaValues {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
[key: string]: any;
diff --git a/src/renderer/data/accounts/getAccount.ts b/src/renderer/data/accounts/getAccount.ts
index 5ee9d7c0..38f351a9 100644
--- a/src/renderer/data/accounts/getAccount.ts
+++ b/src/renderer/data/accounts/getAccount.ts
@@ -1,15 +1,11 @@
import * as sol from '@solana/web3.js';
+import hexdump from 'hexdump-nodejs';
import { LRUCache } from 'typescript-lru-cache';
-
-import { AccountInfo } from './accountInfo';
-
+import { logger } from '@/common/globals';
import { Net, netToURL } from '../ValidatorNetwork/validatorNetworkState';
+import { AccountInfo } from './accountInfo';
import { AccountMetaValues } from './accountState';
-const logger = window.electron.log;
-
-const hexdump = require('hexdump-nodejs');
-
export const BASE58_PUBKEY_REGEX = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;
const HEXDUMP_BYTES = 512;
diff --git a/src/renderer/data/accounts/programChanges.ts b/src/renderer/data/accounts/programChanges.ts
index 572cf56e..3e084581 100644
--- a/src/renderer/data/accounts/programChanges.ts
+++ b/src/renderer/data/accounts/programChanges.ts
@@ -1,11 +1,9 @@
import * as sol from '@solana/web3.js';
+import { logger } from '@/common/globals';
import { Net, netToURL } from '../ValidatorNetwork/validatorNetworkState';
-
import { AccountInfo } from './accountInfo';
import { peekAccount, updateCache } from './getAccount';
-const logger = window.electron.log;
-
export interface ProgramChangesState {
changes: AccountInfo[];
paused: boolean;
diff --git a/src/renderer/index.css b/src/renderer/index.css
new file mode 100644
index 00000000..85752803
--- /dev/null
+++ b/src/renderer/index.css
@@ -0,0 +1,67 @@
+html, body, #root {
+ @apply bg-surface-500 w-full h-full;
+}
+
+::-webkit-scrollbar {
+ width: 10px;
+}
+
+::-webkit-scrollbar-track {
+ @apply bg-surface-400;
+}
+
+::-webkit-scrollbar-thumb {
+ @apply bg-surface-300;
+}
+
+::-webkit-scrollbar-thumb:hover {
+ @apply bg-surface-300;
+}
+
+textarea, input {
+ @apply bg-surface-600 focus:outline-none focus:ring focus:ring-primary-light rounded-md focus:ring-2 ring-offset-2 ring-offset-surface-400 text-contrast p-2;
+ &.dense {
+ @apply p-1;
+ }
+}
+
+svg {
+ @apply align-text-bottom;
+}
+
+code {
+ @apply overflow-ellipsis text-xs bg-surface-300 p-1 rounded-lg border-surface-100 border-1 mr-2;
+}
+
+.btn {
+ @apply bg-primary-base p-1 text-contrast py-3 px-4 rounded-md cursor-pointer focus:outline outline-offset-2 outline-2 outline-primary-base;
+
+ &.btn-sm {
+ @apply text-xs py-2 px-3;
+ }
+}
+
+.gutter {
+ @apply bg-surface-200 transition duration-50 active:bg-surface-100;
+
+ &.gutter-horizontal {
+ cursor: col-resize;
+ }
+
+ &.gutter-vertical {
+ cursor: row-resize;
+ }
+}
+
+/* TODO: move away from bootstrap to have nicer custom buttons and reduce bloat */
+.popover-header {
+ @apply bg-surface-300;
+}
+
+.popover-body, .dropdown-menu {
+ @apply bg-surface-400 text-contrast;
+}
+
+.dropdown-item {
+ @apply text-contrast hover:bg-surface-500 hover:text-contrast;
+}
diff --git a/src/renderer/index.ejs b/src/renderer/index.ejs
deleted file mode 100644
index 7c0d860e..00000000
--- a/src/renderer/index.ejs
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
- Solana Workbench
-
-
-
-
-
diff --git a/src/renderer/index.html b/src/renderer/index.html
new file mode 100644
index 00000000..e1fecfe6
--- /dev/null
+++ b/src/renderer/index.html
@@ -0,0 +1,17 @@
+
+
+
+
+ Solana Workbench
+
+
+
+
+
+
+
diff --git a/src/renderer/index.tsx b/src/renderer/index.tsx
index bce21fab..2d8a0209 100644
--- a/src/renderer/index.tsx
+++ b/src/renderer/index.tsx
@@ -1,16 +1,20 @@
+import { createRoot } from 'react-dom/client';
import { Provider } from 'react-redux';
-import { render } from 'react-dom';
import { HashRouter } from 'react-router-dom';
+import 'virtual:fonts.css';
+import 'virtual:windi.css';
import App from './App';
-
+import './index.css';
import store from './store';
const rootElement = document.getElementById('root');
-render(
+// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+const root = createRoot(rootElement!);
+
+root.render(
- ,
- rootElement
+
);
diff --git a/src/renderer/nav/Account.tsx b/src/renderer/nav/Account.tsx
index 39b53b7d..2f649a1f 100644
--- a/src/renderer/nav/Account.tsx
+++ b/src/renderer/nav/Account.tsx
@@ -1,11 +1,9 @@
-import { Col, Row } from 'react-bootstrap';
-
import Split from 'react-split';
import AccountView from '../components/AccountView';
-import ProgramChangeView from '../components/ProgramChangeView';
import LogView from '../components/LogView';
-import { useAppSelector } from '../hooks';
+import ProgramChangeView from '../components/ProgramChangeView';
import { selectAccountsListState } from '../data/SelectedAccountsList/selectedAccountsState';
+import { useAppSelector } from '../hooks';
function Account() {
const accounts = useAppSelector(selectAccountsListState);
@@ -13,32 +11,30 @@ function Account() {
return (
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
transaction or program details
-
-
-
+
+
+
-
+
-
+
);
}
diff --git a/src/renderer/nav/Anchor.tsx b/src/renderer/nav/Anchor.tsx
index 7463ac73..5f25a895 100644
--- a/src/renderer/nav/Anchor.tsx
+++ b/src/renderer/nav/Anchor.tsx
@@ -24,8 +24,8 @@ function Anchor() {
}, []);
return (
-
-
+
+
Program ID
@@ -43,13 +43,13 @@ function Anchor() {
{idl?.error ? (
-
+
{idl.error?.message}
) : (
''
)}
-
+
{idl.instructions ? (
idl.instructions.map((instruction: any) => {
return (
@@ -57,7 +57,7 @@ function Anchor() {
{instruction.name}
-
+
- Args
diff --git a/src/renderer/nav/Validator.tsx b/src/renderer/nav/Validator.tsx
index 74f3fa4a..ac1eb306 100644
--- a/src/renderer/nav/Validator.tsx
+++ b/src/renderer/nav/Validator.tsx
@@ -4,12 +4,11 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { useEffect, useRef, useState } from 'react';
import { Button, FormControl, InputGroup } from 'react-bootstrap';
import { debounce } from 'underscore';
-
-import { useInterval, useAppSelector } from '../hooks';
import {
NetStatus,
selectValidatorNetworkState,
} from '../data/ValidatorNetwork/validatorNetworkState';
+import { useAppSelector, useInterval } from '../hooks';
const Validator = () => {
const [validatorLogs, setValidatorLogs] = useState('');
@@ -50,7 +49,7 @@ const Validator = () => {
// TODO(nathanleclaire): Don't nest ternary
return (
-
+
{!(validator.status === NetStatus.Running) &&
!(validator.status === NetStatus.Starting) ? (
|