浏览代码

Merge branch 'feature/v4.2' into develop

oldj 2 年之前
父节点
当前提交
11f231adc7
共有 100 个文件被更改,包括 2709 次插入3501 次删除
  1. 0 16
      .babelrc
  2. 1 1
      README.md
  3. 1 1
      README.zh_hans.md
  4. 1 1
      README.zh_hant.md
  5. 3 4
      app/package.json
  6. 2313 2840
      package-lock.json
  7. 69 76
      package.json
  8. 2 0
      scripts/entitlements.mac.plist
  9. 13 6
      scripts/make.js
  10. 13 1
      scripts/version_up.js
  11. 0 20
      scripts/webpack.base.config.js
  12. 0 55
      scripts/webpack.main.config.js
  13. 0 7
      scripts/webpack.main.prod.config.js
  14. 1 1
      src/common/default_configs.ts
  15. 1 1
      src/common/events.ts
  16. 8 15
      src/common/hostsFn.ts
  17. 1 1
      src/common/i18n/index.ts
  18. 7 13
      src/common/i18n/languages/de.ts
  19. 4 7
      src/common/i18n/languages/fr.ts
  20. 14 21
      src/common/i18n/languages/ja.ts
  21. 4 7
      src/common/i18n/languages/zh.ts
  22. 9 2
      src/common/types.d.ts
  23. 4 4
      src/main/actions/checkUpdate.ts
  24. 2 8
      src/main/actions/cmd/changeDataDir.ts
  25. 1 1
      src/main/actions/cmd/getHistoryList.ts
  26. 3 5
      src/main/actions/cmd/tryToRun.ts
  27. 1 1
      src/main/actions/config/all.ts
  28. 1 1
      src/main/actions/config/get.ts
  29. 2 5
      src/main/actions/config/set.ts
  30. 1 2
      src/main/actions/config/update.ts
  31. 3 6
      src/main/actions/find/findBy.ts
  32. 2 10
      src/main/actions/find/findPositionsInContent.ts
  33. 2 5
      src/main/actions/find/splitContent.ts
  34. 5 12
      src/main/actions/getBasicData.ts
  35. 4 6
      src/main/actions/hosts/getContent.ts
  36. 1 1
      src/main/actions/hosts/getHistoryList.ts
  37. 3 3
      src/main/actions/hosts/refresh.ts
  38. 2 4
      src/main/actions/hosts/setContent.ts
  39. 8 26
      src/main/actions/hosts/setSystemHosts.ts
  40. 3 3
      src/main/actions/list/getContentOfList.ts
  41. 2 2
      src/main/actions/list/getItem.ts
  42. 1 1
      src/main/actions/list/getList.ts
  43. 3 3
      src/main/actions/list/moveItemToTrashcan.ts
  44. 1 1
      src/main/actions/list/setList.ts
  45. 1 1
      src/main/actions/migrate/export.ts
  46. 2 6
      src/main/actions/migrate/importFromUrl.ts
  47. 2 2
      src/main/actions/migrate/importV3Data.ts
  48. 3 3
      src/main/actions/migrate/migrateData.ts
  49. 1 1
      src/main/actions/trashcan/clear.ts
  50. 3 3
      src/main/actions/trashcan/deleteItem.ts
  51. 1 1
      src/main/actions/trashcan/getList.ts
  52. 3 6
      src/main/actions/trashcan/restoreItem.ts
  53. 1 1
      src/main/actions/updateTrayTitle.ts
  54. 2 2
      src/main/core/getI18N.ts
  55. 3 5
      src/main/core/message.ts
  56. 1 1
      src/main/core/popupMenu.ts
  57. 3 3
      src/main/http/api/list.ts
  58. 2 2
      src/main/http/api/toggle.ts
  59. 2 4
      src/main/http/index.ts
  60. 3 3
      src/main/libs/cron.ts
  61. 1 1
      src/main/libs/getIndex.ts
  62. 1 1
      src/main/libs/request.ts
  63. 9 7
      src/main/libs/tracer.ts
  64. 7 1
      src/main/main.ts
  65. 2 2
      src/main/preload.ts
  66. 4 10
      src/main/types.d.ts
  67. 1 1
      src/main/ui/checkSystemLocale.ts
  68. 1 1
      src/main/ui/find.ts
  69. 7 16
      src/main/ui/menu.ts
  70. 6 15
      src/main/ui/tray/index.ts
  71. 0 1
      src/renderer/.env
  72. 0 33
      src/renderer/.umirc.ts
  73. 0 19
      src/renderer/app.tsx
  74. 20 0
      src/renderer/common/PageWrapper.tsx
  75. 0 0
      src/renderer/components/About/AboutContent.module.scss
  76. 8 10
      src/renderer/components/About/AboutContent.tsx
  77. 0 0
      src/renderer/components/About/index.module.scss
  78. 5 12
      src/renderer/components/About/index.tsx
  79. 1 1
      src/renderer/components/BrowserLink.tsx
  80. 0 0
      src/renderer/components/EditHostsInfo.module.scss
  81. 15 29
      src/renderer/components/EditHostsInfo.tsx
  82. 2 2
      src/renderer/components/Editor/HostsEditor.module.scss
  83. 9 11
      src/renderer/components/Editor/HostsEditor.tsx
  84. 0 0
      src/renderer/components/Editor/codemirror.module.scss
  85. 0 0
      src/renderer/components/History.module.scss
  86. 11 21
      src/renderer/components/History.tsx
  87. 1 1
      src/renderer/components/HostsViewer.module.scss
  88. 2 6
      src/renderer/components/HostsViewer.tsx
  89. 3 3
      src/renderer/components/Lang.tsx
  90. 0 0
      src/renderer/components/LeftPanel/SystemHostsItem.module.scss
  91. 7 11
      src/renderer/components/LeftPanel/SystemHostsItem.tsx
  92. 0 0
      src/renderer/components/LeftPanel/Trashcan.module.scss
  93. 9 13
      src/renderer/components/LeftPanel/Trashcan.tsx
  94. 0 0
      src/renderer/components/LeftPanel/TrashcanItem.module.scss
  95. 8 9
      src/renderer/components/LeftPanel/TrashcanItem.tsx
  96. 1 1
      src/renderer/components/LeftPanel/index.module.scss
  97. 6 5
      src/renderer/components/LeftPanel/index.tsx
  98. 0 0
      src/renderer/components/List/ListItem.module.scss
  99. 9 8
      src/renderer/components/List/ListItem.tsx
  100. 0 0
      src/renderer/components/List/index.module.scss

+ 0 - 16
.babelrc

@@ -1,16 +0,0 @@
-{
-  "plugins": [
-    [
-      "@babel/plugin-proposal-private-methods",
-      {
-        "loose": true
-      }
-    ],
-    [
-      "@babel/plugin-proposal-private-property-in-object",
-      {
-        "loose": true
-      }
-    ]
-  ]
-}

+ 1 - 1
README.md

