From b56ae1c862643e13291708df0f8cfac5fa1a64c0 Mon Sep 17 00:00:00 2001 From: Keith Date: Wed, 24 Jul 2019 16:33:57 +0800 Subject: [PATCH 01/16] feat: subscribe network list from neuron-wallet in neuron-ui --- .../neuron-ui/src/containers/Main/hooks.ts | 22 ++++++++++------- packages/neuron-ui/src/services/UILayer.ts | 1 - packages/neuron-ui/src/services/subjects.ts | 13 ++++++++-- .../src/states/stateProvider/reducer.ts | 10 ++++++++ packages/neuron-ui/src/utils/initializeApp.ts | 24 +++++++------------ .../src/controllers/app/index.ts | 3 --- 6 files changed, 42 insertions(+), 31 deletions(-) diff --git a/packages/neuron-ui/src/containers/Main/hooks.ts b/packages/neuron-ui/src/containers/Main/hooks.ts index 094bb5a8e3..c9d32b7e78 100644 --- a/packages/neuron-ui/src/containers/Main/hooks.ts +++ b/packages/neuron-ui/src/containers/Main/hooks.ts @@ -15,7 +15,11 @@ import UILayer, { networksCall, } from 'services/UILayer' import { initWindow } from 'services/remote' -import { SystemScript as SystemScriptSubject, DataUpdate as DataUpdateSubject } from 'services/subjects' +import { + SystemScript as SystemScriptSubject, + DataUpdate as DataUpdateSubject, + NetworkList as NetworkListSubject, +} from 'services/subjects' import { ckbCore, getTipBlockNumber, getBlockchainInfo } from 'services/chain' import { Routes, Channel, ConnectionStatus } from 'utils/const' import { @@ -262,14 +266,6 @@ export const useChannelListeners = ({ UILayer.on(Channel.Networks, (_e: Event, method: NetworksMethod, args: ChannelResponse) => { if (args.status) { switch (method) { - case NetworksMethod.GetAll: { - dispatch({ - type: NeuronWalletActions.Settings, - payload: { networks: args.result || [] }, - }) - networksCache.save(args.result || []) - break - } case NetworksMethod.CurrentID: { dispatch({ type: NeuronWalletActions.Chain, @@ -455,9 +451,17 @@ export const useSubscription = ({ } } }) + const networkListSubscription = NetworkListSubject.subscribe(({ currentNetworkList = [] }) => { + dispatch({ + type: NeuronWalletActions.UpdateNetworkList, + payload: currentNetworkList, + }) + networksCache.save(currentNetworkList) + }) return () => { systemScriptSubscription.unsubscribe() dataUpdateSubscription.unsubscribe() + networkListSubscription.unsubscribe() } }, [walletID, pageNo, pageSize, keywords, txHash, dispatch]) } diff --git a/packages/neuron-ui/src/services/UILayer.ts b/packages/neuron-ui/src/services/UILayer.ts index 14d5a9e9aa..c0a8d8790c 100644 --- a/packages/neuron-ui/src/services/UILayer.ts +++ b/packages/neuron-ui/src/services/UILayer.ts @@ -36,7 +36,6 @@ export enum WalletsMethod { } export enum NetworksMethod { - GetAll = 'getAll', Get = 'get', Create = 'create', Update = 'update', diff --git a/packages/neuron-ui/src/services/subjects.ts b/packages/neuron-ui/src/services/subjects.ts index 6523260f5a..bc93517b2d 100644 --- a/packages/neuron-ui/src/services/subjects.ts +++ b/packages/neuron-ui/src/services/subjects.ts @@ -1,3 +1,5 @@ +const SUBJECT_PATH = `./models/subjects` + const FallbackSubject = { subscribe: (args: any) => { console.warn('remote is not supported') @@ -13,18 +15,25 @@ const FallbackSubject = { }, } export const SystemScript = window.remote - ? (window.remote.require('./models/subjects/system-script').default as NeuronWalletSubject<{ codeHash: string }>) + ? (window.remote.require(`${SUBJECT_PATH}/system-script`).default as NeuronWalletSubject<{ codeHash: string }>) : FallbackSubject export const DataUpdate = window.remote - ? (window.remote.require('./models/subjects/data-update').default as NeuronWalletSubject<{ + ? (window.remote.require(`${SUBJECT_PATH}/data-update`).default as NeuronWalletSubject<{ dataType: 'address' | 'transaction' | 'wallet' | 'network' actionType: 'create' | 'update' | 'delete' walletID?: string }>) : FallbackSubject +export const NetworkList = window.remote + ? (window.remote.require(`${SUBJECT_PATH}/networks`).NetworkListSubject as NeuronWalletSubject<{ + currentNetworkList: State.Network[] + }>) + : FallbackSubject + export default { SystemScript, DataUpdate, + NetworkList, } diff --git a/packages/neuron-ui/src/states/stateProvider/reducer.ts b/packages/neuron-ui/src/states/stateProvider/reducer.ts index 9797fdbe8d..632e0a7553 100644 --- a/packages/neuron-ui/src/states/stateProvider/reducer.ts +++ b/packages/neuron-ui/src/states/stateProvider/reducer.ts @@ -7,6 +7,7 @@ export enum NeuronWalletActions { Wallet = 'wallet', Settings = 'settings', UpdateCodeHash = 'updateCodeHash', + UpdateNetworkList = 'updateNetworkList', } export enum AppActions { UpdateTransactionID = 'updateTransactionID', @@ -137,6 +138,15 @@ export const reducer = ( }, } } + case NeuronWalletActions.UpdateNetworkList: { + return { + ...state, + settings: { + ...settings, + networks: payload, + }, + } + } // Actions of App case AppActions.UpdateTipBlockNumber: { /** diff --git a/packages/neuron-ui/src/utils/initializeApp.ts b/packages/neuron-ui/src/utils/initializeApp.ts index 2a7281c665..27415c01e2 100644 --- a/packages/neuron-ui/src/utils/initializeApp.ts +++ b/packages/neuron-ui/src/utils/initializeApp.ts @@ -3,7 +3,6 @@ import initStates from 'states/initStates' import { wallets as walletsCache, - networks as networksCache, addresses as addressesCache, currentNetworkID as currentNetworkIDCache, currentWallet as currentWalletCache, @@ -27,8 +26,6 @@ const intializeApp = ({ }) => { const { locale = '', - networks = [], - currentNetworkID: networkID = '', wallets = [], currentWallet: wallet = initStates.wallet, addresses = [], @@ -47,17 +44,14 @@ const intializeApp = ({ } else { history.push(`${Routes.WalletWizard}${WalletWizardPath.Welcome}`) } - if (networks.length) { - dispatch({ - type: NeuronWalletActions.Initiate, - payload: { - networks, - networkID, - wallet: { ...wallet, balance: addressesToBalance(addresses), addresses }, - wallets, - }, - }) - } + dispatch({ + type: NeuronWalletActions.Initiate, + payload: { + networkID, + wallet: { ...wallet, balance: addressesToBalance(addresses), addresses }, + wallets, + }, + }) dispatch({ type: NeuronWalletActions.Chain, payload: { @@ -69,10 +63,8 @@ const intializeApp = ({ }) currentWalletCache.save(wallet) - currentNetworkIDCache.save(networkID) walletsCache.save(wallets) addressesCache.save(addresses) - networksCache.save(networks) systemScriptCache.save({ codeHash }) } export default intializeApp diff --git a/packages/neuron-wallet/src/controllers/app/index.ts b/packages/neuron-wallet/src/controllers/app/index.ts index 26aafda06f..c648356536 100644 --- a/packages/neuron-wallet/src/controllers/app/index.ts +++ b/packages/neuron-wallet/src/controllers/app/index.ts @@ -29,7 +29,6 @@ export default class AppController { currentWallet = null, wallets = [], currentNetworkID = '', - networks = [], tipNumber = '0', connectionStatus = false, codeHash = '', @@ -37,7 +36,6 @@ export default class AppController { walletsService.getCurrent(), walletsService.getAll(), networksService.getCurrentID(), - networksService.getAll(), SyncInfoController.currentBlockNumber() .then(res => { if (res.status) { @@ -80,7 +78,6 @@ export default class AppController { wallets: [...wallets.map(({ name, id }) => ({ id, name }))], addresses, currentNetworkID, - networks, transactions, locale, tipNumber, From 11736226342e8fc50dab9cada5e7f7ee6b9f1a4f Mon Sep 17 00:00:00 2001 From: Keith Date: Wed, 24 Jul 2019 16:43:09 +0800 Subject: [PATCH 02/16] feat(neuron-ui): subscribe current network id from neuron-wallet in neuron-ui --- .../src/components/ErrorBoundary/index.tsx | 1 + .../neuron-ui/src/containers/Footer/index.tsx | 6 +++--- .../neuron-ui/src/containers/Main/hooks.ts | 17 ++++++++-------- .../neuron-ui/src/containers/Main/index.tsx | 4 ++-- packages/neuron-ui/src/services/subjects.ts | 7 +++++++ .../src/states/stateProvider/reducer.ts | 14 ++++++++++--- packages/neuron-ui/src/utils/initializeApp.ts | 2 -- .../src/controllers/app/index.ts | 5 ----- .../src/models/subjects/networks.ts | 20 +++++-------------- .../neuron-wallet/src/services/networks.ts | 20 +++++++++++++------ 10 files changed, 52 insertions(+), 44 deletions(-) diff --git a/packages/neuron-ui/src/components/ErrorBoundary/index.tsx b/packages/neuron-ui/src/components/ErrorBoundary/index.tsx index 9fd0e25ca9..499867d979 100644 --- a/packages/neuron-ui/src/components/ErrorBoundary/index.tsx +++ b/packages/neuron-ui/src/components/ErrorBoundary/index.tsx @@ -16,6 +16,7 @@ class ErrorBoundary extends Component<{ children: React.ReactChild }, { hasError } static getDerivedStateFromError(error: Error) { + window.alert(error.stack) return handleError(error) } diff --git a/packages/neuron-ui/src/containers/Footer/index.tsx b/packages/neuron-ui/src/containers/Footer/index.tsx index f2b7e66dc6..6363d5dbdb 100644 --- a/packages/neuron-ui/src/containers/Footer/index.tsx +++ b/packages/neuron-ui/src/containers/Footer/index.tsx @@ -67,9 +67,9 @@ const Footer = ({ location: { pathname }, }: React.PropsWithoutRef) => { const { - app: { tipBlockNumber }, - chain: { networkID, connectionStatus, tipBlockNumber: syncedBlockNumber }, - settings: { networks }, + app: { tipBlockNumber = '0' }, + chain: { networkID = '', connectionStatus = ConnectionStatus.Offline, tipBlockNumber: syncedBlockNumber = '0' }, + settings: { networks = [] }, } = useContext(NeuronWalletContext) const [t] = useTranslation() diff --git a/packages/neuron-ui/src/containers/Main/hooks.ts b/packages/neuron-ui/src/containers/Main/hooks.ts index c9d32b7e78..7f774241ac 100644 --- a/packages/neuron-ui/src/containers/Main/hooks.ts +++ b/packages/neuron-ui/src/containers/Main/hooks.ts @@ -19,6 +19,7 @@ import { SystemScript as SystemScriptSubject, DataUpdate as DataUpdateSubject, NetworkList as NetworkListSubject, + CurrentNetworkID as CurrentNetworkIDSubject, } from 'services/subjects' import { ckbCore, getTipBlockNumber, getBlockchainInfo } from 'services/chain' import { Routes, Channel, ConnectionStatus } from 'utils/const' @@ -266,14 +267,6 @@ export const useChannelListeners = ({ UILayer.on(Channel.Networks, (_e: Event, method: NetworksMethod, args: ChannelResponse) => { if (args.status) { switch (method) { - case NetworksMethod.CurrentID: { - dispatch({ - type: NeuronWalletActions.Chain, - payload: { networkID: args.result }, - }) - currentNetworkIDCache.save(args.result) - break - } case NetworksMethod.Create: case NetworksMethod.Update: { history.push(Routes.SettingsNetworks) @@ -458,10 +451,18 @@ export const useSubscription = ({ }) networksCache.save(currentNetworkList) }) + const currentNetworkIDSubscription = CurrentNetworkIDSubject.subscribe(({ currentNetworkID = '' }) => { + dispatch({ + type: NeuronWalletActions.UpdateCurrentNetworkID, + payload: currentNetworkID, + }) + currentNetworkIDCache.save(currentNetworkID) + }) return () => { systemScriptSubscription.unsubscribe() dataUpdateSubscription.unsubscribe() networkListSubscription.unsubscribe() + currentNetworkIDSubscription.unsubscribe() } }, [walletID, pageNo, pageSize, keywords, txHash, dispatch]) } diff --git a/packages/neuron-ui/src/containers/Main/index.tsx b/packages/neuron-ui/src/containers/Main/index.tsx index 55095f47b6..da25f5667d 100644 --- a/packages/neuron-ui/src/containers/Main/index.tsx +++ b/packages/neuron-ui/src/containers/Main/index.tsx @@ -108,9 +108,9 @@ const MainContent = ({ }: React.PropsWithoutRef<{ dispatch: StateDispatch } & RouteComponentProps>) => { const neuronWalletState = useState() const { - wallet: { id: walletID }, + wallet: { id: walletID = '' }, chain, - settings: { networks }, + settings: { networks = [] }, } = neuronWalletState const { networkID } = chain const [, i18n] = useTranslation() diff --git a/packages/neuron-ui/src/services/subjects.ts b/packages/neuron-ui/src/services/subjects.ts index bc93517b2d..5db929ae24 100644 --- a/packages/neuron-ui/src/services/subjects.ts +++ b/packages/neuron-ui/src/services/subjects.ts @@ -32,8 +32,15 @@ export const NetworkList = window.remote }>) : FallbackSubject +export const CurrentNetworkID = window.remote + ? (window.remote.require(`${SUBJECT_PATH}/networks`).CurrentNetworkIDSubject as NeuronWalletSubject<{ + currentNetworkID: string + }>) + : FallbackSubject + export default { SystemScript, DataUpdate, NetworkList, + CurrentNetworkID, } diff --git a/packages/neuron-ui/src/states/stateProvider/reducer.ts b/packages/neuron-ui/src/states/stateProvider/reducer.ts index 632e0a7553..5418b4d306 100644 --- a/packages/neuron-ui/src/states/stateProvider/reducer.ts +++ b/packages/neuron-ui/src/states/stateProvider/reducer.ts @@ -8,6 +8,7 @@ export enum NeuronWalletActions { Settings = 'settings', UpdateCodeHash = 'updateCodeHash', UpdateNetworkList = 'updateNetworkList', + UpdateCurrentNetworkID = 'updateCurrentNetworkID', } export enum AppActions { UpdateTransactionID = 'updateTransactionID', @@ -53,18 +54,16 @@ export const reducer = ( switch (type) { // Actions of Neuron Wallet case NeuronWalletActions.Initiate: { - const { networks, networkID, wallets, wallet: incomingWallet } = payload + const { wallets, wallet: incomingWallet } = payload return { ...state, wallet: incomingWallet || wallet, chain: { ...state.chain, - networkID, }, settings: { ...state.settings, wallets, - networks, }, } } @@ -147,6 +146,15 @@ export const reducer = ( }, } } + case NeuronWalletActions.UpdateCurrentNetworkID: { + return { + ...state, + chain: { + ...chain, + networkID: payload, + }, + } + } // Actions of App case AppActions.UpdateTipBlockNumber: { /** diff --git a/packages/neuron-ui/src/utils/initializeApp.ts b/packages/neuron-ui/src/utils/initializeApp.ts index 27415c01e2..55f489c2dc 100644 --- a/packages/neuron-ui/src/utils/initializeApp.ts +++ b/packages/neuron-ui/src/utils/initializeApp.ts @@ -4,7 +4,6 @@ import initStates from 'states/initStates' import { wallets as walletsCache, addresses as addressesCache, - currentNetworkID as currentNetworkIDCache, currentWallet as currentWalletCache, systemScript as systemScriptCache, language as languageCache, @@ -47,7 +46,6 @@ const intializeApp = ({ dispatch({ type: NeuronWalletActions.Initiate, payload: { - networkID, wallet: { ...wallet, balance: addressesToBalance(addresses), addresses }, wallets, }, diff --git a/packages/neuron-wallet/src/controllers/app/index.ts b/packages/neuron-wallet/src/controllers/app/index.ts index c648356536..282dc25552 100644 --- a/packages/neuron-wallet/src/controllers/app/index.ts +++ b/packages/neuron-wallet/src/controllers/app/index.ts @@ -6,7 +6,6 @@ import app from '../../app' import { URL, contextMenuTemplate } from './options' import TransactionsController from '../transactions' -import NetworksService from '../../services/networks' import WalletsService from '../../services/wallets' import NodeService from '../../services/node' import WalletsController from '../wallets' @@ -18,7 +17,6 @@ import WindowManager from '../../models/window-manager' import i18n from '../../utils/i18n' import env from '../../env' -const networksService = NetworksService.getInstance() const nodeService = NodeService.getInstance() @ControllerDecorator(Channel.App) @@ -28,14 +26,12 @@ export default class AppController { const [ currentWallet = null, wallets = [], - currentNetworkID = '', tipNumber = '0', connectionStatus = false, codeHash = '', ] = await Promise.all([ walletsService.getCurrent(), walletsService.getAll(), - networksService.getCurrentID(), SyncInfoController.currentBlockNumber() .then(res => { if (res.status) { @@ -77,7 +73,6 @@ export default class AppController { }, wallets: [...wallets.map(({ name, id }) => ({ id, name }))], addresses, - currentNetworkID, transactions, locale, tipNumber, diff --git a/packages/neuron-wallet/src/models/subjects/networks.ts b/packages/neuron-wallet/src/models/subjects/networks.ts index 56dcf54594..3e53b21f13 100644 --- a/packages/neuron-wallet/src/models/subjects/networks.ts +++ b/packages/neuron-wallet/src/models/subjects/networks.ts @@ -1,20 +1,10 @@ -import { Subject } from 'rxjs' -import { debounceTime } from 'rxjs/operators' -import DataUpdateSubject from './data-update' +import { BehaviorSubject } from 'rxjs' -const DEBOUNCE_TIME = 50 - -export const NetworkListSubject = new Subject<{ +export const NetworkListSubject = new BehaviorSubject<{ currentNetworkList: Controller.Network[] -}>() -export const CurrentNetworkIDSubject = new Subject<{ currentNetworkID: Controller.NetworkID }>() - -NetworkListSubject.pipe(debounceTime(DEBOUNCE_TIME)).subscribe(() => { - DataUpdateSubject.next({ dataType: 'network', actionType: 'update' }) -}) - -CurrentNetworkIDSubject.pipe(debounceTime(DEBOUNCE_TIME)).subscribe(() => { - DataUpdateSubject.next({ dataType: 'network', actionType: 'update' }) +}>({ currentNetworkList: [] }) +export const CurrentNetworkIDSubject = new BehaviorSubject<{ currentNetworkID: Controller.NetworkID }>({ + currentNetworkID: '', }) export default { diff --git a/packages/neuron-wallet/src/services/networks.ts b/packages/neuron-wallet/src/services/networks.ts index 8942747201..6a48326dea 100644 --- a/packages/neuron-wallet/src/services/networks.ts +++ b/packages/neuron-wallet/src/services/networks.ts @@ -45,6 +45,20 @@ export default class NetworksService extends Store { constructor() { super('networks', 'index.json', JSON.stringify(env.presetNetworks)) + this.getAll().then(currentNetworkList => { + if (currentNetworkList) { + NetworkListSubject.next({ + currentNetworkList, + }) + } + }) + + this.getCurrentID().then(currentNetworkID => { + if (currentNetworkID) { + CurrentNetworkIDSubject.next({ currentNetworkID }) + } + }) + this.on(NetworksKey.List, async (_, currentNetworkList: NetworkWithID[] = []) => { NetworkListSubject.next({ currentNetworkList }) @@ -69,12 +83,6 @@ export default class NetworksService extends Store { NodeService.getInstance().setNetwork(currentNetwork.remote) networkSwitchSubject.next(currentNetwork) }) - - this.getCurrentID().then(currentID => { - if (currentID) { - this.emit(NetworksKey.Current, null, currentID) - } - }) } public getAll = async () => { From c4bc431466d9aabc6413ca01da92d9eb24244082 Mon Sep 17 00:00:00 2001 From: Keith Date: Wed, 24 Jul 2019 18:31:15 +0800 Subject: [PATCH 03/16] feat(neuron-ui): call networks controller's methods by remote module --- .../src/components/NetworkEditor/hooks.ts | 87 ++++++++++++- .../src/components/NetworkEditor/index.tsx | 2 +- .../src/components/NetworkSetting/index.tsx | 16 +-- .../neuron-ui/src/containers/Main/hooks.ts | 38 ------ packages/neuron-ui/src/services/UILayer.ts | 22 ---- packages/neuron-ui/src/services/remote.ts | 101 ++++++++++++++++ .../stateProvider/actionCreators/index.ts | 2 - .../stateProvider/actionCreators/networks.ts | 114 ------------------ .../src/states/stateProvider/reducer.ts | 1 + 9 files changed, 192 insertions(+), 191 deletions(-) delete mode 100644 packages/neuron-ui/src/states/stateProvider/actionCreators/networks.ts diff --git a/packages/neuron-ui/src/components/NetworkEditor/hooks.ts b/packages/neuron-ui/src/components/NetworkEditor/hooks.ts index c3bf8cf0ef..4548ae8d6b 100644 --- a/packages/neuron-ui/src/components/NetworkEditor/hooks.ts +++ b/packages/neuron-ui/src/components/NetworkEditor/hooks.ts @@ -1,7 +1,8 @@ import { useState, useEffect, useMemo, useCallback } from 'react' import { AppActions, StateDispatch } from 'states/stateProvider/reducer' -import actionCreators from 'states/stateProvider/actionCreators' +import { Message, MAX_NETWORK_NAME_LENGTH, Routes } from 'utils/const' +import { createNetwork, updateNetwork } from 'services/remote' import i18n from 'utils/i18n' @@ -119,11 +120,89 @@ export const useHandleSubmit = ( name: string = '', remote: string = '', networks: State.Network[] = [], + history: any, dispatch: StateDispatch ) => - useCallback(() => { - dispatch(actionCreators.createOrUpdateNetwork({ id, name, remote }, networks)) - }, [id, name, remote, networks, dispatch]) + useCallback(async () => { + const warning = { + type: 'warning', + timestamp: Date.now(), + content: '', + } + let res + if (!name) { + return dispatch({ + type: AppActions.AddNotification, + payload: { + ...warning, + content: i18n.t(Message.NameRequired), + }, + }) + } + if (name.length > MAX_NETWORK_NAME_LENGTH) { + return dispatch({ + type: AppActions.AddNotification, + payload: { + ...warning, + content: i18n.t(Message.LengthOfNameShouldBeLessThanOrEqualTo, { + length: MAX_NETWORK_NAME_LENGTH, + }), + }, + }) + } + if (!remote) { + return dispatch({ + type: AppActions.AddNotification, + payload: { + ...warning, + content: i18n.t(Message.URLRequired), + }, + }) + } + if (!remote.startsWith('http')) { + return dispatch({ + type: AppActions.AddNotification, + payload: { + ...warning, + content: i18n.t(Message.ProtocolRequired), + }, + }) + } + // verification, for now, only name is unique + if (id === 'new') { + if (networks.some(network => network.name === name)) { + return dispatch({ + type: AppActions.AddNotification, + payload: { + ...warning, + content: i18n.t(Message.NetworkNameUsed), + }, + }) + } + res = await createNetwork({ + name, + remote, + }) + } else { + if (networks.some(network => network.name === name && network.id !== id)) { + return dispatch({ + type: AppActions.AddNotification, + payload: { + ...warning, + content: i18n.t(Message.NetworkNameUsed), + }, + }) + } + res = await updateNetwork(id!, { + name, + remote, + }) + } + if (res && res.status) { + history.push(Routes.SettingsNetworks) + } + return res + }, [id, name, remote, networks, history, dispatch]) export default { useInitialize, diff --git a/packages/neuron-ui/src/components/NetworkEditor/index.tsx b/packages/neuron-ui/src/components/NetworkEditor/index.tsx index 82903bc3ae..e41d6df20a 100644 --- a/packages/neuron-ui/src/components/NetworkEditor/index.tsx +++ b/packages/neuron-ui/src/components/NetworkEditor/index.tsx @@ -24,7 +24,7 @@ const NetworkEditor = ({ const cachedNetworks = useRef(networks) const cachedNetwork = cachedNetworks.current.find(network => network.id === id) const { invalidParams, notModified } = useIsInputsValid(editor, cachedNetwork) - const handleSubmit = useHandleSubmit(id, editor.name.value, editor.remote.value, networks, dispatch) + const handleSubmit = useHandleSubmit(id, editor.name.value, editor.remote.value, networks, history, dispatch) return ( diff --git a/packages/neuron-ui/src/components/NetworkSetting/index.tsx b/packages/neuron-ui/src/components/NetworkSetting/index.tsx index 6bc3a74e6c..ea5ef2dea6 100644 --- a/packages/neuron-ui/src/components/NetworkSetting/index.tsx +++ b/packages/neuron-ui/src/components/NetworkSetting/index.tsx @@ -4,9 +4,9 @@ import { useTranslation } from 'react-i18next' import { Stack, PrimaryButton, ChoiceGroup, IChoiceGroupOption } from 'office-ui-fabric-react' import { StateWithDispatch } from 'states/stateProvider/reducer' -import actionCreators from 'states/stateProvider/actionCreators' import chainState from 'states/initStates/chain' import { appCalls } from 'services/UILayer' +import { setCurrentNetowrk } from 'services/remote' import { Routes } from 'utils/const' @@ -17,19 +17,15 @@ const onContextMenu = (id: string = '') => () => { const NetworkSetting = ({ chain = chainState, settings: { networks = [] }, - dispatch, history, }: React.PropsWithoutRef) => { const [t] = useTranslation() - const onChoiceChange = useCallback( - (_e, option?: IChoiceGroupOption) => { - if (option) { - dispatch(actionCreators.setNetwork(option.key)) - } - }, - [dispatch] - ) + const onChoiceChange = useCallback((_e, option?: IChoiceGroupOption) => { + if (option) { + setCurrentNetowrk(option.key) + } + }, []) const goToCreateNetwork = useCallback(() => { history.push(`${Routes.NetworkEditor}/new`) diff --git a/packages/neuron-ui/src/containers/Main/hooks.ts b/packages/neuron-ui/src/containers/Main/hooks.ts index 7f774241ac..98e60cb0c3 100644 --- a/packages/neuron-ui/src/containers/Main/hooks.ts +++ b/packages/neuron-ui/src/containers/Main/hooks.ts @@ -7,12 +7,10 @@ import { actionCreators } from 'states/stateProvider/actionCreators' import UILayer, { AppMethod, ChainMethod, - NetworksMethod, TransactionsMethod, WalletsMethod, walletsCall, transactionsCall, - networksCall, } from 'services/UILayer' import { initWindow } from 'services/remote' import { @@ -263,37 +261,6 @@ export const useChannelListeners = ({ }) } }) - - UILayer.on(Channel.Networks, (_e: Event, method: NetworksMethod, args: ChannelResponse) => { - if (args.status) { - switch (method) { - case NetworksMethod.Create: - case NetworksMethod.Update: { - history.push(Routes.SettingsNetworks) - break - } - case NetworksMethod.Activate: { - dispatch({ - type: NeuronWalletActions.Chain, - payload: { network: args.result }, - }) - break - } - default: { - break - } - } - } else { - dispatch({ - type: AppActions.AddNotification, - payload: { - type: 'alert', - content: args.msg, - timestamp: Date.now(), - }, - }) - } - }) }, [walletID, i18n, chain, dispatch, history]) export const useSyncChainData = ({ chainURL, dispatch }: { chainURL: string; dispatch: StateDispatch }) => { @@ -434,11 +401,6 @@ export const useSubscription = ({ walletsCall.getCurrent() break } - case 'network': { - networksCall.getAll() - networksCall.currentID() - break - } default: { break } diff --git a/packages/neuron-ui/src/services/UILayer.ts b/packages/neuron-ui/src/services/UILayer.ts index c0a8d8790c..e93bc77e0a 100644 --- a/packages/neuron-ui/src/services/UILayer.ts +++ b/packages/neuron-ui/src/services/UILayer.ts @@ -35,15 +35,6 @@ export enum WalletsMethod { GetAllAddresses = 'getAllAddresses', } -export enum NetworksMethod { - Get = 'get', - Create = 'create', - Update = 'update', - Delete = 'delete', - Activate = 'activate', - CurrentID = 'currentID', -} - export enum TransactionsMethod { GetAll = 'getAll', GetAllByKeywords = 'getAllByKeywords', @@ -96,19 +87,6 @@ export const appCalls = instantiateMethodCall(app) as { handleViewError: (errorMessage: string) => void } -export const networks = (method: NetworksMethod, ...params: any[]) => { - UILayer.send(Channel.Networks, method, ...params) -} -export const networksCall = instantiateMethodCall(networks) as { - getAll: () => void - get: (id: string) => void - create: (network: State.NetworkProperty) => void - update: (id: string, options: Partial) => void - delete: (id: string) => void - currentID: () => void - activate: (id: string) => void -} - export const transactions = (method: TransactionsMethod, params: string | GetTransactionsParams) => { UILayer.send(Channel.Transactions, method, params) } diff --git a/packages/neuron-ui/src/services/remote.ts b/packages/neuron-ui/src/services/remote.ts index 38398c3c28..dbb544357a 100644 --- a/packages/neuron-ui/src/services/remote.ts +++ b/packages/neuron-ui/src/services/remote.ts @@ -1,3 +1,31 @@ +// TODO: use error code +interface SuccessFromController { + status: 1 + result: any +} +interface FailureFromController { + status: 0 + message: { + title: string + content?: string + } +} +type ControllerResponse = SuccessFromController | FailureFromController + +const RemoteNotLoadError = { + status: 0 as 0, + message: { + title: 'remote is not supported', + }, +} + +const controllerNotLoaded = (controllerName: string) => ({ + status: 0 as 0, + message: { + title: `${controllerName} controller not loaded`, + }, +}) + export const initWindow = () => { if (!window.remote) { console.warn('remote is not supported') @@ -16,6 +44,78 @@ export const validateMnemonic = (mnemonic: string): boolean => { return remoteValidateMnemonic(mnemonic) } +export const setCurrentNetowrk = async (networkID: string): Promise => { + if (!window.remote) { + return RemoteNotLoadError + } + const networkController = window.remote.require('./controllers/networks').default + if (networkController) { + const res = await networkController.activate(networkID) + if (res.status) { + return { + status: 1, + result: true, + } + } + return { + status: 0, + message: res.status.msg || '', + } + } + return controllerNotLoaded('network') +} + +export const createNetwork = async ({ + name, + remote, +}: { + name: string + remote: string +}): Promise => { + if (!window.remote) { + return RemoteNotLoadError + } + const networkController = window.remote.require('./controllers/networks').default + if (networkController) { + const res = await networkController.create({ name, remote }) + if (res.status) { + return { + status: 1, + result: true, + } + } + return { + status: 0, + message: res.status.msg || '', + } + } + return controllerNotLoaded('network') +} + +export const updateNetwork = async ( + networkID: string, + options: Partial<{ name: string; remote: string }> +): Promise => { + if (!window.remote) { + return RemoteNotLoadError + } + const networkController = window.remote.require('./controllers/networks').default + if (networkController) { + const res = await networkController.update(networkID, options) + if (res.status) { + return { + status: 1, + result: true, + } + } + return { + status: 0, + message: res.status.msg || '', + } + } + return controllerNotLoaded('network') +} + export const showMessage = (options: any, callback: Function) => { if (!window.remote) { console.warn('remote is not supported') @@ -37,6 +137,7 @@ export const showErrorMessage = (title: string, content: string) => { export default { initWindow, validateMnemonic, + setCurrentNetowrk, showMessage, showErrorMessage, } diff --git a/packages/neuron-ui/src/states/stateProvider/actionCreators/index.ts b/packages/neuron-ui/src/states/stateProvider/actionCreators/index.ts index 02b7819f24..8bf9984b6c 100644 --- a/packages/neuron-ui/src/states/stateProvider/actionCreators/index.ts +++ b/packages/neuron-ui/src/states/stateProvider/actionCreators/index.ts @@ -1,12 +1,10 @@ import wallets from './wallets' -import networks from './networks' import send from './send' import transactions from './transactions' import settings from './settings' export const actionCreators = { ...wallets, - ...networks, ...send, ...transactions, ...settings, diff --git a/packages/neuron-ui/src/states/stateProvider/actionCreators/networks.ts b/packages/neuron-ui/src/states/stateProvider/actionCreators/networks.ts deleted file mode 100644 index 89da2f3feb..0000000000 --- a/packages/neuron-ui/src/states/stateProvider/actionCreators/networks.ts +++ /dev/null @@ -1,114 +0,0 @@ -import { networksCall } from 'services/UILayer' - -import { Message, MAX_NETWORK_NAME_LENGTH, UNREMOVABLE_NETWORK_ID, UNREMOVABLE_NETWORK } from 'utils/const' -import i18n from 'utils/i18n' -import { AppActions } from '../reducer' - -export default { - createOrUpdateNetwork: ({ id, name, remote }: State.Network, networks: State.Network[]) => { - const warning = { - type: 'warning', - timestamp: Date.now(), - content: '', - } - if (!name) { - return { - type: AppActions.AddNotification, - payload: { - ...warning, - content: i18n.t(Message.NameRequired), - }, - } - } - if (name.length > MAX_NETWORK_NAME_LENGTH) { - return { - type: AppActions.AddNotification, - payload: { - ...warning, - content: i18n.t(Message.LengthOfNameShouldBeLessThanOrEqualTo, { - length: MAX_NETWORK_NAME_LENGTH, - }), - }, - } - } - if (!remote) { - return { - type: AppActions.AddNotification, - payload: { - ...warning, - content: i18n.t(Message.URLRequired), - }, - } - } - if (!remote.startsWith('http')) { - return { - type: AppActions.AddNotification, - payload: { - ...warning, - content: i18n.t(Message.ProtocolRequired), - }, - } - } - // verification, for now, only name is unique - if (id === 'new') { - if (networks.some(network => network.name === name)) { - return { - type: AppActions.AddNotification, - payload: { - ...warning, - content: i18n.t(Message.NetworkNameUsed), - }, - } - } - networksCall.create({ - name, - remote, - }) - } else { - if (networks.some(network => network.name === name && network.id !== id)) { - return { - type: AppActions.AddNotification, - payload: { - ...warning, - content: i18n.t(Message.NetworkNameUsed), - }, - } - } - networksCall.update(id!, { - name, - remote, - }) - } - return { - type: AppActions.Ignore, - payload: null, - } - }, - deleteNetwork: (id?: string) => { - if (id === undefined) { - throw new Error('No network id found') - } - if (id === UNREMOVABLE_NETWORK_ID) { - return { - type: AppActions.AddNotification, - payload: { - type: 'warning', - timestamp: Date.now(), - conetent: i18n.t(`messages.is-unremovable`, { target: UNREMOVABLE_NETWORK }), - }, - } - } - networksCall.delete(id) - return { - type: AppActions.Ignore, - payload: null, - } - }, - setNetwork: (id: string) => { - networksCall.activate(id) - return { - type: AppActions.Ignore, - payload: null, - } - }, -} diff --git a/packages/neuron-ui/src/states/stateProvider/reducer.ts b/packages/neuron-ui/src/states/stateProvider/reducer.ts index 5418b4d306..9c70cc8274 100644 --- a/packages/neuron-ui/src/states/stateProvider/reducer.ts +++ b/packages/neuron-ui/src/states/stateProvider/reducer.ts @@ -7,6 +7,7 @@ export enum NeuronWalletActions { Wallet = 'wallet', Settings = 'settings', UpdateCodeHash = 'updateCodeHash', + // networks UpdateNetworkList = 'updateNetworkList', UpdateCurrentNetworkID = 'updateCurrentNetworkID', } From 47518170c1c23f2383e67e6a2f512c7a14621d9e Mon Sep 17 00:00:00 2001 From: Keith Date: Wed, 24 Jul 2019 20:53:08 +0800 Subject: [PATCH 04/16] feat(neuron-ui): call transactions controller methods with remote module --- .../src/components/Addresses/index.tsx | 8 +- .../neuron-ui/src/components/History/hooks.ts | 16 +- .../src/components/NetworkEditor/hooks.ts | 9 +- .../src/components/Overview/index.tsx | 18 ++- .../src/components/Transaction/index.tsx | 15 +- .../src/components/TransactionList/index.tsx | 15 +- .../neuron-ui/src/containers/Main/hooks.ts | 95 +++--------- packages/neuron-ui/src/services/UILayer.ts | 25 --- packages/neuron-ui/src/services/remote.ts | 143 ------------------ .../remote/controllerMethodWrapper.ts | 56 +++++++ .../neuron-ui/src/services/remote/index.ts | 44 ++++++ .../neuron-ui/src/services/remote/networks.ts | 25 +++ .../src/services/remote/transactions.ts | 32 ++++ .../actionCreators/transactions.ts | 21 +-- .../src/states/stateProvider/reducer.ts | 21 +++ packages/neuron-ui/src/utils/hooks.ts | 23 +-- 16 files changed, 252 insertions(+), 314 deletions(-) delete mode 100644 packages/neuron-ui/src/services/remote.ts create mode 100644 packages/neuron-ui/src/services/remote/controllerMethodWrapper.ts create mode 100644 packages/neuron-ui/src/services/remote/index.ts create mode 100644 packages/neuron-ui/src/services/remote/networks.ts create mode 100644 packages/neuron-ui/src/services/remote/transactions.ts diff --git a/packages/neuron-ui/src/components/Addresses/index.tsx b/packages/neuron-ui/src/components/Addresses/index.tsx index 25d95b0bbb..2a8064ae4e 100644 --- a/packages/neuron-ui/src/components/Addresses/index.tsx +++ b/packages/neuron-ui/src/components/Addresses/index.tsx @@ -20,9 +20,8 @@ import { MIN_CELL_WIDTH, Routes } from 'utils/const' import { localNumberFormatter, shannonToCKBFormatter } from 'utils/formatters' const Addresses = ({ - wallet: { id, addresses = [] }, + wallet: { addresses = [] }, settings: { showAddressBook = false }, - dispatch, history, }: React.PropsWithoutRef) => { const [t] = useTranslation() @@ -33,8 +32,6 @@ const Addresses = ({ }, [showAddressBook, history]) const { localDescription, onDescriptionPress, onDescriptionFieldBlur, onDescriptionChange } = useLocalDescription( - 'address', - id, useMemo( () => addresses.map(({ address: key = '', description = '' }) => ({ @@ -42,8 +39,7 @@ const Addresses = ({ description, })), [addresses] - ), - dispatch + ) ) const theme = getTheme() diff --git a/packages/neuron-ui/src/components/History/hooks.ts b/packages/neuron-ui/src/components/History/hooks.ts index a8dff387a5..d63a323c00 100644 --- a/packages/neuron-ui/src/components/History/hooks.ts +++ b/packages/neuron-ui/src/components/History/hooks.ts @@ -1,7 +1,7 @@ import { useState, useEffect } from 'react' -import { AppActions } from 'states/stateProvider/reducer' -import actionCreators from 'states/stateProvider/actionCreators' +import { NeuronWalletActions, AppActions } from 'states/stateProvider/reducer' import { queryParsers } from 'utils/parser' +import { getTransactionList } from 'services/remote' const backToTop = () => { const container = document.querySelector('main') as HTMLElement @@ -31,8 +31,16 @@ export const useSearch = (search: string = '', walletID: string = '', dispatch: type: AppActions.CleanTransactions, payload: null, }) - - dispatch(actionCreators.getTransactions({ ...params, keywords: params.keywords, walletID })) + getTransactionList({ ...params, keywords: params.keywords, walletID }).then(res => { + if (res.status) { + dispatch({ + type: NeuronWalletActions.UpdateTransactionList, + payload: res.result, + }) + } else { + // TODO: notification + } + }) }, [search, walletID, dispatch]) return { keywords, onKeywordsChange, setKeywords } } diff --git a/packages/neuron-ui/src/components/NetworkEditor/hooks.ts b/packages/neuron-ui/src/components/NetworkEditor/hooks.ts index 4548ae8d6b..e6e6d84b2e 100644 --- a/packages/neuron-ui/src/components/NetworkEditor/hooks.ts +++ b/packages/neuron-ui/src/components/NetworkEditor/hooks.ts @@ -193,9 +193,12 @@ export const useHandleSubmit = ( }, }) } - res = await updateNetwork(id!, { - name, - remote, + res = await updateNetwork({ + networkID: id!, + options: { + name, + remote, + }, }) } if (res && res.status) { diff --git a/packages/neuron-ui/src/components/Overview/index.tsx b/packages/neuron-ui/src/components/Overview/index.tsx index 4136a16f85..d80b3ab076 100644 --- a/packages/neuron-ui/src/components/Overview/index.tsx +++ b/packages/neuron-ui/src/components/Overview/index.tsx @@ -21,10 +21,9 @@ import { MessageBarType, } from 'office-ui-fabric-react' -import { StateWithDispatch } from 'states/stateProvider/reducer' -import actionCreators from 'states/stateProvider/actionCreators' +import { StateWithDispatch, NeuronWalletActions } from 'states/stateProvider/reducer' -import { showErrorMessage } from 'services/remote' +import { showErrorMessage, getTransactionList } from 'services/remote' import { localNumberFormatter, shannonToCKBFormatter, uniformTimeFormatter as timeFormatter } from 'utils/formatters' import { PAGE_SIZE, MIN_CELL_WIDTH } from 'utils/const' @@ -100,7 +99,18 @@ const Overview = ({ const minerInfoRef = useRef(null) useEffect(() => { - dispatch(actionCreators.getTransactions({ pageNo: 1, pageSize: PAGE_SIZE, keywords: '', walletID: id })) + getTransactionList({ + pageNo: 1, + pageSize: PAGE_SIZE, + keywords: '', + walletID: id, + }).then(res => { + if (res.status) { + dispatch({ type: NeuronWalletActions.UpdateTransactionList, payload: res.result }) + } else { + // TODO: notification + } + }) }, [id, dispatch]) const onTransactionRowRender = useCallback((props?: IDetailsRowProps) => { diff --git a/packages/neuron-ui/src/components/Transaction/index.tsx b/packages/neuron-ui/src/components/Transaction/index.tsx index 3cfcc51c68..b85507feee 100644 --- a/packages/neuron-ui/src/components/Transaction/index.tsx +++ b/packages/neuron-ui/src/components/Transaction/index.tsx @@ -3,11 +3,11 @@ import { RouteComponentProps } from 'react-router-dom' import { useTranslation } from 'react-i18next' import { Stack, DetailsList, Text, DetailsListLayoutMode, CheckboxVisibility, IColumn } from 'office-ui-fabric-react' -import { AppActions, StateWithDispatch } from 'states/stateProvider/reducer' -import actionCreators from 'states/stateProvider/actionCreators' +import { AppActions, StateWithDispatch, NeuronWalletActions } from 'states/stateProvider/reducer' import chainState from 'states/initStates/chain' import { localNumberFormatter, uniformTimeFormatter } from 'utils/formatters' +import { getTransaction } from 'services/remote' const MIN_CELL_WIDTH = 70 @@ -105,7 +105,16 @@ const Transaction = ({ type: AppActions.CleanTransaction, payload: null, }) - dispatch(actionCreators.getTransaction(walletID, match.params.hash)) + getTransaction({ walletID, hash: match.params.hash }).then(res => { + if (res.status) { + dispatch({ + type: NeuronWalletActions.UpdateTransaction, + payload: res.result, + }) + } else { + // TODO: notification + } + }) }, [match.params.hash, dispatch, walletID]) const basicInfoItems = useMemo( diff --git a/packages/neuron-ui/src/components/TransactionList/index.tsx b/packages/neuron-ui/src/components/TransactionList/index.tsx index 6186dbbf98..74de95abfa 100644 --- a/packages/neuron-ui/src/components/TransactionList/index.tsx +++ b/packages/neuron-ui/src/components/TransactionList/index.tsx @@ -52,20 +52,10 @@ const onRenderHeader = ({ group }: any) => { ) } -const TransactionList = ({ - walletID, - items = [], - dispatch, -}: { - walletID: string - items: State.Transaction[] - dispatch: StateDispatch -}) => { +const TransactionList = ({ items = [] }: { walletID: string; items: State.Transaction[]; dispatch: StateDispatch }) => { const [t] = useTranslation() const { localDescription, onDescriptionPress, onDescriptionFieldBlur, onDescriptionChange } = useLocalDescription( - 'transaction', - walletID, useMemo( () => items.map(({ hash: key, description = '' }) => ({ @@ -73,8 +63,7 @@ const TransactionList = ({ description, })), [items] - ), - dispatch + ) ) const transactionColumns: IColumn[] = useMemo( diff --git a/packages/neuron-ui/src/containers/Main/hooks.ts b/packages/neuron-ui/src/containers/Main/hooks.ts index 98e60cb0c3..c43cc6ac60 100644 --- a/packages/neuron-ui/src/containers/Main/hooks.ts +++ b/packages/neuron-ui/src/containers/Main/hooks.ts @@ -4,15 +4,8 @@ import { WalletWizardPath } from 'components/WalletWizard' import { NeuronWalletActions, StateDispatch, AppActions } from 'states/stateProvider/reducer' import { actionCreators } from 'states/stateProvider/actionCreators' -import UILayer, { - AppMethod, - ChainMethod, - TransactionsMethod, - WalletsMethod, - walletsCall, - transactionsCall, -} from 'services/UILayer' -import { initWindow } from 'services/remote' +import UILayer, { AppMethod, ChainMethod, WalletsMethod, walletsCall } from 'services/UILayer' +import { initWindow, getTransactionList, getTransaction } from 'services/remote' import { SystemScript as SystemScriptSubject, DataUpdate as DataUpdateSubject, @@ -95,71 +88,6 @@ export const useChannelListeners = ({ } }) - UILayer.on(Channel.Transactions, (_e: Event, method: TransactionsMethod, args: ChannelResponse) => { - if (args.status) { - switch (method) { - case TransactionsMethod.GetAllByKeywords: { - // TODO: verify the wallet id the transactions belong to - dispatch({ - type: NeuronWalletActions.Chain, - payload: { transactions: { ...chain.transactions, ...args.result } }, - }) - break - } - case TransactionsMethod.Get: { - dispatch({ - type: NeuronWalletActions.Chain, - payload: { transaction: args.result }, - }) - break - } - case TransactionsMethod.TransactionUpdated: { - const updatedTransaction: State.Transaction = args.result - if ( - (!chain.transactions.items.length || - updatedTransaction.timestamp === null || - +(updatedTransaction.timestamp || updatedTransaction.createdAt) > - +(chain.transactions.items[0].timestamp || chain.transactions.items[0].createdAt)) && - chain.transactions.pageNo === 1 - ) { - /** - * 1. transaction list is empty or the coming transaction is pending or the coming transaction is later than latest transaction in current list - * 2. the current page number is 1 - */ - const newTransactionItems = [updatedTransaction, ...chain.transactions.items].slice( - 0, - chain.transactions.pageSize - ) - dispatch({ - type: NeuronWalletActions.Chain, - payload: { transactions: { ...chain.transactions, items: newTransactionItems } }, - }) - } else { - const newTransactionItems = [...chain.transactions.items] - const idx = newTransactionItems.findIndex(item => item.hash === updatedTransaction.hash) - if (idx >= 0) { - newTransactionItems[idx] = updatedTransaction - dispatch({ - type: NeuronWalletActions.Chain, - payload: { transactions: { ...chain.transactions, items: newTransactionItems } }, - }) - } - } - if (chain.transaction.hash === updatedTransaction.hash) { - dispatch({ - type: NeuronWalletActions.Chain, - payload: { transaction: updatedTransaction }, - }) - } - break - } - default: { - break - } - } - } - }) - UILayer.on(Channel.Wallets, (_e: Event, method: WalletsMethod, args: ChannelResponse) => { if (args.status) { switch (method) { @@ -334,11 +262,18 @@ export const useOnCurrentWalletChange = ({ useEffect(() => { if (walletID) { walletsCall.getAllAddresses(walletID) - transactionsCall.getAllByKeywords({ + getTransactionList({ walletID, keywords: '', pageNo, pageSize, + }).then(res => { + if (res.status) { + dispatch({ + type: NeuronWalletActions.UpdateTransactionList, + payload: res.result, + }) + } }) } else { initWindow() @@ -387,13 +322,19 @@ export const useSubscription = ({ break } case 'transaction': { - transactionsCall.getAllByKeywords({ + getTransactionList({ walletID, keywords, pageNo, pageSize, + }).then(res => { + if (res.status) { + dispatch({ type: NeuronWalletActions.UpdateTransactionList, payload: res.result }) + } else { + // TODO: notification + } }) - transactionsCall.get(walletID, txHash) + getTransaction({ walletID, hash: txHash }) break } case 'wallet': { diff --git a/packages/neuron-ui/src/services/UILayer.ts b/packages/neuron-ui/src/services/UILayer.ts index e93bc77e0a..681209a26c 100644 --- a/packages/neuron-ui/src/services/UILayer.ts +++ b/packages/neuron-ui/src/services/UILayer.ts @@ -35,25 +35,10 @@ export enum WalletsMethod { GetAllAddresses = 'getAllAddresses', } -export enum TransactionsMethod { - GetAll = 'getAll', - GetAllByKeywords = 'getAllByKeywords', - Get = 'get', - UpdateDescription = 'updateDescription', - TransactionUpdated = 'transactionUpdated', -} - export enum HelpersMethod { GenerateMnemonic = 'generateMnemonic', } -export interface GetTransactionsParams { - pageNo: number - pageSize: number - keywords?: string - walletID: string -} - const UILayer = (() => { if (window.bridge) { return new SyntheticEventEmitter(window.bridge.ipcRenderer) @@ -87,16 +72,6 @@ export const appCalls = instantiateMethodCall(app) as { handleViewError: (errorMessage: string) => void } -export const transactions = (method: TransactionsMethod, params: string | GetTransactionsParams) => { - UILayer.send(Channel.Transactions, method, params) -} - -export const transactionsCall = instantiateMethodCall(transactions) as { - getAllByKeywords: (params: GetTransactionsParams) => void - get: (walletID: string, hash: string) => void - updateDescription: (params: { hash: string; description: string }) => void -} - export const wallets = ( method: WalletsMethod, params: diff --git a/packages/neuron-ui/src/services/remote.ts b/packages/neuron-ui/src/services/remote.ts deleted file mode 100644 index dbb544357a..0000000000 --- a/packages/neuron-ui/src/services/remote.ts +++ /dev/null @@ -1,143 +0,0 @@ -// TODO: use error code -interface SuccessFromController { - status: 1 - result: any -} -interface FailureFromController { - status: 0 - message: { - title: string - content?: string - } -} -type ControllerResponse = SuccessFromController | FailureFromController - -const RemoteNotLoadError = { - status: 0 as 0, - message: { - title: 'remote is not supported', - }, -} - -const controllerNotLoaded = (controllerName: string) => ({ - status: 0 as 0, - message: { - title: `${controllerName} controller not loaded`, - }, -}) - -export const initWindow = () => { - if (!window.remote) { - console.warn('remote is not supported') - return Promise.reject(new Error('remote is not supported')) - } - const appController = window.remote.require('./controllers/app').default - return appController.getInitState() -} - -export const validateMnemonic = (mnemonic: string): boolean => { - if (!window.remote) { - console.warn('remote is not supported') - return true - } - const { validateMnemonic: remoteValidateMnemonic } = window.remote.require('./models/keys/mnemonic') - return remoteValidateMnemonic(mnemonic) -} - -export const setCurrentNetowrk = async (networkID: string): Promise => { - if (!window.remote) { - return RemoteNotLoadError - } - const networkController = window.remote.require('./controllers/networks').default - if (networkController) { - const res = await networkController.activate(networkID) - if (res.status) { - return { - status: 1, - result: true, - } - } - return { - status: 0, - message: res.status.msg || '', - } - } - return controllerNotLoaded('network') -} - -export const createNetwork = async ({ - name, - remote, -}: { - name: string - remote: string -}): Promise => { - if (!window.remote) { - return RemoteNotLoadError - } - const networkController = window.remote.require('./controllers/networks').default - if (networkController) { - const res = await networkController.create({ name, remote }) - if (res.status) { - return { - status: 1, - result: true, - } - } - return { - status: 0, - message: res.status.msg || '', - } - } - return controllerNotLoaded('network') -} - -export const updateNetwork = async ( - networkID: string, - options: Partial<{ name: string; remote: string }> -): Promise => { - if (!window.remote) { - return RemoteNotLoadError - } - const networkController = window.remote.require('./controllers/networks').default - if (networkController) { - const res = await networkController.update(networkID, options) - if (res.status) { - return { - status: 1, - result: true, - } - } - return { - status: 0, - message: res.status.msg || '', - } - } - return controllerNotLoaded('network') -} - -export const showMessage = (options: any, callback: Function) => { - if (!window.remote) { - console.warn('remote is not supported') - window.alert(options.message) - } else { - window.remote.require('electron').dialog.showMessageBox(options, callback) - } -} - -export const showErrorMessage = (title: string, content: string) => { - if (!window.remote) { - console.warn('remote is not supported') - window.alert(`${title}: ${content}`) - } else { - window.remote.require('electron').dialog.showErrorBox(title, content) - } -} - -export default { - initWindow, - validateMnemonic, - setCurrentNetowrk, - showMessage, - showErrorMessage, -} diff --git a/packages/neuron-ui/src/services/remote/controllerMethodWrapper.ts b/packages/neuron-ui/src/services/remote/controllerMethodWrapper.ts new file mode 100644 index 0000000000..a2063e99f1 --- /dev/null +++ b/packages/neuron-ui/src/services/remote/controllerMethodWrapper.ts @@ -0,0 +1,56 @@ +// TODO: use error code +interface SuccessFromController { + status: 1 + result: any +} +interface FailureFromController { + status: 0 + message: { + title: string + content?: string + } +} +export type ControllerResponse = SuccessFromController | FailureFromController + +export const RemoteNotLoadError = { + status: 0 as 0, + message: { + title: 'remote is not supported', + }, +} + +export const controllerNotLoaded = (controllerName: string) => ({ + status: 0 as 0, + message: { + title: `${controllerName} controller not loaded`, + }, +}) + +export const controllerMethodWrapper = (controllerName: string) => ( + callControllerMethod: (controller: any) => (params: any) => Promise<{ status: any; result: any; msg: string }> +) => async (realParams: any): Promise => { + if (!window.remote) { + return RemoteNotLoadError + } + const controller = window.remote.require(`./controllers/${controllerName}`).default + if (!controller) { + return controllerNotLoaded(controllerName) + } + const res = await callControllerMethod(controller)(realParams) + if (res.status) { + return { + status: 1, + result: res.result || true, + } + } + return { + status: 0, + message: res.status.msg || '', + } +} + +export default { + RemoteNotLoadError, + controllerNotLoaded, + controllerMethodWrapper, +} diff --git a/packages/neuron-ui/src/services/remote/index.ts b/packages/neuron-ui/src/services/remote/index.ts new file mode 100644 index 0000000000..b353acc0ac --- /dev/null +++ b/packages/neuron-ui/src/services/remote/index.ts @@ -0,0 +1,44 @@ +export * from './networks' +export * from './transactions' +export const initWindow = () => { + if (!window.remote) { + console.warn('remote is not supported') + return Promise.reject(new Error('remote is not supported')) + } + const appController = window.remote.require('./controllers/app').default + return appController.getInitState() +} + +export const validateMnemonic = (mnemonic: string): boolean => { + if (!window.remote) { + console.warn('remote is not supported') + return true + } + const { validateMnemonic: remoteValidateMnemonic } = window.remote.require('./models/keys/mnemonic') + return remoteValidateMnemonic(mnemonic) +} + +export const showMessage = (options: any, callback: Function) => { + if (!window.remote) { + console.warn('remote is not supported') + window.alert(options.message) + } else { + window.remote.require('electron').dialog.showMessageBox(options, callback) + } +} + +export const showErrorMessage = (title: string, content: string) => { + if (!window.remote) { + console.warn('remote is not supported') + window.alert(`${title}: ${content}`) + } else { + window.remote.require('electron').dialog.showErrorBox(title, content) + } +} + +export default { + initWindow, + validateMnemonic, + showMessage, + showErrorMessage, +} diff --git a/packages/neuron-ui/src/services/remote/networks.ts b/packages/neuron-ui/src/services/remote/networks.ts new file mode 100644 index 0000000000..c8edab3d6d --- /dev/null +++ b/packages/neuron-ui/src/services/remote/networks.ts @@ -0,0 +1,25 @@ +import { controllerMethodWrapper } from './controllerMethodWrapper' + +const CONTROLLER_NAME = 'networks' + +export const setCurrentNetowrk = controllerMethodWrapper(CONTROLLER_NAME)((controller: any) => (networkID: string) => { + return controller.activate(networkID) +}) + +export const createNetwork = controllerMethodWrapper(CONTROLLER_NAME)( + controller => ({ name, remote }: { name: string; remote: string }) => { + return controller.create({ name, remote }) + } +) + +export const updateNetwork = controllerMethodWrapper(CONTROLLER_NAME)( + controller => ({ networkID, options }: { networkID: string; options: Partial<{ name: string; remote: string }> }) => { + return controller.update(networkID, options) + } +) + +export default { + createNetwork, + updateNetwork, + setCurrentNetowrk, +} diff --git a/packages/neuron-ui/src/services/remote/transactions.ts b/packages/neuron-ui/src/services/remote/transactions.ts new file mode 100644 index 0000000000..f770b0d7dd --- /dev/null +++ b/packages/neuron-ui/src/services/remote/transactions.ts @@ -0,0 +1,32 @@ +import { controllerMethodWrapper } from './controllerMethodWrapper' + +export interface GetTransactionListParams { + pageNo: number + pageSize: number + keywords?: string + walletID: string +} + +const CONTROLLER_NAME = 'transactions' + +export const getTransactionList = controllerMethodWrapper(CONTROLLER_NAME)( + controller => (params: GetTransactionListParams) => { + return controller.getAllByKeywords(params) + } +) + +export const getTransaction = controllerMethodWrapper(CONTROLLER_NAME)( + controller => ({ walletID, hash }: { walletID: string; hash: string }) => { + return controller.get(walletID, hash) + } +) +export const updateTransactionDescription = controllerMethodWrapper(CONTROLLER_NAME)( + controller => (params: { hash: string; description: string }) => { + return controller.updateDescription(params) + } +) + +export default { + getTransactionList, + getTransaction, +} diff --git a/packages/neuron-ui/src/states/stateProvider/actionCreators/transactions.ts b/packages/neuron-ui/src/states/stateProvider/actionCreators/transactions.ts index 416ce61334..4832377655 100644 --- a/packages/neuron-ui/src/states/stateProvider/actionCreators/transactions.ts +++ b/packages/neuron-ui/src/states/stateProvider/actionCreators/transactions.ts @@ -1,22 +1,7 @@ -import { transactionsCall, GetTransactionsParams, walletsCall } from 'services/UILayer' +import { walletsCall } from 'services/UILayer' import { AppActions } from '../reducer' export default { - getTransaction: (walletID: string, hash: string) => { - transactionsCall.get(walletID, hash) - return { - type: AppActions.Ignore, - payload: null, - } - }, - - getTransactions: (params: GetTransactionsParams) => { - transactionsCall.getAllByKeywords(params) - return { - type: AppActions.Ignore, - payload: null, - } - }, updateDescription: ({ type, walletID, @@ -40,10 +25,6 @@ export default { } } if (type === 'transaction') { - transactionsCall.updateDescription({ - hash: key, - description, - }) return { type: AppActions.Ignore, payload: null, diff --git a/packages/neuron-ui/src/states/stateProvider/reducer.ts b/packages/neuron-ui/src/states/stateProvider/reducer.ts index 9c70cc8274..66dcacbcaa 100644 --- a/packages/neuron-ui/src/states/stateProvider/reducer.ts +++ b/packages/neuron-ui/src/states/stateProvider/reducer.ts @@ -7,6 +7,9 @@ export enum NeuronWalletActions { Wallet = 'wallet', Settings = 'settings', UpdateCodeHash = 'updateCodeHash', + // transactions + UpdateTransactionList = 'updateTransactionList', + UpdateTransaction = 'updateTransaction', // networks UpdateNetworkList = 'updateNetworkList', UpdateCurrentNetworkID = 'updateCurrentNetworkID', @@ -138,6 +141,24 @@ export const reducer = ( }, } } + case NeuronWalletActions.UpdateTransactionList: { + return { + ...state, + chain: { + ...chain, + transactions: payload, + }, + } + } + case NeuronWalletActions.UpdateTransaction: { + return { + ...state, + chain: { + ...chain, + transaction: payload, + }, + } + } case NeuronWalletActions.UpdateNetworkList: { return { ...state, diff --git a/packages/neuron-ui/src/utils/hooks.ts b/packages/neuron-ui/src/utils/hooks.ts index 818586e535..a508cfcf36 100644 --- a/packages/neuron-ui/src/utils/hooks.ts +++ b/packages/neuron-ui/src/utils/hooks.ts @@ -1,5 +1,5 @@ import { useEffect, useState, useCallback } from 'react' -import actionCreators from 'states/stateProvider/actionCreators' +import { updateTransactionDescription } from 'services/remote' export const useGoBack = (history: any) => { return useCallback(() => { @@ -7,12 +7,7 @@ export const useGoBack = (history: any) => { }, [history]) } -export const useLocalDescription = ( - type: 'address' | 'transaction', - walletID: string, - owners: { key: string; description: string }[], - dispatch: any -) => { +export const useLocalDescription = (owners: { key: string; description: string }[]) => { const [localDescription, setLocalDescription] = useState([]) useEffect(() => { @@ -24,16 +19,12 @@ export const useLocalDescription = ( if (owners[idx].description === localDescription[idx]) { return } - dispatch( - actionCreators.updateDescription({ - type, - walletID, - key: owners[idx].key, - description: localDescription[idx], - }) - ) + updateTransactionDescription({ + hash: owners[idx].key, + description: localDescription[idx], + }) }, - [type, walletID, dispatch, localDescription, owners] + [localDescription, owners] ) const onDescriptionFieldBlur = useCallback( From 7e74cc9a4c5d2112ebaada42570b753439277602 Mon Sep 17 00:00:00 2001 From: Keith Date: Wed, 24 Jul 2019 22:03:33 +0800 Subject: [PATCH 05/16] feat(subscribe synced block number and connection status from neuron-wallet in neuron-ui by remote m --- .../neuron-ui/src/containers/Main/hooks.ts | 47 +++++++------------ packages/neuron-ui/src/services/UILayer.ts | 5 -- packages/neuron-ui/src/services/subjects.ts | 10 ++++ .../src/states/stateProvider/reducer.ts | 21 +++++++++ packages/neuron-ui/src/utils/const.ts | 1 - .../models/subjects/current-block-subject.ts | 8 +--- .../neuron-wallet/src/models/subjects/node.ts | 6 +++ .../src/models/window-manager.ts | 1 - .../neuron-wallet/src/services/networks.ts | 2 - packages/neuron-wallet/src/services/node.ts | 16 ++++--- packages/neuron-wallet/src/utils/const.ts | 1 - 11 files changed, 67 insertions(+), 51 deletions(-) create mode 100644 packages/neuron-wallet/src/models/subjects/node.ts diff --git a/packages/neuron-ui/src/containers/Main/hooks.ts b/packages/neuron-ui/src/containers/Main/hooks.ts index c43cc6ac60..7d05d96c12 100644 --- a/packages/neuron-ui/src/containers/Main/hooks.ts +++ b/packages/neuron-ui/src/containers/Main/hooks.ts @@ -4,13 +4,15 @@ import { WalletWizardPath } from 'components/WalletWizard' import { NeuronWalletActions, StateDispatch, AppActions } from 'states/stateProvider/reducer' import { actionCreators } from 'states/stateProvider/actionCreators' -import UILayer, { AppMethod, ChainMethod, WalletsMethod, walletsCall } from 'services/UILayer' +import UILayer, { AppMethod, WalletsMethod, walletsCall } from 'services/UILayer' import { initWindow, getTransactionList, getTransaction } from 'services/remote' import { SystemScript as SystemScriptSubject, DataUpdate as DataUpdateSubject, NetworkList as NetworkListSubject, CurrentNetworkID as CurrentNetworkIDSubject, + ConnectionStatus as ConnectionStatusSubject, + SyncedBlockNumber as SyncedBlockNumberSubject, } from 'services/subjects' import { ckbCore, getTipBlockNumber, getBlockchainInfo } from 'services/chain' import { Routes, Channel, ConnectionStatus } from 'utils/const' @@ -60,34 +62,6 @@ export const useChannelListeners = ({ } }) - UILayer.on(Channel.Chain, (_e: Event, method: ChainMethod, args: ChannelResponse) => { - if (args && args.status) { - switch (method) { - case ChainMethod.Status: { - dispatch({ - type: NeuronWalletActions.Chain, - payload: { - connectionStatus: args.result ? ConnectionStatus.Online : ConnectionStatus.Offline, - }, - }) - break - } - case ChainMethod.TipBlockNumber: { - dispatch({ - type: NeuronWalletActions.Chain, - payload: { - tipBlockNumber: args.result || '0', - }, - }) - break - } - default: { - break - } - } - } - }) - UILayer.on(Channel.Wallets, (_e: Event, method: WalletsMethod, args: ChannelResponse) => { if (args.status) { switch (method) { @@ -361,11 +335,26 @@ export const useSubscription = ({ }) currentNetworkIDCache.save(currentNetworkID) }) + const connectionStatusSubscription = ConnectionStatusSubject.subscribe(status => { + dispatch({ + type: NeuronWalletActions.UpdateConnectionStatus, + payload: status ? ConnectionStatus.Online : ConnectionStatus.Offline, + }) + }) + + const syncedBlockNumberSubscription = SyncedBlockNumberSubject.subscribe(syncedBlockNumber => { + dispatch({ + type: NeuronWalletActions.UpdateSyncedBlockNumber, + payload: syncedBlockNumber, + }) + }) return () => { systemScriptSubscription.unsubscribe() dataUpdateSubscription.unsubscribe() networkListSubscription.unsubscribe() currentNetworkIDSubscription.unsubscribe() + connectionStatusSubscription.unsubscribe() + syncedBlockNumberSubscription.unsubscribe() } }, [walletID, pageNo, pageSize, keywords, txHash, dispatch]) } diff --git a/packages/neuron-ui/src/services/UILayer.ts b/packages/neuron-ui/src/services/UILayer.ts index 681209a26c..bbbbcfb110 100644 --- a/packages/neuron-ui/src/services/UILayer.ts +++ b/packages/neuron-ui/src/services/UILayer.ts @@ -10,11 +10,6 @@ export enum AppMethod { HandleViewError = 'handleViewError', } -export enum ChainMethod { - Status = 'status', - TipBlockNumber = 'tipBlockNumber', -} - export enum WalletsMethod { GetAll = 'getAll', Get = 'get', diff --git a/packages/neuron-ui/src/services/subjects.ts b/packages/neuron-ui/src/services/subjects.ts index 5db929ae24..fc3169ec5b 100644 --- a/packages/neuron-ui/src/services/subjects.ts +++ b/packages/neuron-ui/src/services/subjects.ts @@ -38,9 +38,19 @@ export const CurrentNetworkID = window.remote }>) : FallbackSubject +export const ConnectionStatus = window.remote + ? (window.remote.require(`${SUBJECT_PATH}/node`).ConnectionStatusSubject as NeuronWalletSubject) + : FallbackSubject + +export const SyncedBlockNumber = window.remote + ? (window.remote.require(`${SUBJECT_PATH}/node`).SyncedBlockNumberSubject as NeuronWalletSubject) + : FallbackSubject + export default { SystemScript, DataUpdate, NetworkList, CurrentNetworkID, + ConnectionStatus, + SyncedBlockNumber, } diff --git a/packages/neuron-ui/src/states/stateProvider/reducer.ts b/packages/neuron-ui/src/states/stateProvider/reducer.ts index 66dcacbcaa..5548528fbc 100644 --- a/packages/neuron-ui/src/states/stateProvider/reducer.ts +++ b/packages/neuron-ui/src/states/stateProvider/reducer.ts @@ -13,6 +13,9 @@ export enum NeuronWalletActions { // networks UpdateNetworkList = 'updateNetworkList', UpdateCurrentNetworkID = 'updateCurrentNetworkID', + // Connection + UpdateConnectionStatus = 'updateConnectionStatus', + UpdateSyncedBlockNumber = 'updateSyncedBlockNumber', } export enum AppActions { UpdateTransactionID = 'updateTransactionID', @@ -177,6 +180,24 @@ export const reducer = ( }, } } + case NeuronWalletActions.UpdateConnectionStatus: { + return { + ...state, + chain: { + ...chain, + connectionStatus: payload, + }, + } + } + case NeuronWalletActions.UpdateSyncedBlockNumber: { + return { + ...state, + chain: { + ...chain, + tipBlockNumber: payload, + }, + } + } // Actions of App case AppActions.UpdateTipBlockNumber: { /** diff --git a/packages/neuron-ui/src/utils/const.ts b/packages/neuron-ui/src/utils/const.ts index e6a991e4ca..25e539a6f3 100644 --- a/packages/neuron-ui/src/utils/const.ts +++ b/packages/neuron-ui/src/utils/const.ts @@ -16,7 +16,6 @@ export enum ConnectionStatus { export enum Channel { NavTo = 'navTo', App = 'app', - Chain = 'chain', Networks = 'networks', Transactions = 'transactions', Wallets = 'wallets', diff --git a/packages/neuron-wallet/src/models/subjects/current-block-subject.ts b/packages/neuron-wallet/src/models/subjects/current-block-subject.ts index d2e653fc07..9dc263bc0e 100644 --- a/packages/neuron-wallet/src/models/subjects/current-block-subject.ts +++ b/packages/neuron-wallet/src/models/subjects/current-block-subject.ts @@ -1,7 +1,6 @@ import { ReplaySubject } from 'rxjs' import { sampleTime } from 'rxjs/operators' -import windowManager from '../window-manager' -import { Channel, ResponseCode } from '../../utils/const' +import { SyncedBlockNumberSubject } from './node' export interface CurrentBlockInfo { blockNumber: string @@ -17,10 +16,7 @@ export class CurrentBlockSubject { static subscribe() { CurrentBlockSubject.subject.pipe(sampleTime(500)).subscribe(({ blockNumber }) => { - windowManager.broadcast(Channel.Chain, 'tipBlockNumber', { - status: ResponseCode.Success, - result: blockNumber, - }) + SyncedBlockNumberSubject.next(blockNumber) }) } } diff --git a/packages/neuron-wallet/src/models/subjects/node.ts b/packages/neuron-wallet/src/models/subjects/node.ts new file mode 100644 index 0000000000..d965107205 --- /dev/null +++ b/packages/neuron-wallet/src/models/subjects/node.ts @@ -0,0 +1,6 @@ +import { BehaviorSubject } from 'rxjs' + +export const ConnectionStatusSubject = new BehaviorSubject(false) +export const SyncedBlockNumberSubject = new BehaviorSubject('0') + +export default { ConnectionStatusSubject, SyncedBlockNumberSubject } diff --git a/packages/neuron-wallet/src/models/window-manager.ts b/packages/neuron-wallet/src/models/window-manager.ts index 8c095f0938..96aba90daa 100644 --- a/packages/neuron-wallet/src/models/window-manager.ts +++ b/packages/neuron-wallet/src/models/window-manager.ts @@ -14,7 +14,6 @@ interface SendMessage { (channel: Channel.Transactions, method: Controller.TransactionsMethod | 'transactionUpdated', params: any): void (channel: Channel.Networks, method: Controller.NetworksMethod, params: any): void (channel: Channel.Helpers, method: Controller.HelpersMethod, params: any): void - (channel: Channel.Chain, method: 'status' | 'tipBlockNumber', params: any): void } export default class WindowManager { diff --git a/packages/neuron-wallet/src/services/networks.ts b/packages/neuron-wallet/src/services/networks.ts index 6a48326dea..ca18304b28 100644 --- a/packages/neuron-wallet/src/services/networks.ts +++ b/packages/neuron-wallet/src/services/networks.ts @@ -6,7 +6,6 @@ import Store from '../models/store' import env from '../env' import { Validate, Required } from '../decorators' -import NodeService from './node' import { UsedName, NetworkNotFound, InvalidFormat } from '../exceptions' import { NetworkListSubject, CurrentNetworkIDSubject } from '../models/subjects/networks' @@ -80,7 +79,6 @@ export default class NetworksService extends Store { throw new NetworkNotFound(currentNetworkID) } CurrentNetworkIDSubject.next({ currentNetworkID }) - NodeService.getInstance().setNetwork(currentNetwork.remote) networkSwitchSubject.next(currentNetwork) }) } diff --git a/packages/neuron-wallet/src/services/node.ts b/packages/neuron-wallet/src/services/node.ts index c83ffa1e39..a003c1da62 100644 --- a/packages/neuron-wallet/src/services/node.ts +++ b/packages/neuron-wallet/src/services/node.ts @@ -2,8 +2,9 @@ import Core from '@nervosnetwork/ckb-sdk-core' import { interval, BehaviorSubject, merge } from 'rxjs' import { distinctUntilChanged, sampleTime, flatMap, delay, retry, debounceTime } from 'rxjs/operators' import { ShouldBeTypeOf } from '../exceptions' -import windowManager from '../models/window-manager' -import { Channel, ResponseCode } from '../utils/const' +import { ConnectionStatusSubject } from '../models/subjects/node' +import { CurrentNetworkIDSubject } from '../models/subjects/networks' +import NetworksService from './networks' class NodeService { private static instance: NodeService @@ -25,6 +26,12 @@ class NodeService { constructor() { this.start() this.syncConnectionStatus() + CurrentNetworkIDSubject.subscribe(async ({ currentNetworkID }) => { + const currentNetwork = await NetworksService.getInstance().get(currentNetworkID) + if (currentNetwork) { + this.setNetwork(currentNetwork.remote) + } + }) } public syncConnectionStatus = () => { @@ -33,10 +40,7 @@ class NodeService { merge(periodSync, realtimeSync) .pipe(debounceTime(500)) .subscribe(connectionStatus => { - windowManager.broadcast(Channel.Chain, 'status', { - status: ResponseCode.Success, - result: connectionStatus, - }) + ConnectionStatusSubject.next(connectionStatus) }) } diff --git a/packages/neuron-wallet/src/utils/const.ts b/packages/neuron-wallet/src/utils/const.ts index 2503fe7eda..12ab0c9766 100644 --- a/packages/neuron-wallet/src/utils/const.ts +++ b/packages/neuron-wallet/src/utils/const.ts @@ -3,7 +3,6 @@ export const MAX_PASSWORD_LENGTH = 50 export enum Channel { App = 'app', - Chain = 'chain', Networks = 'networks', Wallets = 'wallets', Transactions = 'transactions', From 5a27c7bf11d3e4b813592538e809d7176ad81670 Mon Sep 17 00:00:00 2001 From: Keith Date: Wed, 24 Jul 2019 22:12:10 +0800 Subject: [PATCH 06/16] feat(neuron-ui): call generate mnemonic method from neuron-wallet in neuron-ui with remote module --- .../src/components/WalletWizard/index.tsx | 21 +++++-------- .../neuron-ui/src/services/remote/index.ts | 10 ++++++ .../neuron-wallet/src/controllers/helpers.ts | 31 ------------------- .../neuron-wallet/src/controllers/index.ts | 2 -- 4 files changed, 17 insertions(+), 47 deletions(-) delete mode 100644 packages/neuron-wallet/src/controllers/helpers.ts diff --git a/packages/neuron-ui/src/components/WalletWizard/index.tsx b/packages/neuron-ui/src/components/WalletWizard/index.tsx index 1e9d80909a..a7265c9cd0 100644 --- a/packages/neuron-ui/src/components/WalletWizard/index.tsx +++ b/packages/neuron-ui/src/components/WalletWizard/index.tsx @@ -7,8 +7,8 @@ import withWizard, { WizardElementProps, WithWizardState } from 'components/with import { MnemonicAction, BUTTON_GAP } from 'utils/const' import { verifyWalletSubmission } from 'utils/validators' -import { helpersCall, walletsCall } from 'services/UILayer' -import { validateMnemonic, showErrorMessage } from 'services/remote' +import { walletsCall } from 'services/UILayer' +import { generateMnemonic, validateMnemonic, showErrorMessage } from 'services/remote' import { registerIcons, buttonGrommetIconStyles } from 'utils/icons' export enum WalletWizardPath { @@ -104,18 +104,11 @@ const Mnemonic = ({ useEffect(() => { if (type === MnemonicAction.Create) { - helpersCall - .generateMnemonic() - .then((res: string) => { - dispatch({ - type: 'generated', - payload: res, - }) - }) - .catch(err => { - console.error(err) - history.goBack() - }) + const mnemonic = generateMnemonic() + dispatch({ + type: 'generated', + payload: mnemonic, + }) } else { dispatch({ type: 'imported', diff --git a/packages/neuron-ui/src/services/remote/index.ts b/packages/neuron-ui/src/services/remote/index.ts index b353acc0ac..14a00e8f1b 100644 --- a/packages/neuron-ui/src/services/remote/index.ts +++ b/packages/neuron-ui/src/services/remote/index.ts @@ -18,6 +18,15 @@ export const validateMnemonic = (mnemonic: string): boolean => { return remoteValidateMnemonic(mnemonic) } +export const generateMnemonic = (): string => { + if (!window.remote) { + console.warn('remote is not supported') + return '' + } + const { generateMnemonic: remoteGenerateMnemonic } = window.remote.require('./models/keys/key') + return remoteGenerateMnemonic() +} + export const showMessage = (options: any, callback: Function) => { if (!window.remote) { console.warn('remote is not supported') @@ -39,6 +48,7 @@ export const showErrorMessage = (title: string, content: string) => { export default { initWindow, validateMnemonic, + generateMnemonic, showMessage, showErrorMessage, } diff --git a/packages/neuron-wallet/src/controllers/helpers.ts b/packages/neuron-wallet/src/controllers/helpers.ts deleted file mode 100644 index e06ef5995d..0000000000 --- a/packages/neuron-wallet/src/controllers/helpers.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { generateMnemonic } from '../models/keys/key' -import { Controller as ControllerDecorator, CatchControllerError } from '../decorators' -import { Channel, ResponseCode } from '../utils/const' -import { FailToCreateMnemonic } from '../exceptions' - -/** - * @class HelpersController - * @description handle messages from helpers channel - */ -@ControllerDecorator(Channel.Helpers) -export default class HelpersController { - @CatchControllerError - public static async generateMnemonic() { - const mnemonic = generateMnemonic() - if (mnemonic) { - return { - status: ResponseCode.Success, - result: mnemonic, - } - } - throw new FailToCreateMnemonic() - } -} - -/* eslint-disable */ -declare global { - module Controller { - type HelpersMethod = Exclude - } -} -/* eslint-enable */ diff --git a/packages/neuron-wallet/src/controllers/index.ts b/packages/neuron-wallet/src/controllers/index.ts index 4ba08e834c..600f3d2981 100644 --- a/packages/neuron-wallet/src/controllers/index.ts +++ b/packages/neuron-wallet/src/controllers/index.ts @@ -2,7 +2,6 @@ import AppController from './app' import NetworksController from './networks' import WalletsController from './wallets' import TransactionsController from './transactions' -import HelpersController from './helpers' import SyncInfoController from './sync-info' export default { @@ -10,6 +9,5 @@ export default { NetworksController, WalletsController, TransactionsController, - HelpersController, SyncInfoController, } From cdc93a0149361652f03a0ab7e2a1445f48838863 Mon Sep 17 00:00:00 2001 From: Keith Date: Thu, 25 Jul 2019 00:52:58 +0800 Subject: [PATCH 07/16] feat: call methods of app controller with remote module --- .../src/components/Addresses/index.tsx | 5 +- .../src/components/ErrorBoundary/index.tsx | 5 +- .../src/components/GeneralSetting/index.tsx | 4 +- .../neuron-ui/src/components/History/hooks.ts | 15 +--- .../src/components/NetworkEditor/hooks.ts | 2 +- .../src/components/NetworkSetting/index.tsx | 5 +- .../src/components/Overview/index.tsx | 15 ++-- .../src/components/PasswordRequest/index.tsx | 13 +--- .../src/components/Transaction/index.tsx | 15 +--- .../src/components/TransactionList/index.tsx | 4 +- .../src/components/WalletEditor/hooks.ts | 12 ++-- .../src/components/WalletSetting/index.tsx | 8 +-- .../neuron-ui/src/containers/Main/hooks.ts | 72 +++++++++---------- .../neuron-ui/src/containers/Main/index.tsx | 1 + packages/neuron-ui/src/services/UILayer.ts | 38 ---------- packages/neuron-ui/src/services/remote/app.ts | 15 ++++ .../remote/controllerMethodWrapper.ts | 8 ++- .../neuron-ui/src/services/remote/index.ts | 10 +++ packages/neuron-ui/src/services/subjects.ts | 9 +++ .../stateProvider/actionCreators/index.ts | 4 ++ .../stateProvider/actionCreators/send.ts | 52 +++++++------- .../stateProvider/actionCreators/settings.ts | 20 +++--- .../actionCreators/transactions.ts | 56 ++++++--------- .../stateProvider/actionCreators/wallets.ts | 60 ++++++---------- packages/neuron-ui/src/utils/const.ts | 5 -- .../src/controllers/app/index.ts | 27 ++++--- .../src/models/subjects/command.ts | 5 ++ .../src/models/window-manager.ts | 4 -- .../neuron-wallet/src/services/networks.ts | 5 ++ packages/neuron-wallet/src/utils/const.ts | 2 - 30 files changed, 214 insertions(+), 282 deletions(-) create mode 100644 packages/neuron-ui/src/services/remote/app.ts create mode 100644 packages/neuron-wallet/src/models/subjects/command.ts diff --git a/packages/neuron-ui/src/components/Addresses/index.tsx b/packages/neuron-ui/src/components/Addresses/index.tsx index 2a8064ae4e..f321ec1aa4 100644 --- a/packages/neuron-ui/src/components/Addresses/index.tsx +++ b/packages/neuron-ui/src/components/Addresses/index.tsx @@ -12,8 +12,7 @@ import { } from 'office-ui-fabric-react' import { StateWithDispatch } from 'states/stateProvider/reducer' - -import { appCalls } from 'services/UILayer' +import { contextMenu } from 'services/remote' import { useLocalDescription } from 'utils/hooks' import { MIN_CELL_WIDTH, Routes } from 'utils/const' @@ -162,7 +161,7 @@ const Addresses = ({ columns={addressColumns.map(col => ({ ...col, name: t(col.name) }))} items={addresses} onItemContextMenu={item => { - appCalls.contextMenu({ type: 'addressList', id: item.identifier }) + contextMenu({ type: 'addressList', id: item.identifier }) }} styles={{ contentWrapper: { diff --git a/packages/neuron-ui/src/components/ErrorBoundary/index.tsx b/packages/neuron-ui/src/components/ErrorBoundary/index.tsx index 499867d979..e2e169e7ff 100644 --- a/packages/neuron-ui/src/components/ErrorBoundary/index.tsx +++ b/packages/neuron-ui/src/components/ErrorBoundary/index.tsx @@ -1,9 +1,9 @@ import React, { Component } from 'react' -import { appCalls } from 'services/UILayer' import { Stack, Spinner } from 'office-ui-fabric-react' +import { handleViewError } from 'services/remote' const handleError = (error: Error) => { - appCalls.handleViewError(error.toString()) + handleViewError(error.toString()) setTimeout(() => { window.location.reload() }, 0) @@ -16,7 +16,6 @@ class ErrorBoundary extends Component<{ children: React.ReactChild }, { hasError } static getDerivedStateFromError(error: Error) { - window.alert(error.stack) return handleError(error) } diff --git a/packages/neuron-ui/src/components/GeneralSetting/index.tsx b/packages/neuron-ui/src/components/GeneralSetting/index.tsx index ccf99e36dd..b4ff6155d5 100644 --- a/packages/neuron-ui/src/components/GeneralSetting/index.tsx +++ b/packages/neuron-ui/src/components/GeneralSetting/index.tsx @@ -3,12 +3,12 @@ import { Stack, Toggle } from 'office-ui-fabric-react' import { useTranslation } from 'react-i18next' import { StateWithDispatch } from 'states/stateProvider/reducer' -import actionCreators from 'states/stateProvider/actionCreators' +import { toggleAddressBook } from 'states/stateProvider/actionCreators' const GeneralSetting = ({ settings: { showAddressBook }, dispatch }: React.PropsWithoutRef) => { const [t] = useTranslation() const onToggle = useCallback(() => { - dispatch(actionCreators.toggleAddressBook()) + dispatch(toggleAddressBook()) }, [dispatch]) return ( diff --git a/packages/neuron-ui/src/components/History/hooks.ts b/packages/neuron-ui/src/components/History/hooks.ts index d63a323c00..2733e4f59f 100644 --- a/packages/neuron-ui/src/components/History/hooks.ts +++ b/packages/neuron-ui/src/components/History/hooks.ts @@ -1,7 +1,7 @@ import { useState, useEffect } from 'react' -import { NeuronWalletActions, AppActions } from 'states/stateProvider/reducer' +import { AppActions } from 'states/stateProvider/reducer' +import { updateTransactionList } from 'states/stateProvider/actionCreators/transactions' import { queryParsers } from 'utils/parser' -import { getTransactionList } from 'services/remote' const backToTop = () => { const container = document.querySelector('main') as HTMLElement @@ -31,16 +31,7 @@ export const useSearch = (search: string = '', walletID: string = '', dispatch: type: AppActions.CleanTransactions, payload: null, }) - getTransactionList({ ...params, keywords: params.keywords, walletID }).then(res => { - if (res.status) { - dispatch({ - type: NeuronWalletActions.UpdateTransactionList, - payload: res.result, - }) - } else { - // TODO: notification - } - }) + updateTransactionList({ ...params, keywords: params.keywords, walletID })(dispatch) }, [search, walletID, dispatch]) return { keywords, onKeywordsChange, setKeywords } } diff --git a/packages/neuron-ui/src/components/NetworkEditor/hooks.ts b/packages/neuron-ui/src/components/NetworkEditor/hooks.ts index e6e6d84b2e..9128ad6d59 100644 --- a/packages/neuron-ui/src/components/NetworkEditor/hooks.ts +++ b/packages/neuron-ui/src/components/NetworkEditor/hooks.ts @@ -1,8 +1,8 @@ import { useState, useEffect, useMemo, useCallback } from 'react' import { AppActions, StateDispatch } from 'states/stateProvider/reducer' -import { Message, MAX_NETWORK_NAME_LENGTH, Routes } from 'utils/const' import { createNetwork, updateNetwork } from 'services/remote' +import { Message, MAX_NETWORK_NAME_LENGTH, Routes } from 'utils/const' import i18n from 'utils/i18n' diff --git a/packages/neuron-ui/src/components/NetworkSetting/index.tsx b/packages/neuron-ui/src/components/NetworkSetting/index.tsx index ea5ef2dea6..32a07c7f40 100644 --- a/packages/neuron-ui/src/components/NetworkSetting/index.tsx +++ b/packages/neuron-ui/src/components/NetworkSetting/index.tsx @@ -5,13 +5,12 @@ import { Stack, PrimaryButton, ChoiceGroup, IChoiceGroupOption } from 'office-ui import { StateWithDispatch } from 'states/stateProvider/reducer' import chainState from 'states/initStates/chain' -import { appCalls } from 'services/UILayer' -import { setCurrentNetowrk } from 'services/remote' +import { setCurrentNetowrk, contextMenu } from 'services/remote' import { Routes } from 'utils/const' const onContextMenu = (id: string = '') => () => { - appCalls.contextMenu({ type: 'networkList', id }) + contextMenu({ type: 'networkList', id }) } const NetworkSetting = ({ diff --git a/packages/neuron-ui/src/components/Overview/index.tsx b/packages/neuron-ui/src/components/Overview/index.tsx index d80b3ab076..a8f55fe6f6 100644 --- a/packages/neuron-ui/src/components/Overview/index.tsx +++ b/packages/neuron-ui/src/components/Overview/index.tsx @@ -21,9 +21,10 @@ import { MessageBarType, } from 'office-ui-fabric-react' -import { StateWithDispatch, NeuronWalletActions } from 'states/stateProvider/reducer' +import { StateWithDispatch } from 'states/stateProvider/reducer' +import { updateTransactionList } from 'states/stateProvider/actionCreators' -import { showErrorMessage, getTransactionList } from 'services/remote' +import { showErrorMessage } from 'services/remote' import { localNumberFormatter, shannonToCKBFormatter, uniformTimeFormatter as timeFormatter } from 'utils/formatters' import { PAGE_SIZE, MIN_CELL_WIDTH } from 'utils/const' @@ -99,18 +100,12 @@ const Overview = ({ const minerInfoRef = useRef(null) useEffect(() => { - getTransactionList({ + updateTransactionList({ pageNo: 1, pageSize: PAGE_SIZE, keywords: '', walletID: id, - }).then(res => { - if (res.status) { - dispatch({ type: NeuronWalletActions.UpdateTransactionList, payload: res.result }) - } else { - // TODO: notification - } - }) + })(dispatch) }, [id, dispatch]) const onTransactionRowRender = useCallback((props?: IDetailsRowProps) => { diff --git a/packages/neuron-ui/src/components/PasswordRequest/index.tsx b/packages/neuron-ui/src/components/PasswordRequest/index.tsx index c2db0839ac..08dfb7bb78 100644 --- a/packages/neuron-ui/src/components/PasswordRequest/index.tsx +++ b/packages/neuron-ui/src/components/PasswordRequest/index.tsx @@ -23,20 +23,9 @@ const PasswordRequest = ({ }, [dispatch]) const onConfirm = useCallback(() => { - const params = { id: walletID, password } switch (actionType) { - case 'delete': { - dispatch(actionCreators.deleteWallet(params)) - break - } - case 'backup': { - dispatch(actionCreators.backupWallet(params)) - break - } case 'send': { - dispatch( - actionCreators.submitTransaction(txID, walletID, outputs, description, password, priceToFee(price, cycles)) - ) + submitTransaction(txID, walletID, outputs, description, password, priceToFee(price, cycles))(dispatch) break } default: { diff --git a/packages/neuron-ui/src/components/Transaction/index.tsx b/packages/neuron-ui/src/components/Transaction/index.tsx index b85507feee..be364f19e4 100644 --- a/packages/neuron-ui/src/components/Transaction/index.tsx +++ b/packages/neuron-ui/src/components/Transaction/index.tsx @@ -3,11 +3,11 @@ import { RouteComponentProps } from 'react-router-dom' import { useTranslation } from 'react-i18next' import { Stack, DetailsList, Text, DetailsListLayoutMode, CheckboxVisibility, IColumn } from 'office-ui-fabric-react' -import { AppActions, StateWithDispatch, NeuronWalletActions } from 'states/stateProvider/reducer' +import { AppActions, StateWithDispatch } from 'states/stateProvider/reducer' +import { updateTransaction } from 'states/stateProvider/actionCreators' import chainState from 'states/initStates/chain' import { localNumberFormatter, uniformTimeFormatter } from 'utils/formatters' -import { getTransaction } from 'services/remote' const MIN_CELL_WIDTH = 70 @@ -105,16 +105,7 @@ const Transaction = ({ type: AppActions.CleanTransaction, payload: null, }) - getTransaction({ walletID, hash: match.params.hash }).then(res => { - if (res.status) { - dispatch({ - type: NeuronWalletActions.UpdateTransaction, - payload: res.result, - }) - } else { - // TODO: notification - } - }) + updateTransaction({ walletID, hash: match.params.hash })(dispatch) }, [match.params.hash, dispatch, walletID]) const basicInfoItems = useMemo( diff --git a/packages/neuron-ui/src/components/TransactionList/index.tsx b/packages/neuron-ui/src/components/TransactionList/index.tsx index 74de95abfa..f8a70618e5 100644 --- a/packages/neuron-ui/src/components/TransactionList/index.tsx +++ b/packages/neuron-ui/src/components/TransactionList/index.tsx @@ -14,8 +14,8 @@ import { import { FormUp as ExpandIcon } from 'grommet-icons' import { StateDispatch } from 'states/stateProvider/reducer' +import { contextMenu } from 'services/remote' -import { appCalls } from 'services/UILayer' import { useLocalDescription } from 'utils/hooks' import { shannonToCKBFormatter, uniformTimeFormatter as timeFormatter, uniformTimeFormatter } from 'utils/formatters' import { registerIcons } from 'utils/icons' @@ -190,7 +190,7 @@ const TransactionList = ({ items = [] }: { walletID: string; items: State.Transa checkboxVisibility={CheckboxVisibility.hidden} onItemContextMenu={item => { if (item) { - appCalls.contextMenu({ type: 'transactionList', id: item.hash }) + contextMenu({ type: 'transactionList', id: item.hash }) } }} styles={{ diff --git a/packages/neuron-ui/src/components/WalletEditor/hooks.ts b/packages/neuron-ui/src/components/WalletEditor/hooks.ts index 0afb93d271..e2ef2415c2 100644 --- a/packages/neuron-ui/src/components/WalletEditor/hooks.ts +++ b/packages/neuron-ui/src/components/WalletEditor/hooks.ts @@ -1,5 +1,5 @@ import { useState, useMemo, useCallback } from 'react' -import actionCreators from 'states/stateProvider/actionCreators' +import { updateWallet } from 'states/stateProvider/actionCreators' import { StateDispatch } from 'states/stateProvider/reducer' import i18n from 'utils/i18n' @@ -37,12 +37,10 @@ export const useInputs = ({ name }: ReturnType) => { export const useOnConfirm = (name: string = '', id: string = '', dispatch: StateDispatch) => { return useCallback(() => { - dispatch( - actionCreators.updateWallet({ - id, - name, - }) - ) + updateWallet({ + id, + name, + })(dispatch) }, [name, id, dispatch]) } diff --git a/packages/neuron-ui/src/components/WalletSetting/index.tsx b/packages/neuron-ui/src/components/WalletSetting/index.tsx index fe2c74a9e4..7ab9046727 100644 --- a/packages/neuron-ui/src/components/WalletSetting/index.tsx +++ b/packages/neuron-ui/src/components/WalletSetting/index.tsx @@ -4,11 +4,11 @@ import { useTranslation } from 'react-i18next' import { Stack, PrimaryButton, ChoiceGroup, IChoiceGroupOption } from 'office-ui-fabric-react' import { StateWithDispatch } from 'states/stateProvider/reducer' -import actionCreators from 'states/stateProvider/actionCreators' +import { activateWallet } from 'states/stateProvider/actionCreators' import { WalletWizardPath } from 'components/WalletWizard' -import { appCalls } from 'services/UILayer' +import { contextMenu } from 'services/remote' import { Routes, MnemonicAction } from 'utils/const' const buttons = [ @@ -32,14 +32,14 @@ const WalletSetting = ({ const onChange = useCallback( (_e, option) => { if (option) { - dispatch(actionCreators.activateWallet(option.key)) + activateWallet(option.key)(dispatch) } }, [dispatch] ) const onContextMenu = useCallback( (id: string = '') => () => { - appCalls.contextMenu({ type: 'walletList', id }) + contextMenu({ type: 'walletList', id }) }, [] ) diff --git a/packages/neuron-ui/src/containers/Main/hooks.ts b/packages/neuron-ui/src/containers/Main/hooks.ts index 7d05d96c12..6d6898d2f4 100644 --- a/packages/neuron-ui/src/containers/Main/hooks.ts +++ b/packages/neuron-ui/src/containers/Main/hooks.ts @@ -2,10 +2,10 @@ import { useEffect } from 'react' import { WalletWizardPath } from 'components/WalletWizard' import { NeuronWalletActions, StateDispatch, AppActions } from 'states/stateProvider/reducer' -import { actionCreators } from 'states/stateProvider/actionCreators' +import { toggleAddressBook, updateTransactionList, updateTransaction } from 'states/stateProvider/actionCreators' -import UILayer, { AppMethod, WalletsMethod, walletsCall } from 'services/UILayer' -import { initWindow, getTransactionList, getTransaction } from 'services/remote' +import UILayer, { WalletsMethod, walletsCall } from 'services/UILayer' +import { initWindow, getWinID } from 'services/remote' import { SystemScript as SystemScriptSubject, DataUpdate as DataUpdateSubject, @@ -13,6 +13,7 @@ import { CurrentNetworkID as CurrentNetworkIDSubject, ConnectionStatus as ConnectionStatusSubject, SyncedBlockNumber as SyncedBlockNumberSubject, + Command as CommandSubject, } from 'services/subjects' import { ckbCore, getTipBlockNumber, getBlockchainInfo } from 'services/chain' import { Routes, Channel, ConnectionStatus } from 'utils/const' @@ -44,24 +45,6 @@ export const useChannelListeners = ({ i18n: any }) => useEffect(() => { - UILayer.on(Channel.App, (_e: Event, method: AppMethod, args: ChannelResponse) => { - if (args && args.status) { - switch (method) { - case AppMethod.NavTo: { - history.push(args.result) - break - } - case AppMethod.ToggleAddressBook: { - dispatch(actionCreators.toggleAddressBook()) - break - } - default: { - break - } - } - } - }) - UILayer.on(Channel.Wallets, (_e: Event, method: WalletsMethod, args: ChannelResponse) => { if (args.status) { switch (method) { @@ -236,19 +219,12 @@ export const useOnCurrentWalletChange = ({ useEffect(() => { if (walletID) { walletsCall.getAllAddresses(walletID) - getTransactionList({ + updateTransactionList({ walletID, keywords: '', pageNo, pageSize, - }).then(res => { - if (res.status) { - dispatch({ - type: NeuronWalletActions.UpdateTransactionList, - payload: res.result, - }) - } - }) + })(dispatch) } else { initWindow() .then((initializedState: any) => { @@ -270,10 +246,12 @@ export const useOnCurrentWalletChange = ({ export const useSubscription = ({ walletID, chain, + history, dispatch, }: { walletID: string chain: State.Chain + history: any dispatch: StateDispatch }) => { const { pageNo, pageSize, keywords } = chain.transactions @@ -296,19 +274,13 @@ export const useSubscription = ({ break } case 'transaction': { - getTransactionList({ + updateTransactionList({ walletID, keywords, pageNo, pageSize, - }).then(res => { - if (res.status) { - dispatch({ type: NeuronWalletActions.UpdateTransactionList, payload: res.result }) - } else { - // TODO: notification - } - }) - getTransaction({ walletID, hash: txHash }) + })(dispatch) + updateTransaction({ walletID, hash: txHash }) break } case 'wallet': { @@ -348,6 +320,25 @@ export const useSubscription = ({ payload: syncedBlockNumber, }) }) + const commandSubscription = CommandSubject.subscribe( + ({ winID, type, payload }: { winID: number; type: 'nav' | 'toggleAddressBook'; payload: string | null }) => { + if (getWinID() === winID) { + switch (type) { + case 'nav': { + history.push(payload) + break + } + case 'toggleAddressBook': { + dispatch(toggleAddressBook()) + break + } + default: { + break + } + } + } + } + ) return () => { systemScriptSubscription.unsubscribe() dataUpdateSubscription.unsubscribe() @@ -355,8 +346,9 @@ export const useSubscription = ({ currentNetworkIDSubscription.unsubscribe() connectionStatusSubscription.unsubscribe() syncedBlockNumberSubscription.unsubscribe() + commandSubscription.unsubscribe() } - }, [walletID, pageNo, pageSize, keywords, txHash, dispatch]) + }, [walletID, pageNo, pageSize, keywords, txHash, history, dispatch]) } export default { diff --git a/packages/neuron-ui/src/containers/Main/index.tsx b/packages/neuron-ui/src/containers/Main/index.tsx index da25f5667d..2a3b512126 100644 --- a/packages/neuron-ui/src/containers/Main/index.tsx +++ b/packages/neuron-ui/src/containers/Main/index.tsx @@ -125,6 +125,7 @@ const MainContent = ({ useSubscription({ walletID, chain, + history, dispatch, }) diff --git a/packages/neuron-ui/src/services/UILayer.ts b/packages/neuron-ui/src/services/UILayer.ts index bbbbcfb110..9b740180e2 100644 --- a/packages/neuron-ui/src/services/UILayer.ts +++ b/packages/neuron-ui/src/services/UILayer.ts @@ -2,14 +2,6 @@ import { Channel } from 'utils/const' import SyntheticEventEmitter from 'utils/SyntheticEventEmitter' import instantiateMethodCall from 'utils/instantiateMethodCall' -export enum AppMethod { - ToggleAddressBook = 'toggleAddressBook', - ContextMenu = 'contextMenu', - NavTo = 'navTo', - SetUILocale = 'setUILocale', - HandleViewError = 'handleViewError', -} - export enum WalletsMethod { GetAll = 'getAll', Get = 'get', @@ -30,10 +22,6 @@ export enum WalletsMethod { GetAllAddresses = 'getAllAddresses', } -export enum HelpersMethod { - GenerateMnemonic = 'generateMnemonic', -} - const UILayer = (() => { if (window.bridge) { return new SyntheticEventEmitter(window.bridge.ipcRenderer) @@ -58,15 +46,6 @@ const UILayer = (() => { } })() -export const app = (method: AppMethod, ...params: any) => { - UILayer.send(Channel.App, method, ...params) -} - -export const appCalls = instantiateMethodCall(app) as { - contextMenu: ({ type, id }: { type: string; id: string }) => void - handleViewError: (errorMessage: string) => void -} - export const wallets = ( method: WalletsMethod, params: @@ -116,21 +95,4 @@ export const walletsCall = instantiateMethodCall(wallets) as { updateAddressDescription: (params: { walletID: string; address: string; description: string }) => void } -export const helpers = (method: HelpersMethod, ...params: any) => { - return new Promise((res, rej) => { - UILayer.send(Channel.Helpers, method, ...params) - UILayer.once(Channel.Helpers, (_e: Event, _method: HelpersMethod, args: ChannelResponse) => { - if (args.status) { - res(args.result) - } else { - rej(args.msg) - } - }) - }) -} - -export const helpersCall = instantiateMethodCall(helpers) as { - generateMnemonic: () => Promise -} - export default UILayer diff --git a/packages/neuron-ui/src/services/remote/app.ts b/packages/neuron-ui/src/services/remote/app.ts new file mode 100644 index 0000000000..1293269df3 --- /dev/null +++ b/packages/neuron-ui/src/services/remote/app.ts @@ -0,0 +1,15 @@ +import { controllerMethodWrapper } from './controllerMethodWrapper' + +const CONTROLLER_NAME = 'app' + +export const handleViewError = controllerMethodWrapper(CONTROLLER_NAME)(controller => (errorMessage: string) => + controller.handleViewError(errorMessage) +) +export const contextMenu = controllerMethodWrapper(CONTROLLER_NAME)( + controller => (params: { type: string; id: string }) => controller.contextMenu(params) +) + +export default { + handleViewError, + contextMenu, +} diff --git a/packages/neuron-ui/src/services/remote/controllerMethodWrapper.ts b/packages/neuron-ui/src/services/remote/controllerMethodWrapper.ts index a2063e99f1..04f6dc66ba 100644 --- a/packages/neuron-ui/src/services/remote/controllerMethodWrapper.ts +++ b/packages/neuron-ui/src/services/remote/controllerMethodWrapper.ts @@ -37,10 +37,16 @@ export const controllerMethodWrapper = (controllerName: string) => ( return controllerNotLoaded(controllerName) } const res = await callControllerMethod(controller)(realParams) + if (!res) { + return { + status: 1, + result: null, + } + } if (res.status) { return { status: 1, - result: res.result || true, + result: res.result || null, } } return { diff --git a/packages/neuron-ui/src/services/remote/index.ts b/packages/neuron-ui/src/services/remote/index.ts index 14a00e8f1b..27c82be78b 100644 --- a/packages/neuron-ui/src/services/remote/index.ts +++ b/packages/neuron-ui/src/services/remote/index.ts @@ -1,5 +1,14 @@ +export * from './app' export * from './networks' export * from './transactions' + +export const getWinID = () => { + if (!window.remote) { + console.warn('remote is not supported') + return -1 + } + return window.remote.getCurrentWindow().id +} export const initWindow = () => { if (!window.remote) { console.warn('remote is not supported') @@ -51,4 +60,5 @@ export default { generateMnemonic, showMessage, showErrorMessage, + getWinID, } diff --git a/packages/neuron-ui/src/services/subjects.ts b/packages/neuron-ui/src/services/subjects.ts index fc3169ec5b..1dfe162cf7 100644 --- a/packages/neuron-ui/src/services/subjects.ts +++ b/packages/neuron-ui/src/services/subjects.ts @@ -46,6 +46,14 @@ export const SyncedBlockNumber = window.remote ? (window.remote.require(`${SUBJECT_PATH}/node`).SyncedBlockNumberSubject as NeuronWalletSubject) : FallbackSubject +export const Command = window.remote + ? (window.remote.require(`${SUBJECT_PATH}/command`).default as NeuronWalletSubject<{ + winID: number + type: 'nav' | 'toggleAddressBook' + payload: string | null + }>) + : FallbackSubject + export default { SystemScript, DataUpdate, @@ -53,4 +61,5 @@ export default { CurrentNetworkID, ConnectionStatus, SyncedBlockNumber, + Command, } diff --git a/packages/neuron-ui/src/states/stateProvider/actionCreators/index.ts b/packages/neuron-ui/src/states/stateProvider/actionCreators/index.ts index 8bf9984b6c..b9b5e8842b 100644 --- a/packages/neuron-ui/src/states/stateProvider/actionCreators/index.ts +++ b/packages/neuron-ui/src/states/stateProvider/actionCreators/index.ts @@ -3,6 +3,10 @@ import send from './send' import transactions from './transactions' import settings from './settings' +export * from './wallets' +export * from './send' +export * from './transactions' +export * from './settings' export const actionCreators = { ...wallets, ...send, diff --git a/packages/neuron-ui/src/states/stateProvider/actionCreators/send.ts b/packages/neuron-ui/src/states/stateProvider/actionCreators/send.ts index 848e10f36b..1c6bdb72d5 100644 --- a/packages/neuron-ui/src/states/stateProvider/actionCreators/send.ts +++ b/packages/neuron-ui/src/states/stateProvider/actionCreators/send.ts @@ -3,31 +3,33 @@ import { walletsCall } from 'services/UILayer' import { CKBToShannonFormatter } from 'utils/formatters' import { TransactionOutput } from 'components/Send' -import { AppActions } from '../reducer' +import { AppActions, StateDispatch } from '../reducer' + +export const submitTransaction = ( + id: string = '', + walletID: string = '', + items: TransactionOutput[] = [], + description: string = '', + password: string = '', + fee: string = '0' +) => (dispatch: StateDispatch) => { + walletsCall.sendCapacity({ + id, + walletID, + items: items.map(item => ({ + address: item.address, + capacity: CKBToShannonFormatter(item.amount, item.unit), + })), + password, + fee, + description, + }) + dispatch({ + type: AppActions.DismissPasswordRequest, + payload: null, + }) +} export default { - submitTransaction: ( - id: string = '', - walletID: string = '', - items: TransactionOutput[] = [], - description: string = '', - password: string = '', - fee: string = '0' - ) => { - walletsCall.sendCapacity({ - id, - walletID, - items: items.map(item => ({ - address: item.address, - capacity: CKBToShannonFormatter(item.amount, item.unit), - })), - password, - fee, - description, - }) - return { - type: AppActions.DismissPasswordRequest, - payload: null, - } - }, + submitTransaction, } diff --git a/packages/neuron-ui/src/states/stateProvider/actionCreators/settings.ts b/packages/neuron-ui/src/states/stateProvider/actionCreators/settings.ts index 88309b407b..2a723673c8 100644 --- a/packages/neuron-ui/src/states/stateProvider/actionCreators/settings.ts +++ b/packages/neuron-ui/src/states/stateProvider/actionCreators/settings.ts @@ -1,14 +1,16 @@ import { addressBook } from 'utils/localCache' import { NeuronWalletActions } from '../reducer' +export const toggleAddressBook = () => { + addressBook.toggleVisibility() + return { + type: NeuronWalletActions.Settings, + payload: { + toggleAddressBook: true, + }, + } +} + export default { - toggleAddressBook: () => { - addressBook.toggleVisibility() - return { - type: NeuronWalletActions.Settings, - payload: { - toggleAddressBook: true, - }, - } - }, + toggleAddressBook, } diff --git a/packages/neuron-ui/src/states/stateProvider/actionCreators/transactions.ts b/packages/neuron-ui/src/states/stateProvider/actionCreators/transactions.ts index 4832377655..028b072ba9 100644 --- a/packages/neuron-ui/src/states/stateProvider/actionCreators/transactions.ts +++ b/packages/neuron-ui/src/states/stateProvider/actionCreators/transactions.ts @@ -1,38 +1,28 @@ -import { walletsCall } from 'services/UILayer' -import { AppActions } from '../reducer' +import { NeuronWalletActions, StateDispatch } from 'states/stateProvider/reducer' +import { GetTransactionListParams, getTransaction, getTransactionList } from 'services/remote' -export default { - updateDescription: ({ - type, - walletID, - key, - description, - }: { - type: 'address' | 'transaction' - walletID: string - key: string - description: string - }) => { - if (type === 'address') { - walletsCall.updateAddressDescription({ - walletID, - address: key, - description, +export const updateTransaction = (params: { walletID: string; hash: string }) => (dispatch: StateDispatch) => { + getTransaction(params).then(res => { + if (res.status) { + dispatch({ + type: NeuronWalletActions.UpdateTransaction, + payload: res.result, }) - return { - type: AppActions.Ignore, - payload: null, - } - } - if (type === 'transaction') { - return { - type: AppActions.Ignore, - payload: null, - } } - return { - type: AppActions.Ignore, - payload: null, + }) +} +export const updateTransactionList = (params: GetTransactionListParams) => (dispatch: StateDispatch) => { + getTransactionList(params).then(res => { + if (res.status) { + dispatch({ + type: NeuronWalletActions.UpdateTransactionList, + payload: res.result, + }) } - }, + }) +} + +export default { + updateTransaction, + updateTransactionList, } diff --git a/packages/neuron-ui/src/states/stateProvider/actionCreators/wallets.ts b/packages/neuron-ui/src/states/stateProvider/actionCreators/wallets.ts index 938147ffaf..da848b5e42 100644 --- a/packages/neuron-ui/src/states/stateProvider/actionCreators/wallets.ts +++ b/packages/neuron-ui/src/states/stateProvider/actionCreators/wallets.ts @@ -1,44 +1,26 @@ -import { AppActions } from 'states/stateProvider/reducer' +import { AppActions, StateDispatch } from 'states/stateProvider/reducer' import { walletsCall } from 'services/UILayer' import { NeuronWalletActions } from '../reducer' +export const activateWallet = (id: string) => (dispatch: StateDispatch) => { + walletsCall.activate(id) + dispatch({ + type: NeuronWalletActions.Wallet, + payload: id, + }) +} + +export const updateWallet = (params: { id: string; password?: string; newPassword?: string; name?: string }) => ( + dispatch: StateDispatch +) => { + walletsCall.update(params) + dispatch({ + type: AppActions.Ignore, + payload: null, + }) +} + export default { - getAll: () => { - walletsCall.getAll() - return { - type: NeuronWalletActions.Wallet, - } - }, - activateWallet: (id: string) => { - walletsCall.activate(id) - return { - type: NeuronWalletActions.Wallet, - payload: id, - } - }, - updateWallet: (params: { id: string; password?: string; newPassword?: string; name?: string }) => { - walletsCall.update(params) - return { - type: AppActions.Ignore, - payload: null, - } - }, - deleteWallet: (params: { id: string; password: string }) => { - setTimeout(() => { - walletsCall.delete(params) - }, 100) - return { - type: AppActions.DismissPasswordRequest, - payload: null, - } - }, - backupWallet: (params: { id: string; password: string }) => { - setTimeout(() => { - walletsCall.backup(params) - }, 100) - return { - type: AppActions.DismissPasswordRequest, - payload: null, - } - }, + updateWallet, + activateWallet, } diff --git a/packages/neuron-ui/src/utils/const.ts b/packages/neuron-ui/src/utils/const.ts index 25e539a6f3..0b1b42736b 100644 --- a/packages/neuron-ui/src/utils/const.ts +++ b/packages/neuron-ui/src/utils/const.ts @@ -14,12 +14,7 @@ export enum ConnectionStatus { } export enum Channel { - NavTo = 'navTo', - App = 'app', - Networks = 'networks', - Transactions = 'transactions', Wallets = 'wallets', - Helpers = 'helpers', } export enum Routes { diff --git a/packages/neuron-wallet/src/controllers/app/index.ts b/packages/neuron-wallet/src/controllers/app/index.ts index 282dc25552..12a4d99643 100644 --- a/packages/neuron-wallet/src/controllers/app/index.ts +++ b/packages/neuron-wallet/src/controllers/app/index.ts @@ -12,10 +12,11 @@ import WalletsController from '../wallets' import SyncInfoController from '../sync-info' import { Controller as ControllerDecorator } from '../../decorators' -import { Channel, ResponseCode } from '../../utils/const' +import { Channel } from '../../utils/const' import WindowManager from '../../models/window-manager' import i18n from '../../utils/i18n' import env from '../../env' +import CommandSubject from '../../models/subjects/command' const nodeService = NodeService.getInstance() @@ -100,23 +101,19 @@ export default class AppController { } public static toggleAddressBook() { - WindowManager.broadcast(Channel.App, 'toggleAddressBook', { - status: ResponseCode.Success, - }) + if (WindowManager.mainWindow) { + CommandSubject.next({ + winID: WindowManager.mainWindow.id, + type: 'toggleAddressBook', + payload: null, + }) + } } public static navTo(url: string) { - WindowManager.sendToMainWindow(Channel.App, 'navTo', { - status: ResponseCode.Success, - result: url, - }) - } - - public static setUILocale(locale: string) { - WindowManager.broadcast(Channel.App, 'setUILocale', { - status: ResponseCode.Success, - result: locale, - }) + if (WindowManager.mainWindow) { + CommandSubject.next({ winID: WindowManager.mainWindow.id, type: 'nav', payload: url }) + } } public static openExternal(url: string) { diff --git a/packages/neuron-wallet/src/models/subjects/command.ts b/packages/neuron-wallet/src/models/subjects/command.ts new file mode 100644 index 0000000000..8a7d4d4e0d --- /dev/null +++ b/packages/neuron-wallet/src/models/subjects/command.ts @@ -0,0 +1,5 @@ +import { Subject } from 'rxjs' + +const CommandSubject = new Subject<{ winID: number; type: 'nav' | 'toggleAddressBook'; payload: string | null }>() + +export default CommandSubject diff --git a/packages/neuron-wallet/src/models/window-manager.ts b/packages/neuron-wallet/src/models/window-manager.ts index 96aba90daa..be14689a9c 100644 --- a/packages/neuron-wallet/src/models/window-manager.ts +++ b/packages/neuron-wallet/src/models/window-manager.ts @@ -5,15 +5,11 @@ import logger from '../utils/logger' const error = { level: 'error', message: 'Electron is not loaded' } interface SendMessage { - (channel: Channel.App, method: Controller.AppMethod, params: any): void ( channel: Channel.Wallets, method: Controller.WalletsMethod | 'allAddresses' | 'sendingStatus' | 'requestPassword', params: any ): void - (channel: Channel.Transactions, method: Controller.TransactionsMethod | 'transactionUpdated', params: any): void - (channel: Channel.Networks, method: Controller.NetworksMethod, params: any): void - (channel: Channel.Helpers, method: Controller.HelpersMethod, params: any): void } export default class WindowManager { diff --git a/packages/neuron-wallet/src/services/networks.ts b/packages/neuron-wallet/src/services/networks.ts index ca18304b28..7796ab6555 100644 --- a/packages/neuron-wallet/src/services/networks.ts +++ b/packages/neuron-wallet/src/services/networks.ts @@ -55,6 +55,11 @@ export default class NetworksService extends Store { this.getCurrentID().then(currentNetworkID => { if (currentNetworkID) { CurrentNetworkIDSubject.next({ currentNetworkID }) + this.get(currentNetworkID).then(network => { + if (network) { + networkSwitchSubject.next(network) + } + }) } }) diff --git a/packages/neuron-wallet/src/utils/const.ts b/packages/neuron-wallet/src/utils/const.ts index 12ab0c9766..db587ce125 100644 --- a/packages/neuron-wallet/src/utils/const.ts +++ b/packages/neuron-wallet/src/utils/const.ts @@ -6,8 +6,6 @@ export enum Channel { Networks = 'networks', Wallets = 'wallets', Transactions = 'transactions', - Helpers = 'helpers', - DataUpdate = 'dataUpdate', } export enum ResponseCode { From ad7723241538a60ee70a162f2c27af56f45e74a6 Mon Sep 17 00:00:00 2001 From: classicalliu Date: Thu, 25 Jul 2019 16:14:19 +0800 Subject: [PATCH 08/16] fix(neuron-wallet): check min capacity --- .../neuron-wallet/src/exceptions/transaction.ts | 7 +++++++ packages/neuron-wallet/src/locales/en.ts | 1 + packages/neuron-wallet/src/locales/zh.ts | 1 + packages/neuron-wallet/src/services/cells.ts | 14 +++++++++++--- .../neuron-wallet/src/services/transactions.ts | 11 +++++++++-- packages/neuron-wallet/src/services/wallets.ts | 6 +++--- 6 files changed, 32 insertions(+), 8 deletions(-) diff --git a/packages/neuron-wallet/src/exceptions/transaction.ts b/packages/neuron-wallet/src/exceptions/transaction.ts index f1700d2ad0..bedcb67e8e 100644 --- a/packages/neuron-wallet/src/exceptions/transaction.ts +++ b/packages/neuron-wallet/src/exceptions/transaction.ts @@ -6,6 +6,13 @@ export class TransactionNotFound extends Error { } } +export class CapacityTooSmall extends Error { + constructor() { + super(i18n.t('messages.capacity-too-small')) + } +} + export default { TransactionNotFound, + CapacityTooSmall, } diff --git a/packages/neuron-wallet/src/locales/en.ts b/packages/neuron-wallet/src/locales/en.ts index cff66affe6..e1facce921 100644 --- a/packages/neuron-wallet/src/locales/en.ts +++ b/packages/neuron-wallet/src/locales/en.ts @@ -85,6 +85,7 @@ export default { 'invalid-mnemonic': 'Mnemonic is invalid', 'unsupported-cipher': 'Unsupported cipher', 'capacity-not-enough': 'Capacity is not enough', + 'capacity-too-small': 'Capacity less than min', 'should-be-type-of': '{{field}} should be type of {{type}}', }, contextMenu: { diff --git a/packages/neuron-wallet/src/locales/zh.ts b/packages/neuron-wallet/src/locales/zh.ts index 9e51973b1c..7d752e8a17 100644 --- a/packages/neuron-wallet/src/locales/zh.ts +++ b/packages/neuron-wallet/src/locales/zh.ts @@ -84,6 +84,7 @@ export default { 'invalid-mnemonic': '助记词不合法', 'unsupported-cipher': '不支持的 Cipher', 'capacity-not-enough': '余额不足', + 'capacity-too-small': '金额小于最低金额', 'should-be-type-of': '{{field}} 应该为 {{type}} 类型', }, contextMenu: { diff --git a/packages/neuron-wallet/src/services/cells.ts b/packages/neuron-wallet/src/services/cells.ts index 20e1611ed2..3084f46579 100644 --- a/packages/neuron-wallet/src/services/cells.ts +++ b/packages/neuron-wallet/src/services/cells.ts @@ -4,7 +4,7 @@ import { Cell, OutPoint, Input } from '../types/cell-types' import { CapacityNotEnough } from '../exceptions' import { OutputStatus } from './transactions' -const MIN_CELL_CAPACITY = '40' +export const MIN_CELL_CAPACITY = '6000000000' /* eslint @typescript-eslint/no-unused-vars: "warn" */ /* eslint no-await-in-loop: "warn" */ @@ -51,12 +51,18 @@ export default class CellsService { // gather inputs for generateTx public static gatherInputs = async ( capacity: string, - lockHashes: string[] + lockHashes: string[], + fee: string = '0' ): Promise<{ inputs: Input[] capacities: string }> => { const capacityInt = BigInt(capacity) + const feeInt = BigInt(fee) + const totalCapacities: bigint = capacityInt + feeInt + + // use min secp size (without data) + const minChangeCapacity = BigInt(MIN_CELL_CAPACITY) if (capacityInt < BigInt(MIN_CELL_CAPACITY)) { throw new Error(`capacity can't be less than ${MIN_CELL_CAPACITY}`) @@ -92,7 +98,9 @@ export default class CellsService { } inputs.push(input) inputCapacities += BigInt(cell.capacity) - if (inputCapacities > capacityInt) { + + const diff = inputCapacities - totalCapacities + if (diff >= minChangeCapacity || diff === BigInt(0)) { return false } return true diff --git a/packages/neuron-wallet/src/services/transactions.ts b/packages/neuron-wallet/src/services/transactions.ts index a3b7a90ede..8883dd4464 100644 --- a/packages/neuron-wallet/src/services/transactions.ts +++ b/packages/neuron-wallet/src/services/transactions.ts @@ -1,12 +1,13 @@ import { getConnection, In, ObjectLiteral } from 'typeorm' import { ReplaySubject } from 'rxjs' import { OutPoint, Transaction, TransactionWithoutHash, Input, Cell, TransactionStatus } from '../types/cell-types' -import CellsService from './cells' +import CellsService, { MIN_CELL_CAPACITY } from './cells' import InputEntity from '../database/chain/entities/input' import OutputEntity from '../database/chain/entities/output' import TransactionEntity from '../database/chain/entities/transaction' import NodeService from './node' import LockUtils from '../models/lock-utils' +import { CapacityTooSmall } from '../exceptions' const { core } = NodeService.getInstance() @@ -504,11 +505,15 @@ export default class TransactionsService { .map(o => BigInt(o.capacity)) .reduce((result, c) => result + c, BigInt(0)) - const { inputs, capacities } = await CellsService.gatherInputs(needCapacities.toString(), lockHashes) + const minCellCapacity = BigInt(MIN_CELL_CAPACITY) const outputs: Cell[] = targetOutputs.map(o => { const { capacity, address } = o + if (BigInt(capacity) < minCellCapacity) { + throw new CapacityTooSmall() + } + const blake160: string = LockUtils.addressToBlake160(address) const output: Cell = { @@ -523,6 +528,8 @@ export default class TransactionsService { return output }) + const { inputs, capacities } = await CellsService.gatherInputs(needCapacities.toString(), lockHashes, fee) + // change if (BigInt(capacities) > needCapacities + BigInt(fee)) { const changeBlake160: string = LockUtils.addressToBlake160(changeAddress) diff --git a/packages/neuron-wallet/src/services/wallets.ts b/packages/neuron-wallet/src/services/wallets.ts index 83a8483131..4ea50acedc 100644 --- a/packages/neuron-wallet/src/services/wallets.ts +++ b/packages/neuron-wallet/src/services/wallets.ts @@ -10,7 +10,7 @@ import LockUtils from '../models/lock-utils' import { Witness, TransactionWithoutHash, Input } from '../types/cell-types' import ConvertTo from '../types/convert-to' import Blake2b from '../utils/blake2b' -import { CurrentWalletNotSet, WalletNotFound, IsRequired, UsedName } from '../exceptions' +import { WalletNotFound, IsRequired, UsedName } from '../exceptions' import AddressService from './addresses' import { Address as AddressInterface } from '../database/address/dao' import Keychain from '../models/keys/keychain' @@ -305,7 +305,7 @@ export default class WalletService { ) => { const wallet = await this.get(walletID) if (!wallet) { - throw new CurrentWalletNotSet() + throw new WalletNotFound(walletID) } if (password === '') { @@ -320,7 +320,7 @@ export default class WalletService { const targetOutputs = items.map(item => ({ ...item, - capacity: (BigInt(item.capacity) * BigInt(1)).toString(), + capacity: BigInt(item.capacity).toString(), })) const changeAddress: string = await this.getChangeAddress() From 991b0197722ca070f37a49d9f8f18d8d26bb45cc Mon Sep 17 00:00:00 2001 From: James Chen Date: Fri, 26 Jul 2019 09:54:10 +0900 Subject: [PATCH 09/16] chore(deps): Add electron-updater --- packages/neuron-wallet/package.json | 1 + yarn.lock | 21 ++++++++++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/packages/neuron-wallet/package.json b/packages/neuron-wallet/package.json index b8132d4534..5394db273c 100644 --- a/packages/neuron-wallet/package.json +++ b/packages/neuron-wallet/package.json @@ -35,6 +35,7 @@ "async": "3.0.1", "bn.js": "4.11.8", "chalk": "2.4.2", + "electron-updater": "^4.1.2", "electron-window-state": "5.0.3", "elliptic": "6.4.1", "i18next": "15.1.3", diff --git a/yarn.lock b/yarn.lock index 8f634a85ba..697dd605f0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3208,6 +3208,11 @@ "@types/prop-types" "*" csstype "^2.2.0" +"@types/semver@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-6.0.1.tgz#a984b405c702fa5a7ec6abc56b37f2ba35ef5af6" + integrity sha512-ffCdcrEE5h8DqVxinQjo+2d1q+FV5z7iNtPofw3JsrltSoSVlOGaW0rY8XxtO9XukdTn8TaCGWmk2VFGhI70mg== + "@types/sqlite3@3.1.5": version "3.1.5" resolved "https://registry.yarnpkg.com/@types/sqlite3/-/sqlite3-3.1.5.tgz#c9bbc94b8e8ed0654e1f8bc98716aba6030e9533" @@ -7216,6 +7221,20 @@ electron-to-chromium@^1.3.122, electron-to-chromium@^1.3.150: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.159.tgz#4292643c5cb77678821ce01557ba6dd0f562db5e" integrity sha512-bhiEr8/A97GUBcUzNb9MFNhzQOjakbKmEKBEAa6UMY45zG2e8PM63LOgAPXEJE9bQiaQH6nOdYiYf8X821tZjQ== +electron-updater@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/electron-updater/-/electron-updater-4.1.2.tgz#46a6e62cc8d0c7d935db7aff83207da2a21ff788" + integrity sha512-4Sk8IW0LfOilDz+WAB/gEDmX7+FUFRbKHGN1zGjehPilnd6H9cmjgBHK6Xzq/FLq/uOHGJ6GX/9tsF+jr7CvnA== + dependencies: + "@types/semver" "^6.0.1" + builder-util-runtime "8.3.0" + fs-extra "^8.1.0" + js-yaml "^3.13.1" + lazy-val "^1.0.4" + lodash.isequal "^4.5.0" + pako "^1.0.10" + semver "^6.2.0" + electron-window-state@5.0.3: version "5.0.3" resolved "https://registry.yarnpkg.com/electron-window-state/-/electron-window-state-5.0.3.tgz#4f36d09e3f953d87aff103bf010f460056050aa8" @@ -12675,7 +12694,7 @@ package-json@^6.3.0: registry-url "^5.0.0" semver "^6.1.1" -pako@~1.0.5: +pako@^1.0.10, pako@~1.0.5: version "1.0.10" resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.10.tgz#4328badb5086a426aa90f541977d4955da5c9732" integrity sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw== From f2f314584f2ae1371666b30169019e2dd3aca1b1 Mon Sep 17 00:00:00 2001 From: Keith Date: Fri, 26 Jul 2019 02:33:10 +0800 Subject: [PATCH 10/16] feat(neuron-ui): remove UILayer --- .../src/components/Addresses/index.tsx | 46 ++-- .../src/components/ErrorBoundary/index.tsx | 4 +- .../src/components/History/index.tsx | 5 +- .../src/components/NetworkEditor/hooks.ts | 43 ++-- .../src/components/PasswordRequest/index.tsx | 36 ++- .../src/components/Receive/index.tsx | 2 +- .../neuron-ui/src/components/Send/index.tsx | 9 +- .../src/components/TransactionList/index.tsx | 50 +++-- .../src/components/WalletEditor/hooks.ts | 10 +- .../src/components/WalletEditor/index.tsx | 2 +- .../src/components/WalletSetting/index.tsx | 4 +- .../src/components/WalletWizard/index.tsx | 21 +- .../neuron-ui/src/containers/Footer/index.tsx | 4 +- .../neuron-ui/src/containers/Main/hooks.ts | 196 ++++------------- .../neuron-ui/src/containers/Main/index.tsx | 9 +- packages/neuron-ui/src/index.tsx | 8 + packages/neuron-ui/src/locales/en.json | 6 +- packages/neuron-ui/src/locales/zh.json | 7 +- packages/neuron-ui/src/services/UILayer.ts | 98 --------- packages/neuron-ui/src/services/remote/app.ts | 4 + .../remote/controllerMethodWrapper.ts | 11 +- .../neuron-ui/src/services/remote/index.ts | 17 +- .../neuron-ui/src/services/remote/networks.ts | 6 +- .../src/services/remote/transactions.ts | 2 +- .../neuron-ui/src/services/remote/wallets.ts | 47 ++++ packages/neuron-ui/src/services/subjects.ts | 4 +- .../neuron-ui/src/states/initStates/app.ts | 5 + .../neuron-ui/src/states/initStates/wallet.ts | 1 - .../stateProvider/actionCreators/app.ts | 75 +++++++ .../stateProvider/actionCreators/index.ts | 6 +- .../stateProvider/actionCreators/send.ts | 35 --- .../stateProvider/actionCreators/settings.ts | 42 +++- .../actionCreators/transactions.ts | 49 ++++- .../stateProvider/actionCreators/wallets.ts | 208 +++++++++++++++++- .../src/states/stateProvider/reducer.ts | 98 ++++----- .../src/stories/PasswordRequest.stories.tsx | 16 +- .../src/stories/TransactionList.stories.tsx | 7 +- packages/neuron-ui/src/types/App/index.d.ts | 6 +- .../neuron-ui/src/types/Channel/index.d.ts | 5 - .../neuron-ui/src/types/Controller/index.d.ts | 57 +++++ .../neuron-ui/src/types/Subject/index.d.ts | 5 + packages/neuron-ui/src/utils/const.ts | 4 - packages/neuron-ui/src/utils/hooks.ts | 62 ++++-- packages/neuron-ui/src/utils/i18n.ts | 8 +- packages/neuron-ui/src/utils/initializeApp.ts | 68 ------ packages/neuron-ui/src/utils/localCache.ts | 12 - .../src/controllers/app/index.ts | 42 +--- .../src/controllers/app/options.ts | 4 +- .../src/controllers/wallets/index.ts | 15 +- .../src/models/subjects/command.ts | 6 +- .../src/models/window-manager.ts | 40 ---- .../neuron-wallet/src/services/wallets.ts | 20 +- .../src/utils/application-menu.ts | 4 +- 53 files changed, 826 insertions(+), 725 deletions(-) delete mode 100644 packages/neuron-ui/src/services/UILayer.ts create mode 100644 packages/neuron-ui/src/services/remote/wallets.ts create mode 100644 packages/neuron-ui/src/states/stateProvider/actionCreators/app.ts delete mode 100644 packages/neuron-ui/src/states/stateProvider/actionCreators/send.ts delete mode 100644 packages/neuron-ui/src/types/Channel/index.d.ts create mode 100644 packages/neuron-ui/src/types/Controller/index.d.ts delete mode 100644 packages/neuron-ui/src/utils/initializeApp.ts diff --git a/packages/neuron-ui/src/components/Addresses/index.tsx b/packages/neuron-ui/src/components/Addresses/index.tsx index f321ec1aa4..f922a12fc9 100644 --- a/packages/neuron-ui/src/components/Addresses/index.tsx +++ b/packages/neuron-ui/src/components/Addresses/index.tsx @@ -2,7 +2,7 @@ import React, { useEffect, useMemo } from 'react' import { RouteComponentProps } from 'react-router-dom' import { useTranslation } from 'react-i18next' import { - DetailsList, + ShimmeredDetailsList, TextField, IColumn, DetailsListLayoutMode, @@ -11,17 +11,21 @@ import { getTheme, } from 'office-ui-fabric-react' -import { StateWithDispatch } from 'states/stateProvider/reducer' import { contextMenu } from 'services/remote' +import { StateWithDispatch } from 'states/stateProvider/reducer' import { useLocalDescription } from 'utils/hooks' import { MIN_CELL_WIDTH, Routes } from 'utils/const' import { localNumberFormatter, shannonToCKBFormatter } from 'utils/formatters' const Addresses = ({ - wallet: { addresses = [] }, + app: { + loadings: { addressList: isLoading }, + }, + wallet: { addresses = [], id: walletID }, settings: { showAddressBook = false }, history, + dispatch, }: React.PropsWithoutRef) => { const [t] = useTranslation() useEffect(() => { @@ -31,6 +35,8 @@ const Addresses = ({ }, [showAddressBook, history]) const { localDescription, onDescriptionPress, onDescriptionFieldBlur, onDescriptionChange } = useLocalDescription( + 'address', + walletID, useMemo( () => addresses.map(({ address: key = '', description = '' }) => ({ @@ -38,7 +44,8 @@ const Addresses = ({ description, })), [addresses] - ) + ), + dispatch ) const theme = getTheme() @@ -92,15 +99,17 @@ const Addresses = ({ maxWidth: 350, isResizable: true, isCollapsible: false, - onRender: (item?: State.Address, idx?: number) => { - return item && undefined !== idx ? ( + onRender: (item?: State.Address) => { + return item ? ( local.key === item.address) || { description: '' }).description || '' + } + onKeyPress={onDescriptionPress(item.address)} + onBlur={onDescriptionFieldBlur(item.address)} + onChange={onDescriptionChange(item.address)} styles={(props: ITextFieldStyleProps) => { return { root: { @@ -155,7 +164,8 @@ const Addresses = ({ ) return ( - ({ ...col, name: t(col.name) }))} @@ -163,20 +173,6 @@ const Addresses = ({ onItemContextMenu={item => { contextMenu({ type: 'addressList', id: item.identifier }) }} - styles={{ - contentWrapper: { - selectors: { - '.ms-DetailsRow-cell': { - display: 'flex', - alignItems: 'center', - }, - '.text-overflow': { - overflow: 'hidden', - textOverflow: 'ellipsis', - }, - }, - }, - }} /> ) } diff --git a/packages/neuron-ui/src/components/ErrorBoundary/index.tsx b/packages/neuron-ui/src/components/ErrorBoundary/index.tsx index e2e169e7ff..7b99d2cbf7 100644 --- a/packages/neuron-ui/src/components/ErrorBoundary/index.tsx +++ b/packages/neuron-ui/src/components/ErrorBoundary/index.tsx @@ -4,9 +4,7 @@ import { handleViewError } from 'services/remote' const handleError = (error: Error) => { handleViewError(error.toString()) - setTimeout(() => { - window.location.reload() - }, 0) + window.location.reload() return { hasError: true } } diff --git a/packages/neuron-ui/src/components/History/index.tsx b/packages/neuron-ui/src/components/History/index.tsx index 0f99c15067..cbb19b3572 100644 --- a/packages/neuron-ui/src/components/History/index.tsx +++ b/packages/neuron-ui/src/components/History/index.tsx @@ -34,6 +34,9 @@ registerIcons({ }) const History = ({ + app: { + loadings: { transactionList: isLoading }, + }, wallet: { id }, chain: { transactions: { pageNo = 1, pageSize = 15, totalCount = 0, items = [] }, @@ -64,7 +67,7 @@ const History = ({ iconProps={{ iconName: 'Search', styles: { root: { height: '18px' } } }} /> - + network.name === name && network.id !== id)) { - return dispatch({ - type: AppActions.AddNotification, - payload: { - ...warning, - content: i18n.t(Message.NetworkNameUsed), - }, - }) - } - res = await updateNetwork({ - networkID: id!, - options: { - name, - remote, + })(dispatch, history) + } + if (networks.some(network => network.name === name && network.id !== id)) { + return dispatch({ + type: AppActions.AddNotification, + payload: { + ...warning, + content: i18n.t(Message.NetworkNameUsed), }, }) } - if (res && res.status) { - history.push(Routes.SettingsNetworks) - } - return res + return updateNetwork({ + networkID: id!, + options: { + name, + remote, + }, + })(dispatch, history) }, [id, name, remote, networks, history, dispatch]) export default { diff --git a/packages/neuron-ui/src/components/PasswordRequest/index.tsx b/packages/neuron-ui/src/components/PasswordRequest/index.tsx index 08dfb7bb78..e57c2f8439 100644 --- a/packages/neuron-ui/src/components/PasswordRequest/index.tsx +++ b/packages/neuron-ui/src/components/PasswordRequest/index.tsx @@ -1,9 +1,10 @@ import React, { useCallback, useMemo } from 'react' +import { RouteComponentProps } from 'react-router-dom' import { useTranslation } from 'react-i18next' import { Stack, Text, Label, Modal, TextField, PrimaryButton, DefaultButton } from 'office-ui-fabric-react' import { StateWithDispatch, AppActions } from 'states/stateProvider/reducer' -import actionCreators from 'states/stateProvider/actionCreators' -import { priceToFee } from 'utils/formatters' +import { sendTransaction, deleteWallet, backupWallet } from 'states/stateProvider/actionCreators' +import { priceToFee, CKBToShannonFormatter } from 'utils/formatters' const PasswordRequest = ({ app: { @@ -11,8 +12,9 @@ const PasswordRequest = ({ passwordRequest: { walletID = '', actionType = null, password = '' }, }, settings: { wallets = [] }, + history, dispatch, -}: React.PropsWithoutRef) => { +}: React.PropsWithoutRef) => { const [t] = useTranslation() const wallet = useMemo(() => wallets.find(w => w.id === walletID), [walletID, wallets]) const onDismiss = useCallback(() => { @@ -25,14 +27,38 @@ const PasswordRequest = ({ const onConfirm = useCallback(() => { switch (actionType) { case 'send': { - submitTransaction(txID, walletID, outputs, description, password, priceToFee(price, cycles))(dispatch) + sendTransaction({ + id: txID, + walletID, + items: outputs.map(output => ({ + address: output.address, + capacity: CKBToShannonFormatter(output.amount, output.unit), + })), + description, + password, + fee: priceToFee(price, cycles), + })(dispatch, history) + break + } + case 'delete': { + deleteWallet({ + id: walletID, + password, + })(dispatch) + break + } + case 'backup': { + backupWallet({ + id: walletID, + password, + })(dispatch) break } default: { break } } - }, [dispatch, walletID, password, actionType, txID, description, outputs, cycles, price]) + }, [dispatch, walletID, password, actionType, txID, description, outputs, cycles, price, history]) const onChange = useCallback( (_e, value?: string) => { diff --git a/packages/neuron-ui/src/components/Receive/index.tsx b/packages/neuron-ui/src/components/Receive/index.tsx index 19a3801b6a..bfd0821141 100644 --- a/packages/neuron-ui/src/components/Receive/index.tsx +++ b/packages/neuron-ui/src/components/Receive/index.tsx @@ -32,7 +32,7 @@ const Receive = ({ return ( <> - + diff --git a/packages/neuron-ui/src/components/Send/index.tsx b/packages/neuron-ui/src/components/Send/index.tsx index d905190856..c35577f261 100644 --- a/packages/neuron-ui/src/components/Send/index.tsx +++ b/packages/neuron-ui/src/components/Send/index.tsx @@ -33,8 +33,11 @@ export interface TransactionOutput { } const Send = ({ - app: { send = appState.send }, - wallet: { id: walletID = '', sending = false, balance = '' }, + app: { + send = appState.send, + loadings: { sending = false }, + }, + wallet: { id: walletID = '', balance = '' }, dispatch, history, match: { @@ -61,7 +64,7 @@ const Send = ({ ) return ( - + { ) } -const TransactionList = ({ items = [] }: { walletID: string; items: State.Transaction[]; dispatch: StateDispatch }) => { +const TransactionList = ({ + isLoading = false, + items = [], + walletID, + dispatch, +}: { + isLoading: boolean + walletID: string + items: State.Transaction[] + dispatch: StateDispatch +}) => { const [t] = useTranslation() const { localDescription, onDescriptionPress, onDescriptionFieldBlur, onDescriptionChange } = useLocalDescription( + 'transaction', + walletID, useMemo( () => items.map(({ hash: key, description = '' }) => ({ @@ -63,7 +75,8 @@ const TransactionList = ({ items = [] }: { walletID: string; items: State.Transa description, })), [items] - ) + ), + dispatch ) const transactionColumns: IColumn[] = useMemo( @@ -104,14 +117,16 @@ const TransactionList = ({ items = [] }: { walletID: string; items: State.Transa fieldName: 'description', minWidth: MIN_CELL_WIDTH, maxWidth: 200, - onRender: (item?: FormatTransaction, idx?: number) => { - return item && undefined !== idx ? ( + onRender: (item?: FormatTransaction) => { + return item ? ( local.key === item.hash) || { description: '' }).description || '' + } + onKeyPress={onDescriptionPress(item.hash)} + onBlur={onDescriptionFieldBlur(item.hash)} + onChange={onDescriptionChange(item.hash)} borderless styles={(props: ITextFieldStyleProps) => { return { @@ -180,7 +195,8 @@ const TransactionList = ({ items = [] }: { walletID: string; items: State.Transa }, [items]) return ( - group.count !== 0)} @@ -193,20 +209,6 @@ const TransactionList = ({ items = [] }: { walletID: string; items: State.Transa contextMenu({ type: 'transactionList', id: item.hash }) } }} - styles={{ - contentWrapper: { - selectors: { - '.ms-DetailsRow-cell': { - display: 'flex', - alignItems: 'center', - }, - '.text-overflow': { - overflow: 'hidden', - textOverflow: 'ellipsis', - }, - }, - }, - }} /> ) } diff --git a/packages/neuron-ui/src/components/WalletEditor/hooks.ts b/packages/neuron-ui/src/components/WalletEditor/hooks.ts index e2ef2415c2..38190028cb 100644 --- a/packages/neuron-ui/src/components/WalletEditor/hooks.ts +++ b/packages/neuron-ui/src/components/WalletEditor/hooks.ts @@ -1,5 +1,5 @@ import { useState, useMemo, useCallback } from 'react' -import { updateWallet } from 'states/stateProvider/actionCreators' +import { updateWalletProperty } from 'states/stateProvider/actionCreators' import { StateDispatch } from 'states/stateProvider/reducer' import i18n from 'utils/i18n' @@ -35,13 +35,13 @@ export const useInputs = ({ name }: ReturnType) => { ) } -export const useOnConfirm = (name: string = '', id: string = '', dispatch: StateDispatch) => { +export const useOnConfirm = (name: string = '', id: string = '', history: any, dispatch: StateDispatch) => { return useCallback(() => { - updateWallet({ + updateWalletProperty({ id, name, - })(dispatch) - }, [name, id, dispatch]) + })(dispatch, history) + }, [name, id, history, dispatch]) } export const useAreParamsValid = (name: string) => { diff --git a/packages/neuron-ui/src/components/WalletEditor/index.tsx b/packages/neuron-ui/src/components/WalletEditor/index.tsx index d2d95951bb..fd40c3ef19 100644 --- a/packages/neuron-ui/src/components/WalletEditor/index.tsx +++ b/packages/neuron-ui/src/components/WalletEditor/index.tsx @@ -43,7 +43,7 @@ const WalletEditor = ({ const inputs = useInputs(editor) const areParamsValid = useAreParamsValid(editor.name.value) - const onConfirm = useOnConfirm(editor.name.value, wallet.id, dispatch) + const onConfirm = useOnConfirm(editor.name.value, wallet.id, history, dispatch) const goBack = useGoBack(history) if (!wallet.id) { diff --git a/packages/neuron-ui/src/components/WalletSetting/index.tsx b/packages/neuron-ui/src/components/WalletSetting/index.tsx index 7ab9046727..0a745e1b4a 100644 --- a/packages/neuron-ui/src/components/WalletSetting/index.tsx +++ b/packages/neuron-ui/src/components/WalletSetting/index.tsx @@ -4,7 +4,7 @@ import { useTranslation } from 'react-i18next' import { Stack, PrimaryButton, ChoiceGroup, IChoiceGroupOption } from 'office-ui-fabric-react' import { StateWithDispatch } from 'states/stateProvider/reducer' -import { activateWallet } from 'states/stateProvider/actionCreators' +import { setCurrentWallet } from 'states/stateProvider/actionCreators' import { WalletWizardPath } from 'components/WalletWizard' @@ -32,7 +32,7 @@ const WalletSetting = ({ const onChange = useCallback( (_e, option) => { if (option) { - activateWallet(option.key)(dispatch) + setCurrentWallet(option.key)(dispatch) } }, [dispatch] diff --git a/packages/neuron-ui/src/components/WalletWizard/index.tsx b/packages/neuron-ui/src/components/WalletWizard/index.tsx index a7265c9cd0..74dc1b072b 100644 --- a/packages/neuron-ui/src/components/WalletWizard/index.tsx +++ b/packages/neuron-ui/src/components/WalletWizard/index.tsx @@ -4,12 +4,12 @@ import { Stack, Text, Label, Image, PrimaryButton, DefaultButton, TextField, Fon import { FormAdd, FormUpload } from 'grommet-icons' import withWizard, { WizardElementProps, WithWizardState } from 'components/withWizard' - -import { MnemonicAction, BUTTON_GAP } from 'utils/const' -import { verifyWalletSubmission } from 'utils/validators' -import { walletsCall } from 'services/UILayer' import { generateMnemonic, validateMnemonic, showErrorMessage } from 'services/remote' +import { createWalletWithMnemonic, importWalletWithMnemonic } from 'states/stateProvider/actionCreators' + +import { Routes, MnemonicAction, BUTTON_GAP } from 'utils/const' import { registerIcons, buttonGrommetIconStyles } from 'utils/icons' +import { verifyWalletSubmission } from 'utils/validators' export enum WalletWizardPath { Welcome = '/welcome', @@ -44,8 +44,13 @@ registerIcons({ }, }) -const Welcome = ({ rootPath = '/wizard', history }: WizardElementProps<{ rootPath: string }>) => { +const Welcome = ({ rootPath = '/wizard', wallets = [], history }: WizardElementProps<{ rootPath: string }>) => { const [t] = useTranslation() + useEffect(() => { + if (wallets.length) { + history.push(Routes.Overview) + } + }, [wallets, history]) const next = useCallback( (link: string) => () => { @@ -239,11 +244,11 @@ const Submission = ({ mnemonic: imported, } if (type === MnemonicAction.Create) { - walletsCall.create(p) + createWalletWithMnemonic(p)(dispatch, history) } else { - walletsCall.importMnemonic(p) + importWalletWithMnemonic(p)(dispatch, history) } - }, [type, name, password, imported]) + }, [type, name, password, imported, history, dispatch]) const disableNext = !verifyWalletSubmission({ name, password, confirmPassword }) diff --git a/packages/neuron-ui/src/containers/Footer/index.tsx b/packages/neuron-ui/src/containers/Footer/index.tsx index 6363d5dbdb..7e7ee2cc17 100644 --- a/packages/neuron-ui/src/containers/Footer/index.tsx +++ b/packages/neuron-ui/src/containers/Footer/index.tsx @@ -88,7 +88,9 @@ const Footer = ({ horizontalAlign="space-between" verticalFill verticalAlign="center" - padding="0 15px" + tokens={{ + padding: '0 15px', + }} styles={stackStyles} > diff --git a/packages/neuron-ui/src/containers/Main/hooks.ts b/packages/neuron-ui/src/containers/Main/hooks.ts index 6d6898d2f4..1fb68650c1 100644 --- a/packages/neuron-ui/src/containers/Main/hooks.ts +++ b/packages/neuron-ui/src/containers/Main/hooks.ts @@ -1,11 +1,17 @@ import { useEffect } from 'react' -import { WalletWizardPath } from 'components/WalletWizard' import { NeuronWalletActions, StateDispatch, AppActions } from 'states/stateProvider/reducer' -import { toggleAddressBook, updateTransactionList, updateTransaction } from 'states/stateProvider/actionCreators' +import { + toggleAddressBook, + updateTransactionList, + updateTransaction, + updateCurrentWallet, + updateWalletList, + updateAddressList, + initAppState, +} from 'states/stateProvider/actionCreators' -import UILayer, { WalletsMethod, walletsCall } from 'services/UILayer' -import { initWindow, getWinID } from 'services/remote' +import { getWinID } from 'services/remote' import { SystemScript as SystemScriptSubject, DataUpdate as DataUpdateSubject, @@ -16,138 +22,17 @@ import { Command as CommandSubject, } from 'services/subjects' import { ckbCore, getTipBlockNumber, getBlockchainInfo } from 'services/chain' -import { Routes, Channel, ConnectionStatus } from 'utils/const' +import { Routes, ConnectionStatus } from 'utils/const' +import { WalletWizardPath } from 'components/WalletWizard' import { - wallets as walletsCache, networks as networksCache, - addresses as addressesCache, currentNetworkID as currentNetworkIDCache, - currentWallet as currentWalletCache, systemScript as systemScriptCache, } from 'utils/localCache' -import addressesToBalance from 'utils/addressesToBalance' -import initializeApp from 'utils/initializeApp' let timer: NodeJS.Timeout const SYNC_INTERVAL_TIME = 10000 -export const useChannelListeners = ({ - walletID, - chain, - dispatch, - history, - i18n, -}: { - walletID: string - chain: State.Chain - dispatch: StateDispatch - history: any - i18n: any -}) => - useEffect(() => { - UILayer.on(Channel.Wallets, (_e: Event, method: WalletsMethod, args: ChannelResponse) => { - if (args.status) { - switch (method) { - case WalletsMethod.Create: - case WalletsMethod.ImportMnemonic: - case WalletsMethod.Update: { - let template = '' - if (method === WalletsMethod.Create) { - template = 'messages.wallet-created-successfully' - } else if (method === WalletsMethod.Update) { - template = 'messages.wallet-updated-successfully' - } else { - template = 'messages.wallet-imported-successfully' - } - const content = i18n.t(template, { name: args.result.name }) - dispatch({ - type: AppActions.AddNotification, - payload: { - type: 'success', - content, - timestamp: Date.now(), - }, - }) - history.push(Routes.Overview) - break - } - case WalletsMethod.GetAll: { - dispatch({ - type: NeuronWalletActions.Settings, - payload: { wallets: args.result }, - }) - walletsCache.save(args.result) - break - } - case WalletsMethod.GetCurrent: { - dispatch({ - type: NeuronWalletActions.Wallet, - payload: args.result, - }) - currentWalletCache.save(args.result) - break - } - case WalletsMethod.SendCapacity: { - if (args.result) { - history.push(Routes.History) - } - break - } - case WalletsMethod.SendingStatus: { - dispatch({ - type: NeuronWalletActions.Wallet, - payload: { - sending: args.result, - }, - }) - break - } - case WalletsMethod.GetAllAddresses: { - const addresses = args.result || [] - dispatch({ - type: NeuronWalletActions.Wallet, - payload: { - addresses, - balance: addressesToBalance(addresses), - }, - }) - addressesCache.save(addresses) - break - } - case WalletsMethod.RequestPassword: { - dispatch({ - type: AppActions.RequestPassword, - payload: { - walletID: args.result.walletID || '', - actionType: args.result.actionType || '', - }, - }) - break - } - default: { - break - } - } - } else { - if (!args.msg) { - return - } - if (method === WalletsMethod.GetCurrent) { - return - } - const { content } = typeof args.msg === 'string' ? { content: args.msg } : args.msg || { content: '' } - dispatch({ - type: AppActions.AddNotification, - payload: { - type: 'alert', - content, - timestamp: Date.now(), - }, - }) - } - }) - }, [walletID, i18n, chain, dispatch, history]) - export const useSyncChainData = ({ chainURL, dispatch }: { chainURL: string; dispatch: StateDispatch }) => { useEffect(() => { const syncTipNumber = () => @@ -203,8 +88,6 @@ export const useSyncChainData = ({ chainURL, dispatch }: { chainURL: string; dis export const useOnCurrentWalletChange = ({ walletID, - chain, - i18n, history, dispatch, }: { @@ -215,32 +98,14 @@ export const useOnCurrentWalletChange = ({ dispatch: StateDispatch }) => { - const { pageNo, pageSize } = chain.transactions useEffect(() => { if (walletID) { - walletsCall.getAllAddresses(walletID) - updateTransactionList({ - walletID, - keywords: '', - pageNo, - pageSize, - })(dispatch) + initAppState()(dispatch, history) } else { - initWindow() - .then((initializedState: any) => { - initializeApp({ - initializedState, - i18n, - history, - dispatch, - }) - }) - .catch((err: Error) => { - console.error(err) - history.push(`${Routes.WalletWizard}${WalletWizardPath.Welcome}`) - }) + history.push(`${Routes.WalletWizard}${WalletWizardPath.Welcome}`) + initAppState()(dispatch, history) } - }, [walletID, pageNo, pageSize, dispatch, i18n, history]) + }, [walletID, dispatch, history]) } export const useSubscription = ({ @@ -270,7 +135,7 @@ export const useSubscription = ({ } switch (dataType) { case 'address': { - walletsCall.getAllAddresses(walletID) + updateAddressList(walletID)(dispatch) break } case 'transaction': { @@ -284,8 +149,8 @@ export const useSubscription = ({ break } case 'wallet': { - walletsCall.getAll() - walletsCall.getCurrent() + updateWalletList()(dispatch) + updateCurrentWallet()(dispatch) break } default: { @@ -321,7 +186,7 @@ export const useSubscription = ({ }) }) const commandSubscription = CommandSubject.subscribe( - ({ winID, type, payload }: { winID: number; type: 'nav' | 'toggleAddressBook'; payload: string | null }) => { + ({ winID, type, payload }: { winID: number; type: Command.Type; payload: Command.payload }) => { if (getWinID() === winID) { switch (type) { case 'nav': { @@ -332,6 +197,26 @@ export const useSubscription = ({ dispatch(toggleAddressBook()) break } + case 'deleteWallet': { + dispatch({ + type: AppActions.RequestPassword, + payload: { + walletID: payload || '', + actionType: 'delete', + }, + }) + break + } + case 'backupWallet': { + dispatch({ + type: AppActions.RequestPassword, + payload: { + walletID: payload || '', + actionType: 'backup', + }, + }) + break + } default: { break } @@ -352,7 +237,6 @@ export const useSubscription = ({ } export default { - useChannelListeners, useSyncChainData, useOnCurrentWalletChange, useSubscription, diff --git a/packages/neuron-ui/src/containers/Main/index.tsx b/packages/neuron-ui/src/containers/Main/index.tsx index 2a3b512126..e5685aa3ea 100644 --- a/packages/neuron-ui/src/containers/Main/index.tsx +++ b/packages/neuron-ui/src/containers/Main/index.tsx @@ -20,7 +20,7 @@ import PasswordRequest from 'components/PasswordRequest' import { Routes } from 'utils/const' -import { useChannelListeners, useSubscription, useSyncChainData, useOnCurrentWalletChange } from './hooks' +import { useSubscription, useSyncChainData, useOnCurrentWalletChange } from './hooks' export const mainContents: CustomRouter.Route[] = [ { @@ -114,13 +114,6 @@ const MainContent = ({ } = neuronWalletState const { networkID } = chain const [, i18n] = useTranslation() - useChannelListeners({ - walletID: neuronWalletState.wallet.id, - chain: neuronWalletState.chain, - dispatch, - history, - i18n, - }) useSubscription({ walletID, diff --git a/packages/neuron-ui/src/index.tsx b/packages/neuron-ui/src/index.tsx index f49c66b6ea..83942aec94 100755 --- a/packages/neuron-ui/src/index.tsx +++ b/packages/neuron-ui/src/index.tsx @@ -2,6 +2,7 @@ import React from 'react' import ReactDOM from 'react-dom' import { HashRouter as Router, Route } from 'react-router-dom' import { loadTheme } from 'office-ui-fabric-react' +import { Alert as AlertIcon } from 'grommet-icons' import 'styles/index.scss' import 'utils/i18n' @@ -13,6 +14,7 @@ import Main from 'containers/Main' import Footer from 'containers/Footer' import ErrorBoundary from 'components/ErrorBoundary' import withProviders from 'states/stateProvider' +import { registerIcons } from 'utils/icons' loadTheme({ fonts: { @@ -30,6 +32,12 @@ loadTheme({ }, }) +registerIcons({ + icons: { + errorbadge: , + }, +}) + export const containers: CustomRouter.Route[] = [ { name: 'Navbar', diff --git a/packages/neuron-ui/src/locales/en.json b/packages/neuron-ui/src/locales/en.json index 1239aaf03f..a11554c401 100644 --- a/packages/neuron-ui/src/locales/en.json +++ b/packages/neuron-ui/src/locales/en.json @@ -29,8 +29,7 @@ "lock-arg": "Lock Arg", "address": "Address", "code-hash": "Code Hash", - "copy-pubkey-hash": "Copy Lock Arg (Pubkey Hash)", - "can-not-find-the-default-address": "Cannot find the default address" + "copy-pubkey-hash": "Copy Lock Arg (Pubkey Hash)" }, "wizard": { "welcome-to-nervos-neuron": "Welcome to Neuron", @@ -216,7 +215,8 @@ "no-transactions": "No transactions", "error": "Error", "invalid-mnemonic": "Invalid mnemonic words", - "camera-not-available-or-disabled": "Camera is unavailable or disabled" + "camera-not-available-or-disabled": "Camera is unavailable or disabled", + "can-not-find-the-default-address": "Cannot find the default address" }, "sync": { "syncing": "Syncing", diff --git a/packages/neuron-ui/src/locales/zh.json b/packages/neuron-ui/src/locales/zh.json index f0986b9900..fb647aa758 100644 --- a/packages/neuron-ui/src/locales/zh.json +++ b/packages/neuron-ui/src/locales/zh.json @@ -29,8 +29,7 @@ "lock-arg": "Lock Arg", "address": "地址", "code-hash": "Code Hash", - "copy-pubkey-hash": "复制 Lock Arg (Pubkey Hash)", - "can-not-find-the-default-address": "未获得默认地址" + "copy-pubkey-hash": "复制 Lock Arg (Pubkey Hash)" }, "wizard": { "welcome-to-nervos-ckb": "欢迎使用 Neuron", @@ -216,8 +215,8 @@ "no-transactions": "没有交易", "error": "错误", "invalid-mnemonic": "助记词不合法", - "can-not-find-the-default-address": "找不到默认地址", - "camera-not-available-or-disabled": "摄像头不可用或被禁用" + "camera-not-available-or-disabled": "摄像头不可用或被禁用", + "can-not-find-the-default-address": "未获得默认地址" }, "sync": { "syncing": "同步中", diff --git a/packages/neuron-ui/src/services/UILayer.ts b/packages/neuron-ui/src/services/UILayer.ts deleted file mode 100644 index 9b740180e2..0000000000 --- a/packages/neuron-ui/src/services/UILayer.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { Channel } from 'utils/const' -import SyntheticEventEmitter from 'utils/SyntheticEventEmitter' -import instantiateMethodCall from 'utils/instantiateMethodCall' - -export enum WalletsMethod { - GetAll = 'getAll', - Get = 'get', - GenerateMnemonic = 'generateMnemonic', - ImportMnemonic = 'importMnemonic', - ImportKeystore = 'importKeystore', - Create = 'create', - Update = 'update', - Delete = 'delete', - Export = 'export', - GetCurrent = 'getCurrent', - Activate = 'activate', - Backup = 'backup', - SendCapacity = 'sendCapacity', - SendingStatus = 'sendingStatus', - UpdateAddressDescription = 'updateAddressDescription', - RequestPassword = 'requestPassword', - GetAllAddresses = 'getAllAddresses', -} - -const UILayer = (() => { - if (window.bridge) { - return new SyntheticEventEmitter(window.bridge.ipcRenderer) - } - return { - send: (channel: string, ...msg: any[]) => { - console.warn(`Message: ${msg} to channel ${channel} failed due to Electron not loaded`) - }, - sendSync: (channel: string, ...msg: any[]) => { - console.warn(`Message: ${msg} to channel ${channel} failed due to Electron not loaded`) - }, - on: (channel: string, cb: Function) => { - console.warn(`Channel ${channel} and Function ${cb.toString()} failed due to Electron not loaded`) - }, - once: (channel: string, cb: Function) => { - console.warn(`Channel ${channel} and Function ${cb.toString()} failed due to Electron not loaded`) - }, - removeAllListeners: (channel?: string) => { - console.warn(`Channel ${channel} cannot be removed due to Electron not loaded`) - }, - addEventListener: (event: string, cb: EventListenerOrEventListenerObject) => window.addEventListener(event, cb), - } -})() - -export const wallets = ( - method: WalletsMethod, - params: - | undefined - | string - | { name: string; password: string } - | { keystore: string; password: string } - | { mnemonic: string; password: string } - | { id: string; password: string } - | { id: string; name?: string; password: string; newPassword?: string } - | { - id: string - walletID: string - items: { address: string; capacity: string }[] - password: string - fee: string - description: string - } -) => { - UILayer.send(Channel.Wallets, method, params) -} - -export const walletsCall = instantiateMethodCall(wallets) as { - getAll: () => void - get: (id: string) => void - generateMnemonic: () => void - importKeystore: (params: { name: string; keystore: string; password: string }) => void - importMnemonic: (params: { name: string; mnemonic: string; password: string }) => void - create: (params: { name: string; mnemonic: string; password: string }) => void - update: (params: { id: string; password?: string; newPassword?: string; name?: string }) => void - delete: (params: { id: string; password: string }) => void - getCurrent: () => void - activate: (id: string) => void - backup: (params: { id: string; password: string }) => void - sendCapacity: (params: { - id: string - walletID: string - items: { - address: string - capacity: string - }[] - password: string - fee: string - description: string - }) => void - getAllAddresses: (id: string) => void - updateAddressDescription: (params: { walletID: string; address: string; description: string }) => void -} - -export default UILayer diff --git a/packages/neuron-ui/src/services/remote/app.ts b/packages/neuron-ui/src/services/remote/app.ts index 1293269df3..c3443322d9 100644 --- a/packages/neuron-ui/src/services/remote/app.ts +++ b/packages/neuron-ui/src/services/remote/app.ts @@ -1,6 +1,9 @@ import { controllerMethodWrapper } from './controllerMethodWrapper' const CONTROLLER_NAME = 'app' +export const getNeuronWalletState = controllerMethodWrapper(CONTROLLER_NAME)(controller => () => + controller.getInitState() +) export const handleViewError = controllerMethodWrapper(CONTROLLER_NAME)(controller => (errorMessage: string) => controller.handleViewError(errorMessage) @@ -10,6 +13,7 @@ export const contextMenu = controllerMethodWrapper(CONTROLLER_NAME)( ) export default { + getNeuronWalletState, handleViewError, contextMenu, } diff --git a/packages/neuron-ui/src/services/remote/controllerMethodWrapper.ts b/packages/neuron-ui/src/services/remote/controllerMethodWrapper.ts index 04f6dc66ba..be8efaa72a 100644 --- a/packages/neuron-ui/src/services/remote/controllerMethodWrapper.ts +++ b/packages/neuron-ui/src/services/remote/controllerMethodWrapper.ts @@ -28,7 +28,7 @@ export const controllerNotLoaded = (controllerName: string) => ({ export const controllerMethodWrapper = (controllerName: string) => ( callControllerMethod: (controller: any) => (params: any) => Promise<{ status: any; result: any; msg: string }> -) => async (realParams: any): Promise => { +) => async (realParams?: any): Promise => { if (!window.remote) { return RemoteNotLoadError } @@ -37,6 +37,13 @@ export const controllerMethodWrapper = (controllerName: string) => ( return controllerNotLoaded(controllerName) } const res = await callControllerMethod(controller)(realParams) + if (process.env.NODE_ENV === 'development' && window.localStorage.getItem('log-response')) { + /* eslint-disable no-console */ + console.group(`${controllerName} controller`) + console.info(JSON.stringify(res, null, 2)) + console.groupEnd() + /* eslint-enable no-console */ + } if (!res) { return { status: 1, @@ -51,7 +58,7 @@ export const controllerMethodWrapper = (controllerName: string) => ( } return { status: 0, - message: res.status.msg || '', + message: { title: (res && res.msg) || '' }, } } diff --git a/packages/neuron-ui/src/services/remote/index.ts b/packages/neuron-ui/src/services/remote/index.ts index 27c82be78b..c6b832ccec 100644 --- a/packages/neuron-ui/src/services/remote/index.ts +++ b/packages/neuron-ui/src/services/remote/index.ts @@ -1,21 +1,22 @@ export * from './app' +export * from './wallets' export * from './networks' export * from './transactions' -export const getWinID = () => { +export const getLocale = () => { if (!window.remote) { console.warn('remote is not supported') - return -1 + return window.navigator.language } - return window.remote.getCurrentWindow().id + return window.remote.require('electron').app.getLocale() } -export const initWindow = () => { + +export const getWinID = () => { if (!window.remote) { console.warn('remote is not supported') - return Promise.reject(new Error('remote is not supported')) + return -1 } - const appController = window.remote.require('./controllers/app').default - return appController.getInitState() + return window.remote.getCurrentWindow().id } export const validateMnemonic = (mnemonic: string): boolean => { @@ -55,7 +56,7 @@ export const showErrorMessage = (title: string, content: string) => { } export default { - initWindow, + getLocale, validateMnemonic, generateMnemonic, showMessage, diff --git a/packages/neuron-ui/src/services/remote/networks.ts b/packages/neuron-ui/src/services/remote/networks.ts index c8edab3d6d..5bcda628b9 100644 --- a/packages/neuron-ui/src/services/remote/networks.ts +++ b/packages/neuron-ui/src/services/remote/networks.ts @@ -7,13 +7,13 @@ export const setCurrentNetowrk = controllerMethodWrapper(CONTROLLER_NAME)((contr }) export const createNetwork = controllerMethodWrapper(CONTROLLER_NAME)( - controller => ({ name, remote }: { name: string; remote: string }) => { - return controller.create({ name, remote }) + controller => (params: Controller.CreateNetworkParams) => { + return controller.create(params) } ) export const updateNetwork = controllerMethodWrapper(CONTROLLER_NAME)( - controller => ({ networkID, options }: { networkID: string; options: Partial<{ name: string; remote: string }> }) => { + controller => ({ networkID, options }: Controller.UpdateNetworkParams) => { return controller.update(networkID, options) } ) diff --git a/packages/neuron-ui/src/services/remote/transactions.ts b/packages/neuron-ui/src/services/remote/transactions.ts index f770b0d7dd..474cb3755c 100644 --- a/packages/neuron-ui/src/services/remote/transactions.ts +++ b/packages/neuron-ui/src/services/remote/transactions.ts @@ -21,7 +21,7 @@ export const getTransaction = controllerMethodWrapper(CONTROLLER_NAME)( } ) export const updateTransactionDescription = controllerMethodWrapper(CONTROLLER_NAME)( - controller => (params: { hash: string; description: string }) => { + controller => (params: Controller.UpdateTransactionDescriptionParams) => { return controller.updateDescription(params) } ) diff --git a/packages/neuron-ui/src/services/remote/wallets.ts b/packages/neuron-ui/src/services/remote/wallets.ts new file mode 100644 index 0000000000..c5c83aebb3 --- /dev/null +++ b/packages/neuron-ui/src/services/remote/wallets.ts @@ -0,0 +1,47 @@ +import { controllerMethodWrapper } from './controllerMethodWrapper' + +const CONTROLLER_NAME = 'wallets' + +export const updateWallet = controllerMethodWrapper(CONTROLLER_NAME)( + controller => (params: Controller.UpdateWalletParams) => controller.update(params) +) +export const getCurrentWallet = controllerMethodWrapper(CONTROLLER_NAME)(controller => () => controller.getCurrent()) +export const getWalletList = controllerMethodWrapper(CONTROLLER_NAME)(controller => () => controller.getAll()) +export const importMnemonic = controllerMethodWrapper(CONTROLLER_NAME)( + controller => (params: Controller.ImportMnemonicParams) => controller.importMnemonic(params) +) + +export const deleteWallet = controllerMethodWrapper(CONTROLLER_NAME)( + controller => (params: Controller.DeleteWalletParams) => controller.delete(params) +) + +export const backupWallet = controllerMethodWrapper(CONTROLLER_NAME)( + controller => (params: Controller.DeleteWalletParams) => controller.backup(params) +) + +export const setCurrentWallet = controllerMethodWrapper(CONTROLLER_NAME)( + controller => (id: Controller.SetCurrentWalletParams) => controller.activate(id) +) +export const sendCapacity = controllerMethodWrapper(CONTROLLER_NAME)( + controller => (params: Controller.SendTransaction) => controller.sendCapacity(params) +) + +export const getAddressesByWalletID = controllerMethodWrapper(CONTROLLER_NAME)( + controller => (walletID: Controller.GetAddressesByWalletIDParams) => controller.getAllAddresses(walletID) +) + +export const updateAddressDescription = controllerMethodWrapper(CONTROLLER_NAME)( + controller => (params: Controller.UpdateAddressDescriptionParams) => controller.updateAddressDescription(params) +) + +export default { + updateWallet, + getWalletList, + importMnemonic, + deleteWallet, + backupWallet, + getCurrentWallet, + sendCapacity, + getAddressesByWalletID, + updateAddressDescription, +} diff --git a/packages/neuron-ui/src/services/subjects.ts b/packages/neuron-ui/src/services/subjects.ts index 1dfe162cf7..d3f4c09178 100644 --- a/packages/neuron-ui/src/services/subjects.ts +++ b/packages/neuron-ui/src/services/subjects.ts @@ -49,8 +49,8 @@ export const SyncedBlockNumber = window.remote export const Command = window.remote ? (window.remote.require(`${SUBJECT_PATH}/command`).default as NeuronWalletSubject<{ winID: number - type: 'nav' | 'toggleAddressBook' - payload: string | null + type: Command.Type + payload: Command.payload }>) : FallbackSubject diff --git a/packages/neuron-ui/src/states/initStates/app.ts b/packages/neuron-ui/src/states/initStates/app.ts index ef1d188b69..7124e596f0 100644 --- a/packages/neuron-ui/src/states/initStates/app.ts +++ b/packages/neuron-ui/src/states/initStates/app.ts @@ -32,6 +32,11 @@ const appState: State.App = { wizard: null, }, notifications: [], + loadings: { + sending: false, + addressList: false, + transactionList: false, + }, } export default appState diff --git a/packages/neuron-ui/src/states/initStates/wallet.ts b/packages/neuron-ui/src/states/initStates/wallet.ts index 7ce6e47bbb..7108e8ac2e 100644 --- a/packages/neuron-ui/src/states/initStates/wallet.ts +++ b/packages/neuron-ui/src/states/initStates/wallet.ts @@ -7,7 +7,6 @@ export const walletState: State.Wallet = { id: wallet.id || '', balance: '0', addresses: addresses.load(), - sending: false, } export default walletState diff --git a/packages/neuron-ui/src/states/stateProvider/actionCreators/app.ts b/packages/neuron-ui/src/states/stateProvider/actionCreators/app.ts new file mode 100644 index 0000000000..46a7fa8405 --- /dev/null +++ b/packages/neuron-ui/src/states/stateProvider/actionCreators/app.ts @@ -0,0 +1,75 @@ +import { NeuronWalletActions, AppActions, StateDispatch } from 'states/stateProvider/reducer' +import { getNeuronWalletState } from 'services/remote' +import initStates from 'states/initStates' +import { Routes } from 'utils/const' +import { WalletWizardPath } from 'components/WalletWizard' +import addressesToBalance from 'utils/addressesToBalance' +import { + wallets as walletsCache, + addresses as addressesCache, + currentWallet as currentWalletCache, +} from 'utils/localCache' + +export const initAppState = () => (dispatch: StateDispatch, history: any) => { + dispatch({ + type: AppActions.UpdateLoadings, + payload: { + addressList: true, + transactionList: true, + }, + }) + setTimeout(() => {}) + getNeuronWalletState() + .then(res => { + if (res.status) { + const { + wallets = [], + currentWallet: wallet = initStates.wallet, + addresses = [], + transactions = initStates.chain.transactions, + } = res.result + dispatch({ + type: NeuronWalletActions.InitiateCurrentWalletAndWalletList, + payload: { + wallet: { ...wallet, balance: addressesToBalance(addresses), addresses }, + wallets, + }, + }) + dispatch({ + type: NeuronWalletActions.UpdateTransactionList, + payload: transactions, + }) + + currentWalletCache.save(wallet) + walletsCache.save(wallets) + addressesCache.save(addresses) + } else { + history.push(`${Routes.WalletWizard}${WalletWizardPath.Welcome}`) + } + }) + .finally(() => { + dispatch({ + type: AppActions.UpdateLoadings, + payload: { + addressList: false, + transactionList: false, + }, + }) + }) +} + +export const addNotification = ({ type, content }: { type: 'alert'; content: string }) => (dispatch: StateDispatch) => { + dispatch({ + type: AppActions.AddNotification, + payload: { + type, + content, + timestamp: Date.now(), + }, + }) +} + +export default { + initAppState, + addNotification, +} diff --git a/packages/neuron-ui/src/states/stateProvider/actionCreators/index.ts b/packages/neuron-ui/src/states/stateProvider/actionCreators/index.ts index b9b5e8842b..b1ea341f64 100644 --- a/packages/neuron-ui/src/states/stateProvider/actionCreators/index.ts +++ b/packages/neuron-ui/src/states/stateProvider/actionCreators/index.ts @@ -1,15 +1,15 @@ +import app from './app' import wallets from './wallets' -import send from './send' import transactions from './transactions' import settings from './settings' +export * from './app' export * from './wallets' -export * from './send' export * from './transactions' export * from './settings' export const actionCreators = { + ...app, ...wallets, - ...send, ...transactions, ...settings, } diff --git a/packages/neuron-ui/src/states/stateProvider/actionCreators/send.ts b/packages/neuron-ui/src/states/stateProvider/actionCreators/send.ts deleted file mode 100644 index 1c6bdb72d5..0000000000 --- a/packages/neuron-ui/src/states/stateProvider/actionCreators/send.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { walletsCall } from 'services/UILayer' - -import { CKBToShannonFormatter } from 'utils/formatters' -import { TransactionOutput } from 'components/Send' - -import { AppActions, StateDispatch } from '../reducer' - -export const submitTransaction = ( - id: string = '', - walletID: string = '', - items: TransactionOutput[] = [], - description: string = '', - password: string = '', - fee: string = '0' -) => (dispatch: StateDispatch) => { - walletsCall.sendCapacity({ - id, - walletID, - items: items.map(item => ({ - address: item.address, - capacity: CKBToShannonFormatter(item.amount, item.unit), - })), - password, - fee, - description, - }) - dispatch({ - type: AppActions.DismissPasswordRequest, - payload: null, - }) -} - -export default { - submitTransaction, -} diff --git a/packages/neuron-ui/src/states/stateProvider/actionCreators/settings.ts b/packages/neuron-ui/src/states/stateProvider/actionCreators/settings.ts index 2a723673c8..95a06310c6 100644 --- a/packages/neuron-ui/src/states/stateProvider/actionCreators/settings.ts +++ b/packages/neuron-ui/src/states/stateProvider/actionCreators/settings.ts @@ -1,16 +1,48 @@ +import { createNetwork as createRemoteNetwork, updateNetwork as updateRemoteNetwork } from 'services/remote' import { addressBook } from 'utils/localCache' -import { NeuronWalletActions } from '../reducer' +import { Routes } from 'utils/const' +import { addNotification } from './app' + +import { AppActions, StateDispatch } from '../reducer' export const toggleAddressBook = () => { addressBook.toggleVisibility() return { - type: NeuronWalletActions.Settings, - payload: { - toggleAddressBook: true, - }, + type: AppActions.ToggleAddressBookVisibility, + payload: null, } } +export const createNetwork = (params: Controller.CreateNetworkParams) => (dispatch: StateDispatch, history: any) => { + createRemoteNetwork(params).then(res => { + if (res.status) { + dispatch({ + type: AppActions.Ignore, + payload: null, + }) + history.push(Routes.SettingsNetworks) + } else { + addNotification({ type: 'alert', content: res.message.title })(dispatch) + } + }) +} + +export const updateNetwork = (params: Controller.UpdateNetworkParams) => (dispatch: StateDispatch, history: any) => { + updateRemoteNetwork(params).then(res => { + if (res.status) { + dispatch({ + type: AppActions.Ignore, + payload: null, + }) + history.push(Routes.SettingsNetworks) + } else { + addNotification({ type: 'alert', content: res.message.title })(dispatch) + } + }) +} + export default { toggleAddressBook, + createNetwork, + updateNetwork, } diff --git a/packages/neuron-ui/src/states/stateProvider/actionCreators/transactions.ts b/packages/neuron-ui/src/states/stateProvider/actionCreators/transactions.ts index 028b072ba9..04d4254e9e 100644 --- a/packages/neuron-ui/src/states/stateProvider/actionCreators/transactions.ts +++ b/packages/neuron-ui/src/states/stateProvider/actionCreators/transactions.ts @@ -1,5 +1,11 @@ -import { NeuronWalletActions, StateDispatch } from 'states/stateProvider/reducer' -import { GetTransactionListParams, getTransaction, getTransactionList } from 'services/remote' +import { NeuronWalletActions, AppActions, StateDispatch } from 'states/stateProvider/reducer' +import { + GetTransactionListParams, + getTransaction, + getTransactionList, + updateTransactionDescription as updateRemoteTransactionDescription, +} from 'services/remote' +import { addNotification } from './app' export const updateTransaction = (params: { walletID: string; hash: string }) => (dispatch: StateDispatch) => { getTransaction(params).then(res => { @@ -8,16 +14,47 @@ export const updateTransaction = (params: { walletID: string; hash: string }) => type: NeuronWalletActions.UpdateTransaction, payload: res.result, }) + } else { + addNotification({ type: 'alert', content: res.message.title })(dispatch) } }) } export const updateTransactionList = (params: GetTransactionListParams) => (dispatch: StateDispatch) => { - getTransactionList(params).then(res => { - if (res.status) { + dispatch({ + type: AppActions.UpdateLoadings, + payload: { + transactionList: true, + }, + }) + getTransactionList(params) + .then(res => { + if (res.status) { + dispatch({ + type: NeuronWalletActions.UpdateTransactionList, + payload: res.result, + }) + } else { + addNotification({ type: 'alert', content: res.message.title })(dispatch) + } + }) + .finally(() => { dispatch({ - type: NeuronWalletActions.UpdateTransactionList, - payload: res.result, + type: AppActions.UpdateLoadings, + payload: { + transactionList: false, + }, }) + }) +} + +export const updateTransactionDescription = (params: Controller.UpdateTransactionDescriptionParams) => ( + dispatch: StateDispatch +) => { + updateRemoteTransactionDescription(params).then(res => { + if (res.status) { + dispatch({ type: AppActions.Ignore, payload: null }) + } else { + addNotification({ type: 'alert', content: res.message.title })(dispatch) } }) } diff --git a/packages/neuron-ui/src/states/stateProvider/actionCreators/wallets.ts b/packages/neuron-ui/src/states/stateProvider/actionCreators/wallets.ts index da848b5e42..db77f61c39 100644 --- a/packages/neuron-ui/src/states/stateProvider/actionCreators/wallets.ts +++ b/packages/neuron-ui/src/states/stateProvider/actionCreators/wallets.ts @@ -1,26 +1,216 @@ import { AppActions, StateDispatch } from 'states/stateProvider/reducer' -import { walletsCall } from 'services/UILayer' +import { + getWalletList, + importMnemonic, + getCurrentWallet, + updateWallet, + setCurrentWallet as setRemoteCurrentWallet, + sendCapacity, + getAddressesByWalletID, + updateAddressDescription as updateRemoteAddressDescription, + deleteWallet as deleteRemoteWallet, + backupWallet as backupRemoteWallet, +} from 'services/remote' +import { wallets as walletsCache, currentWallet as currentWalletCache } from 'utils/localCache' +import initStates from 'states/initStates' +import { Routes } from 'utils/const' import { NeuronWalletActions } from '../reducer' +import { addNotification } from './app' + +export const updateCurrentWallet = () => (dispatch: StateDispatch) => { + getCurrentWallet().then(res => { + if (res.status) { + const payload = res.result || initStates.wallet + dispatch({ + type: NeuronWalletActions.UpdateCurrentWallet, + payload, + }) + currentWalletCache.save(payload) + } else { + addNotification({ type: 'alert', content: res.message.title })(dispatch) + } + }) +} + +export const createWalletWithMnemonic = (params: Controller.ImportMnemonicParams) => ( + dispatch: StateDispatch, + history: any +) => { + importMnemonic(params).then(res => { + if (res.status) { + dispatch({ + type: AppActions.Ignore, + payload: null, + }) + history.push(Routes.Overview) + } else { + addNotification({ type: 'alert', content: res.message.title })(dispatch) + } + }) +} + +export const importWalletWithMnemonic = (params: Controller.ImportMnemonicParams) => ( + dispatch: StateDispatch, + history: any +) => { + importMnemonic(params).then(res => { + if (res.status) { + dispatch({ + type: AppActions.Ignore, + payload: null, + }) + history.push(Routes.Overview) + } else { + addNotification({ type: 'alert', content: res.message.title })(dispatch) + } + }) +} +export const updateWalletList = () => (dispatch: StateDispatch) => { + getWalletList().then(res => { + if (res.status) { + const payload = res.result || [] + dispatch({ + type: NeuronWalletActions.UpdateWalletList, + payload, + }) + walletsCache.save(payload) + } else { + addNotification({ type: 'alert', content: res.message.title })(dispatch) + } + }) +} + +export const updateWalletProperty = (params: Controller.UpdateWalletParams) => ( + dispatch: StateDispatch, + history?: any +) => { + updateWallet(params).then(res => { + if (res.status) { + dispatch({ + type: AppActions.Ignore, + payload: null, + }) + if (history) { + history.push(Routes.SettingsWallets) + } + } else { + addNotification({ type: 'alert', content: res.message.title })(dispatch) + } + }) +} +export const setCurrentWallet = (id: string) => (dispatch: StateDispatch) => { + setRemoteCurrentWallet(id).then(res => { + if (res.status) { + dispatch({ + type: AppActions.Ignore, + payload: null, + }) + } else { + addNotification({ type: 'alert', content: res.message.title })(dispatch) + } + }) +} -export const activateWallet = (id: string) => (dispatch: StateDispatch) => { - walletsCall.activate(id) +export const sendTransaction = (params: Controller.SendTransaction) => (dispatch: StateDispatch, history: any) => { dispatch({ - type: NeuronWalletActions.Wallet, - payload: id, + type: AppActions.UpdateLoadings, + payload: { + sending: true, + }, }) + sendCapacity(params) + .then(res => { + if (res.status) { + history.push(Routes.History) + } else { + addNotification({ type: 'alert', content: JSON.stringify(res.message.title) })(dispatch) + } + dispatch({ + type: AppActions.DismissPasswordRequest, + payload: null, + }) + }) + .finally(() => { + dispatch({ + type: AppActions.UpdateLoadings, + payload: { + sending: false, + }, + }) + }) } -export const updateWallet = (params: { id: string; password?: string; newPassword?: string; name?: string }) => ( +export const updateAddressList = (params: Controller.GetAddressesByWalletIDParams) => (dispatch: StateDispatch) => { + getAddressesByWalletID(params).then(res => { + if (res.status) { + dispatch({ + type: NeuronWalletActions.UpdateAddressList, + payload: res.result, + }) + } else { + addNotification({ type: 'alert', content: res.message.title })(dispatch) + } + }) +} + +export const updateAddressDescription = (params: Controller.UpdateAddressDescriptionParams) => ( dispatch: StateDispatch ) => { - walletsCall.update(params) + updateRemoteAddressDescription(params).then(res => { + if (res.status) { + dispatch({ + type: AppActions.Ignore, + payload: null, + }) + } else { + addNotification({ type: 'alert', content: res.message.title })(dispatch) + } + }) +} + +export const deleteWallet = (params: Controller.DeleteWalletParams) => (dispatch: StateDispatch) => { dispatch({ - type: AppActions.Ignore, + type: AppActions.DismissPasswordRequest, payload: null, }) + deleteRemoteWallet(params).then(res => { + if (res.status) { + dispatch({ + type: AppActions.Ignore, + payload: null, + }) + } else { + addNotification({ type: 'alert', content: res.message.title })(dispatch) + } + }) } +export const backupWallet = (params: Controller.BackupWalletParams) => (dispatch: StateDispatch) => { + dispatch({ + type: AppActions.DismissPasswordRequest, + payload: null, + }) + backupRemoteWallet(params).then(res => { + if (res.status) { + dispatch({ + type: AppActions.Ignore, + payload: null, + }) + } else { + addNotification({ type: 'alert', content: res.message.title })(dispatch) + } + }) +} export default { + createWalletWithMnemonic, + importWalletWithMnemonic, + updateCurrentWallet, + updateWalletList, updateWallet, - activateWallet, + setCurrentWallet, + sendTransaction, + updateAddressList, + updateAddressDescription, + deleteWallet, + backupWallet, } diff --git a/packages/neuron-ui/src/states/stateProvider/reducer.ts b/packages/neuron-ui/src/states/stateProvider/reducer.ts index 5548528fbc..48f135c47c 100644 --- a/packages/neuron-ui/src/states/stateProvider/reducer.ts +++ b/packages/neuron-ui/src/states/stateProvider/reducer.ts @@ -1,12 +1,12 @@ -import emptyWalletState from 'states/initStates/wallet' import initStates from 'states/initStates' export enum NeuronWalletActions { - Initiate = 'initiate', - Chain = 'chain', - Wallet = 'wallet', - Settings = 'settings', + InitiateCurrentWalletAndWalletList = 'initiateCurrentWalletAndWalletList', UpdateCodeHash = 'updateCodeHash', + // wallets + UpdateCurrentWallet = 'updateCurrentWallet', + UpdateWalletList = 'updateWalletList', + UpdateAddressList = 'updateAddressList', // transactions UpdateTransactionList = 'updateTransactionList', UpdateTransaction = 'updateTransaction', @@ -18,6 +18,7 @@ export enum NeuronWalletActions { UpdateSyncedBlockNumber = 'updateSyncedBlockNumber', } export enum AppActions { + ToggleAddressBookVisibility = 'toggleAddressBookVisibility', UpdateTransactionID = 'updateTransactionID', AddSendOutput = 'addSendOutput', RemoveSendOutput = 'removeSendOutput', @@ -37,6 +38,7 @@ export enum AppActions { UpdatePassword = 'updatePassword', UpdateTipBlockNumber = 'updateTipBlockNumber', UpdateChainInfo = 'updateChainInfo', + UpdateLoadings = 'updateLoadings', Ignore = 'ignore', } @@ -50,17 +52,16 @@ export const reducer = ( { type, payload }: { type: StateActions; payload: any } ): State.AppWithNeuronWallet => { const { app, wallet, settings, chain } = state - if (process.env.NODE_ENV === 'development') { + if (process.env.NODE_ENV === 'development' && window.localStorage.getItem('log-action')) { /* eslint-disable no-console */ - console.group() - console.info('type', type) - console.info('payload', payload) + console.group(`type: ${type}`) + console.info(payload) console.groupEnd() /* eslint-enable no-console */ } switch (type) { // Actions of Neuron Wallet - case NeuronWalletActions.Initiate: { + case NeuronWalletActions.InitiateCurrentWalletAndWalletList: { const { wallets, wallet: incomingWallet } = payload return { ...state, @@ -74,73 +75,48 @@ export const reducer = ( }, } } - case NeuronWalletActions.Wallet: { - if (!payload) { - return { - ...state, - wallet: emptyWalletState, - } - } + case AppActions.ToggleAddressBookVisibility: { return { ...state, - wallet: { - ...state.wallet, - ...payload, + settings: { + ...settings, + showAddressBook: !settings.showAddressBook, }, } } - case NeuronWalletActions.Chain: { - const newState: State.AppWithNeuronWallet = { + case NeuronWalletActions.UpdateCodeHash: { + return { ...state, chain: { ...chain, - ...payload, + codeHash: payload, }, } - const pendingTxs = newState.chain.transactions.items - .filter(item => item.status === 'pending') - .sort((item1, item2) => +(item2.timestamp || item2.createdAt) - +(item1.timestamp || item1.createdAt)) - const determinedTxs = newState.chain.transactions.items - .filter(item => item.status !== 'pending') - .sort((item1, item2) => +(item2.timestamp || item2.createdAt) - +(item1.timestamp || item1.createdAt)) - newState.chain.transactions.items = [...pendingTxs, ...determinedTxs] - return newState - } - case NeuronWalletActions.Settings: { - if (payload.toggleAddressBook) { - return { - ...state, - settings: { - ...settings, - showAddressBook: !state.settings.showAddressBook, - }, - } - } - let currentWalletName = wallet.name - if (payload.wallets) { - const currentWallet = payload.wallets.find((w: { id: string; name: string }) => w.id === wallet.id) - if (currentWallet) { - currentWalletName = currentWallet.name - } - } + } + case NeuronWalletActions.UpdateCurrentWallet: { return { ...state, wallet: { ...wallet, - name: currentWalletName, + ...payload, }, + } + } + case NeuronWalletActions.UpdateWalletList: { + return { + ...state, settings: { ...settings, - ...payload, + wallets: payload, }, } } - case NeuronWalletActions.UpdateCodeHash: { + case NeuronWalletActions.UpdateAddressList: { return { ...state, - chain: { - ...chain, - codeHash: payload, + wallet: { + ...wallet, + addresses: payload, }, } } @@ -442,6 +418,18 @@ export const reducer = ( }, } } + case AppActions.UpdateLoadings: { + return { + ...state, + app: { + ...app, + loadings: { + ...app.loadings, + ...payload, + }, + }, + } + } default: { return state } diff --git a/packages/neuron-ui/src/stories/PasswordRequest.stories.tsx b/packages/neuron-ui/src/stories/PasswordRequest.stories.tsx index 894b16b849..7dafffb22f 100644 --- a/packages/neuron-ui/src/stories/PasswordRequest.stories.tsx +++ b/packages/neuron-ui/src/stories/PasswordRequest.stories.tsx @@ -1,8 +1,11 @@ import React from 'react' +import { Route, RouteComponentProps } from 'react-router-dom' import { storiesOf } from '@storybook/react' import { action } from '@storybook/addon-actions' -import PasswordRquest from 'components/PasswordRequest' +import StoryRouter from 'storybook-react-router' +import PasswordRequest from 'components/PasswordRequest' import initStates from 'states/initStates' +import { StateWithDispatch } from 'states/stateProvider/reducer' const states: { [title: string]: State.AppWithNeuronWallet } = { 'Wallet not Found': { @@ -93,10 +96,17 @@ const states: { [title: string]: State.AppWithNeuronWallet } = { }, } -const stories = storiesOf('PasswordRequest', module) +const PasswordRequestWithRouteProps = (props: StateWithDispatch) => ( + } /> +) + +const stories = storiesOf('PasswordRequest', module).addDecorator(StoryRouter()) Object.entries(states).forEach(([title, props]) => { stories.add(title, () => ( - action('Dispatch')(JSON.stringify(reducerAction, null, 2))} /> + action('Dispatch')(JSON.stringify(reducerAction, null, 2))} + /> )) }) diff --git a/packages/neuron-ui/src/stories/TransactionList.stories.tsx b/packages/neuron-ui/src/stories/TransactionList.stories.tsx index 4ea538c4c2..ca89de6dda 100644 --- a/packages/neuron-ui/src/stories/TransactionList.stories.tsx +++ b/packages/neuron-ui/src/stories/TransactionList.stories.tsx @@ -5,13 +5,18 @@ import transactions from './data/transactions' const stories = storiesOf('TransactionList', module) Object.entries(transactions).forEach(([title, list]) => { - stories.add(title, () => {}} />) + stories.add(title, () => {}} />) }) stories.add('Wtih empty pending list', () => ( item.status !== 'pending')} dispatch={() => {}} /> )) + +stories.add('Shimmered List', () => { + return {}} /> +}) diff --git a/packages/neuron-ui/src/types/App/index.d.ts b/packages/neuron-ui/src/types/App/index.d.ts index 691ade8b74..b903d38a0f 100644 --- a/packages/neuron-ui/src/types/App/index.d.ts +++ b/packages/neuron-ui/src/types/App/index.d.ts @@ -75,6 +75,11 @@ declare namespace State { [index: string]: Message | null } notifications: Message[] + loadings: { + sending: boolean + addressList: boolean + transactionList: boolean + } } interface NetworkProperty { @@ -104,7 +109,6 @@ declare namespace State { interface Wallet extends WalletIdentity { balance: string addresses: Address[] - sending: boolean } interface Chain { diff --git a/packages/neuron-ui/src/types/Channel/index.d.ts b/packages/neuron-ui/src/types/Channel/index.d.ts deleted file mode 100644 index 87af9ac4b6..0000000000 --- a/packages/neuron-ui/src/types/Channel/index.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -interface ChannelResponse { - status: number - result: T - msg?: string -} diff --git a/packages/neuron-ui/src/types/Controller/index.d.ts b/packages/neuron-ui/src/types/Controller/index.d.ts new file mode 100644 index 0000000000..55e0beeb6c --- /dev/null +++ b/packages/neuron-ui/src/types/Controller/index.d.ts @@ -0,0 +1,57 @@ +declare namespace Controller { + interface ImportMnemonicParams { + name: string + mnemonic: string + password: string + } + interface UpdateWalletParams { + id: string + password?: string + newPassword?: string + name?: string + } + + interface DeleteWalletParams { + id: string + password: string + } + + interface BackupWalletParams { + id: string + password: string + } + + type SetCurrentWalletParams = string + interface SendTransaction { + id: string + walletID: string + items: { + address: string + capacity: string + }[] + password: string + fee: string + description: string + } + + type GetAddressesByWalletIDParams = string + interface UpdateAddressDescriptionParams { + walletID: string + address: string + description: string + } + + interface CreateNetworkParams { + name: string + remote: string + } + + interface UpdateNetworkParams { + networkID: string + options: Partial<{ name: string; remote: string }> + } + interface UpdateTransactionDescriptionParams { + hash: string + description: string + } +} diff --git a/packages/neuron-ui/src/types/Subject/index.d.ts b/packages/neuron-ui/src/types/Subject/index.d.ts index 88eed10de2..e53a33eeee 100644 --- a/packages/neuron-ui/src/types/Subject/index.d.ts +++ b/packages/neuron-ui/src/types/Subject/index.d.ts @@ -5,3 +5,8 @@ interface NeuronWalletSubject { subscribe: (onData?: (data: T) => void, onError?: (error: Error) => void, onComplete?: () => void) => Subscription unsubscribe: () => void } + +declare namespace Command { + type Type = 'nav' | 'toggleAddressBook' | 'deleteWallet' | 'backupWallet' + type payload = string | null +} diff --git a/packages/neuron-ui/src/utils/const.ts b/packages/neuron-ui/src/utils/const.ts index 0b1b42736b..f6e983f345 100644 --- a/packages/neuron-ui/src/utils/const.ts +++ b/packages/neuron-ui/src/utils/const.ts @@ -13,10 +13,6 @@ export enum ConnectionStatus { Offline = 'offline', } -export enum Channel { - Wallets = 'wallets', -} - export enum Routes { Launch = '/', Overview = '/overview', diff --git a/packages/neuron-ui/src/utils/hooks.ts b/packages/neuron-ui/src/utils/hooks.ts index a508cfcf36..191a5c4fc2 100644 --- a/packages/neuron-ui/src/utils/hooks.ts +++ b/packages/neuron-ui/src/utils/hooks.ts @@ -1,5 +1,6 @@ import { useEffect, useState, useCallback } from 'react' -import { updateTransactionDescription } from 'services/remote' +import { updateTransactionDescription, updateAddressDescription } from 'states/stateProvider/actionCreators' +import { StateDispatch } from 'states/stateProvider/reducer' export const useGoBack = (history: any) => { return useCallback(() => { @@ -7,45 +8,68 @@ export const useGoBack = (history: any) => { }, [history]) } -export const useLocalDescription = (owners: { key: string; description: string }[]) => { - const [localDescription, setLocalDescription] = useState([]) +export const useLocalDescription = ( + type: 'address' | 'transaction', + walletID: string, + owners: { key: string; description: string }[], + dispatch: StateDispatch +) => { + const [localDescription, setLocalDescription] = useState<{ description: string; key: string }[]>([]) useEffect(() => { - setLocalDescription(owners.map(owner => owner.description)) - }, [owners]) + setLocalDescription( + owners.map(owner => { + const local = localDescription.find(localDesc => localDesc.key === owner.key) + if (local && local.description) { + return local + } + return owner + }) + ) + }, [owners, localDescription]) const submitDescription = useCallback( - (idx: number) => { - if (owners[idx].description === localDescription[idx]) { + (key: string) => { + const ownerDesc = owners.find(owner => owner.key === key) + const localDesc = localDescription.find(local => local.key === key) + if (ownerDesc && localDesc && ownerDesc.description === localDesc.description) { return } - updateTransactionDescription({ - hash: owners[idx].key, - description: localDescription[idx], - }) + if (localDesc && type === 'transaction') { + updateTransactionDescription({ + hash: key, + description: localDesc.description, + })(dispatch) + } + if (localDesc && type === 'address') { + updateAddressDescription({ + walletID, + address: key, + description: localDesc.description, + })(dispatch) + } }, - [localDescription, owners] + [type, walletID, localDescription, owners, dispatch] ) const onDescriptionFieldBlur = useCallback( - (idx: number): React.FocusEventHandler => () => { - submitDescription(idx) + (key: string): React.FocusEventHandler => () => { + submitDescription(key) }, [submitDescription] ) const onDescriptionPress = useCallback( - (idx: number) => (e: React.KeyboardEvent) => { + (key: string) => (e: React.KeyboardEvent) => { if (e.key && e.key === 'Enter') { - submitDescription(idx) + submitDescription(key) } }, [submitDescription] ) const onDescriptionChange = useCallback( - (idx: number) => (_e: React.FormEvent, value?: string) => { + (key: string) => (_e: React.FormEvent, value?: string) => { if (undefined !== value) { - const newDesc = [...localDescription] - newDesc[idx] = value + const newDesc = [...localDescription].map(desc => (desc.key === key ? { key, description: value } : desc)) setLocalDescription(newDesc) } }, diff --git a/packages/neuron-ui/src/utils/i18n.ts b/packages/neuron-ui/src/utils/i18n.ts index 71a69dab9d..fd44c750c3 100644 --- a/packages/neuron-ui/src/utils/i18n.ts +++ b/packages/neuron-ui/src/utils/i18n.ts @@ -1,15 +1,19 @@ import i18n from 'i18next' import { initReactI18next } from 'react-i18next' -import { language } from 'utils/localCache' +import { getLocale } from 'services/remote' + import zh from 'locales/zh.json' import en from 'locales/en.json' +const locale = getLocale() +const lng = ['zh', 'zh-CN'].includes(locale) ? 'zh' : 'en' + i18n.use(initReactI18next).init({ resources: { en, zh, }, - fallbackLng: language.load(), + fallbackLng: lng, interpolation: { escapeValue: false, }, diff --git a/packages/neuron-ui/src/utils/initializeApp.ts b/packages/neuron-ui/src/utils/initializeApp.ts deleted file mode 100644 index 55f489c2dc..0000000000 --- a/packages/neuron-ui/src/utils/initializeApp.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { NeuronWalletActions, StateDispatch } from 'states/stateProvider/reducer' -import initStates from 'states/initStates' - -import { - wallets as walletsCache, - addresses as addressesCache, - currentWallet as currentWalletCache, - systemScript as systemScriptCache, - language as languageCache, -} from 'utils/localCache' -import { Routes, ConnectionStatus } from 'utils/const' -import { WalletWizardPath } from 'components/WalletWizard' -import addressesToBalance from 'utils/addressesToBalance' - -const intializeApp = ({ - initializedState, - i18n, - history, - dispatch, -}: { - initializedState: any - i18n: any - history: any - dispatch: StateDispatch -}) => { - const { - locale = '', - wallets = [], - currentWallet: wallet = initStates.wallet, - addresses = [], - transactions = initStates.chain.transactions, - tipNumber = '0', - connectionStatus = false, - codeHash = '', - } = initializedState - const lng = ['zh', 'zh-CN'].includes(locale) ? 'zh' : 'en' - if (lng !== i18n.language) { - i18n.changeLanguage(lng) - languageCache.save(lng) - } - if (wallet && wallet.id) { - history.push(Routes.Overview) - } else { - history.push(`${Routes.WalletWizard}${WalletWizardPath.Welcome}`) - } - dispatch({ - type: NeuronWalletActions.Initiate, - payload: { - wallet: { ...wallet, balance: addressesToBalance(addresses), addresses }, - wallets, - }, - }) - dispatch({ - type: NeuronWalletActions.Chain, - payload: { - tipBlockNumber: tipNumber, - codeHash, - connectionStatus: connectionStatus ? ConnectionStatus.Online : ConnectionStatus.Offline, - transactions: { ...initStates.chain.transactions, ...transactions }, - }, - }) - - currentWalletCache.save(wallet) - walletsCache.save(wallets) - addressesCache.save(addresses) - systemScriptCache.save({ codeHash }) -} -export default intializeApp diff --git a/packages/neuron-ui/src/utils/localCache.ts b/packages/neuron-ui/src/utils/localCache.ts index 7302aa2926..2861d7c3aa 100644 --- a/packages/neuron-ui/src/utils/localCache.ts +++ b/packages/neuron-ui/src/utils/localCache.ts @@ -6,7 +6,6 @@ export enum LocalCacheKey { CurrentWallet = 'currentWallet', CurrentNetworkID = 'currentNetworkID', SystemScript = 'systemScript', - Language = 'lng', } enum AddressBookVisibility { Invisible = '0', @@ -142,16 +141,6 @@ export const systemScript = { }, } -export const language = { - save: (lng: string) => { - window.localStorage.setItem(LocalCacheKey.Language, lng) - return true - }, - load: () => { - return window.localStorage.getItem(LocalCacheKey.Language) || 'en' - }, -} - export default { LocalCacheKey, addressBook, @@ -161,5 +150,4 @@ export default { currentWallet, currentNetworkID, systemScript, - language, } diff --git a/packages/neuron-wallet/src/controllers/app/index.ts b/packages/neuron-wallet/src/controllers/app/index.ts index 12a4d99643..97d9452863 100644 --- a/packages/neuron-wallet/src/controllers/app/index.ts +++ b/packages/neuron-wallet/src/controllers/app/index.ts @@ -1,59 +1,26 @@ import path from 'path' import { dialog, shell, Menu, MessageBoxOptions, SaveDialogOptions, BrowserWindow } from 'electron' -import { take } from 'rxjs/operators' -import systemScriptSubject from '../../models/subjects/system-script' import app from '../../app' import { URL, contextMenuTemplate } from './options' import TransactionsController from '../transactions' import WalletsService from '../../services/wallets' -import NodeService from '../../services/node' import WalletsController from '../wallets' -import SyncInfoController from '../sync-info' import { Controller as ControllerDecorator } from '../../decorators' -import { Channel } from '../../utils/const' +import { Channel, ResponseCode } from '../../utils/const' import WindowManager from '../../models/window-manager' import i18n from '../../utils/i18n' import env from '../../env' import CommandSubject from '../../models/subjects/command' -const nodeService = NodeService.getInstance() - @ControllerDecorator(Channel.App) export default class AppController { public static getInitState = async () => { const walletsService = WalletsService.getInstance() - const [ - currentWallet = null, - wallets = [], - tipNumber = '0', - connectionStatus = false, - codeHash = '', - ] = await Promise.all([ + const [currentWallet = null, wallets = []] = await Promise.all([ walletsService.getCurrent(), walletsService.getAll(), - SyncInfoController.currentBlockNumber() - .then(res => { - if (res.status) { - return res.result.currentBlockNumber - } - return '0' - }) - .catch(() => '0'), - new Promise(resolve => { - nodeService.connectionStatusSubject.pipe(take(1)).subscribe( - status => { - resolve(status) - }, - () => { - resolve(false) - } - ) - }), - new Promise(resolve => { - systemScriptSubject.pipe(take(1)).subscribe(({ codeHash: currentCodeHash }) => resolve(currentCodeHash)) - }), ]) const addresses: Controller.Address[] = await (currentWallet ? WalletsController.getAllAddresses(currentWallet.id).then(res => res.result) @@ -76,11 +43,8 @@ export default class AppController { addresses, transactions, locale, - tipNumber, - connectionStatus, - codeHash, } - return initState + return { status: ResponseCode.Success, result: initState } } public static handleViewError = (error: string) => { diff --git a/packages/neuron-wallet/src/controllers/app/options.ts b/packages/neuron-wallet/src/controllers/app/options.ts index 385681d84a..eec6e791f8 100644 --- a/packages/neuron-wallet/src/controllers/app/options.ts +++ b/packages/neuron-wallet/src/controllers/app/options.ts @@ -121,7 +121,7 @@ export const contextMenuTemplate: { { label: i18n.t('contextMenu.backup'), click: async () => { - walletsService.requestPassword(id, 'backup') + walletsService.requestPassword(id, 'backupWallet') }, }, { @@ -133,7 +133,7 @@ export const contextMenuTemplate: { { label: i18n.t('contextMenu.delete'), click: async () => { - walletsService.requestPassword(id, 'delete') + walletsService.requestPassword(id, 'deleteWallet') }, }, ] diff --git a/packages/neuron-wallet/src/controllers/wallets/index.ts b/packages/neuron-wallet/src/controllers/wallets/index.ts index 7c70947923..a3df9b6c68 100644 --- a/packages/neuron-wallet/src/controllers/wallets/index.ts +++ b/packages/neuron-wallet/src/controllers/wallets/index.ts @@ -17,7 +17,6 @@ import { IncorrectPassword, } from '../../exceptions' import i18n from '../../utils/i18n' -import windowManager from '../../models/window-manager' import AddressService from '../../services/addresses' import WalletCreatedSubject from '../../models/subjects/wallet-created-subject' @@ -342,10 +341,6 @@ export default class WalletsController { throw new IsRequired('Parameters') } try { - windowManager.broadcast(Channel.Wallets, 'sendingStatus', { - status: ResponseCode.Success, - result: true, - }) const walletsService = WalletsService.getInstance() const hash = await walletsService.sendCapacity( params.walletID, @@ -361,16 +356,8 @@ export default class WalletsController { } catch (err) { return { status: ResponseCode.Fail, - msg: { - content: `Error: "${err.message}"`, - id: params.id, - }, + msg: `Error: "${err.message}"`, } - } finally { - windowManager.broadcast(Channel.Wallets, 'sendingStatus', { - status: ResponseCode.Success, - result: false, - }) } } diff --git a/packages/neuron-wallet/src/models/subjects/command.ts b/packages/neuron-wallet/src/models/subjects/command.ts index 8a7d4d4e0d..861dddd616 100644 --- a/packages/neuron-wallet/src/models/subjects/command.ts +++ b/packages/neuron-wallet/src/models/subjects/command.ts @@ -1,5 +1,9 @@ import { Subject } from 'rxjs' -const CommandSubject = new Subject<{ winID: number; type: 'nav' | 'toggleAddressBook'; payload: string | null }>() +const CommandSubject = new Subject<{ + winID: number + type: 'nav' | 'toggleAddressBook' | 'deleteWallet' | 'backupWallet' + payload: string | null +}>() export default CommandSubject diff --git a/packages/neuron-wallet/src/models/window-manager.ts b/packages/neuron-wallet/src/models/window-manager.ts index be14689a9c..1837fea737 100644 --- a/packages/neuron-wallet/src/models/window-manager.ts +++ b/packages/neuron-wallet/src/models/window-manager.ts @@ -1,45 +1,5 @@ import { BrowserWindow } from 'electron' -import { Channel } from '../utils/const' -import logger from '../utils/logger' - -const error = { level: 'error', message: 'Electron is not loaded' } - -interface SendMessage { - ( - channel: Channel.Wallets, - method: Controller.WalletsMethod | 'allAddresses' | 'sendingStatus' | 'requestPassword', - params: any - ): void -} export default class WindowManager { public static mainWindow: BrowserWindow | null - public static broadcast: SendMessage = (channel: Channel, method: string, params: any): void => { - if (!BrowserWindow) { - logger.log(error) - return - } - BrowserWindow.getAllWindows().forEach(window => { - if (window && window.webContents) { - window.webContents.send(channel, method, params) - } - }) - } - - public static sendToFocusedWindow: SendMessage = (channel: Channel, method: string, params: any): void => { - if (!BrowserWindow) { - logger.log(error) - return - } - const window = BrowserWindow.getFocusedWindow() - if (window) { - window.webContents.send(channel, method, params) - } - } - - public static sendToMainWindow: SendMessage = (channel: Channel, method: string, params: any): void => { - if (WindowManager.mainWindow) { - WindowManager.mainWindow.webContents.send(channel, method, params) - } - } } diff --git a/packages/neuron-wallet/src/services/wallets.ts b/packages/neuron-wallet/src/services/wallets.ts index 83a8483131..fbb0173555 100644 --- a/packages/neuron-wallet/src/services/wallets.ts +++ b/packages/neuron-wallet/src/services/wallets.ts @@ -17,9 +17,9 @@ import Keychain from '../models/keys/keychain' import AddressDbChangedSubject from '../models/subjects/address-db-changed-subject' import AddressesUsedSubject from '../models/subjects/addresses-used-subject' import { WalletListSubject, CurrentWalletSubject } from '../models/subjects/wallets' -import { Channel, ResponseCode } from '../utils/const' -import windowManager from '../models/window-manager' import dataUpdateSubject from '../models/subjects/data-update' +import CommandSubject from '../models/subjects/command' +import WindowManager from '../models/window-manager' const { core } = NodeService.getInstance() const fileService = FileService.getInstance() @@ -412,13 +412,13 @@ export default class WalletService { })) } - public requestPassword = (walletID: string, actionType: 'delete' | 'backup') => { - windowManager.sendToMainWindow(Channel.Wallets, 'requestPassword', { - status: ResponseCode.Success, - result: { - walletID, - actionType, - }, - }) + public requestPassword = (walletID: string, actionType: 'deleteWallet' | 'backupWallet') => { + if (WindowManager.mainWindow) { + CommandSubject.next({ + winID: WindowManager.mainWindow.id, + type: actionType, + payload: walletID, + }) + } } } diff --git a/packages/neuron-wallet/src/utils/application-menu.ts b/packages/neuron-wallet/src/utils/application-menu.ts index dff3278f85..b366be9c2a 100644 --- a/packages/neuron-wallet/src/utils/application-menu.ts +++ b/packages/neuron-wallet/src/utils/application-menu.ts @@ -79,7 +79,7 @@ export const walletMenuItem: MenuItemConstructorOptions = { // TODO: show the error message return } - walletsService.requestPassword(currentWallet.id, 'backup') + walletsService.requestPassword(currentWallet.id, 'backupWallet') }, }, { @@ -92,7 +92,7 @@ export const walletMenuItem: MenuItemConstructorOptions = { // TODO: show the error message return } - walletsService.requestPassword(currentWallet.id, 'delete') + walletsService.requestPassword(currentWallet.id, 'deleteWallet') }, }, /** From 57933ff5296e169a6a161d5b190bda8b3eb56167 Mon Sep 17 00:00:00 2001 From: James Chen Date: Fri, 26 Jul 2019 14:21:58 +0900 Subject: [PATCH 11/16] chore: Add repository info to package.json --- package.json | 4 ++++ packages/neuron-ui/package.json | 4 ++++ packages/neuron-wallet/package.json | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/package.json b/package.json index 38a2618fe4..d66e67c53e 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,10 @@ "email": "dev@nervos.org", "url": "https://github.com/nervosnetwork/neuron" }, + "repository": { + "type" : "git", + "url" : "https://github.com/nervosnetwork/neuron" + }, "license": "MIT", "engines": { "node": ">= 12.0", diff --git a/packages/neuron-ui/package.json b/packages/neuron-ui/package.json index 156489be6b..6774a14d06 100644 --- a/packages/neuron-ui/package.json +++ b/packages/neuron-ui/package.json @@ -7,6 +7,10 @@ "email": "dev@nervos.org", "url": "https://github.com/nervosnetwork/neuron" }, + "repository": { + "type" : "git", + "url" : "https://github.com/nervosnetwork/neuron" + }, "homepage": "./", "main": "./build", "license": "MIT", diff --git a/packages/neuron-wallet/package.json b/packages/neuron-wallet/package.json index 5394db273c..3fec053813 100644 --- a/packages/neuron-wallet/package.json +++ b/packages/neuron-wallet/package.json @@ -10,6 +10,10 @@ "email": "dev@nervos.org", "url": "https://github.com/nervosnetwork/neuron" }, + "repository": { + "type" : "git", + "url" : "https://github.com/nervosnetwork/neuron" + }, "main": "dist/main.js", "license": "MIT", "scripts": { From e3d473e862eb04f7c8cca6c4c063c7aee6b827de Mon Sep 17 00:00:00 2001 From: James Chen Date: Fri, 26 Jul 2019 15:04:45 +0900 Subject: [PATCH 12/16] feat(package): Rename package task to release, publish to GitHub with electron-builder --- azure-pipelines.yml | 25 +++++---------------- package.json | 2 +- packages/neuron-wallet/electron-builder.yml | 3 +++ scripts/package.sh | 21 ----------------- scripts/release.sh | 21 +++++++++++++++++ 5 files changed, 31 insertions(+), 41 deletions(-) delete mode 100755 scripts/package.sh create mode 100755 scripts/release.sh diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 24a44847e2..b76ce2a572 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -104,8 +104,8 @@ jobs: - script: yarn test:e2e name: Test - - job: Package - condition: startsWith(variables['Build.SourceBranch'], 'refs/tags/') + - job: Release + condition: eq(variables['build.sourceBranch'], 'refs/heads/master') pool: vmImage: 'macos-10.14' steps: @@ -127,8 +127,9 @@ jobs: displayName: 'Download Windows Signing Certificate' inputs: secureFile: Neuron_win.p12 - - script: yarn package - name: Build + - script: yarn release + name: Release + displayName: 'Sign and Release' env: CSC_LINK: $(macSiginingCertificate.secureFilePath) CSC_KEY_PASSWORD: $(macSiginingCertificatePassword) @@ -136,18 +137,4 @@ jobs: WIN_CSC_KEY_PASSWORD: $(winSiginingCertificatePassword) APPLE_ID: $(appleId) APPLE_ID_PASSWORD: $(appleIdPassword) - - task: GitHubRelease@0 - inputs: - gitHubConnection: nervos-bot - repositoryName: nervosnetwork/neuron - action: edit - tag: $(Build.SourceBranchName) - assets: | - $(Build.SourcesDirectory)/release/*.zip - $(Build.SourcesDirectory)/release/*.dmg - $(Build.SourcesDirectory)/release/*.exe - $(Build.SourcesDirectory)/release/*.deb - $(Build.SourcesDirectory)/release/*.AppImage - assetUploadMode: replace - isPreRelease: true - addChangeLog: false + GH_TOKEN: $(ghToken) diff --git a/package.json b/package.json index d66e67c53e..5cff0185be 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "clean": "lerna run --stream clean", "prebuild": "yarn clean", "build": "lerna run --stream build", - "package": "yarn build && ./scripts/copy-ui-files.sh && ./scripts/package.sh", + "release": "yarn build && ./scripts/copy-ui-files.sh && ./scripts/release.sh", "test": "lerna run --parallel test", "test:e2e": "yarn build && ./scripts/copy-ui-files.sh && lerna run --parallel test:e2e", "lint": "lerna run --stream lint", diff --git a/packages/neuron-wallet/electron-builder.yml b/packages/neuron-wallet/electron-builder.yml index 95baa45b15..4db8d52eae 100644 --- a/packages/neuron-wallet/electron-builder.yml +++ b/packages/neuron-wallet/electron-builder.yml @@ -29,6 +29,9 @@ files: - from: "../../node_modules/escape-string-regexp" to: "node_modules/escape-string-regexp" +publish: + - github + nsis: oneClick: false createDesktopShortcut: always diff --git a/scripts/package.sh b/scripts/package.sh deleted file mode 100755 index 7585e8165c..0000000000 --- a/scripts/package.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash - -function package() { - case $1 in - mac) - electron-builder --mac - ;; - win) - electron-builder --win --x64 - ;; - linux) - electron-builder --linux - ;; - *) - electron-builder -mwl - ;; - esac -} - -cd packages/neuron-wallet/ -package $1 diff --git a/scripts/release.sh b/scripts/release.sh new file mode 100755 index 0000000000..50823104a1 --- /dev/null +++ b/scripts/release.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +function release() { + case $1 in + mac) + electron-builder --mac -p always + ;; + win) + electron-builder --win --x64 -p always + ;; + linux) + electron-builder --linux -p always + ;; + *) + electron-builder -mwl -p always + ;; + esac +} + +cd packages/neuron-wallet/ +release $1 From a2ad858225696be735863cc61f4c8d23ec33a875 Mon Sep 17 00:00:00 2001 From: James Chen Date: Fri, 26 Jul 2019 15:43:36 +0900 Subject: [PATCH 13/16] feat: Trigger auto update on app launch --- packages/neuron-wallet/src/main.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/neuron-wallet/src/main.ts b/packages/neuron-wallet/src/main.ts index 98b0a5d277..fb5aa36c7f 100644 --- a/packages/neuron-wallet/src/main.ts +++ b/packages/neuron-wallet/src/main.ts @@ -1,4 +1,5 @@ import { app } from 'electron' +import { autoUpdater } from 'electron-updater' import 'reflect-metadata' import i18n from './utils/i18n' import { updateApplicationMenu } from './utils/application-menu' @@ -46,6 +47,8 @@ app.on('ready', async () => { await initConnection() createSyncBlockTask() openWindow() + + autoUpdater.checkForUpdatesAndNotify() }) app.on('activate', openWindow) From 62da0326a0d0a35956b2df99774bcae508725d3c Mon Sep 17 00:00:00 2001 From: Keith Date: Fri, 26 Jul 2019 15:49:55 +0800 Subject: [PATCH 14/16] refactor(neuron-ui): register icons at the entry of neuron-ui --- .../src/components/History/index.tsx | 24 +--------- .../src/components/Overview/index.tsx | 10 +---- .../src/components/Receive/index.tsx | 5 +-- .../neuron-ui/src/components/Send/index.tsx | 17 ++++--- .../src/components/Settings/index.tsx | 9 ++-- .../components/TransactionFeePanel/index.tsx | 9 ---- .../src/components/TransactionList/index.tsx | 8 ---- .../src/components/WalletWizard/index.tsx | 10 +---- .../neuron-ui/src/containers/Footer/index.tsx | 9 ++-- .../src/containers/Notification/index.tsx | 5 +-- packages/neuron-ui/src/index.tsx | 45 ++++++++++++++++++- .../neuron-ui/src/widgets/QRScanner/index.tsx | 19 ++++++-- 12 files changed, 86 insertions(+), 84 deletions(-) diff --git a/packages/neuron-ui/src/components/History/index.tsx b/packages/neuron-ui/src/components/History/index.tsx index cbb19b3572..ef75a0c9af 100644 --- a/packages/neuron-ui/src/components/History/index.tsx +++ b/packages/neuron-ui/src/components/History/index.tsx @@ -1,38 +1,16 @@ import React, { useCallback, useEffect } from 'react' import { RouteComponentProps } from 'react-router-dom' import { useTranslation } from 'react-i18next' -import { Stack, SearchBox, getTheme } from 'office-ui-fabric-react' +import { Stack, SearchBox } from 'office-ui-fabric-react' import { Pagination } from '@uifabric/experiments' -import { - Search as SearchIcon, - LinkDown as LinkDownIcon, - LinkBottom as LinkBottomIcon, - LinkTop as LinkTopIcon, - LinkUp as LinkUpIcon, - FormClose as ClearIcon, -} from 'grommet-icons' import TransactionList from 'components/TransactionList' import { StateWithDispatch } from 'states/stateProvider/reducer' import { Routes } from 'utils/const' -import { registerIcons } from 'utils/icons' import { useSearch } from './hooks' -const theme = getTheme() -const { semanticColors } = theme -registerIcons({ - icons: { - Search: , - FirstPage: , - LastPage: , - PrevPage: , - NextPage: , - Clear: , - }, -}) - const History = ({ app: { loadings: { transactionList: isLoading }, diff --git a/packages/neuron-ui/src/components/Overview/index.tsx b/packages/neuron-ui/src/components/Overview/index.tsx index a8f55fe6f6..1b99a0f414 100644 --- a/packages/neuron-ui/src/components/Overview/index.tsx +++ b/packages/neuron-ui/src/components/Overview/index.tsx @@ -1,7 +1,6 @@ import React, { useState, useCallback, useMemo, useEffect, useRef } from 'react' import { RouteComponentProps } from 'react-router-dom' import { useTranslation } from 'react-i18next' -import { Copy } from 'grommet-icons' import { Stack, Text, @@ -28,13 +27,6 @@ import { showErrorMessage } from 'services/remote' import { localNumberFormatter, shannonToCKBFormatter, uniformTimeFormatter as timeFormatter } from 'utils/formatters' import { PAGE_SIZE, MIN_CELL_WIDTH } from 'utils/const' -import { registerIcons } from 'utils/icons' - -registerIcons({ - icons: { - Copy: , - }, -}) const TITLE_FONT_SIZE = 'xxLarge' @@ -359,7 +351,7 @@ const Overview = ({ - + {t('overview.copy-pubkey-hash')} diff --git a/packages/neuron-ui/src/components/Receive/index.tsx b/packages/neuron-ui/src/components/Receive/index.tsx index bfd0821141..2d08248ace 100644 --- a/packages/neuron-ui/src/components/Receive/index.tsx +++ b/packages/neuron-ui/src/components/Receive/index.tsx @@ -1,11 +1,10 @@ import React, { useState, useCallback, useMemo } from 'react' import { RouteComponentProps } from 'react-router-dom' import { useTranslation } from 'react-i18next' -import { Stack, Text, TextField, TooltipHost, Modal, FontSizes } from 'office-ui-fabric-react' +import { Stack, Text, TextField, TooltipHost, Modal, FontSizes, IconButton } from 'office-ui-fabric-react' import { StateWithDispatch } from 'states/stateProvider/reducer' import QRCode from 'widgets/QRCode' -import { Copy } from 'grommet-icons' const Receive = ({ wallet: { addresses = [] }, @@ -50,7 +49,7 @@ const Receive = ({ onClick={copyAddress} description={t('receive.prompt')} /> - + diff --git a/packages/neuron-ui/src/components/Send/index.tsx b/packages/neuron-ui/src/components/Send/index.tsx index c35577f261..b3672203e4 100644 --- a/packages/neuron-ui/src/components/Send/index.tsx +++ b/packages/neuron-ui/src/components/Send/index.tsx @@ -13,7 +13,6 @@ import { Spinner, Separator, } from 'office-ui-fabric-react' -import { AddCircle as AddIcon, SubtractCircle as RemoveIcon } from 'grommet-icons' import TransactionFeePanel from 'components/TransactionFeePanel' import QRScanner from 'widgets/QRScanner' @@ -104,9 +103,11 @@ const Send = ({ {send.outputs.length > 1 ? ( - removeTransactionOutput(idx)}> - - + removeTransactionOutput(idx)} + /> ) : null} @@ -137,9 +138,11 @@ const Send = ({ {idx === send.outputs.length - 1 ? ( - addTransactionOutput()} ariaLabel={t('send.add-one')}> - - + addTransactionOutput()} + ariaLabel={t('send.add-one')} + /> ) : null} diff --git a/packages/neuron-ui/src/components/Settings/index.tsx b/packages/neuron-ui/src/components/Settings/index.tsx index fa6c20346d..dccb8244b0 100644 --- a/packages/neuron-ui/src/components/Settings/index.tsx +++ b/packages/neuron-ui/src/components/Settings/index.tsx @@ -2,7 +2,6 @@ import React, { useCallback } from 'react' import { Route, RouteComponentProps } from 'react-router-dom' import { useTranslation } from 'react-i18next' import { Stack, Pivot, PivotItem, IconButton, Text } from 'office-ui-fabric-react' -import { FormPreviousLink } from 'grommet-icons' import { StateWithDispatch } from 'states/stateProvider/reducer' @@ -56,9 +55,11 @@ const Settings = ({ - - - + diff --git a/packages/neuron-ui/src/components/TransactionFeePanel/index.tsx b/packages/neuron-ui/src/components/TransactionFeePanel/index.tsx index a87ed13d11..340bec3dad 100644 --- a/packages/neuron-ui/src/components/TransactionFeePanel/index.tsx +++ b/packages/neuron-ui/src/components/TransactionFeePanel/index.tsx @@ -1,10 +1,7 @@ import React, { useState } from 'react' import { Stack, Label, TextField, Dropdown, Toggle, Icon, IDropdownOption } from 'office-ui-fabric-react' -import { Down } from 'grommet-icons' import { useTranslation } from 'react-i18next' -import { registerIcons } from 'utils/icons' - interface TransactionFee { fee: string cycles: string @@ -12,12 +9,6 @@ interface TransactionFee { onPriceChange: any } -registerIcons({ - icons: { - ArrowDown: , - }, -}) - const calculateSpeed = (price: number) => { if (price >= 160) { return '180' diff --git a/packages/neuron-ui/src/components/TransactionList/index.tsx b/packages/neuron-ui/src/components/TransactionList/index.tsx index f9b7899e92..ce27238333 100644 --- a/packages/neuron-ui/src/components/TransactionList/index.tsx +++ b/packages/neuron-ui/src/components/TransactionList/index.tsx @@ -11,20 +11,12 @@ import { ITextFieldStyleProps, getTheme, } from 'office-ui-fabric-react' -import { FormUp as ExpandIcon } from 'grommet-icons' import { StateDispatch } from 'states/stateProvider/reducer' import { contextMenu } from 'services/remote' import { useLocalDescription } from 'utils/hooks' import { shannonToCKBFormatter, uniformTimeFormatter as timeFormatter, uniformTimeFormatter } from 'utils/formatters' -import { registerIcons } from 'utils/icons' - -registerIcons({ - icons: { - ChevronRightMed: , - }, -}) const theme = getTheme() diff --git a/packages/neuron-ui/src/components/WalletWizard/index.tsx b/packages/neuron-ui/src/components/WalletWizard/index.tsx index 74dc1b072b..dcda01aeb9 100644 --- a/packages/neuron-ui/src/components/WalletWizard/index.tsx +++ b/packages/neuron-ui/src/components/WalletWizard/index.tsx @@ -1,14 +1,13 @@ import React, { useCallback, useEffect } from 'react' import { useTranslation } from 'react-i18next' import { Stack, Text, Label, Image, PrimaryButton, DefaultButton, TextField, FontSizes } from 'office-ui-fabric-react' -import { FormAdd, FormUpload } from 'grommet-icons' import withWizard, { WizardElementProps, WithWizardState } from 'components/withWizard' import { generateMnemonic, validateMnemonic, showErrorMessage } from 'services/remote' import { createWalletWithMnemonic, importWalletWithMnemonic } from 'states/stateProvider/actionCreators' import { Routes, MnemonicAction, BUTTON_GAP } from 'utils/const' -import { registerIcons, buttonGrommetIconStyles } from 'utils/icons' +import { buttonGrommetIconStyles } from 'utils/icons' import { verifyWalletSubmission } from 'utils/validators' export enum WalletWizardPath { @@ -37,13 +36,6 @@ const submissionInputs = [ { label: 'confirm-password', key: 'confirmPassword', type: 'password', autoFocus: false }, ] -registerIcons({ - icons: { - Import: , - Create: , - }, -}) - const Welcome = ({ rootPath = '/wizard', wallets = [], history }: WizardElementProps<{ rootPath: string }>) => { const [t] = useTranslation() useEffect(() => { diff --git a/packages/neuron-ui/src/containers/Footer/index.tsx b/packages/neuron-ui/src/containers/Footer/index.tsx index 7e7ee2cc17..619724ada7 100644 --- a/packages/neuron-ui/src/containers/Footer/index.tsx +++ b/packages/neuron-ui/src/containers/Footer/index.tsx @@ -2,8 +2,7 @@ import React, { useCallback, useContext } from 'react' import { createPortal } from 'react-dom' import { RouteComponentProps } from 'react-router-dom' import { useTranslation } from 'react-i18next' -import { Stack, getTheme, Text, ProgressIndicator } from 'office-ui-fabric-react' -import { Alert as AlertIcon, Nodes as ConnectIcon } from 'grommet-icons' +import { Stack, getTheme, Text, ProgressIndicator, Icon } from 'office-ui-fabric-react' import { StateWithDispatch } from 'states/stateProvider/reducer' import { ConnectionStatus, FULL_SCREENS, Routes } from 'utils/const' @@ -56,7 +55,11 @@ export const SyncStatus = ({ export const NetworkStatus = ({ name, online }: { name: string; online: boolean }) => { return ( - {online ? : } + + {name} ) diff --git a/packages/neuron-ui/src/containers/Notification/index.tsx b/packages/neuron-ui/src/containers/Notification/index.tsx index 2f16cad050..40c97aab95 100644 --- a/packages/neuron-ui/src/containers/Notification/index.tsx +++ b/packages/neuron-ui/src/containers/Notification/index.tsx @@ -5,7 +5,6 @@ import { useTranslation } from 'react-i18next' import { MessageBar, MessageBarType, IconButton } from 'office-ui-fabric-react' import { NeuronWalletContext } from 'states/stateProvider' import { StateWithDispatch, AppActions } from 'states/stateProvider/reducer' -import { Close } from 'grommet-icons' const notificationType = (type: 'success' | 'warning' | 'alert') => { switch (type) { @@ -25,9 +24,7 @@ const notificationType = (type: 'success' | 'warning' | 'alert') => { } const DismissButton = ({ onDismiss }: { onDismiss: React.MouseEventHandler }) => ( - - - + ) const NoticeContent = ({ dispatch }: React.PropsWithoutRef) => { diff --git a/packages/neuron-ui/src/index.tsx b/packages/neuron-ui/src/index.tsx index 83942aec94..2909f81934 100755 --- a/packages/neuron-ui/src/index.tsx +++ b/packages/neuron-ui/src/index.tsx @@ -1,8 +1,27 @@ import React from 'react' import ReactDOM from 'react-dom' import { HashRouter as Router, Route } from 'react-router-dom' -import { loadTheme } from 'office-ui-fabric-react' -import { Alert as AlertIcon } from 'grommet-icons' +import { loadTheme, getTheme } from 'office-ui-fabric-react' +import { + AddCircle as AddIcon, + Alert as AlertIcon, + Close as DismissIcon, + Copy as CopyIcon, + Down as ArrowDownIcon, + FormClose as ClearIcon, + FormAdd as CreateIcon, + FormPreviousLink as LeaveIcon, + FormUp as ExpandIcon, + FormUpload as ImportIcon, + LinkBottom as LinkBottomIcon, + LinkDown as LinkDownIcon, + LinkTop as LinkTopIcon, + LinkUp as LinkUpIcon, + Nodes as ConnectedIcon, + Scan as ScanIcon, + Search as SearchIcon, + SubtractCircle as RemoveIcon, +} from 'grommet-icons' import 'styles/index.scss' import 'utils/i18n' @@ -32,9 +51,31 @@ loadTheme({ }, }) +const theme = getTheme() +const { semanticColors } = theme + registerIcons({ icons: { errorbadge: , + MiniCopy: , + Search: , + FirstPage: , + LastPage: , + PrevPage: , + NextPage: , + ArrowDown: , + ChevronRightMed: , + Scan: , + Import: , + Create: , + Add: , + Remove: , + Copy: , + Clear: , + Dismiss: , + Leave: , + Connected: , + Disconnected: , }, }) diff --git a/packages/neuron-ui/src/widgets/QRScanner/index.tsx b/packages/neuron-ui/src/widgets/QRScanner/index.tsx index 4583808e70..5a69297a32 100644 --- a/packages/neuron-ui/src/widgets/QRScanner/index.tsx +++ b/packages/neuron-ui/src/widgets/QRScanner/index.tsx @@ -1,7 +1,14 @@ import React, { useState, useEffect, useMemo, useRef, useCallback } from 'react' import { useTranslation } from 'react-i18next' -import { TextField, PrimaryButton, DefaultButton, Dialog, DialogFooter, Stack } from 'office-ui-fabric-react' -import { Scan as ScanIcon } from 'grommet-icons' +import { + TextField, + PrimaryButton, + DefaultButton, + Dialog, + DialogFooter, + Stack, + IconButton, +} from 'office-ui-fabric-react' import jsQR from 'jsqr' import { showErrorMessage } from 'services/remote' @@ -103,7 +110,13 @@ const QRScanner = ({ title, label, onConfirm, styles }: QRScannerProps) => { onKeyPress={() => {}} type="button" > - +