Skip to content

Commit

Permalink
Ipc/account saving (#129)
Browse files Browse the repository at this point in the history
* human name saves to config using PromiseIPC

Signed-off-by: Sven Dowideit <[email protected]>

* use react-editext for inline editing - styling and fixes to come

Signed-off-by: Sven Dowideit <[email protected]>

* AccountView Alias edit styling hack

Signed-off-by: Sven Dowideit <[email protected]>

* linties

Signed-off-by: Sven Dowideit <[email protected]>

* save the private key when WB creates a new KeyPair

Signed-off-by: Sven Dowideit <[email protected]>

* linties

Signed-off-by: Sven Dowideit <[email protected]>
  • Loading branch information
SvenDowideit authored May 20, 2022
1 parent b41430a commit 5e7f96b
Show file tree
Hide file tree
Showing 15 changed files with 293 additions and 242 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,7 @@
"react": "^18.1.0",
"react-bootstrap": "^2.0.2",
"react-dom": "^18.1.0",
"react-editext": "^4.2.1",
"react-outside-click-handler": "^1.3.0",
"react-redux": "^8.0.1",
"react-router": "^6.2.2",
Expand Down
31 changes: 31 additions & 0 deletions src/main/ipc/accounts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import cfg from 'electron-cfg';
import promiseIpc from 'electron-promise-ipc';
import type { IpcMainEvent, IpcRendererEvent } from 'electron';

import { logger } from '../logger';

declare type IpcEvent = IpcRendererEvent & IpcMainEvent;

// Need to import the file and call a function (from the main process) to get the IPC promise to exist.
export function initAccountPromises() {
// gets written to .\AppData\Roaming\SolanaWorkbench\electron-cfg.json on windows
promiseIpc.on('ACCOUNT-GetAll', (event: IpcEvent | undefined) => {
logger.silly('main: called ACCOUNT-GetAll', event);
const config = cfg.get('accounts');
if (!config) {
return {};
}
return config;
});
// TODO: so the idea is that this == a list of private keys with annotations (like human name...)
// so it could be key: public key, value is a map[string]interface{} with a convention that 'privatekey' contains that in X form...
promiseIpc.on(
'ACCOUNT-Set',
(key: unknown, val: unknown, event?: IpcEvent | undefined) => {
logger.silly(`main: called ACCOUNT-Set, ${key}, ${val}, ${event}`);
return cfg.set(`accounts.${key}`, val);
}
);
}

export default {};
2 changes: 1 addition & 1 deletion src/main/config.ts → src/main/ipc/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import cfg from 'electron-cfg';
import promiseIpc from 'electron-promise-ipc';
import type { IpcMainEvent, IpcRendererEvent } from 'electron';

import { logger } from './logger';
import { logger } from '../logger';

declare type IpcEvent = IpcRendererEvent & IpcMainEvent;

Expand Down
4 changes: 3 additions & 1 deletion src/main/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import MenuBuilder from './menu';
import { resolveHtmlPath } from './util';
import { logger, initLogging } from './logger';
import { runValidator, validatorLogs } from './validator';
import { initConfigPromises } from './config';
import { initConfigPromises } from './ipc/config';
import { initAccountPromises } from './ipc/accounts';
import fetchAnchorIdl from './anchor';

import {
Expand All @@ -29,6 +30,7 @@ let mainWindow: BrowserWindow | null = null;
const MAX_STRING_LOG_LENGTH = 32;

initConfigPromises();
initAccountPromises();

ipcMain.on(
'main',
Expand Down
19 changes: 19 additions & 0 deletions src/renderer/App.scss
Original file line number Diff line number Diff line change
Expand Up @@ -191,4 +191,23 @@ th,

.vscroll {
overflow-y: auto;
}

// EdiText - https://github.com/alioguzhan/react-editext#styling-with-styled-components
div[editext='view-container'],
div[editext='view'],
div[editext='edit-container'] {
flex: 0 0 auto;
width: 100%;
}

div[editext='view'] {
width: calc(100% - 32px);
}
.align-center {
flex: 0 0 auto;
width: 100%;
display: flex;
align-items: center;
height: 2.4em; /* TODO: this is a terrible hack for aligning the "Editable Alias" with the inline edit box height. */
}
46 changes: 0 additions & 46 deletions src/renderer/components/AccountNameEditable.tsx

This file was deleted.

104 changes: 88 additions & 16 deletions src/renderer/components/AccountView.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@
import { useState } from 'react';
import { faTerminal } from '@fortawesome/free-solid-svg-icons';
import { useState, useEffect } from 'react';
import {
faTerminal,
faEdit,
faSave,
faCancel,
faKey,
} from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import Container from 'react-bootstrap/Container';
import ButtonGroup from 'react-bootstrap/ButtonGroup';
import ButtonToolbar from 'react-bootstrap/ButtonToolbar';
import { useInterval, useAppSelector } from '../hooks';
import EdiText from 'react-editext';
import { useInterval, useAppSelector, useAppDispatch } from '../hooks';

import analytics from '../common/analytics';
import { AccountInfo } from '../data/accounts/accountInfo';
import {
setAccountValues,
useAccountMeta,
} from '../data/accounts/accountState';
import {
truncateLamportAmount,
getHumanName,
Expand Down Expand Up @@ -43,6 +54,9 @@ const explorerURL = (net: Net, address: string) => {
function AccountView(props: { pubKey: string | undefined }) {
const { pubKey } = props;
const { net, status } = useAppSelector(selectValidatorNetworkState);
const dispatch = useAppDispatch();
const accountMeta = useAccountMeta(pubKey);
const [humanName, setHumanName] = useState<string>('');

const [account, setSelectedAccountInfo] = useState<AccountInfo | undefined>(
undefined
Expand All @@ -61,9 +75,28 @@ function AccountView(props: { pubKey: string | undefined }) {
}
}, 666);

const humanName = account
? getHumanName(account)
: 'No on-chain account selected';
useEffect(() => {
const alias = getHumanName(accountMeta);
setHumanName(alias);
logger.info(`get human name for pubKey ${pubKey} == ${alias}`);
}, [pubKey, accountMeta]);

const handleHumanNameSave = (val: string) => {
if (!pubKey) {
return;
}
dispatch(
setAccountValues({
key: pubKey,
value: {
...accountMeta,
humanname: val,
},
})
);
};

// const humanName = getHumanName(accountMeta);
return (
<Container>
<ButtonToolbar aria-label="Toolbar with button groups">
Expand All @@ -72,21 +105,40 @@ function AccountView(props: { pubKey: string | undefined }) {
<TransferSolButton pubKey={pubKey} />
</ButtonGroup>
</ButtonToolbar>
<div className="row">
<div className="col-auto">
<div>
<h6 className="ms-1">
{humanName !== '' ? humanName : <div>&nbsp;</div>}
</h6>
</div>
</div>
</div>

<div className="row">
<div className="col">
<div className="row">
<div className="col-auto">
<div className="col col-md-12 ">
<table className="table table-borderless table-sm mb-0">
<tbody>
<tr>
<td className="col-md-4">
<div className="align-center">
<div>
<small className="text-muted">Editable Alias</small>
</div>
</div>
</td>
<td className="col-md-8">
<small>
<EdiText
submitOnEnter
cancelOnEscape
buttonsAlign="after"
type="text"
value={humanName}
onSave={handleHumanNameSave}
hideIcons
editButtonContent={<FontAwesomeIcon icon={faEdit} />}
saveButtonContent={<FontAwesomeIcon icon={faSave} />}
cancelButtonContent={
<FontAwesomeIcon icon={faCancel} />
}
/>
</small>
</td>
</tr>
<tr>
<td>
<small className="text-muted">Pubkey</small>
Expand Down Expand Up @@ -127,6 +179,26 @@ function AccountView(props: { pubKey: string | undefined }) {
)}
</td>
</tr>
<tr>
<td>
<small className="text-muted">Private key known</small>
</td>
<td>
{accountMeta?.privatekey ? (
<div>
<FontAwesomeIcon
className="border-success rounded p-1 exe-icon"
icon={faKey}
/>
<small className="ms-1 mb-1">Yes</small>
</div>
) : (
<small className="fst-italic fw-light text-muted">
No
</small>
)}
</td>
</tr>
<tr>
<td>
<small className="text-muted">Explorer</small>
Expand Down
Loading

0 comments on commit 5e7f96b

Please sign in to comment.