@@ -6,7 +6,7 @@
 Homepage: [https://switchhosts.vercel.app](https://switchhosts.vercel.app)
 
 SwitchHosts is an App for managing hosts file, it is based on [Electron](http://electron.atom.io/)
-, [React](https://facebook.github.io/react/), [UmiJS](https://umijs.org/)
+, [React](https://facebook.github.io/react/), [Jotai](https://jotai.org/)
 , [Chakra UI](https://chakra-ui.com/), [CodeMirror](http://codemirror.net/), etc.
 
 ## Screenshot

+ 1 - 1
README.zh_hans.md

@@ -6,7 +6,7 @@
 项目主页:[https://switchhosts.vercel.app](https://switchhosts.vercel.app)
 
 SwitchHosts 是一个管理 hosts 文件的应用,基于 [Electron](http://electron.atom.io/)
-、[React](https://facebook.github.io/react/)、[UmiJS](https://umijs.org/)
+、[React](https://facebook.github.io/react/)、[Jotai](https://jotai.org/)
 、[Chakra UI](https://chakra-ui.com/)、[CodeMirror](http://codemirror.net/) 等技术开发。
 
 ## 截图

+ 1 - 1
README.zh_hant.md

@@ -6,7 +6,7 @@
 項目主頁:[https://switchhosts.vercel.app](https://switchhosts.vercel.app)
 
 SwitchHosts 是一個管理 hosts 檔案的應用程式,基於 [Electron](http://electron.atom.io/)
-、[React](https://facebook.github.io/react/)、[UmiJS](https://umijs.org/)
+、[React](https://facebook.github.io/react/)、[Jotai](https://jotai.org/)
 、[Chakra UI](https://chakra-ui.com/)、[CodeMirror](http://codemirror.net/) 等技術開發。
 
 ## 螢幕截圖

+ 3 - 4
app/package.json

@@ -1,7 +1,7 @@
 {
   "name": "switchhosts",
   "productName": "SwitchHosts",
-  "version": "4.0.0",
+  "version": "4.2.0.6099",
   "description": "Switch hosts quickly!",
   "main": "./main.js",
   "author": {
@@ -10,8 +10,7 @@
     "url": "https://github.com/oldj/SwitchHosts"
   },
   "homepage": "https://switchhosts.vercel.app",
-  "scripts": {
-  },
+  "scripts": {},
   "license": "Apache-2.0",
   "dependencies": {}
-}
+}

文件差异内容过多而无法显示
+ 2313 - 2840
package-lock.json


+ 69 - 76
package.json

@@ -1,92 +1,85 @@
 {
   "private": true,
   "scripts": {
-    "start": "electron ./build/main.js",
-    "postinstall": "umi generate tmp",
-    "test:umi": "umi-test",
-    "test:coverage": "umi-test --coverage",
+    "start": "cross-env NODE_ENV=development electron ./build/main.js",
     "test": "rm -rf ./test/tmp/* && mocha -r espower-typescript/guess -r tsconfig-paths/register \"test/**/*.test.ts\"",
-    "dev": "concurrently \"npm run dev:main\" \"npm run dev:renderer\"",
-    "dev:main": "webpack --config scripts/webpack.main.config.js -w",
-    "dev:renderer": "cross-env APP_ROOT=src/renderer umi dev",
+    "clean:dist": "rimraf ./dist/*",
+    "clean:build": "rimraf ./build/*",
+    "dev": "npm run clean:build && concurrently \"npm run dev:main\" \"npm run dev:renderer\"",
+    "dev:main": "vite build --watch --config ./vite.main.config.ts",
+    "dev:renderer": "vite --config ./vite.render.config.ts",
     "version:up": "node ./scripts/version_up.js",
-    "build": "npm run version:up && concurrently \"npm run build:main\" \"npm run build:renderer\"",
-    "build:main": "cross-env NODE_ENV=production webpack --config scripts/webpack.main.prod.config.js",
-    "build:renderer": "cross-env APP_ROOT=src/renderer umi build",
+    "_build": "npm run clean:build && npm run version:up && concurrently \"npm run build:main\" \"npm run build:renderer\"",
+    "build:main": "cross-env NODE_ENV=production vite build --config ./vite.main.config.ts",
+    "build:renderer": "cross-env NODE_ENV=production vite build --config ./vite.render.config.ts",
+    "build": "npm run _build",
     "make": "node scripts/make.js",
     "make:dev": "cross-env SKIP_NOTARIZATION=1 cross-env MAKE_FOR=dev npm run make",
     "make:linux": "cross-env SKIP_NOTARIZATION=1 cross-env MAKE_FOR=linux npm run make",
     "make:win": "cross-env SKIP_NOTARIZATION=1 cross-env MAKE_FOR=win npm run make"
   },
   "dependencies": {
-    "axios": "^0.27.2",
-    "compare-versions": "^4.1.3",
-    "dayjs": "^1.11.2",
-    "electron-window-state": "^5.0.3",
-    "express": "^4.18.1",
-    "lodash": "^4.17.21",
-    "md5": "^2.3.0",
-    "md5-file": "^5.0.0",
-    "mkdirp": "^1.0.4",
-    "potdb": "^2.3.3",
-    "tslib": "^2.4.0",
-    "uuid": "^8.3.2"
+    "axios": "1.3.0",
+    "compare-versions": "5.0.3",
+    "dayjs": "1.11.7",
+    "electron-window-state": "5.0.3",
+    "express": "4.18.2",
+    "lodash": "4.17.21",
+    "md5": "2.3.0",
+    "md5-file": "5.0.0",
+    "mkdirp": "2.1.3",
+    "potdb": "2.5.4",
+    "tslib": "2.5.0",
+    "uuid": "9.0.0"
   },
   "devDependencies": {
-    "@babel/plugin-proposal-class-properties": "^7.17.12",
-    "@babel/plugin-proposal-decorators": "^7.18.2",
-    "@babel/preset-env": "^7.18.2",
-    "@babel/preset-typescript": "^7.17.12",
-    "@chakra-ui/react": "^2.1.2",
-    "@emotion/react": "^11.9.0",
-    "@emotion/styled": "^11.8.1",
-    "@types/assert": "^1.5.6",
-    "@types/codemirror": "^5.60.5",
-    "@types/express": "^4.17.13",
-    "@types/lodash": "^4.14.182",
-    "@types/md5": "^2.3.2",
-    "@types/mkdirp": "^1.0.2",
-    "@types/mocha": "^9.1.1",
-    "@types/node": "^17.0.35",
-    "@types/react": "^18.0.9",
-    "@types/react-dom": "^18.0.5",
-    "@types/react-window": "^1.8.5",
-    "@types/uuid": "^8.3.4",
-    "@umijs/preset-react": "2.x",
-    "@umijs/test": "^3.5.24",
-    "ahooks": "^3.4.0",
-    "babel-loader": "^8.2.5",
-    "clsx": "^1.1.1",
-    "codemirror": "^5.65.4",
-    "concurrently": "^7.2.1",
-    "copy-webpack-plugin": "^11.0.0",
-    "cross-env": "^7.0.3",
-    "dotenv": "^16.0.1",
-    "electron": "^19.1.8",
-    "electron-builder": "^23.0.9",
-    "electron-notarize": "^1.2.1",
-    "espower-typescript": "^10.0.0",
-    "execa": "^6.1.0",
-    "fork-ts-checker-webpack-plugin": "^7.2.11",
-    "fs-extra": "^10.1.0",
-    "mocha": "^10.0.0",
-    "power-assert": "^1.6.1",
-    "prettier": "^2.6.2",
-    "pretty-bytes": "^6.0.0",
-    "react": "^18.1.0",
-    "react-dom": "^18.1.0",
-    "react-icons": "^4.3.1",
-    "react-window": "^1.8.7",
-    "smooth-scroll-into-view-if-needed": "^1.1.33",
-    "ts-node": "^10.8.0",
-    "tsconfig-paths-webpack-plugin": "^3.5.2",
-    "typescript": "^4.7.2",
-    "umi": "^3.5.35",
-    "webpack": "^5.72.1",
-    "webpack-cli": "^4.9.2",
-    "webpack-merge": "^5.8.0",
-    "webpack-node-externals": "^3.0.0",
-    "yorkie": "^2.0.0"
+    "@chakra-ui/react": "2.4.9",
+    "@emotion/react": "11.10.5",
+    "@emotion/styled": "11.10.5",
+    "@types/assert": "1.5.6",
+    "@types/codemirror": "5.60.7",
+    "@types/express": "4.17.16",
+    "@types/lodash": "4.14.191",
+    "@types/md5": "2.3.2",
+    "@types/mkdirp": "1.0.2",
+    "@types/mocha": "10.0.1",
+    "@types/node": "18.11.18",
+    "@types/react": "18.0.27",
+    "@types/react-dom": "18.0.10",
+    "@types/react-window": "1.8.5",
+    "@types/uuid": "9.0.0",
+    "@vitejs/plugin-react": "3.0.1",
+    "ahooks": "3.7.4",
+    "clsx": "1.2.1",
+    "codemirror": "5.65.11",
+    "concurrently": "7.6.0",
+    "cross-env": "7.0.3",
+    "dotenv": "16.0.3",
+    "electron": "22.1.0",
+    "electron-builder": "23.6.0",
+    "electron-notarize": "1.2.1",
+    "espower-typescript": "10.0.1",
+    "execa": "6.1.0",
+    "fs-extra": "11.1.0",
+    "jotai": "2.0.0",
+    "mocha": "10.2.0",
+    "power-assert": "1.6.1",
+    "prettier": "2.8.3",
+    "pretty-bytes": "6.0.0",
+    "react": "18.2.0",
+    "react-dom": "18.2.0",
+    "react-icons": "4.7.1",
+    "react-router-dom": "6.8.0",
+    "react-window": "1.8.8",
+    "rimraf": "^4.1.2",
+    "sass": "1.58.0",
+    "smooth-scroll-into-view-if-needed": "1.1.33",
+    "ts-node": "10.9.1",
+    "typescript": "4.9.5",
+    "vite": "4.0.4",
+    "vite-plugin-static-copy": "0.13.0",
+    "vite-plugin-svgr": "2.4.0",
+    "vite-tsconfig-paths": "4.0.5"
   },
   "build": {
     "afterSign": "scripts/notarize.js"

+ 2 - 0
scripts/entitlements.mac.plist

@@ -4,5 +4,7 @@
     <dict>
         <key>com.apple.security.cs.allow-unsigned-executable-memory</key>
         <true/>
+        <key>com.apple.security.cs.allow-jit</key>
+        <true/>
     </dict>
 </plist>

+ 13 - 6
scripts/make.js

@@ -37,7 +37,7 @@ const TARGET_PLATFORMS_configs = {
     win: ['nsis:ia32', 'nsis:x64', 'portable:ia32'],
   },
   all: {
-    mac: ['dmg:x64', 'dmg:arm64', 'dmg:universal'],
+    mac: ['dmg:x64', 'dmg:arm64'],
     linux: [
       'AppImage:x64',
       'deb:x64',
@@ -100,14 +100,21 @@ const afterMake = async () => {
 const doMake = async () => {
   console.log('-> make...')
 
+  const { MAKE_FOR } = process.env
   let targets = TARGET_PLATFORMS_configs.all
-  if (process.env.MAKE_FOR === 'dev') {
-    targets = TARGET_PLATFORMS_configs.macs
-  } else if (process.env.MAKE_FOR === 'mac') {
+
+  cfg_common.compression = 'maximum'
+  if (MAKE_FOR && MAKE_FOR !== 'all') {
+    cfg_common.compression = 'store'
+  }
+
+  if (MAKE_FOR === 'dev') {
     targets = TARGET_PLATFORMS_configs.mac
-  } else if (process.env.MAKE_FOR === 'win') {
+  } else if (MAKE_FOR === 'mac') {
+    targets = TARGET_PLATFORMS_configs.macs
+  } else if (MAKE_FOR === 'win') {
     targets = TARGET_PLATFORMS_configs.win
-  } else if (process.env.MAKE_FOR === 'linux') {
+  } else if (MAKE_FOR === 'linux') {
     targets = TARGET_PLATFORMS_configs.linux
   }
 

+ 13 - 1
scripts/version_up.js

@@ -9,8 +9,20 @@ const path = require('path')
 
 const version_file = path.join(path.dirname(__dirname), 'src', 'version.json')
 const version = require(version_file)
+const app_package = require('../app/package.json')
 
-version[3]++
+const versionInc = (v) => {
+  return ++v
+}
+
+version[3] = versionInc(version[3])
 
 console.log(`version -> ${version.slice(0, 3).join('.')}(${version[3]})`)
 fs.writeFileSync(version_file, `[${version.join(', ')}]`)
+
+app_package.version = version.slice(0, 3).join('.') + '.' + version[3]
+fs.writeFileSync(
+  path.join(path.dirname(__dirname), 'app', 'package.json'),
+  JSON.stringify(app_package, null, 2),
+  'utf8',
+)

+ 0 - 20
scripts/webpack.base.config.js

@@ -1,20 +0,0 @@
-'use strict'
-
-const path = require('path')
-
-module.exports = {
-  mode: 'development',
-  output: {
-    path: path.resolve(__dirname, '..', 'build'),
-    filename: '[name].js',
-  },
-  node: {
-    __dirname: false,
-    __filename: false,
-  },
-  resolve: {
-    extensions: ['.tsx', '.ts', '.js', '.json'],
-  },
-  devtool: 'source-map',
-  plugins: [],
-}

+ 0 - 55
scripts/webpack.main.config.js

@@ -1,55 +0,0 @@
-const webpack = require('webpack')
-const { merge } = require('webpack-merge')
-const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin')
-const CopyPlugin = require('copy-webpack-plugin')
-const nodeExternals = require('webpack-node-externals')
-
-const baseConfig = require('./webpack.base.config')
-
-module.exports = merge(baseConfig, {
-  target: 'electron-main',
-  entry: {
-    main: './src/main/main.ts',
-    preload: './src/main/preload.ts',
-  },
-  resolve: {
-    plugins: [new TsconfigPathsPlugin({})],
-  },
-  externals: [nodeExternals()],
-  module: {
-    rules: [
-      {
-        test: /\.ts$/,
-        exclude: /node_modules/,
-        loader: 'babel-loader',
-        options: {
-          cacheDirectory: true,
-          babelrc: false,
-          presets: [
-            ['@babel/preset-env', { targets: 'maintained node versions' }],
-            '@babel/preset-typescript',
-          ],
-          plugins: [
-            ['@babel/plugin-proposal-decorators', { legacy: true }],
-            ['@babel/plugin-proposal-class-properties', { loose: true }],
-            ['@babel/plugin-proposal-private-methods', { loose: true }],
-            [
-              '@babel/plugin-proposal-private-property-in-object',
-              { loose: true },
-            ],
-          ],
-        },
-      },
-    ],
-  },
-  plugins: [
-    new webpack.DefinePlugin({
-      'process.env.NODE_ENV': JSON.stringify(
-        process.env.NODE_ENV || 'development',
-      ),
-    }),
-    new CopyPlugin({
-      patterns: [{ from: 'src/assets', to: 'assets' }],
-    }),
-  ],
-})

+ 0 - 7
scripts/webpack.main.prod.config.js

@@ -1,7 +0,0 @@
-const { merge } = require('webpack-merge')
-
-const baseConfig = require('./webpack.main.config')
-
-module.exports = merge(baseConfig, {
-  mode: 'production',
-})

+ 1 - 1
src/common/default_configs.ts

@@ -1,4 +1,4 @@
-import { LocaleName } from '@root/common/i18n'
+import { LocaleName } from '@common/i18n'
 import { FolderModeType } from './data.d'
 
 export type WriteModeType = null | 'overwrite' | 'append'

+ 1 - 1
src/common/events.ts

@@ -31,7 +31,7 @@ export default {
   toggle_comment: 'toggle_comment',
   toggle_developer_tools: 'toggle_developer_tools',
   toggle_item: 'toggle_item',
-  toggle_left_pannel: 'toggle_left_pannel',
+  toggle_left_panel: 'toggle_left_panel',
   tray_list_updated: 'tray:list_updated',
   write_hosts_to_system: 'write_hosts_to_system',
 }

+ 8 - 15
src/common/hostsFn.ts

@@ -3,11 +3,7 @@
  * @homepage: https://oldj.net
  */
 
-import {
-  FolderModeType,
-  IHostsBasicData,
-  IHostsListObject,
-} from '@root/common/data'
+import { FolderModeType, IHostsBasicData, IHostsListObject } from '@common/data'
 import lodash from 'lodash'
 
 type PartHostsObjectType = Partial<IHostsListObject> & { id: string }
@@ -77,7 +73,7 @@ export const setOnStateOfItem = (
   id: string,
   on: boolean,
   default_choice_mode: FolderModeType = 0,
-  multi_chose_folder_switch_all: boolean = false
+  multi_chose_folder_switch_all: boolean = false,
 ): IHostsListObject[] => {
   let new_list: IHostsListObject[] = lodash.cloneDeep(list)
 
@@ -86,7 +82,7 @@ export const setOnStateOfItem = (
 
   item.on = on
 
-  let itemIsInTopLevel = isInTopLevel(list, id);
+  let itemIsInTopLevel = isInTopLevel(list, id)
   if (multi_chose_folder_switch_all) {
     item = switchFolderChild(item, on)
     !itemIsInTopLevel && switchItemParentIsON(new_list, item, on)
@@ -129,9 +125,9 @@ export const setOnStateOfItem = (
 }
 
 export const switchItemParentIsON = (
-    list: IHostsListObject[],
-    item: IHostsListObject,
-    on: boolean
+  list: IHostsListObject[],
+  item: IHostsListObject,
+  on: boolean,
 ) => {
   let parent = getParentOfItem(list, item.id)
 
@@ -158,10 +154,7 @@ export const switchItemParentIsON = (
   }
 }
 
-export const switchFolderChild = (
-    item: IHostsListObject,
-    on: boolean,
-): IHostsListObject => {
+export const switchFolderChild = (item: IHostsListObject, on: boolean): IHostsListObject => {
   if (item.type != 'folder') {
     return item
   }
@@ -179,7 +172,7 @@ export const switchFolderChild = (
     })
   }
 
-  return item;
+  return item
 }
 
 export const deleteItemById = (list: IHostsListObject[], id: string) => {

+ 1 - 1
src/common/i18n/index.ts

@@ -9,7 +9,7 @@ import zh from './languages/zh'
 import fr from './languages/fr'
 import de from './languages/de'
 import ja from './languages/ja'
-import { LanguageDict, LanguageKey } from '@root/common/types'
+import { LanguageDict, LanguageKey } from '@common/types'
 
 export const languages = {
   en,

+ 7 - 13
src/common/i18n/languages/de.ts

@@ -3,7 +3,7 @@
  * @homepage: https://bergo.dev
  */
 
-import { LanguageDict } from '@root/common/types'
+import { LanguageDict } from '@common/types'
 
 const lang: LanguageDict = {
   _app_name: 'SwitchHosts',
@@ -32,8 +32,7 @@ const lang: LanguageDict = {
   close: 'Schließen',
   colon: ': ',
   commands: 'Befehle',
-  commands_help:
-    'Die folgenden Systembefehle werden ausgeführt, wenn Hosts angewendet werden:',
+  commands_help: 'Die folgenden Systembefehle werden ausgeführt, wenn Hosts angewendet werden:',
   commands_title: 'Befehl nach dem Anlegen eines Hosts',
   comment_current_line: 'Aktuelle Zeile kommentieren',
   content: 'Inhalt',
@@ -67,8 +66,7 @@ const lang: LanguageDict = {
   host: 'Gastgeber',
   hosts_add: 'Neue Hosts hinzufügen',
   hosts_delete: 'Diesen Host löschen',
-  hosts_delete_confirm:
-    'Sind Sie sicher, dass Sie die aktuellen Hosts löschen wollen?',
+  hosts_delete_confirm: 'Sind Sie sicher, dass Sie die aktuellen Hosts löschen wollen?',
   hosts_edit: 'Hosts bearbeiten',
   hosts_title: 'Titel des Hosts',
   hosts_type: 'Hosts Typ',
@@ -105,8 +103,7 @@ const lang: LanguageDict = {
   minutes: 'Minuten',
   move_items_to_trashcan: 'Verschiebe {0} Objekte in den Mülleimer',
   move_to_trashcan: 'In die Mülltonne verschieben',
-  multi_chose_folder_switch_all:
-    'Mehrfachauswahl-Ordnerschalter zur Steuerung von Unterelementen',
+  multi_chose_folder_switch_all: 'Mehrfachauswahl-Ordnerschalter zur Steuerung von Unterelementen',
   need_to_relaunch: 'Muss neu gestartet werden',
   need_to_relaunch_after_setting_changed:
     'Die Einstellungen wurden geändert und werden erst nach einem Neustart der App wirksam.',
@@ -153,8 +150,7 @@ const lang: LanguageDict = {
   sudo_prompt_title: 'Geben Sie Ihr sudo-Passwort ein',
   system_hosts: 'System-Hosts',
   system_hosts_history: 'Historische Versionen der System-Hosts',
-  system_hosts_history_delete_confirm:
-    'Sind Sie sicher, dass Sie dieses Element löschen wollen?',
+  system_hosts_history_delete_confirm: 'Sind Sie sicher, dass Sie dieses Element löschen wollen?',
   system_hosts_history_help:
     'Wenn die Gesamtzahl der historischen Einträge diese Grenze überschreitet, wird der älteste Eintrag gelöscht.',
   system_hosts_history_limit: 'Maximale Anzahl von Datensätzen: ',
@@ -169,8 +165,7 @@ const lang: LanguageDict = {
   toggle_full_screen: 'Vollbildmodus einschalten',
   trashcan: 'Mülleimer',
   trashcan_clear: 'Den Mülleimer leeren',
-  trashcan_clear_confirm:
-    'Sind Sie sicher, dass Sie den Mülleimer leeren wollen?',
+  trashcan_clear_confirm: 'Sind Sie sicher, dass Sie den Mülleimer leeren wollen?',
   trashcan_delete_confirm: 'Möchten Sie dieses Objekt vollständig löschen?',
   trashcan_restore: 'Wiederherstellen',
   tray_mini_window: 'Taskleistensymbol-Verknüpfung',
@@ -192,8 +187,7 @@ const lang: LanguageDict = {
   write_mode: 'Schreibmodus',
   write_mode_append_help:
     'Hängen Sie die neuen Datensätze an das Ende der Hosts-Datei des Systems an.',
-  write_mode_overwrite_help:
-    'Überschreibt die Systemhosts-Datei mit den neuen Datensätzen.',
+  write_mode_overwrite_help: 'Überschreibt die Systemhosts-Datei mit den neuen Datensätzen.',
   write_mode_set: 'Schreibmodus einstellen',
   your_data_is: 'Ihre Datendateien sind gespeichert in:',
   your_hosts_file_is: 'Ihre Hosts-Datei befindet sich in:',

+ 4 - 7
src/common/i18n/languages/fr.ts

@@ -3,7 +3,7 @@
  * @homepage: https://github.com/Aktilor
  */
 
-import { LanguageDict } from '@root/common/types'
+import { LanguageDict } from '@common/types'
 
 const lang: LanguageDict = {
   _app_name: 'SwitchHosts',
@@ -32,8 +32,7 @@ const lang: LanguageDict = {
   close: 'Fermer',
   colon: ' : ',
   commands: 'Commandes',
-  commands_help:
-    "Les commandes systèmes suivantes seront exécutées quand l'hosts sera activé :",
+  commands_help: "Les commandes systèmes suivantes seront exécutées quand l'hosts sera activé :",
   commands_title: "Commandes une fois qu'un hosts est activé",
   comment_current_line: 'Commenter cette ligne',
   content: 'Contenu',
@@ -152,8 +151,7 @@ const lang: LanguageDict = {
   sudo_prompt_title: 'Entrez votre mot de passe sudo',
   system_hosts: 'Hosts du système',
   system_hosts_history: 'Historique des versions hosts du système',
-  system_hosts_history_delete_confirm:
-    'Êtes-vous sûr de vouloir supprimer cet élément ?',
+  system_hosts_history_delete_confirm: 'Êtes-vous sûr de vouloir supprimer cet élément ?',
   system_hosts_history_help:
     "Si le nombre total d'enregistrements dépasse cette limite, l'enregistrement le plus ancien sera supprimé.",
   system_hosts_history_limit: "Nombre max. d'enregistrements : ",
@@ -176,8 +174,7 @@ const lang: LanguageDict = {
   unhide: 'Démasquer',
   untitled: 'Sans titre',
   url_placeholder: 'http:// ou https:// ou file://',
-  usage_data_agree:
-    "Oui, soumettre de manière anonyme mes données d'utilisation",
+  usage_data_agree: "Oui, soumettre de manière anonyme mes données d'utilisation",
   usage_data_help:
     "Voulez-vous nous aider à améliorer SwitchHosts en soumettant périodiquement vos données d'utilisation de manière anonyme ?",
   usage_data_title: 'Rendez SwitchHosts meilleur !',

+ 14 - 21
src/common/i18n/languages/ja.ts

@@ -3,7 +3,7 @@
  * @homepage: https://kamatte.me
  */
 
-import { LanguageDict } from '@root/common/types'
+import { LanguageDict } from '@common/types'
 
 const lang: LanguageDict = {
   _app_name: 'SwitchHosts',
@@ -22,7 +22,7 @@ const lang: LanguageDict = {
   choice_mode: '選択モード',
   choice_mode_default: 'デフォルト',
   choice_mode_desc:
-      '最上位階層のhostsにのみ有効で、各フォルダーでは独自に選択モードを設定できます。',
+    '最上位階層のhostsにのみ有効で、各フォルダーでは独自に選択モードを設定できます。',
   choice_mode_multiple: '複数',
   choice_mode_single: '単一',
   choices: '選択',
@@ -32,8 +32,7 @@ const lang: LanguageDict = {
   close: '閉じる',
   colon: ': ',
   commands: 'コマンド',
-  commands_help:
-      'hostsが適用されたとき、以下のシステムコマンドを実行します:',
+  commands_help: 'hostsが適用されたとき、以下のシステムコマンドを実行します:',
   commands_title: 'hosts適用後のコマンド',
   comment_current_line: '現在の行をコメントアウト',
   content: '内容',
@@ -76,7 +75,7 @@ const lang: LanguageDict = {
   hours: '時間',
   http_api_on: 'HTTP APIを有効化',
   http_api_on_desc:
-      '{0}番ポートで実行され、Alfredなどのサードパーティソフトウェアでhostsを切り替えるために使用できます。',
+    '{0}番ポートで実行され、Alfredなどのサードパーティソフトウェアでhostsを切り替えるために使用できます。',
   http_api_only_local: 'HTTP APIを 127.0.0.1 のみでリッスンする',
   ignore_case: '大文字と小文字を区別しない',
   import: 'インポート',
@@ -97,18 +96,17 @@ const lang: LanguageDict = {
   local: 'ローカル',
   match: '一致',
   migrate_confirm:
-      'SwitchHosts v4.0は新しいデータ保存形式を使用します。古いデータを新しい形式に移行しますか?',
+    'SwitchHosts v4.0は新しいデータ保存形式を使用します。古いデータを新しい形式に移行しますか?',
   migrate_data: 'データ移行',
   minimize: '最小化',
   minute: '分',
   minutes: '分',
   move_items_to_trashcan: '{0}件をごみ箱に入れる',
   move_to_trashcan: 'ゴミ箱に入れる',
-  multi_chose_folder_switch_all:
-      'フォルダーの切り替えで配下のアイテムを一括操作',
+  multi_chose_folder_switch_all: 'フォルダーの切り替えで配下のアイテムを一括操作',
   need_to_relaunch: '再起動が必要です',
   need_to_relaunch_after_setting_changed:
-      '変更された設定はアプリケーションの再起動後に有効になります。',
+    '変更された設定はアプリケーションの再起動後に有効になります。',
   never: 'なし',
   new: '新規',
   new_version_found: '新しいバージョンが見つかりました',
@@ -132,13 +130,12 @@ const lang: LanguageDict = {
   remote: 'リモート',
   remove_duplicate_records: '重複レコードを削除',
   remove_duplicate_records_desc:
-      '1つのドメインに複数のIPアドレスを指定している場合、先頭のIPアドレスのみが有効になり、以降のIPアドレスはコメントに変換されます。',
+    '1つのドメインに複数のIPアドレスを指定している場合、先頭のIPアドレスのみが有効になり、以降のIPアドレスはコメントに変換されます。',
   replace: '置換',
   replace_all: 'すべて置換',
   replace_history: '置換履歴',
   reset: 'リセット',
-  reset_data_dir_confirm:
-      'データフォルダーの場所をデフォルト ({0}) に戻してもよろしいですか?',
+  reset_data_dir_confirm: 'データフォルダーの場所をデフォルト ({0}) に戻してもよろしいですか?',
   reset_zoom: 'ズームをリセット',
   search: '検索',
   select_all: 'すべて選択',
@@ -152,8 +149,7 @@ const lang: LanguageDict = {
   sudo_prompt_title: '管理者パスワードを入力してください',
   system_hosts: 'システムhosts',
   system_hosts_history: 'システムhostsのバージョン履歴',
-  system_hosts_history_delete_confirm:
-      'この履歴を削除してもよろしいですか?',
+  system_hosts_history_delete_confirm: 'この履歴を削除してもよろしいですか?',
   system_hosts_history_help: '履歴件数がこれを超えると、最も古い履歴が削除されます。',
   system_hosts_history_limit: '履歴の最大件数: ',
   test: 'テスト',
@@ -176,21 +172,18 @@ const lang: LanguageDict = {
   untitled: '無題',
   url_placeholder: 'http:// または https:// または file://',
   usage_data_agree: 'はい、匿名の利用データを送信します。',
-  usage_data_help:
-      '匿名の利用データを定期的に送信し、SwitchHostsの改善にご協力いただけませんか?',
+  usage_data_help: '匿名の利用データを定期的に送信し、SwitchHostsの改善にご協力いただけませんか?',
   usage_data_title: 'SwitchHostsの改善に協力する',
   use_proxy: 'プロキシを使用',
   use_system_window_frame:
-      'システムのウィンドウフレームを使用。アプリケーションの再起動が必要です。',
+    'システムのウィンドウフレームを使用。アプリケーションの再起動が必要です。',
   view: '表示',
   where_is_my_data: 'データはどこに保存されますか?',
   where_is_my_hosts: 'hostsファイルはどこにありますか?',
   window: 'ウィンドウ',
   write_mode: '書き込みモード',
-  write_mode_append_help:
-      '新しいレコードをシステムhostsの末尾に追記します。',
-  write_mode_overwrite_help:
-      '新しいレコードでシステムhostsを上書きします。',
+  write_mode_append_help: '新しいレコードをシステムhostsの末尾に追記します。',
+  write_mode_overwrite_help: '新しいレコードでシステムhostsを上書きします。',
   write_mode_set: '書き込みモードを設定',
   your_data_is: 'あなたのデータファイルはこちらに保存されています:',
   your_hosts_file_is: 'あなたのhostsファイルはこちらにあります:',

+ 4 - 7
src/common/i18n/languages/zh.ts

@@ -3,7 +3,7 @@
  * @homepage: https://oldj.net
  */
 
-import { LanguageDict } from '@root/common/types'
+import { LanguageDict } from '@common/types'
 
 const lang: LanguageDict = {
   _app_name: 'SwitchHosts',
@@ -93,8 +93,7 @@ const lang: LanguageDict = {
   loading: '加载中...',
   local: '本地',
   match: '匹配',
-  migrate_confirm:
-    'SwitchHosts v4.0 使用了新的数据存储格式,是否迁移旧数据为新格式?',
+  migrate_confirm: 'SwitchHosts v4.0 使用了新的数据存储格式,是否迁移旧数据为新格式?',
   migrate_data: '迁移数据',
   minimize: '最小化',
   minute: '分钟',
@@ -126,8 +125,7 @@ const lang: LanguageDict = {
   reload: '重载',
   remote: '远程',
   remove_duplicate_records: '移除重复的记录',
-  remove_duplicate_records_desc:
-    '如果一个域名指向多个 IP,只有第一条会生效,后面的将被转为注释。',
+  remove_duplicate_records_desc: '如果一个域名指向多个 IP,只有第一条会生效,后面的将被转为注释。',
   replace: '替换',
   replace_all: '替换所有',
   replace_history: '替换历史',
@@ -147,8 +145,7 @@ const lang: LanguageDict = {
   system_hosts: '系统 Hosts',
   system_hosts_history: '系统 Hosts 历史版本',
   system_hosts_history_delete_confirm: '确实要删除该项记录吗?',
-  system_hosts_history_help:
-    '如果历史记录的总数超过这个限制,最老的记录将被删除。',
+  system_hosts_history_help: '如果历史记录的总数超过这个限制,最老的记录将被删除。',
   system_hosts_history_limit: '最大记录数:',
   test: '测试',
   theme: '主题',

+ 9 - 2
src/common/types.d.ts

@@ -4,13 +4,20 @@
  * @homepage: https://oldj.net
  */
 
-import { HostsType } from '@root/common/data'
-import { MenuItemConstructorOptions } from 'electron'
+import { HostsType } from '@common/data'
+import { MenuItemConstructorOptions, WebContents } from 'electron'
 import { default as lang } from './i18n/languages/en'
+import * as actions from '@main/actions'
 
 export type LanguageDict = typeof lang
 export type LanguageKey = keyof LanguageDict
 
+export interface IActionFunc {
+  sender: WebContents
+}
+
+export type Actions = typeof actions & IActionFunc
+
 export interface IMenuItemOption extends MenuItemConstructorOptions {
   // 参见:https://www.electronjs.org/docs/api/menu-item
 

+ 4 - 4
src/main/actions/checkUpdate.ts

@@ -7,10 +7,10 @@
 import { broadcast } from '@main/core/agent'
 import { localdb } from '@main/data'
 import { GET } from '@main/libs/request'
-import { server_url } from '@root/common/constants'
-import events from '@root/common/events'
-import version from '@root/version.json'
-import compareVersions from 'compare-versions'
+import { server_url } from '@common/constants'
+import events from '@common/events'
+import version from '@/version.json'
+import { compareVersions } from 'compare-versions'
 import { v4 as uuid4 } from 'uuid'
 import type { AxiosResponse } from 'axios'
 

+ 2 - 8
src/main/actions/cmd/changeDataDir.ts

@@ -3,17 +3,11 @@
  * @homepage: https://oldj.net
  */
 
-import {
-  app,
-  BrowserWindow,
-  dialog,
-  OpenDialogOptions,
-  OpenDialogReturnValue,
-} from 'electron'
+import { app, BrowserWindow, dialog, OpenDialogOptions, OpenDialogReturnValue } from 'electron'
 import { localdb } from '@main/data'
 import getDataFolder, { getDefaultDataDir } from '@main/libs/getDataDir'
 import getI18N from '@main/core/getI18N'
-import { IActionFunc } from '@root/main/types'
+import { IActionFunc } from '@common/types'
 
 export default async function (
   this: IActionFunc,

+ 1 - 1
src/main/actions/cmd/getHistoryList.ts

@@ -5,7 +5,7 @@
  */
 
 import { cfgdb } from '@main/data'
-import { ICommandRunResult } from '@root/common/data'
+import { ICommandRunResult } from '@common/data'
 
 export default async (): Promise<ICommandRunResult[]> => {
   return await cfgdb.collection.cmd_history.all()

+ 3 - 5
src/main/actions/cmd/tryToRun.ts

@@ -5,10 +5,10 @@
  */
 
 import { cfgdb } from '@main/data'
-import { ICommandRunResult } from '@root/common/data'
+import { ICommandRunResult } from '@common/data'
 import { exec } from 'child_process'
 import { broadcast } from '@main/core/agent'
-import events from '@root/common/events'
+import events from '@common/events'
 
 const run = (cmd: string): Promise<ICommandRunResult> =>
   new Promise((resolve) => {
@@ -44,9 +44,7 @@ export default async () => {
   if (all.length > max_records) {
     let n = all.length - max_records
     for (let i = 0; i < n; i++) {
-      await cfgdb.collection.cmd_history.delete(
-        (item) => item._id === all[i]._id,
-      )
+      await cfgdb.collection.cmd_history.delete((item) => item._id === all[i]._id)
     }
   }
 

+ 1 - 1
src/main/actions/config/all.ts

@@ -4,7 +4,7 @@
  */
 
 import { cfgdb } from '@main/data'
-import default_configs, { ConfigsType } from '@root/common/default_configs'
+import default_configs, { ConfigsType } from '@common/default_configs'
 
 export default async (): Promise<ConfigsType> => {
   if (!default_configs.locale && global.system_locale) {

+ 1 - 1
src/main/actions/config/get.ts

@@ -4,7 +4,7 @@
  */
 
 import { cfgdb } from '@main/data'
-import default_configs, { ConfigsType } from '@root/common/default_configs'
+import default_configs, { ConfigsType } from '@common/default_configs'
 
 export default async <K extends keyof ConfigsType>(key: K) => {
   return (await cfgdb.dict.cfg.get(key, default_configs[key])) as ConfigsType[K]

+ 2 - 5
src/main/actions/config/set.ts

@@ -4,12 +4,9 @@
  */
 
 import { cfgdb } from '@main/data'
-import { ConfigsType } from '@root/common/default_configs'
+import { ConfigsType } from '@common/default_configs'
 
-export default async <K extends keyof ConfigsType>(
-  key: K,
-  value: ConfigsType[K],
-) => {
+export default async <K extends keyof ConfigsType>(key: K, value: ConfigsType[K]) => {
   console.log(`config:store.set [${key}]: ${value}`)
   await cfgdb.dict.cfg.set(key, value)
 }

+ 1 - 2
src/main/actions/config/update.ts

@@ -7,7 +7,7 @@ import { updateTrayTitle } from '@main/actions'
 import { cfgdb } from '@main/data'
 import * as http_api from '@main/http'
 import { makeMainMenu } from '@main/ui/menu'
-import { ConfigsType } from '@root/common/default_configs'
+import { ConfigsType } from '@common/default_configs'
 import { app } from 'electron'
 
 export default async (data: Partial<ConfigsType>) => {
@@ -33,7 +33,6 @@ export default async (data: Partial<ConfigsType>) => {
     }
   }
 
-
   if (old_configs.hide_dock_icon !== data.hide_dock_icon) {
     if (data.hide_dock_icon) {
       app.dock.hide()

+ 3 - 6
src/main/actions/find/findBy.ts

@@ -5,8 +5,8 @@
 
 import splitContent from '@main/actions/find/splitContent'
 import getContentOfHosts from '@main/actions/hosts/getContent'
-import { flatten } from '@root/common/hostsFn'
-import { IFindItem } from '@root/common/types'
+import { flatten } from '@common/hostsFn'
+import { IFindItem } from '@common/types'
 import findInContent from 'src/main/actions/find/findPositionsInContent'
 import { getList } from '../index'
 
@@ -15,10 +15,7 @@ export interface IFindOptions {
   is_ignore_case: boolean
 }
 
-export default async (
-  keyword: string,
-  options: IFindOptions,
-): Promise<IFindItem[]> => {
+export default async (keyword: string, options: IFindOptions): Promise<IFindItem[]> => {
   console.log(keyword)
   let result_items: IFindItem[] = []
 

+ 2 - 10
src/main/actions/find/findPositionsInContent.ts

@@ -3,19 +3,11 @@
  * @homepage: https://oldj.net
  */
 
-import { IFindPosition } from '@root/common/types'
+import { IFindPosition } from '@common/types'
 
 type MatchResult = Pick<
   IFindPosition,
-  | 'start'
-  | 'end'
-  | 'before'
-  | 'match'
-  | 'after'
-  | 'line'
-  | 'line_pos'
-  | 'end_line'
-  | 'end_line_pos'
+  'start' | 'end' | 'before' | 'match' | 'after' | 'line' | 'line_pos' | 'end_line' | 'end_line_pos'
 >
 
 export default (content: string, exp: RegExp): MatchResult[] => {

+ 2 - 5
src/main/actions/find/splitContent.ts

@@ -3,16 +3,13 @@
  * @homepage: https://oldj.net
  */
 
-import { IFindPosition, IFindSplitter } from '@root/common/types'
+import { IFindPosition, IFindSplitter } from '@common/types'
 
 type MatchResult = Pick<IFindPosition, 'start' | 'end' | 'match'> & {
   [key: string]: any
 }
 
-export default (
-  content: string,
-  find_results: MatchResult[],
-): IFindSplitter[] => {
+export default (content: string, find_results: MatchResult[]): IFindSplitter[] => {
   let spliters: IFindSplitter[] = []
 
   let last_end = 0

+ 5 - 12
src/main/actions/getBasicData.ts

@@ -4,15 +4,10 @@
  */
 
 import { swhdb } from '@main/data'
-import {
-  IHostsBasicData,
-  IHostsListObject,
-  ITrashcanListObject,
-  VersionType,
-} from '@root/common/data'
-import { flatten } from '@root/common/hostsFn'
+import { IHostsBasicData, IHostsListObject, ITrashcanListObject, VersionType } from '@common/data'
+import { flatten } from '@common/hostsFn'
 import { v4 as uuid4 } from 'uuid'
-import version from '@root/version.json'
+import version from '@/version.json'
 
 const normalizeList = (list: IHostsListObject[]): IHostsListObject[] => {
   let flat = flatten(list)
@@ -25,9 +20,7 @@ const normalizeList = (list: IHostsListObject[]): IHostsListObject[] => {
   return list
 }
 
-const normalizeTrashcan = (
-  list: ITrashcanListObject[],
-): ITrashcanListObject[] => {
+const normalizeTrashcan = (list: ITrashcanListObject[]): ITrashcanListObject[] => {
   list.map((item) => {
     if (!item.id) {
       item.id = uuid4()
@@ -46,7 +39,7 @@ export default async (): Promise<IHostsBasicData> => {
 
   let list = normalizeList(await swhdb.list.tree.all())
   let trashcan = normalizeTrashcan(await swhdb.list.trashcan.all())
-  let v = await swhdb.dict.meta.get<VersionType>('version', version)
+  let v = (await swhdb.dict.meta.get<VersionType>('version', version)) || [0, 0, 0, 0]
 
   return {
     ...default_data,

+ 4 - 6
src/main/actions/hosts/getContent.ts

@@ -5,13 +5,11 @@
 
 import { configGet, getItemFromList, getList } from '@main/actions'
 import { swhdb } from '@main/data'
-import { IHostsContentObject } from '@root/common/data'
-import { findItemById, flatten } from '@root/common/hostsFn'
+import { IHostsContentObject } from '@common/data'
+import { findItemById, flatten } from '@common/hostsFn'
 
 const getContentById = async (id: string) => {
-  let hosts_content = await swhdb.collection.hosts.find<IHostsContentObject>(
-    (i) => i.id === id,
-  )
+  let hosts_content = await swhdb.collection.hosts.find<IHostsContentObject>((i) => i.id === id)
   return hosts_content?.content || ''
 }
 
@@ -28,7 +26,7 @@ const getContentOfHosts = async (id: string): Promise<string> => {
 
   let list = await getList()
 
-  let multi_chose_folder_switch_all = await configGet('multi_chose_folder_switch_all');
+  let multi_chose_folder_switch_all = await configGet('multi_chose_folder_switch_all')
   let isSkipFolder = multi_chose_folder_switch_all && hosts.folder_mode !== 1
 
   if (type === 'folder' && !isSkipFolder) {

+ 1 - 1
src/main/actions/hosts/getHistoryList.ts

@@ -5,7 +5,7 @@
  */
 
 import { swhdb } from '@main/data'
-import { IHostsHistoryObject } from '@root/common/data'
+import { IHostsHistoryObject } from '@common/data'
 
 export default async (): Promise<IHostsHistoryObject[]> => {
   let list = await swhdb.collection.history.all<IHostsHistoryObject>()

+ 3 - 3
src/main/actions/hosts/refresh.ts

@@ -9,9 +9,9 @@ import { broadcast } from '@main/core/agent'
 
 import { swhdb } from '@main/data'
 import { GET } from '@main/libs/request'
-import { IHostsListObject, IOperationResult } from '@root/common/data'
-import events from '@root/common/events'
-import * as hostsFn from '@root/common/hostsFn'
+import { IHostsListObject, IOperationResult } from '@common/data'
+import events from '@common/events'
+import * as hostsFn from '@common/hostsFn'
 import dayjs from 'dayjs'
 import * as fs from 'fs'
 import { URL } from 'url'

+ 2 - 4
src/main/actions/hosts/setContent.ts

@@ -4,12 +4,10 @@
  */
 
 import { swhdb } from '@main/data'
-import { IHostsContentObject } from '@root/common/data'
+import { IHostsContentObject } from '@common/data'
 
 export default async (id: string, content: string) => {
-  let d = await swhdb.collection.hosts.find<IHostsContentObject>(
-    (i) => i.id === id,
-  )
+  let d = await swhdb.collection.hosts.find<IHostsContentObject>((i) => i.id === id)
   if (!d || !d._id) {
     await swhdb.collection.hosts.insert({ id, content })
   } else {

+ 8 - 26
src/main/actions/hosts/setSystemHosts.ts

@@ -3,19 +3,14 @@
  * @homepage: https://oldj.net
  */
 
-import {
-  configGet,
-  deleteHistory,
-  getHistoryList,
-  updateTrayTitle,
-} from '@main/actions'
+import { configGet, deleteHistory, getHistoryList, updateTrayTitle } from '@main/actions'
 import tryToRun from '@main/actions/cmd/tryToRun'
 import { broadcast } from '@main/core/agent'
 import { swhdb } from '@main/data'
 import safePSWD from '@main/libs/safePSWD'
 import { IHostsWriteOptions } from '@main/types'
-import { IHostsHistoryObject } from '@root/common/data'
-import events from '@root/common/events'
+import { IHostsHistoryObject } from '@common/data'
+import events from '@common/events'
 import { exec } from 'child_process'
 import * as fs from 'fs'
 import md5 from 'md5'
@@ -68,15 +63,9 @@ const addHistory = async (content: string) => {
   }
 }
 
-const writeWithSudo = (
-  sys_hosts_path: string,
-  content: string,
-): Promise<IWriteResult> =>
+const writeWithSudo = (sys_hosts_path: string, content: string): Promise<IWriteResult> =>
   new Promise((resolve) => {
-    let tmp_fn = path.join(
-      os.tmpdir(),
-      `swh_${new Date().getTime()}_${Math.random()}.txt`,
-    )
+    let tmp_fn = path.join(os.tmpdir(), `swh_${new Date().getTime()}_${Math.random()}.txt`)
     fs.writeFileSync(tmp_fn, content, 'utf-8')
 
     let cmd = [
@@ -117,10 +106,7 @@ const writeWithSudo = (
     })
   })
 
-const write = async (
-  content: string,
-  options?: IHostsWriteOptions,
-): Promise<IWriteResult> => {
+const write = async (content: string, options?: IHostsWriteOptions): Promise<IWriteResult> => {
   const sys_hosts_path = await getPathOfSystemHosts()
   const fn_md5 = await md5File(sys_hosts_path)
   const content_md5 = md5(content)
@@ -184,8 +170,7 @@ const makeAppendContent = async (content: string): Promise<string> => {
   const old_content = await fs.promises.readFile(sys_hosts_path, 'utf-8')
 
   let index = old_content.indexOf(CONTENT_START)
-  let new_content =
-    index > -1 ? old_content.substring(0, index).trimEnd() : old_content
+  let new_content = index > -1 ? old_content.substring(0, index).trimEnd() : old_content
 
   if (!content) {
     return new_content + '\n'
@@ -210,10 +195,7 @@ const setSystemHosts = async (
   if (success) {
     if (typeof old_content === 'string') {
       let histories = await getHistoryList()
-      if (
-        histories.length === 0 ||
-        histories[histories.length - 1].content !== old_content
-      ) {
+      if (histories.length === 0 || histories[histories.length - 1].content !== old_content) {
         await addHistory(old_content)
       }
     }

+ 3 - 3
src/main/actions/list/getContentOfList.ts

@@ -4,9 +4,9 @@
  */
 
 import { configGet, getHostsContent } from '@main/actions'
-import { IHostsListObject } from '@root/common/data'
-import { flatten } from '@root/common/hostsFn'
-import normalize, { INormalizeOptions } from '@root/common/normalize'
+import { IHostsListObject } from '@common/data'
+import { flatten } from '@common/hostsFn'
+import normalize, { INormalizeOptions } from '@common/normalize'
 
 const getContentOfList = async (list: IHostsListObject[]): Promise<string> => {
   const content_list: string[] = []

+ 2 - 2
src/main/actions/list/getItem.ts

@@ -4,8 +4,8 @@
  */
 
 import { getList } from '@main/actions'
-import { IHostsListObject } from '@root/common/data'
-import { findItemById } from '@root/common/hostsFn'
+import { IHostsListObject } from '@common/data'
+import { findItemById } from '@common/hostsFn'
 
 export default async (id: string): Promise<IHostsListObject | undefined> => {
   let list = await getList()

+ 1 - 1
src/main/actions/list/getList.ts

@@ -4,7 +4,7 @@
  */
 
 import { swhdb } from '@main/data'
-import { IHostsListObject } from '@root/common/data'
+import { IHostsListObject } from '@common/data'
 
 export default async (): Promise<IHostsListObject[]> => {
   return await swhdb.list.tree.all()

+ 3 - 3
src/main/actions/list/moveItemToTrashcan.ts

@@ -6,9 +6,9 @@
 import { getList } from '@main/actions'
 import { broadcast } from '@main/core/agent'
 import { swhdb } from '@main/data'
-import { IHostsListObject, ITrashcanObject } from '@root/common/data'
-import events from '@root/common/events'
-import * as hostsFn from '@root/common/hostsFn'
+import { IHostsListObject, ITrashcanObject } from '@common/data'
+import events from '@common/events'
+import * as hostsFn from '@common/hostsFn'
 
 export default async (id: string) => {
   let list: IHostsListObject[] = await getList()

+ 1 - 1
src/main/actions/list/setList.ts

@@ -4,7 +4,7 @@
  */
 
 import { swhdb } from '@main/data'
-import { IHostsListObject } from '@root/common/data'
+import { IHostsListObject } from '@common/data'
 
 export default async (list: IHostsListObject[]) => {
   await swhdb.list.tree.set(list)

+ 1 - 1
src/main/actions/migrate/export.ts

@@ -9,7 +9,7 @@ import { swhdb } from '@main/data'
 import { dialog } from 'electron'
 import { promises as fs } from 'fs'
 import * as path from 'path'
-import version from '@root/version.json'
+import version from '@/version.json'
 
 export default async (): Promise<string | null | false> => {
   let { lang } = await getI18N()

+ 2 - 6
src/main/actions/migrate/importFromUrl.ts

@@ -13,7 +13,7 @@ export default async (url: string): Promise<boolean | null | string> => {
   let res
   try {
     res = await GET(url)
-  } catch (e) {
+  } catch (e: any) {
     console.error(e)
     return e.message
   }
@@ -35,11 +35,7 @@ export default async (url: string): Promise<boolean | null | string> => {
     data = res.data
   }
 
-  if (
-    typeof data !== 'object' ||
-    !data.version ||
-    !Array.isArray(data.version)
-  ) {
+  if (typeof data !== 'object' || !data.version || !Array.isArray(data.version)) {
     return 'invalid_data'
   }
 

+ 2 - 2
src/main/actions/migrate/importV3Data.ts

@@ -7,8 +7,8 @@
 // import data from v3 to v4
 
 import { swhdb } from '@main/data'
-import { cleanHostsList, flatten } from '@root/common/hostsFn'
-import version from '@root/version.json'
+import { cleanHostsList, flatten } from '@common/hostsFn'
+import version from '@/version.json'
 
 export default async (old_data: any) => {
   old_data = cleanHostsList(old_data)

+ 3 - 3
src/main/actions/migrate/migrateData.ts

@@ -8,9 +8,9 @@
 
 import importV3Data from '@main/actions/migrate/importV3Data'
 import getDataFolder from '@main/libs/getDataDir'
-import { IHostsBasicData, VersionType } from '@root/common/data'
-import { cleanHostsList } from '@root/common/hostsFn'
-import version from '@root/version.json'
+import { IHostsBasicData, VersionType } from '@common/data'
+import { cleanHostsList } from '@common/hostsFn'
+import version from '@/version.json'
 import * as fs from 'fs'
 import path from 'path'
 

+ 1 - 1
src/main/actions/trashcan/clear.ts

@@ -4,7 +4,7 @@
  */
 
 import { swhdb } from '@main/data'
-import { flatten } from '@root/common/hostsFn'
+import { flatten } from '@common/hostsFn'
 
 export default async () => {
   let trashcan_items = await swhdb.list.trashcan.all()

+ 3 - 3
src/main/actions/trashcan/deleteItem.ts

@@ -4,13 +4,13 @@
  */
 
 import { swhdb } from '@main/data'
-import { ITrashcanListObject } from '@root/common/data'
-import { flatten } from '@root/common/hostsFn'
+import { ITrashcanListObject } from '@common/data'
+import { flatten } from '@common/hostsFn'
 
 export default async (id: string): Promise<boolean> => {
   // Permanently delete the specified item with id.
 
-  let trashcan_item: ITrashcanListObject = await swhdb.list.trashcan.find(
+  let trashcan_item: ITrashcanListObject | undefined = await swhdb.list.trashcan.find(
     (i) => i.data.id === id,
   )
 

+ 1 - 1
src/main/actions/trashcan/getList.ts

@@ -4,7 +4,7 @@
  */
 
 import { swhdb } from '@main/data'
-import { IHostsListObject } from '@root/common/data'
+import { IHostsListObject } from '@common/data'
 
 export default async (): Promise<IHostsListObject[]> => {
   return await swhdb.list.trashcan.all()

+ 3 - 6
src/main/actions/trashcan/restoreItem.ts

@@ -5,14 +5,11 @@
 
 import { getList, setList } from '@main/actions'
 import { swhdb } from '@main/data'
-import { getNodeById } from '@root/common/tree'
-import {
-  IHostsListObject,
-  ITrashcanListObject,
-} from '@root/common/data'
+import { getNodeById } from '@common/tree'
+import { IHostsListObject, ITrashcanListObject } from '@common/data'
 
 export default async (id: string): Promise<boolean> => {
-  let trashcan_item: ITrashcanListObject = await swhdb.list.trashcan.find(
+  let trashcan_item: ITrashcanListObject | undefined = await swhdb.list.trashcan.find(
     (i) => i.data.id === id,
   )
 

+ 1 - 1
src/main/actions/updateTrayTitle.ts

@@ -7,7 +7,7 @@
 import { getList } from '@main/actions/index'
 import { cfgdb } from '@main/data'
 import { tray } from '@main/ui/tray'
-import { flatten } from '@root/common/hostsFn'
+import { flatten } from '@common/hostsFn'
 
 export default async (show?: boolean, title?: string) => {
   if (!tray) return

+ 2 - 2
src/main/core/getI18N.ts

@@ -5,8 +5,8 @@
  */
 
 import { configGet } from '@main/actions'
-import { LocaleName } from '@root/common/i18n'
-import { I18N } from '@root/common/i18n'
+import { LocaleName } from '@common/i18n'
+import { I18N } from '@common/i18n'
 
 export default async (locale?: LocaleName): Promise<I18N> => {
   if (!locale) {

+ 3 - 5
src/main/core/message.ts

@@ -5,9 +5,10 @@
  */
 
 import * as actions from '@main/actions'
-import { ActionData, IActionFunc } from '@main/types'
+import { ActionData } from '@main/types'
 import { ipcMain } from 'electron'
 import { EventEmitter } from 'events'
+import { IActionFunc } from '@common/types'
 
 const ee = new EventEmitter()
 const registered_clients: { [key: string]: any } = {}
@@ -32,10 +33,7 @@ ipcMain.on('x_unreg', (e, d) => {
     delete registered_clients[name]
   } else {
     for (let k in registered_clients) {
-      if (
-        registered_clients.hasOwnProperty(k) &&
-        registered_clients[k] === e.sender
-      ) {
+      if (registered_clients.hasOwnProperty(k) && registered_clients[k] === e.sender) {
         delete registered_clients[k]
         break
       }

+ 1 - 1
src/main/core/popupMenu.ts

@@ -5,7 +5,7 @@
  */
 
 import { broadcast } from '@main/core/agent'
-import { IPopupMenuOption } from '@root/common/types'
+import { IPopupMenuOption } from '@common/types'
 import { ipcMain, Menu, MenuItem } from 'electron'
 
 ipcMain.on('x_popup_menu', (e, options: IPopupMenuOption) => {

+ 3 - 3
src/main/http/api/list.ts

@@ -5,15 +5,15 @@
  */
 
 import { getList } from '@main/actions'
-import { IHostsListObject } from '@root/common/data'
-import { flatten } from '@root/common/hostsFn'
+import { IHostsListObject } from '@common/data'
+import { flatten } from '@common/hostsFn'
 import { Request, Response } from 'express'
 
 const list = async (req: Request, res: Response) => {
   let list: IHostsListObject[]
   try {
     list = await getList()
-  } catch (e) {
+  } catch (e: any) {
     res.end(
       JSON.stringify({
         success: false,

+ 2 - 2
src/main/http/api/toggle.ts

@@ -6,8 +6,8 @@
 
 import { getList } from '@main/actions'
 import { broadcast } from '@main/core/agent'
-import events from '@root/common/events'
-import { findItemById } from '@root/common/hostsFn'
+import events from '@common/events'
+import { findItemById } from '@common/hostsFn'
 import { Request, Response } from 'express'
 
 const toggle = async (req: Request, res: Response) => {

+ 2 - 4
src/main/http/index.ts

@@ -4,7 +4,7 @@
  * @homepage: https://oldj.net
  */
 
-import { http_api_port } from '@root/common/constants'
+import { http_api_port } from '@common/constants'
 import express from 'express'
 import { Server } from 'http'
 import api_router from './api/index'
@@ -37,9 +37,7 @@ export const start = (http_api_only_local: boolean): boolean => {
   try {
     let listenIp = http_api_only_local ? '127.0.0.1' : '0.0.0.0'
     server = app.listen(http_api_port, listenIp, function () {
-      console.log(
-        `SwitchHosts HTTP server is listening on port ${http_api_port}!`,
-      )
+      console.log(`SwitchHosts HTTP server is listening on port ${http_api_port}!`)
       console.log(`-> http://${listenIp}:${http_api_port}`)
     })
   } catch (e) {

+ 3 - 3
src/main/libs/cron.ts

@@ -6,9 +6,9 @@
 
 import { checkUpdate, getList, refreshHosts } from '@main/actions'
 import { broadcast } from '@main/core/agent'
-import { IHostsListObject } from '@root/common/data'
-import events from '@root/common/events'
-import { flatten } from '@root/common/hostsFn'
+import { IHostsListObject } from '@common/data'
+import events from '@common/events'
+import { flatten } from '@common/hostsFn'
 
 let t: any
 let ts_last_server_check = 0

+ 1 - 1
src/main/libs/getIndex.ts

@@ -14,7 +14,7 @@ export default (): string => {
     index = 'http://127.0.0.1:8220'
   } else {
     index = url.format({
-      pathname: path.join(__dirname, 'renderer', 'index.html'),
+      pathname: path.join(__dirname, 'index.html'),
       protocol: 'file:',
       slashes: true,
     })

+ 1 - 1
src/main/libs/request.ts

@@ -7,7 +7,7 @@
 import { configGet } from '@main/actions'
 import axios, { AxiosRequestConfig } from 'axios'
 import querystring from 'querystring'
-import version from '@root/version.json'
+import version from '@/version.json'
 
 interface IParams {
   [key: string]: string | string[] | number

+ 9 - 7
src/main/libs/tracer.ts

@@ -1,6 +1,6 @@
 import { configGet } from '@main/actions'
 import { GET } from '@main/libs/request'
-import { server_url } from '@root/common/constants'
+import { server_url } from '@common/constants'
 
 class Tracer {
   data: string[]
@@ -18,12 +18,14 @@ class Tracer {
 
     let send_usage_data = await configGet('send_usage_data')
     if (send_usage_data) {
-      console.log('send usage data...')
-      await GET(`${server_url}/api/tick/`, {
-        sid: global.session_id,
-        t: 1,
-        a: this.data.join(','),
-      })
+      // Tracking is temporarily disabled.
+      console.log('Tracking is temporarily disabled.')
+      // console.log('send usage data...')
+      // await GET(`${server_url}/api/tick/`, {
+      //   sid: global.session_id,
+      //   t: 1,
+      //   a: this.data.join(','),
+      // })
     }
 
     this.data = []

+ 7 - 1
src/main/main.ts

@@ -1,3 +1,9 @@
+/**
+ * main.ts
+ * @author oldj
+ * @homepage https://oldj.net
+ */
+
 import { configAll, configGet } from '@main/actions'
 import '@main/core/agent'
 import * as message from '@main/core/message'
@@ -12,7 +18,7 @@ import checkSystemLocale from '@main/ui/checkSystemLocale'
 import * as find from '@main/ui/find'
 import { makeMainMenu } from '@main/ui/menu'
 import '@main/ui/tray'
-import version from '@root/version.json'
+import version from '@/version.json'
 import { app, BrowserWindow, ipcMain, nativeTheme } from 'electron'
 import windowStateKeeper from 'electron-window-state'
 import * as path from 'path'

+ 2 - 2
src/main/preload.ts

@@ -4,8 +4,8 @@
  * @homepage: https://oldj.net
  */
 
-import { Actions } from '@main/types'
-import { IPopupMenuOption } from '@root/common/types'
+import { Actions } from '@common/types'
+import { IPopupMenuOption } from '@common/types'
 import { contextBridge, ipcRenderer } from 'electron'
 import { EventEmitter } from 'events'
 

+ 4 - 10
src/main/types.d.ts

@@ -5,15 +5,13 @@
  */
 
 import Tracer from '@main/libs/tracer'
-import { LocaleName } from '@root/common/i18n'
+import { LocaleName } from '@common/i18n'
 import SwhDb from 'potdb'
-import { BrowserWindow, WebContents } from 'electron'
-import * as actions from './actions'
-
-export type Actions = typeof actions
+import { BrowserWindow } from 'electron'
+import * as actions from '@main/actions'
 
 export interface ActionData {
-  action: keyof Actions
+  action: keyof typeof actions
   data?: any
   callback: string
 }
@@ -22,10 +20,6 @@ export interface IHostsWriteOptions {
   sudo_pswd?: string
 }
 
-export interface IActionFunc {
-  sender: WebContents
-}
-
 declare global {
   var data_dir: string | undefined
   var swhdb: SwhDb

+ 1 - 1
src/main/ui/checkSystemLocale.ts

@@ -3,7 +3,7 @@
  * @homepage: https://oldj.net
  */
 
-import { languages, LocaleName } from '@root/common/i18n'
+import { languages, LocaleName } from '@common/i18n'
 import { app } from 'electron'
 
 const isLocaleName = (locale: string): locale is LocaleName => {

+ 1 - 1
src/main/ui/find.ts

@@ -6,7 +6,7 @@
 import { broadcast } from '@main/core/agent'
 import getIndex from '@main/libs/getIndex'
 import isDev from '@main/libs/isDev'
-import events from '@root/common/events'
+import events from '@common/events'
 import { BrowserWindow } from 'electron'
 import path from 'path'
 

+ 7 - 16
src/main/ui/menu.ts

@@ -4,16 +4,10 @@
  */
 
 import { findShow } from '@main/actions'
-import events from '@root/common/events'
-import {
-  BrowserWindow,
-  Menu,
-  MenuItem,
-  MenuItemConstructorOptions,
-  shell,
-} from 'electron'
-import { I18N, LocaleName } from '@root/common/i18n'
-import { homepage_url, feedback_url } from '@root/common/constants'
+import events from '@common/events'
+import { BrowserWindow, Menu, MenuItem, MenuItemConstructorOptions, shell } from 'electron'
+import { I18N, LocaleName } from '@common/i18n'
+import { homepage_url, feedback_url } from '@common/constants'
 import { broadcast } from '@main/core/agent'
 
 export const makeMainMenu = (locale: LocaleName = 'en') => {
@@ -123,8 +117,7 @@ export const makeMainMenu = (locale: LocaleName = 'en') => {
         },
         {
           label: lang.toggle_developer_tools, // 'Toggle Developer Tools',
-          accelerator:
-            process.platform === 'darwin' ? 'Alt+Command+I' : 'Ctrl+Shift+I',
+          accelerator: process.platform === 'darwin' ? 'Alt+Command+I' : 'Ctrl+Shift+I',
           click(item: MenuItem, focusedWindow: BrowserWindow | undefined) {
             if (focusedWindow) focusedWindow.webContents.toggleDevTools()
           },
@@ -282,8 +275,7 @@ export const makeMainMenu = (locale: LocaleName = 'en') => {
       // },
     ]
   } else if (os === 'win32' || os === 'linux') {
-    let submenu = (template[0] &&
-      template[0].submenu) as MenuItemConstructorOptions[]
+    let submenu = (template[0] && template[0].submenu) as MenuItemConstructorOptions[]
 
     if (submenu) {
       submenu.unshift({
@@ -308,8 +300,7 @@ export const makeMainMenu = (locale: LocaleName = 'en') => {
     }
 
     // VIEW
-    submenu = (template[2] &&
-      template[2].submenu) as MenuItemConstructorOptions[]
+    submenu = (template[2] && template[2].submenu) as MenuItemConstructorOptions[]
     submenu.splice(0, 4)
   }
 

+ 6 - 15
src/main/ui/tray/index.ts

@@ -7,17 +7,10 @@
 import { configGet, configSet, updateTrayTitle } from '@main/actions'
 import { broadcast } from '@main/core/agent'
 import { makeWindow } from '@main/ui/tray/window'
-import events from '@root/common/events'
-import { I18N } from '@root/common/i18n'
-import version from '@root/version.json'
-import {
-  app,
-  BrowserWindow,
-  Menu,
-  MenuItemConstructorOptions,
-  screen,
-  Tray,
-} from 'electron'
+import events from '@common/events'
+import { I18N } from '@common/i18n'
+import version from '@/version.json'
+import { app, BrowserWindow, Menu, MenuItemConstructorOptions, screen, Tray } from 'electron'
 import * as path from 'path'
 
 let tray: Tray
@@ -152,8 +145,7 @@ const getPosition = () => {
   }
 
   if (x < 0) x = 0
-  if (x + window_bounds.width > screen_bounds.width)
-    x = screen_bounds.width - window_bounds.width
+  if (x + window_bounds.width > screen_bounds.width) x = screen_bounds.width - window_bounds.width
 
   x = Math.round(x)
   y = Math.round(y)
@@ -208,8 +200,7 @@ const window = () => {
 }
 
 const show = () => {
-  let { x, y } =
-    process.platform === 'linux' ? getLinuxPosition() : getPosition()
+  let { x, y } = process.platform === 'linux' ? getLinuxPosition() : getPosition()
   win.setPosition(x, y, true)
   win.show()
   // win.focus()

+ 0 - 1
src/renderer/.env

@@ -1 +0,0 @@
-PORT=8220

+ 0 - 33
src/renderer/.umirc.ts

@@ -1,33 +0,0 @@
-import * as path from 'path'
-import { defineConfig } from 'umi'
-
-const is_dev = process.env.NODE_ENV === 'development'
-
-export default defineConfig({
-  title: 'SwitchHosts',
-  hash: true,
-  history: {
-    type: 'hash',
-  },
-  publicPath: './',
-  outputPath: '../../build/renderer',
-  nodeModulesTransform: {
-    type: 'none',
-  },
-  alias: {
-    '@main': path.join(path.dirname(__dirname), 'main'),
-    '@renderer': __dirname,
-    '@root': path.dirname(__dirname),
-    '@@': path.join(path.dirname(__dirname), 'renderer', '.umi'),
-  },
-  dynamicImport: {
-    loading: '@renderer/components/Loading',
-  },
-  cssLoader: {
-    modules: {
-      localIdentName: is_dev ? '[path][name]__[local]' : '[hash:base64]',
-    },
-  },
-  webpack5: {},
-  // mfsu: {},
-})

+ 0 - 19
src/renderer/app.tsx

@@ -1,19 +0,0 @@
-/**
- * app
- * @author: oldj
- * @homepage: https://oldj.net
- */
-
-import { ChakraProvider, ColorModeScript } from '@chakra-ui/react'
-import React from 'react'
-import theme from './theme'
-
-export function rootContainer(container: React.ReactElement) {
-  // return React.createElement(ChakraProvider, null, container)
-  return (
-    <ChakraProvider>
-      <ColorModeScript initialColorMode={theme.config.initialColorMode} />
-      {container}
-    </ChakraProvider>
-  )
-}

+ 20 - 0
src/renderer/common/PageWrapper.tsx

@@ -0,0 +1,20 @@
+/**
+ * PageWrapper.tsx
+ * @author: oldj
+ * @homepage: https://oldj.net
+ */
+
+import Loading from '@renderer/components/Loading'
+import React, { Suspense } from 'react'
+
+interface IProps {
+  children?: React.ReactNode
+}
+
+function PageWrapper(props: IProps) {
+  const { children } = props
+
+  return <Suspense fallback={<Loading />}>{children}</Suspense>
+}
+
+export default PageWrapper

+ 0 - 0
src/renderer/components/About/AboutContent.less → src/renderer/components/About/AboutContent.module.scss


+ 8 - 10
src/renderer/components/About/AboutContent.tsx

@@ -4,20 +4,18 @@
  * @homepage: https://oldj.net
  */
 
-import { useModel } from '@@/plugin-model/useModel'
 import { Box, HStack, Image, VStack } from '@chakra-ui/react'
 import { default as Link } from '@renderer/components/BrowserLink'
-import logo from '@root/assets/[email protected]'
-import acknowledgements from '@root/common/acknowledgements'
-import { homepage_url, source_url } from '@root/common/constants'
-import version from '@root/version.json'
+import logo from '@/assets/[email protected]'
+import acknowledgements from '@common/acknowledgements'
+import { homepage_url, source_url } from '@common/constants'
+import useI18n from '@renderer/models/useI18n'
+import version from '@/version.json'
 import React from 'react'
-import styles from './AboutContent.less'
+import styles from './AboutContent.module.scss'
 
-interface Props {}
-
-const AboutContent = (props: Props) => {
-  const { lang } = useModel('useI18n')
+const AboutContent = () => {
+  const { lang } = useI18n()
   const version_str = version.slice(0, 3).join('.') + ` (${version[3]})`
 
   return (

+ 0 - 0
src/renderer/components/About/index.less → src/renderer/components/About/index.module.scss


+ 5 - 12
src/renderer/components/About/index.tsx

@@ -4,24 +4,17 @@
  * @homepage: https://oldj.net
  */
 
-import { useModel } from '@@/plugin-model/useModel'
-import {
-  Button,
-  Modal,
-  ModalBody,
-  ModalContent,
-  ModalFooter,
-  ModalOverlay,
-} from '@chakra-ui/react'
+import { Button, Modal, ModalBody, ModalContent, ModalFooter, ModalOverlay } from '@chakra-ui/react'
 import AboutContent from '@renderer/components/About/AboutContent'
 import useOnBroadcast from '@renderer/core/useOnBroadcast'
-import events from '@root/common/events'
+import events from '@common/events'
 import React, { useState } from 'react'
-import styles from './index.less'
+import styles from './index.module.scss'
+import useI18n from '@renderer/models/useI18n'
 
 const About = () => {
   const [is_open, setIsOpen] = useState(false)
-  const { lang } = useModel('useI18n')
+  const { lang } = useI18n()
 
   const onClose = () => setIsOpen(false)
 

+ 1 - 1
src/renderer/components/BrowserLink.tsx

@@ -5,7 +5,7 @@
  */
 
 import { actions, agent } from '@renderer/core/agent'
-import events from '@root/common/events'
+import events from '@common/events'
 import React from 'react'
 
 interface Props {

+ 0 - 0
src/renderer/components/EditHostsInfo.less → src/renderer/components/EditHostsInfo.module.scss


+ 15 - 29
src/renderer/components/EditHostsInfo.tsx

@@ -4,7 +4,6 @@
  * @homepage: https://oldj.net
  */
 
-import { useModel } from '@@/plugin-model/useModel'
 import {
   Box,
   Button,
@@ -30,20 +29,21 @@ import ItemIcon from '@renderer/components/ItemIcon'
 import Transfer from '@renderer/components/Transfer'
 import { actions, agent } from '@renderer/core/agent'
 import useOnBroadcast from '@renderer/core/useOnBroadcast'
-import { FolderModeType, HostsType, IHostsListObject } from '@root/common/data'
-import events from '@root/common/events'
-import * as hostsFn from '@root/common/hostsFn'
+import { FolderModeType, HostsType, IHostsListObject } from '@common/data'
+import events from '@common/events'
+import * as hostsFn from '@common/hostsFn'
 import lodash from 'lodash'
 import React, { useRef, useState } from 'react'
 import { BiEdit, BiTrash } from 'react-icons/bi'
 import { v4 as uuidv4 } from 'uuid'
-import styles from './EditHostsInfo.less'
+import useHostsData from '../models/useHostsData'
+import useI18n from '../models/useI18n'
+import styles from './EditHostsInfo.module.scss'
 
 const EditHostsInfo = () => {
-  const { lang } = useModel('useI18n')
+  const { lang } = useI18n()
   const [hosts, setHosts] = useState<IHostsListObject | null>(null)
-  const { hosts_data, setList, current_hosts, setCurrentHosts } =
-    useModel('useHostsData')
+  const { hosts_data, setList, current_hosts, setCurrentHosts } = useHostsData()
   const [is_show, setIsShow] = useState(false)
   const [is_add, setIsAdd] = useState(true)
   const [is_refreshing, setIsRefreshing] = useState(false)
@@ -77,10 +77,7 @@ const EditHostsInfo = () => {
       agent.broadcast(events.select_hosts, h.id, 1000)
     } else if (data && data.id) {
       // edit
-      let h: IHostsListObject | undefined = hostsFn.findItemById(
-        hosts_data.list,
-        data.id,
-      )
+      let h: IHostsListObject | undefined = hostsFn.findItemById(hosts_data.list, data.id)
       if (h) {
         Object.assign(h, data)
         await setList([...hosts_data.list])
@@ -95,8 +92,8 @@ const EditHostsInfo = () => {
         return
       }
     } else {
-      // unknow error
-      alert('unknow error!')
+      // unknown error
+      alert('unknown error!')
     }
 
     setIsShow(false)
@@ -147,9 +144,7 @@ const EditHostsInfo = () => {
           <div>
             <Select
               value={hosts?.refresh_interval || 0}
-              onChange={(e) =>
-                onUpdate({ refresh_interval: parseInt(e.target.value) || 0 })
-              }
+              onChange={(e) => onUpdate({ refresh_interval: parseInt(e.target.value) || 0 })}
               style={{ minWidth: 120 }}
             >
               <option value={0}>{lang.never}</option>
@@ -231,9 +226,7 @@ const EditHostsInfo = () => {
     const list = hostsFn.flatten(hosts_data.list)
 
     let source_list: IHostsListObject[] = list
-      .filter(
-        (item) => !item.type || item.type === 'local' || item.type === 'remote',
-      )
+      .filter((item) => !item.type || item.type === 'local' || item.type === 'remote')
       .map((item) => {
         let o = { ...item }
         o.key = o.id
@@ -263,9 +256,7 @@ const EditHostsInfo = () => {
         <FormLabel>{lang.choice_mode}</FormLabel>
         <RadioGroup
           value={(hosts?.folder_mode || 0).toString()}
-          onChange={(v: string) =>
-            onUpdate({ folder_mode: (parseInt(v) || 0) as FolderModeType })
-          }
+          onChange={(v: string) => onUpdate({ folder_mode: (parseInt(v) || 0) as FolderModeType })}
         >
           <HStack spacing={3}>
             <Radio value="0">{lang.choice_mode_default}</Radio>
@@ -312,12 +303,7 @@ const EditHostsInfo = () => {
   )
 
   return (
-    <Drawer
-      initialFocusRef={ipt_title_ref}
-      isOpen={is_show}
-      onClose={onCancel}
-      size="lg"
-    >
+    <Drawer initialFocusRef={ipt_title_ref} isOpen={is_show} onClose={onCancel} size="lg">
       <DrawerOverlay />
       <DrawerContent>
         <DrawerHeader>

+ 2 - 2
src/renderer/components/Editor/HostsEditor.less → src/renderer/components/Editor/HostsEditor.module.scss

@@ -1,7 +1,7 @@
 @import "../../styles/common";
 
 .root {
-  .code;
+  @include code;
   width: 100%;
   height: 100%;
 }
@@ -34,7 +34,7 @@
 
   :global {
     .CodeMirror {
-      font-family: @font-editor;
+      font-family: $font-editor;
       background: var(--swh-editor-bg-color);
       color: var(--swh-editor-text-color);
     }

+ 9 - 11
src/renderer/components/Editor/HostsEditor.tsx

@@ -4,14 +4,13 @@
  * @homepage: https://oldj.net
  */
 
-import { useModel } from '@@/plugin-model/useModel'
 import StatusBar from '@renderer/components/StatusBar'
 import { actions, agent } from '@renderer/core/agent'
 import useOnBroadcast from '@renderer/core/useOnBroadcast'
-import { IHostsListObject } from '@root/common/data'
-import events from '@root/common/events'
-import { IFindShowSourceParam } from '@root/common/types'
-import wait from '@root/common/utils/wait'
+import { IHostsListObject } from '@common/data'
+import events from '@common/events'
+import { IFindShowSourceParam } from '@common/types'
+import wait from '@common/utils/wait'
 import { useDebounceFn } from 'ahooks'
 import clsx from 'clsx'
 import CodeMirror from 'codemirror'
@@ -19,15 +18,14 @@ import 'codemirror/addon/comment/comment'
 import 'codemirror/addon/selection/mark-selection'
 import React, { useEffect, useRef, useState } from 'react'
 import modeHosts from './cm_hl'
-import './codemirror.less'
-import styles from './HostsEditor.less'
+import './codemirror.module.scss'
+import styles from './HostsEditor.module.scss'
+import useHostsData from '@renderer/models/useHostsData'
 
 modeHosts()
 
-interface Props {}
-
-const HostsEditor = (props: Props) => {
-  const { current_hosts, hosts_data, isReadOnly } = useModel('useHostsData')
+const HostsEditor = () => {
+  const { current_hosts, hosts_data, isReadOnly } = useHostsData()
   const [hosts_id, setHostsId] = useState(current_hosts?.id || '0')
   const [content, setContent] = useState('')
   const [is_read_only, setIsReadOnly] = useState(true)

+ 0 - 0
src/renderer/components/Editor/codemirror.less → src/renderer/components/Editor/codemirror.module.scss


+ 0 - 0
src/renderer/components/History.less → src/renderer/components/History.module.scss


+ 11 - 21
src/renderer/components/History.tsx

@@ -4,7 +4,6 @@
  * @homepage: https://oldj.net
  */
 
-import { useModel } from '@@/plugin-model/useModel'
 import {
   Box,
   Button,
@@ -28,14 +27,16 @@ import {
 import HostsViewer from '@renderer/components/HostsViewer'
 import { actions } from '@renderer/core/agent'
 import useOnBroadcast from '@renderer/core/useOnBroadcast'
-import { IHostsHistoryObject } from '@root/common/data'
-import events from '@root/common/events'
+import { IHostsHistoryObject } from '@common/data'
+import events from '@common/events'
 import clsx from 'clsx'
 import dayjs from 'dayjs'
 import prettyBytes from 'pretty-bytes'
 import React, { useState } from 'react'
 import { BiDetail, BiHelpCircle, BiHistory, BiTrash } from 'react-icons/bi'
-import styles from './History.less'
+import useConfigs from '../models/useConfigs'
+import useI18n from '../models/useI18n'
+import styles from './History.module.scss'
 
 interface IHistoryProps {
   list: IHostsHistoryObject[]
@@ -45,7 +46,7 @@ interface IHistoryProps {
 
 const HistoryList = (props: IHistoryProps): React.ReactElement => {
   const { list, selected_item, setSelectedItem } = props
-  const { lang } = useModel('useI18n')
+  const { lang } = useI18n()
 
   if (list.length === 0) {
     return (
@@ -60,13 +61,7 @@ const HistoryList = (props: IHistoryProps): React.ReactElement => {
       <Box flex={1} mr={3} borderWidth="1px" borderRadius="md">
         <HostsViewer content={selected_item ? selected_item.content : ''} />
       </Box>
-      <List
-        w="200px"
-        h="100%"
-        overflow="auto"
-        borderWidth="1px"
-        borderRadius="md"
-      >
+      <List w="200px" h="100%" overflow="auto" borderWidth="1px" borderRadius="md">
         {list.map((item) => (
           <ListItem
             key={item.id}
@@ -81,9 +76,7 @@ const HistoryList = (props: IHistoryProps): React.ReactElement => {
                 <BiDetail />
               </Box>
               <VStack align="left" spacing={0}>
-                <Box>
-                  {dayjs(item.add_time_ms).format('YYYY-MM-DD HH:mm:ss')}
-                </Box>
+                <Box>{dayjs(item.add_time_ms).format('YYYY-MM-DD HH:mm:ss')}</Box>
                 <HStack lineHeight="14px" fontSize="9px" opacity={0.6}>
                   <Box>{item.content.split('\n').length} lines</Box>
                   <Box>{prettyBytes(item.content.length)}</Box>
@@ -107,14 +100,14 @@ const Loading = (): React.ReactElement => {
 }
 
 const History = () => {
-  const { configs, updateConfigs } = useModel('useConfigs')
+  const { configs, updateConfigs } = useConfigs()
   const [is_open, setIsOpen] = useState(false)
   const [is_loading, setIsLoading] = useState(false)
   const [list, setList] = useState<IHostsHistoryObject[]>([])
   const [selected_item, setSelectedItem] = useState<IHostsHistoryObject>()
   // const btn_close = useRef(null)
 
-  const { lang } = useModel('useI18n')
+  const { lang } = useI18n()
 
   const loadData = async () => {
     setIsLoading(true)
@@ -213,10 +206,7 @@ const History = () => {
                 ))}
               </Select>
             </Box>
-            <Tooltip
-              label={lang.system_hosts_history_help}
-              aria-label="A tooltip"
-            >
+            <Tooltip label={lang.system_hosts_history_help} aria-label="A tooltip">
               <Box ml={3}>
                 <BiHelpCircle />
               </Box>

+ 1 - 1
src/renderer/components/HostsViewer.less → src/renderer/components/HostsViewer.module.scss

@@ -1,7 +1,7 @@
 @import "../styles/common";
 
 .root {
-  .code;
+  @include code;
   height: 100%;
 }
 

+ 2 - 6
src/renderer/components/HostsViewer.tsx

@@ -6,7 +6,7 @@
 
 import StatusBar from '@renderer/components/StatusBar'
 import React from 'react'
-import styles from './HostsViewer.less'
+import styles from './HostsViewer.module.scss'
 
 interface Props {
   content: string
@@ -27,11 +27,7 @@ const HostsViewer = (props: Props) => {
           <Line line={line} key={idx} />
         ))}
       </div>
-      <StatusBar
-        line_count={lines.length}
-        bytes={content.length}
-        read_only={true}
-      />
+      <StatusBar line_count={lines.length} bytes={content.length} read_only={true} />
     </div>
   )
 }

+ 3 - 3
src/renderer/components/Lang.tsx

@@ -4,9 +4,9 @@
  * @homepage: https://oldj.net
  */
 
-import { useModel } from '@@/plugin-model/useModel'
-import { LocaleName } from '@root/common/i18n'
+import { LocaleName } from '@common/i18n'
 import React from 'react'
+import useI18n from '@renderer/models/useI18n'
 
 interface Props {
   locale: LocaleName
@@ -14,7 +14,7 @@ interface Props {
 }
 
 const Lang = (props: Props): React.ReactElement | null => {
-  const { locale } = useModel('useI18n')
+  const { locale } = useI18n()
 
   if (locale !== props.locale) {
     return null

+ 0 - 0
src/renderer/components/LeftPanel/SystemHostsItem.less → src/renderer/components/LeftPanel/SystemHostsItem.module.scss


+ 7 - 11
src/renderer/components/LeftPanel/SystemHostsItem.tsx

@@ -4,17 +4,16 @@
  * @homepage: https://oldj.net
  */
 
-import { useModel } from '@@/plugin-model/useModel'
 import ItemIcon from '@renderer/components/ItemIcon'
 import clsx from 'clsx'
 import React from 'react'
-import styles from './SystemHostsItem.less'
+import styles from './SystemHostsItem.module.scss'
+import useI18n from '@renderer/models/useI18n'
+import useHostsData from '@renderer/models/useHostsData'
 
-interface Props {}
-
-const SystemHostsItem = (props: Props) => {
-  const { i18n } = useModel('useI18n')
-  const { current_hosts, setCurrentHosts } = useModel('useHostsData')
+const SystemHostsItem = () => {
+  const { i18n } = useI18n()
+  const { current_hosts, setCurrentHosts } = useHostsData()
 
   const is_selected = !current_hosts
 
@@ -23,10 +22,7 @@ const SystemHostsItem = (props: Props) => {
   }
 
   return (
-    <div
-      className={clsx(styles.root, is_selected && styles.selected)}
-      onClick={showSystemHosts}
-    >
+    <div className={clsx(styles.root, is_selected && styles.selected)} onClick={showSystemHosts}>
       <span className={styles.icon}>
         <ItemIcon type="system" />
       </span>

+ 0 - 0
src/renderer/components/LeftPanel/Trashcan.less → src/renderer/components/LeftPanel/Trashcan.module.scss


+ 9 - 13
src/renderer/components/LeftPanel/Trashcan.tsx

@@ -4,22 +4,20 @@
  * @homepage: https://oldj.net
  */
 
-import { useModel } from '@@/plugin-model/useModel'
 import { Center } from '@chakra-ui/react'
 import TrashcanItem from '@renderer/components/LeftPanel/TrashcanItem'
-import list_styles from '@renderer/components/List/index.less'
+import list_styles from '@renderer/components/List/index.module.scss'
 import { Tree } from '@renderer/components/Tree'
-import { ITrashcanListObject } from '@root/common/data'
+import { ITrashcanListObject } from '@common/data'
 import React, { useEffect, useState } from 'react'
 import { BiChevronRight } from 'react-icons/bi'
-import styles from './Trashcan.less'
+import styles from './Trashcan.module.scss'
+import useI18n from '@renderer/models/useI18n'
+import useHostsData from '@renderer/models/useHostsData'
 
-interface Props {}
-
-const Trashcan = (props: Props) => {
-  const { lang } = useModel('useI18n')
-  const { hosts_data, current_hosts, setCurrentHosts } =
-    useModel('useHostsData')
+const Trashcan = () => {
+  const { lang } = useI18n()
+  const { hosts_data, current_hosts, setCurrentHosts } = useHostsData()
   const [trash_list, setTrashList] = useState<ITrashcanListObject[]>([])
   const [is_collapsed, setIsCollapsed] = useState(true)
 
@@ -66,9 +64,7 @@ const Trashcan = (props: Props) => {
     <div className={styles.root}>
       <Tree
         data={trash_list}
-        nodeRender={(item) => (
-          <TrashcanItem data={item as ITrashcanListObject} />
-        )}
+        nodeRender={(item) => <TrashcanItem data={item as ITrashcanListObject} />}
         collapseArrow={
           <Center w="20px" h="20px">
             <BiChevronRight />

+ 0 - 0
src/renderer/components/LeftPanel/TrashcanItem.less → src/renderer/components/LeftPanel/TrashcanItem.module.scss


+ 8 - 9
src/renderer/components/LeftPanel/TrashcanItem.tsx

@@ -4,15 +4,16 @@
  * @homepage: https://oldj.net
  */
 
-import { useModel } from '@@/plugin-model/useModel'
 import ItemIcon from '@renderer/components/ItemIcon'
-import list_item_styles from '@renderer/components/List/ListItem.less'
+import list_item_styles from '@renderer/components/List/ListItem.module.scss'
 import { actions } from '@renderer/core/agent'
 import { PopupMenu } from '@renderer/core/PopupMenu'
-import { ITrashcanListObject } from '@root/common/data'
+import { ITrashcanListObject } from '@common/data'
+import useI18n from '@renderer/models/useI18n'
 import clsx from 'clsx'
 import React from 'react'
-import styles from './TrashcanItem.less'
+import styles from './TrashcanItem.module.scss'
+import useHostsData from '@renderer/models/useHostsData'
 
 interface Props {
   data: ITrashcanListObject
@@ -20,8 +21,8 @@ interface Props {
 
 const TrashcanItem = (props: Props) => {
   const { data } = props
-  const { lang } = useModel('useI18n')
-  const { hosts_data, loadHostsData } = useModel('useHostsData')
+  const { lang } = useI18n()
+  const { hosts_data, loadHostsData } = useHostsData()
 
   const onSelect = (i: any) => {
     console.log(i)
@@ -87,9 +88,7 @@ const TrashcanItem = (props: Props) => {
 
         {data.data.title || lang.untitled}
 
-        {data.is_root ? (
-          <span className={styles.count}>{data.children?.length || 0}</span>
-        ) : null}
+        {data.is_root ? <span className={styles.count}>{data.children?.length || 0}</span> : null}
       </div>
     </div>
   )

+ 1 - 1
src/renderer/components/LeftPanel/index.less → src/renderer/components/LeftPanel/index.module.scss

@@ -9,6 +9,6 @@
 
 :global(.platform-win32) {
   .list {
-    .swh-scroll-y();
+    @include swh-scroll-y();
   }
 }

+ 6 - 5
src/renderer/components/LeftPanel/index.tsx

@@ -4,22 +4,23 @@
  * @homepage: https://oldj.net
  */
 
-import { useModel } from '@@/plugin-model/useModel'
 import Trashcan from '@renderer/components/LeftPanel/Trashcan'
 import List from '@renderer/components/List'
 import { agent } from '@renderer/core/agent'
 import { PopupMenu } from '@renderer/core/PopupMenu'
-import events from '@root/common/events'
+import events from '@common/events'
+import useI18n from '@renderer/models/useI18n'
 import React from 'react'
-import styles from './index.less'
+import styles from './index.module.scss'
+import useHostsData from '@renderer/models/useHostsData'
 
 interface Props {
   width: number
 }
 
 const Index = (props: Props) => {
-  const { lang } = useModel('useI18n')
-  const { hosts_data } = useModel('useHostsData')
+  const { lang } = useI18n()
+  const { hosts_data } = useHostsData()
 
   const menu = new PopupMenu([
     {

+ 0 - 0
src/renderer/components/List/ListItem.less → src/renderer/components/List/ListItem.module.scss


+ 9 - 8
src/renderer/components/List/ListItem.tsx

@@ -4,21 +4,22 @@
  * @homepage: https://oldj.net
  */
 
-import { useModel } from '@@/plugin-model/useModel'
 import ItemIcon from '@renderer/components/ItemIcon'
 import SwitchButton from '@renderer/components/SwitchButton'
 import { actions, agent } from '@renderer/core/agent'
 import { PopupMenu } from '@renderer/core/PopupMenu'
-import { IHostsListObject } from '@root/common/data'
-import { updateOneItem } from '@root/common/hostsFn'
+import { IHostsListObject } from '@common/data'
+import { updateOneItem } from '@common/hostsFn'
 import clsx from 'clsx'
 import React, { useEffect, useRef, useState } from 'react'
 import { BiEdit } from 'react-icons/bi'
 import { Center, ToastId, useToast } from '@chakra-ui/react'
 import scrollIntoView from 'smooth-scroll-into-view-if-needed'
-import styles from './ListItem.less'
-import events from '@root/common/events'
-import { IMenuItemOption } from '@root/common/types'
+import styles from './ListItem.module.scss'
+import events from '@common/events'
+import { IMenuItemOption } from '@common/types'
+import useI18n from '@renderer/models/useI18n'
+import useHostsData from '@renderer/models/useHostsData'
 
 interface Props {
   data: IHostsListObject
@@ -28,8 +29,8 @@ interface Props {
 
 const ListItem = (props: Props) => {
   const { data, is_tray, selected_ids } = props
-  const { lang, i18n } = useModel('useI18n')
-  const { hosts_data, setList, current_hosts, setCurrentHosts } = useModel('useHostsData')
+  const { lang, i18n } = useI18n()
+  const { hosts_data, setList, current_hosts, setCurrentHosts } = useHostsData()
   const [is_collapsed, setIsCollapsed] = useState(!!data.is_collapsed)
   const [is_on, setIsOn] = useState(data.on)
   const el = useRef<HTMLDivElement>(null)

+ 0 - 0
src/renderer/components/List/index.less → src/renderer/components/List/index.module.scss


部分文件因为文件数量过多而无法显示