diff --git a/packages/neuron-ui/src/components/GeneralSetting/index.tsx b/packages/neuron-ui/src/components/GeneralSetting/index.tsx index ced18634cf..f535311820 100644 --- a/packages/neuron-ui/src/components/GeneralSetting/index.tsx +++ b/packages/neuron-ui/src/components/GeneralSetting/index.tsx @@ -1,8 +1,45 @@ -import React from 'react' -import { Stack } from 'office-ui-fabric-react' +import React, { useCallback, useState } from 'react' +import { useTranslation } from 'react-i18next' +import { Stack, PrimaryButton, Spinner, Text } from 'office-ui-fabric-react' +import { StateWithDispatch } from 'states/stateProvider/reducer' +import { addPopup } from 'states/stateProvider/actionCreators' +import { clearCellCache } from 'services/remote' -const GeneralSetting = () => { - return +const GeneralSetting = ({ dispatch }: React.PropsWithoutRef) => { + const [t] = useTranslation() + const [clearing, setClearing] = useState(false) + + const clearCache = useCallback(() => { + setClearing(true) + setTimeout(() => { + clearCellCache().finally(() => { + addPopup('clear-cache-successfully')(dispatch) + setClearing(false) + }) + }, 100) + }, [dispatch]) + + return ( + + + + {clearing ? : t('settings.general.clear-cache')} + + + + {t('settings.general.clear-cache-description')} + + + ) } GeneralSetting.displayName = 'GeneralSetting' diff --git a/packages/neuron-ui/src/components/Settings/index.tsx b/packages/neuron-ui/src/components/Settings/index.tsx index a2d21a06e5..dccb8244b0 100644 --- a/packages/neuron-ui/src/components/Settings/index.tsx +++ b/packages/neuron-ui/src/components/Settings/index.tsx @@ -13,7 +13,7 @@ import { WalletWizardPath } from 'components/WalletWizard' import { Routes } from 'utils/const' const pivotItems = [ - // { label: 'settings.setting-tabs.general', url: Routes.SettingsGeneral }, + { label: 'settings.setting-tabs.general', url: Routes.SettingsGeneral }, { label: 'settings.setting-tabs.wallets', url: Routes.SettingsWallets }, { label: 'settings.setting-tabs.network', url: Routes.SettingsNetworks }, ] diff --git a/packages/neuron-ui/src/containers/Main/index.tsx b/packages/neuron-ui/src/containers/Main/index.tsx index 53bd745f0a..a065e52df6 100644 --- a/packages/neuron-ui/src/containers/Main/index.tsx +++ b/packages/neuron-ui/src/containers/Main/index.tsx @@ -1,5 +1,5 @@ import React, { useMemo } from 'react' -import { Route, RouteComponentProps, Switch, Redirect } from 'react-router-dom' +import { Route, RouteComponentProps } from 'react-router-dom' import { useTranslation } from 'react-i18next' import { useState } from 'states/stateProvider' @@ -102,12 +102,12 @@ export const mainContents: CustomRouter.Route[] = [ exact: false, comp: ImportKeystore, }, - // { - // name: `PasswordRequest`, - // path: '/', - // exact: false, - // comp: PasswordRequest, - // }, + { + name: `PasswordRequest`, + path: '/', + exact: false, + comp: PasswordRequest, + }, { name: `NervosDAO`, path: Routes.NervosDAO, @@ -158,26 +158,16 @@ const MainContent = ({ return ( <> - { - return - }} - /> - - - {mainContents.map(container => ( - { - return - }} - /> - ))} - + {mainContents.map(container => ( + { + return + }} + /> + ))} ) } diff --git a/packages/neuron-ui/src/locales/en.json b/packages/neuron-ui/src/locales/en.json index 291f2130e6..7521caf19c 100644 --- a/packages/neuron-ui/src/locales/en.json +++ b/packages/neuron-ui/src/locales/en.json @@ -178,7 +178,8 @@ "network": "Network" }, "general": { - "skip-data-and-type": "Skip the Cells which contain Data or Type Script", + "clear-cache": "Clear cache", + "clear-cache-description": "Clear cache if you encounter data sync or balance display problems. Neuron will rescan block data.", "show": "Show", "hide": "Hide" }, @@ -257,6 +258,7 @@ "delete-wallet-successfully": "The wallet was deleted", "create-network-successfully": "The network was created", "update-network-successfully": "The network was updated", + "clear-cache-successfully": "The cache was cleared", "addr-copied": "Address has been copied to the clipboard", "qrcode-copied": "QR Code has been copied to the clipboard", "view-the-run-node-doc": "View the guide in browser", diff --git a/packages/neuron-ui/src/locales/zh.json b/packages/neuron-ui/src/locales/zh.json index 2a9cb9b6ea..4809dc1eae 100644 --- a/packages/neuron-ui/src/locales/zh.json +++ b/packages/neuron-ui/src/locales/zh.json @@ -178,7 +178,8 @@ "network": "网络" }, "general": { - "skip-data-and-type": "忽略包含 Data 或 Type Script 的 Cells", + "clear-cache": "清空缓存", + "clear-cache-description": "当数据同步或显示出现问题时,可以清空缓存,Neuron 会重新同步所有块数据。", "show": "显示", "hide": "隐藏" }, @@ -257,6 +258,7 @@ "delete-wallet-successfully": "已删除钱包", "create-network-successfully": "已添加新节点", "update-network-successfully": "已更新节点信息", + "clear-cache-successfully": "已清空数据缓存", "addr-copied": "已复制地址到剪贴板", "qrcode-copied": "已复制二维码到剪贴板", "view-the-run-node-doc": "打开浏览器查看文档", diff --git a/packages/neuron-ui/src/services/remote/app.ts b/packages/neuron-ui/src/services/remote/app.ts index 69bb68af3a..238c302074 100644 --- a/packages/neuron-ui/src/services/remote/app.ts +++ b/packages/neuron-ui/src/services/remote/app.ts @@ -5,8 +5,11 @@ export const getNeuronWalletState = apiMethodWrapper(api => () => api.load export const handleViewError = apiMethodWrapper(api => errorMessage => api.handleViewError(errorMessage)) export const contextMenu = apiMethodWrapper<{ type: string; id: string }>(api => params => api.contextMenu(params)) +export const clearCellCache = apiMethodWrapper(api => () => api.clearCellCache()) + export default { getNeuronWalletState, handleViewError, contextMenu, + clearCellCache, } diff --git a/packages/neuron-ui/src/states/stateProvider/actionCreators/app.ts b/packages/neuron-ui/src/states/stateProvider/actionCreators/app.ts index c0446b5e7d..9827d871f3 100644 --- a/packages/neuron-ui/src/states/stateProvider/actionCreators/app.ts +++ b/packages/neuron-ui/src/states/stateProvider/actionCreators/app.ts @@ -60,6 +60,7 @@ export const initAppState = () => (dispatch: StateDispatch, history: any) => { }) } +// text: an i18n key under `messages` export const addPopup = (text: string) => (dispatch: StateDispatch) => { dispatch({ type: AppActions.PopIn, diff --git a/packages/neuron-ui/src/stories/GeneralSetting.stories.tsx b/packages/neuron-ui/src/stories/GeneralSetting.stories.tsx index b016ba1553..a8823d6ac1 100644 --- a/packages/neuron-ui/src/stories/GeneralSetting.stories.tsx +++ b/packages/neuron-ui/src/stories/GeneralSetting.stories.tsx @@ -2,9 +2,23 @@ import React from 'react' import { storiesOf } from '@storybook/react' import { withKnobs } from '@storybook/addon-knobs' import GeneralSetting from 'components/GeneralSetting' +import initStates from 'states/initStates' + +const states: { [title: string]: boolean } = { + 'Clear cell cache on': true, + 'Clear cell cache off': false, +} const stories = storiesOf('GeneralSettings', module) +Object.entries(states).forEach(([title]) => { + const props = { ...initStates, settings: { ...initStates.settings }, dispatch: () => {} } + stories.add(title, () => ) +}) + stories.addDecorator(withKnobs).add('With knobs', () => { - return + const props = { + ...initStates, + } + return {}} /> }) diff --git a/packages/neuron-wallet/src/controllers/api.ts b/packages/neuron-wallet/src/controllers/api.ts index 573bc6747d..7316bfbfd4 100644 --- a/packages/neuron-wallet/src/controllers/api.ts +++ b/packages/neuron-wallet/src/controllers/api.ts @@ -4,7 +4,7 @@ import env from 'env' import i18n from 'utils/i18n' import { popContextMenu } from './app/menu' import { showWindow } from './app/show-window' -import { TransactionsController, WalletsController, SyncInfoController, NetworksController } from 'controllers' +import { TransactionsController, WalletsController, SyncController, NetworksController } from 'controllers' import { NetworkType, NetworkID, Network } from 'types/network' import NetworksService from 'services/networks' import WalletsService from 'services/wallets' @@ -40,7 +40,7 @@ export default class ApiController { networksService.getCurrentID(), networksService.getAll(), - SyncInfoController.currentBlockNumber() + SyncController.currentBlockNumber() .then(res => { if (res.status) { return res.result.currentBlockNumber @@ -297,4 +297,12 @@ export default class ApiController { ) { return DaoController.getDaoCells(params) } + + // settings + @MapApiResponse + public static async clearCellCache() { + await SyncController.stopSyncing() + await SyncController.deleteData() + return SyncController.startSyncing() + } } diff --git a/packages/neuron-wallet/src/controllers/index.ts b/packages/neuron-wallet/src/controllers/index.ts index ece40cf0d7..cf339b4cbc 100644 --- a/packages/neuron-wallet/src/controllers/index.ts +++ b/packages/neuron-wallet/src/controllers/index.ts @@ -2,7 +2,7 @@ import AppController from './app' import NetworksController from './networks' import WalletsController from './wallets' import TransactionsController from './transactions' -import SyncInfoController from './sync-info' +import SyncController from './sync' import UpdateController from './update' import ApiController from './api' @@ -12,7 +12,7 @@ export { NetworksController, WalletsController, TransactionsController, - SyncInfoController, + SyncController, UpdateController, ApiController, } diff --git a/packages/neuron-wallet/src/controllers/sync-info.ts b/packages/neuron-wallet/src/controllers/sync-info.ts deleted file mode 100644 index 786380441e..0000000000 --- a/packages/neuron-wallet/src/controllers/sync-info.ts +++ /dev/null @@ -1,16 +0,0 @@ -import BlockNumber from 'services/sync/block-number' -import { ResponseCode } from 'utils/const' - -export default class SyncInfoController { - public static async currentBlockNumber() { - const blockNumber = new BlockNumber() - const current: bigint = await blockNumber.getCurrent() - - return { - status: ResponseCode.Success, - result: { - currentBlockNumber: current.toString(), - }, - } - } -} diff --git a/packages/neuron-wallet/src/controllers/sync.ts b/packages/neuron-wallet/src/controllers/sync.ts new file mode 100644 index 0000000000..bdae9a1d40 --- /dev/null +++ b/packages/neuron-wallet/src/controllers/sync.ts @@ -0,0 +1,45 @@ +import BlockNumber from 'services/sync/block-number' +import { createSyncBlockTask, killSyncBlockTask } from 'startup/sync-block-task/create' +import ChainCleaner from 'database/chain/cleaner' +import { ResponseCode } from 'utils/const' + +export default class SyncController { + public static async startSyncing() { + createSyncBlockTask() + + return { + status: ResponseCode.Success, + result: true + } + } + + public static async stopSyncing() { + killSyncBlockTask() + + return { + status: ResponseCode.Success, + result: true + } + } + + public static async deleteData() { + ChainCleaner.clean() + + return { + status: ResponseCode.Success, + result: true + } + } + + public static async currentBlockNumber() { + const blockNumber = new BlockNumber() + const current: bigint = await blockNumber.getCurrent() + + return { + status: ResponseCode.Success, + result: { + currentBlockNumber: current.toString(), + }, + } + } +} diff --git a/packages/neuron-wallet/src/database/chain/cleaner.ts b/packages/neuron-wallet/src/database/chain/cleaner.ts new file mode 100644 index 0000000000..30ee82a673 --- /dev/null +++ b/packages/neuron-wallet/src/database/chain/cleaner.ts @@ -0,0 +1,21 @@ +import fs from 'fs' +import path from 'path' +import env from 'env' + +// Clean local sqlite storage +export default class ChainCleaner { + // Delete all sqlite files under cells folder. + // It doesn't handle error or throw exception when deleting fails. + public static clean() { + const folder = path.join(env.fileBasePath, 'cells') + fs.readdir(folder, (err, files) => { + if (err) { + return + } + + for (const file of files.filter(f => { return path.extname(f) === '.sqlite' })) { + fs.unlink(path.join(folder, file), () => {}) + } + }) + } +} \ No newline at end of file diff --git a/packages/neuron-wallet/src/database/chain/ormconfig.ts b/packages/neuron-wallet/src/database/chain/ormconfig.ts index 988f8a6c1d..058b5919b5 100644 --- a/packages/neuron-wallet/src/database/chain/ormconfig.ts +++ b/packages/neuron-wallet/src/database/chain/ormconfig.ts @@ -22,9 +22,9 @@ import { AddInputIndexToInput1573461100330 } from './migrations/1573461100330-Ad export const CONNECTION_NOT_FOUND_NAME = 'ConnectionNotFoundError' -const dbPath = (networkName: string): string => { - const name = `cell-${networkName}.sqlite` - return path.join(env.fileBasePath, 'cells', name) +const dbPath = (name: string): string => { + const filename = `cell-${name}.sqlite` + return path.join(env.fileBasePath, 'cells', filename) } const connectOptions = async (genesisBlockHash: string): Promise => { diff --git a/packages/neuron-wallet/src/main.ts b/packages/neuron-wallet/src/main.ts index 257b253887..95b6030ec8 100644 --- a/packages/neuron-wallet/src/main.ts +++ b/packages/neuron-wallet/src/main.ts @@ -1,8 +1,8 @@ import { app } from 'electron' import AppController from 'controllers/app' +import SyncController from 'controllers/sync' import WalletService from 'services/wallets' -import createSyncBlockTask from 'startup/sync-block-task/create' import { changeLanguage } from 'utils/i18n' const appController = new AppController() @@ -11,7 +11,7 @@ app.on('ready', async () => { changeLanguage(app.getLocale()) WalletService.getInstance().generateAddressesIfNecessary() - createSyncBlockTask() + SyncController.startSyncing() appController.openWindow() }) diff --git a/packages/neuron-wallet/src/services/sync/renderer-params.ts b/packages/neuron-wallet/src/services/sync/renderer-params.ts index 30f0fee9c9..e426dcb183 100644 --- a/packages/neuron-wallet/src/services/sync/renderer-params.ts +++ b/packages/neuron-wallet/src/services/sync/renderer-params.ts @@ -1,5 +1,7 @@ import { remote } from 'electron' -export const { networkSwitchSubject, nodeService, addressChangeSubject, addressesUsedSubject } = remote.require( +export const { + networkSwitchSubject, nodeService, addressChangeSubject, addressesUsedSubject +} = remote.require( './startup/sync-block-task/params' ) diff --git a/packages/neuron-wallet/src/startup/sync-block-task/create.ts b/packages/neuron-wallet/src/startup/sync-block-task/create.ts index 222e8791a9..19b8d04fe9 100644 --- a/packages/neuron-wallet/src/startup/sync-block-task/create.ts +++ b/packages/neuron-wallet/src/startup/sync-block-task/create.ts @@ -74,10 +74,17 @@ const loadURL = `file://${path.join(__dirname, 'index.html')}` export { networkSwitchSubject } +let syncBlockBackgroundWindow: BrowserWindow | null + // create a background task to sync transactions // this task is a renderer process -const createSyncBlockTask = () => { - let syncBlockBackgroundWindow: BrowserWindow | null = new BrowserWindow({ +export const createSyncBlockTask = () => { + if (syncBlockBackgroundWindow) { + return + } + + console.info('Start sync block background process') + syncBlockBackgroundWindow = new BrowserWindow({ width: 1366, height: 768, show: false, @@ -86,8 +93,6 @@ const createSyncBlockTask = () => { }, }) - syncBlockBackgroundWindow.loadURL(loadURL) - syncBlockBackgroundWindow.on('ready-to-show', async () => { if (env.isDevMode && process.env.DEV_SYNC_TASK) { syncBlockBackgroundWindow!.show() @@ -100,7 +105,15 @@ const createSyncBlockTask = () => { syncBlockBackgroundWindow = null }) + syncBlockBackgroundWindow.loadURL(loadURL) + return syncBlockBackgroundWindow } -export default createSyncBlockTask +export const killSyncBlockTask = async () => { + if (syncBlockBackgroundWindow) { + console.info('Kill sync block background process') + // TODO: kill block number listener + syncBlockBackgroundWindow.close() + } +} diff --git a/packages/neuron-wallet/src/startup/sync-block-task/sync.ts b/packages/neuron-wallet/src/startup/sync-block-task/sync.ts index 7d0e7d87f8..e0a05985a1 100644 --- a/packages/neuron-wallet/src/startup/sync-block-task/sync.ts +++ b/packages/neuron-wallet/src/startup/sync-block-task/sync.ts @@ -79,4 +79,4 @@ export const switchNetwork = async (url: string, genesisBlockHash: string, _chai }) blockListener.start() -} +} \ No newline at end of file