Feature: sync with picgo 2.4.0 beta 1

This commit is contained in:
萌萌哒赫萝 2023-05-05 17:51:49 +08:00
parent bda1421aa5
commit e8d54fac4c
33 changed files with 1154 additions and 81 deletions

View File

@ -97,6 +97,7 @@
"@types/node": "^16.10.2",
"@types/request-promise-native": "^1.0.17",
"@types/semver": "^7.3.8",
"@types/tunnel": "^0.0.3",
"@types/uuid": "^9.0.0",
"@types/write-file-atomic": "^4.0.0",
"@typescript-eslint/eslint-plugin": "^5.48.0",

View File

@ -27,6 +27,31 @@ SHOW_DEVTOOLS: Show Devtools
CURRENT_PICBED: Current Picbed
START_WATCH_CLIPBOARD: Start Watch Clipboard
STOP_WATCH_CLIPBOARD: Stop Watch Clipboard
OPEN_TOOLBOX: Open Toolbox
TOOLBOX: Toolbox
TOOLBOX_TITLE: Troubleshoot PicList runtime issues
TOOLBOX_SUB_TITLE: Scan the following items immediately to fix usage issues
TOOLBOX_CHECK_CONFIG_FILE_BROKEN: Check if the configuration file is damaged
TOOLBOX_CHECK_GALLERY_FILE_BROKEN: Check if the album file is damaged
TOOLBOX_CHECK_PROBLEM_WITH_CLIPBOARD_PIC_UPLOAD: Check if there is a problem with clipboard picture upload
TOOLBOX_CHECK_PROBLEM_WITH_PROXY: Check if the proxy settings are normal
TOOLBOX_FIX_DONE_NEED_RELOAD: Repair completed, need to restart to take effect, restart or not
TOOLBOX_CANT_AUTO_FIX: Unable to automatically repair, please repair the following problems yourself
TOOLBOX_START_SCAN: Start scanning
TOOLBOX_RE_SCAN: Re scanning
TOOLBOX_START_FIX: Start fixing
TOOLBOX_SUCCESS_TIPS: Congratulations, no problems were found
TOOLBOX_CHECK_CONFIG_FILE_PATH_TIPS: "The configuration file path is: ${path}"
TOOLBOX_CHECK_CONFIG_FILE_BROKEN_TIPS: The configuration file is damaged
TOOLBOX_CHECK_GALLERY_FILE_PATH_TIPS: "The album file path is: ${path}"
TOOLBOX_CHECK_GALLERY_FILE_BROKEN_TIPS: The album file is damaged
TOOLBOX_CHECK_PROXY_SUCCESS_TIPS: Proxy settings normal
TOOLBOX_CHECK_PROXY_NO_PROXY_TIPS: No proxy settings
TOOLBOX_CHECK_PROXY_PROXY_IS_NOT_CORRECT: Proxy settings incorrect
TOOLBOX_CHECK_PROXY_PROXY_IS_NOT_WORKING: Proxy settings unavailable
TOOLBOX_CHECK_CLIPBOARD_FILE_PATH_TIPS: "The temporary folder path for clipboard pictures is: ${path}"
TOOLBOX_CHECK_CLIPBOARD_FILE_PATH_NOT_EXIST_TIPS: "The temporary folder for clipboard pictures does not exist: ${path}"
TOOLBOX_CHECK_CLIPBOARD_FILE_PATH_ERROR_TIPS: "Please create the folder yourself: ${path}"
# ---renderer i18n begin---
@ -63,6 +88,8 @@ CHANGE_IMAGE_URL_SUCCEED: Change Image URL Succeed
COPY_LINK_SUCCEED: Copy Link Succeed
BATCH_COPY_LINK_SUCCEED: Batch Copy Link Succeed
FILE_RENAME: File Rename
COPY_FILE_PATH: Copy file path
OPEN_FILE_PATH: Open file path
GALLERY_SYNC_DELETE: Cloud Sync Delete
GALLERY_SYNC_DELETE_NOTICE_TITLE: Notice
GALLERY_SYNC_DELETE_NOTICE_SUCCEED: Cloud Delete Succeed

View File

@ -27,6 +27,32 @@ SHOW_DEVTOOLS: 打开开发者工具
CURRENT_PICBED: 当前图床
START_WATCH_CLIPBOARD: 开始监听剪贴板
STOP_WATCH_CLIPBOARD: 停止监听剪贴板
OPEN_TOOLBOX: 打开修复工具箱
TOOLBOX: 工具箱
TOOLBOX_TITLE: 排查 PicList 运行时问题
TOOLBOX_SUB_TITLE: 立即扫描以下项目,修复使用问题
TOOLBOX_CHECK_CONFIG_FILE_BROKEN: 检查配置文件是否损坏
TOOLBOX_CHECK_GALLERY_FILE_BROKEN: 检查相册文件是否损坏
TOOLBOX_CHECK_PROBLEM_WITH_CLIPBOARD_PIC_UPLOAD: 检查剪贴板图片上传是否存在问题
TOOLBOX_CHECK_PROBLEM_WITH_PROXY: 检查代理设置是否正常
TOOLBOX_FIX_DONE_NEED_RELOAD: 修复完成,需要重启生效,是否重启
TOOLBOX_CANT_AUTO_FIX: 无法自动修复,请自行修复以下问题
TOOLBOX_START_SCAN: 开始扫描
TOOLBOX_RE_SCAN: 重新扫描
TOOLBOX_START_FIX: 开始修复
TOOLBOX_SUCCESS_TIPS: 恭喜你,没有检查出问题
TOOLBOX_CHECK_CONFIG_FILE_PATH_TIPS: 配置文件路径是:${path}
TOOLBOX_CHECK_CONFIG_FILE_BROKEN_TIPS: 配置文件已损坏
TOOLBOX_CHECK_GALLERY_FILE_PATH_TIPS: 相册文件路径是:${path}
TOOLBOX_CHECK_GALLERY_FILE_BROKEN_TIPS: 相册文件已损坏
TOOLBOX_CHECK_PROXY_SUCCESS_TIPS: 代理设置正常
TOOLBOX_CHECK_PROXY_NO_PROXY_TIPS: 无代理设置
TOOLBOX_CHECK_PROXY_PROXY_IS_NOT_CORRECT: 代理设置不正确
TOOLBOX_CHECK_PROXY_PROXY_IS_NOT_WORKING: 代理设置不可用
TOOLBOX_CHECK_CLIPBOARD_FILE_PATH_TIPS: 剪贴板图片临时文件夹路径是:${path}
TOOLBOX_CHECK_CLIPBOARD_FILE_PATH_NOT_EXIST_TIPS: 剪贴板图片临时文件夹不存在:${path}
TOOLBOX_CHECK_CLIPBOARD_FILE_PATH_ERROR_TIPS: 请自行创建文件夹:${path}
# ---renderer i18n begin---
CHOOSE_YOUR_DEFAULT_PICBED: 选择 ${d} 作为你默认图床:
@ -62,6 +88,8 @@ CHANGE_IMAGE_URL_SUCCEED: 修改图片URL成功
COPY_LINK_SUCCEED: 复制链接成功
BATCH_COPY_LINK_SUCCEED: 批量复制链接成功
FILE_RENAME: 文件改名
COPY_FILE_PATH: 复制文件路径
OPEN_FILE_PATH: 打开文件路径
GALLERY_SYNC_DELETE: 删除云端
GALLERY_SYNC_DELETE_NOTICE_TITLE: 通知
GALLERY_SYNC_DELETE_NOTICE_SUCCEED: 云端删除成功

View File

@ -27,6 +27,32 @@ SHOW_DEVTOOLS: 開啟開發者工具
CURRENT_PICBED: 當前圖床
START_WATCH_CLIPBOARD: 開始監聽剪貼簿
STOP_WATCH_CLIPBOARD: 停止監聽剪貼簿
OPEN_TOOLBOX: 開啟修復工具箱
TOOLBOX: 工具箱
TOOLBOX_TITLE: 排查 PicList 執行時問題
TOOLBOX_SUB_TITLE: 立即掃描以下項目,修復使用問題
TOOLBOX_CHECK_CONFIG_FILE_BROKEN: 檢查配置文件是否損壞
TOOLBOX_CHECK_GALLERY_FILE_BROKEN: 檢查相冊文件是否損壞
TOOLBOX_CHECK_PROBLEM_WITH_CLIPBOARD_PIC_UPLOAD: 檢查剪貼板圖片上傳是否存在問題
TOOLBOX_CHECK_PROBLEM_WITH_PROXY: 檢查代理設置是否正常
TOOLBOX_FIX_DONE_NEED_RELOAD: 修復完成,需要重啓生效,是否重啓
TOOLBOX_CANT_AUTO_FIX: 無法自動修復,請自行修復以下問題
TOOLBOX_START_SCAN: 開始掃描
TOOLBOX_RE_SCAN: 重新掃描
TOOLBOX_START_FIX: 開始修復
TOOLBOX_SUCCESS_TIPS: 恭喜你,沒有檢查出問題
TOOLBOX_CHECK_CONFIG_FILE_PATH_TIPS: 配置文件路徑是:${path}
TOOLBOX_CHECK_CONFIG_FILE_BROKEN_TIPS: 配置文件已損壞
TOOLBOX_CHECK_GALLERY_FILE_PATH_TIPS: 相冊文件路徑是:${path}
TOOLBOX_CHECK_GALLERY_FILE_BROKEN_TIPS: 相冊文件已損壞
TOOLBOX_CHECK_PROXY_SUCCESS_TIPS: 代理設置正常
TOOLBOX_CHECK_PROXY_NO_PROXY_TIPS: 無代理設置
TOOLBOX_CHECK_PROXY_PROXY_IS_NOT_CORRECT: 代理設置不正確
TOOLBOX_CHECK_PROXY_PROXY_IS_NOT_WORKING: 代理設置不可用
TOOLBOX_CHECK_CLIPBOARD_FILE_PATH_TIPS: 剪貼板圖片臨時文件夾路徑是:${path}
TOOLBOX_CHECK_CLIPBOARD_FILE_PATH_NOT_EXIST_TIPS: 剪貼板圖片臨時文件夾不存在:${path}
TOOLBOX_CHECK_CLIPBOARD_FILE_PATH_ERROR_TIPS: 請自行創建文件夾:${path}
# ---renderer i18n begin---
CHOOSE_YOUR_DEFAULT_PICBED: 選擇 ${d} 作為你的預設圖床:
@ -61,7 +87,9 @@ CHANGE_IMAGE_URL: 修改圖片URL
CHANGE_IMAGE_URL_SUCCEED: 修改圖片URL成功
COPY_LINK_SUCCEED: 複製連結成功
BATCH_COPY_LINK_SUCCEED: 批量複製連結成功
FILE_RENAME: 文件改名
FILE_RENAME: 檔案改名
COPY_FILE_PATH: 複製檔案路徑
OPEN_FILE_PATH: 打開檔案路徑
GALLERY_SYNC_DELETE: 刪除雲端
GALLERY_SYNC_DELETE_NOTICE_TITLE: 通知
GALLERY_SYNC_DELETE_NOTICE_SUCCEED: 雲端刪除成功

View File

@ -15,3 +15,7 @@ export const MINI_WINDOW_URL = isDevelopment
export const RENAME_WINDOW_URL = process.env.NODE_ENV === 'development'
? `${(process.env.WEBPACK_DEV_SERVER_URL as string)}#rename-page`
: 'picgo://./index.html#rename-page'
export const TOOLBOX_WINDOW_URL = process.env.NODE_ENV === 'development'
? `${(process.env.WEBPACK_DEV_SERVER_URL as string)}#toolbox-page`
: 'picgo://./index.html#toolbox-page'

View File

@ -2,7 +2,8 @@ import {
SETTING_WINDOW_URL,
TRAY_WINDOW_URL,
MINI_WINDOW_URL,
RENAME_WINDOW_URL
RENAME_WINDOW_URL,
TOOLBOX_WINDOW_URL
} from './constants'
import { IRemoteNoticeTriggerHook, IWindowList } from '#/types/enum'
import bus from '@core/bus'
@ -12,6 +13,7 @@ import { TOGGLE_SHORTKEY_MODIFIED_MODE } from '#/events/constants'
import { app } from 'electron'
import { remoteNoticeHandler } from '../remoteNotice'
import picgo from '~/main/apis/core/picgo'
import { T } from '~/main/i18n'
const windowList = new Map<IWindowList, IWindowListItem>()
@ -189,4 +191,51 @@ windowList.set(IWindowList.RENAME_WINDOW, {
}
})
windowList.set(IWindowList.TOOLBOX_WINDOW, {
isValid: true,
multiple: false,
options () {
const options: IBrowserWindowOptions = {
height: 450,
width: 800,
show: false,
frame: true,
center: true,
fullscreenable: false,
resizable: false,
title: `PicList ${T('TOOLBOX')}`,
vibrancy: 'ultra-dark',
icon: `${__static}/logo.png`,
webPreferences: {
backgroundThrottling: false,
nodeIntegration: !!process.env.ELECTRON_NODE_INTEGRATION,
contextIsolation: !process.env.ELECTRON_NODE_INTEGRATION,
nodeIntegrationInWorker: true,
webSecurity: false
}
}
if (process.platform !== 'darwin') {
options.backgroundColor = '#3f3c37'
options.autoHideMenuBar = true
options.transparent = false
}
return options
},
async callback (window, windowManager) {
window.loadURL(TOOLBOX_WINDOW_URL)
const currentWindow = windowManager.getAvailableWindow()
if (currentWindow && currentWindow.isVisible()) {
const bounds = currentWindow.getBounds()
const positionX = bounds.x + bounds.width / 2 - 400
let positionY
if (bounds.height > 400) {
positionY = bounds.y + bounds.height / 2 - 225
} else {
positionY = bounds.y + bounds.height / 2
}
window.setPosition(positionX, positionY, false)
}
}
})
export default windowList

View File

@ -9,7 +9,7 @@ if (!fs.pathExistsSync(STORE_PATH)) {
fs.mkdirpSync(STORE_PATH)
}
const CONFIG_PATH: string = dbPathChecker()
const DB_PATH: string = getGalleryDBPath().dbPath
export const DB_PATH: string = getGalleryDBPath().dbPath
class ConfigStore {
private db: JSONStore

View File

@ -116,6 +116,13 @@ const buildMainPageMenu = (win: BrowserWindow) => {
win?.webContents?.send(SHOW_MAIN_PAGE_QRCODE)
}
},
{
label: T('OPEN_TOOLBOX'),
click () {
const window = windowManager.create(IWindowList.TOOLBOX_WINDOW)
window?.show()
}
},
{
label: T('SHOW_DEVTOOLS'),
click () {

View File

@ -1,95 +1,57 @@
import { ipcMain, IpcMainEvent } from 'electron'
import { IRPCActionType } from '~/universal/types/enum'
import { RPC_ACTIONS } from '#/events/constants'
import {
deleteUploaderConfig,
getUploaderConfigList,
resetUploaderConfig,
selectUploaderConfig,
updateUploaderConfig
} from '~/main/utils/handleUploaderConfig'
import { configRouter } from './routes/config'
import { toolboxRouter } from './routes/toolbox'
import { systemRouter } from './routes/system'
class RPCServer {
start () {
ipcMain.on(RPC_ACTIONS, (event: IpcMainEvent, action: IRPCActionType, args: any[], callbackId: string) => {
class RPCServer implements IRPCServer {
private routes: IRPCRoutes = new Map()
private rpcEventHandler = async (event: IpcMainEvent, action: IRPCActionType, args: any[], callbackId: string) => {
try {
switch (action) {
case IRPCActionType.GET_PICBED_CONFIG_LIST: {
const configList = this.getPicBedConfigList(args as IGetUploaderConfigListArgs)
this.sendBack(event, action, configList, callbackId)
break
const handler = this.routes.get(action)
if (!handler) {
return this.sendBack(event, action, null, callbackId)
}
case IRPCActionType.DELETE_PICBED_CONFIG: {
const res = this.deleteUploaderConfig(args as IDeleteUploaderConfigArgs)
const res = await handler?.(args, event)
this.sendBack(event, action, res, callbackId)
break
}
case IRPCActionType.SELECT_UPLOADER: {
this.selectUploaderConfig(args as ISelectUploaderConfigArgs)
this.sendBack(event, action, true, callbackId)
break
}
case IRPCActionType.UPDATE_UPLOADER_CONFIG: {
this.updateUploaderConfig(args as IUpdateUploaderConfigArgs)
this.sendBack(event, action, true, callbackId)
break
}
case IRPCActionType.RESET_UPLOADER_CONFIG: {
this.resetUploaderConfig(args as IResetUploaderConfigArgs)
this.sendBack(event, action, true, callbackId)
break
}
default: {
this.sendBack(event, action, null, callbackId)
break
}
}
} catch (e) {
this.sendBack(event, action, null, callbackId)
}
})
}
/**
* if sendback data is null, then it means that the action is not supported or error occurs
* if there is no callbackId, then do not send back
*/
private sendBack (event: IpcMainEvent, action: IRPCActionType, data: any, callbackId: string) {
if (callbackId) {
event.sender.send(RPC_ACTIONS, data, action, callbackId)
}
private getPicBedConfigList (args: IGetUploaderConfigListArgs) {
const [type] = args
const config = getUploaderConfigList(type)
return config
}
private deleteUploaderConfig (args: IDeleteUploaderConfigArgs) {
const [type, id] = args
const config = deleteUploaderConfig(type, id)
return config
start () {
ipcMain.on(RPC_ACTIONS, this.rpcEventHandler)
}
private selectUploaderConfig (args: ISelectUploaderConfigArgs) {
const [type, id] = args
const config = selectUploaderConfig(type, id)
return config
use (routes: IRPCRoutes) {
for (const [action, handler] of routes) {
this.routes.set(action, handler)
}
}
private updateUploaderConfig (args: IUpdateUploaderConfigArgs) {
const [type, id, config] = args
const res = updateUploaderConfig(type, id, config)
return res
}
private resetUploaderConfig (args: IResetUploaderConfigArgs) {
const [type, id] = args
const res = resetUploaderConfig(type, id)
return res
stop () {
ipcMain.off(RPC_ACTIONS, this.rpcEventHandler)
}
}
const rpcServer = new RPCServer()
rpcServer.use(configRouter.routes())
rpcServer.use(toolboxRouter.routes())
rpcServer.use(systemRouter.routes())
export {
rpcServer
}

View File

@ -0,0 +1,13 @@
import { IRPCActionType } from '~/universal/types/enum'
export class RPCRouter implements IRPCRouter {
private routeMap: IRPCRoutes = new Map()
add = <T>(action: IRPCActionType, handler: IRPCHandler<T>) => {
this.routeMap.set(action, handler)
return this
}
routes () {
return this.routeMap
}
}

View File

@ -0,0 +1,36 @@
import { IRPCActionType } from '~/universal/types/enum'
import { RPCRouter } from '../router'
import { deleteUploaderConfig, getUploaderConfigList, selectUploaderConfig, updateUploaderConfig, resetUploaderConfig } from '~/main/utils/handleUploaderConfig'
const configRouter = new RPCRouter()
configRouter
.add(IRPCActionType.GET_PICBED_CONFIG_LIST, async (args) => {
const [type] = args as IGetUploaderConfigListArgs
const config = getUploaderConfigList(type)
return config
})
.add(IRPCActionType.DELETE_PICBED_CONFIG, async (args) => {
const [type, id] = args as IDeleteUploaderConfigArgs
const config = deleteUploaderConfig(type, id)
return config
})
.add(IRPCActionType.SELECT_UPLOADER, async (args) => {
const [type, id] = args as ISelectUploaderConfigArgs
selectUploaderConfig(type, id)
return true
})
.add(IRPCActionType.UPDATE_UPLOADER_CONFIG, async (args) => {
const [type, id, config] = args as IUpdateUploaderConfigArgs
updateUploaderConfig(type, id, config)
return true
})
.add(IRPCActionType.RESET_UPLOADER_CONFIG, async (args) => {
const [type, id] = args as IUpdateUploaderConfigArgs
resetUploaderConfig(type, id)
return true
})
export {
configRouter
}

View File

@ -0,0 +1,23 @@
import { IRPCActionType } from '~/universal/types/enum'
import { RPCRouter } from '../router'
import { app, clipboard, shell } from 'electron'
const systemRouter = new RPCRouter()
systemRouter
.add(IRPCActionType.RELOAD_APP, async () => {
app.relaunch()
app.exit(0)
})
.add(IRPCActionType.OPEN_FILE, async (args) => {
const [filePath] = args as IOpenFileArgs
shell.openPath(filePath)
})
.add(IRPCActionType.COPY_TEXT, async (args) => {
const [text] = args as ICopyTextArgs
return clipboard.writeText(text)
})
export {
systemRouter
}

View File

@ -0,0 +1,77 @@
import fs from 'fs-extra'
import path from 'path'
import { dbPathChecker, defaultConfigPath } from '~/main/apis/core/datastore/dbChecker'
import { IToolboxItemCheckStatus, IToolboxItemType } from '~/universal/types/enum'
import { CLIPBOARD_IMAGE_FOLDER } from '~/universal/utils/static'
import { sendToolboxResWithType } from './utils'
import { T } from '~/main/i18n'
const sendToolboxRes = sendToolboxResWithType(IToolboxItemType.HAS_PROBLEM_WITH_CLIPBOARD_PIC_UPLOAD)
const defaultClipboardImagePath = path.join(defaultConfigPath, CLIPBOARD_IMAGE_FOLDER)
export const checkClipboardUploadMap: IToolboxCheckerMap<
IToolboxItemType.HAS_PROBLEM_WITH_CLIPBOARD_PIC_UPLOAD
> = {
[IToolboxItemType.HAS_PROBLEM_WITH_CLIPBOARD_PIC_UPLOAD]: async (event) => {
sendToolboxRes(event, {
status: IToolboxItemCheckStatus.LOADING
})
const configFilePath = dbPathChecker()
if (fs.existsSync(configFilePath)) {
const dirPath = path.dirname(configFilePath)
const clipboardImagePath = path.join(dirPath, CLIPBOARD_IMAGE_FOLDER)
if (fs.existsSync(clipboardImagePath)) {
sendToolboxRes(event, {
status: IToolboxItemCheckStatus.SUCCESS,
msg: T('TOOLBOX_CHECK_CLIPBOARD_FILE_PATH_TIPS', {
path: clipboardImagePath
}),
value: clipboardImagePath
})
} else {
sendToolboxRes(event, {
status: IToolboxItemCheckStatus.ERROR,
msg: T('TOOLBOX_CHECK_CLIPBOARD_FILE_PATH_NOT_EXIST_TIPS', {
path: clipboardImagePath
}),
value: path.dirname(clipboardImagePath)
})
}
} else {
sendToolboxRes(event, {
status: IToolboxItemCheckStatus.ERROR,
msg: T('TOOLBOX_CHECK_CLIPBOARD_FILE_PATH_NOT_EXIST_TIPS', {
path: defaultClipboardImagePath
}),
value: path.dirname(defaultClipboardImagePath)
})
}
}
}
export const fixClipboardUploadMap: IToolboxFixMap<
IToolboxItemType.HAS_PROBLEM_WITH_CLIPBOARD_PIC_UPLOAD
> = {
[IToolboxItemType.HAS_PROBLEM_WITH_CLIPBOARD_PIC_UPLOAD]: async () => {
const configFilePath = dbPathChecker()
const dirPath = path.dirname(configFilePath)
const clipboardImagePath = path.join(dirPath, CLIPBOARD_IMAGE_FOLDER)
try {
fs.mkdirsSync(clipboardImagePath)
return {
type: IToolboxItemType.HAS_PROBLEM_WITH_CLIPBOARD_PIC_UPLOAD,
status: IToolboxItemCheckStatus.SUCCESS
}
} catch (e) {
return {
type: IToolboxItemType.HAS_PROBLEM_WITH_CLIPBOARD_PIC_UPLOAD,
status: IToolboxItemCheckStatus.ERROR,
msg: T('TOOLBOX_CHECK_CLIPBOARD_FILE_PATH_ERROR_TIPS', {
path: clipboardImagePath
}),
value: path.dirname(clipboardImagePath)
}
}
}
}

View File

@ -0,0 +1,87 @@
import fs from 'fs-extra'
import { IpcMainEvent } from 'electron'
import { IToolboxItemCheckStatus, IToolboxItemType } from '~/universal/types/enum'
import { sendToolboxResWithType } from './utils'
import { dbPathChecker } from '~/main/apis/core/datastore/dbChecker'
import { GalleryDB, DB_PATH } from '~/main/apis/core/datastore'
import path from 'path'
import { T } from '~/main/i18n'
export const checkFileMap: IToolboxCheckerMap<
IToolboxItemType.IS_CONFIG_FILE_BROKEN | IToolboxItemType.IS_GALLERY_FILE_BROKEN
> = {
[IToolboxItemType.IS_CONFIG_FILE_BROKEN]: async (event: IpcMainEvent) => {
const sendToolboxRes = sendToolboxResWithType(IToolboxItemType.IS_CONFIG_FILE_BROKEN)
sendToolboxRes(event, {
status: IToolboxItemCheckStatus.LOADING
})
const configFilePath = dbPathChecker()
try {
if (fs.existsSync(configFilePath)) {
await fs.readJSON(configFilePath)
sendToolboxRes(event, {
status: IToolboxItemCheckStatus.SUCCESS,
msg: T('TOOLBOX_CHECK_CONFIG_FILE_PATH_TIPS', {
path: configFilePath
}),
value: configFilePath
})
}
} catch (e) {
sendToolboxRes(event, {
status: IToolboxItemCheckStatus.ERROR,
msg: T('TOOLBOX_CHECK_CONFIG_FILE_BROKEN_TIPS'),
value: path.dirname(configFilePath)
})
}
},
[IToolboxItemType.IS_GALLERY_FILE_BROKEN]: async (event) => {
const sendToolboxRes = sendToolboxResWithType(IToolboxItemType.IS_GALLERY_FILE_BROKEN)
sendToolboxRes(event, {
status: IToolboxItemCheckStatus.LOADING
})
const galleryDB = GalleryDB.getInstance()
if (galleryDB.errorList.length === 0) {
sendToolboxRes(event, {
status: IToolboxItemCheckStatus.SUCCESS,
msg: T('TOOLBOX_CHECK_GALLERY_FILE_PATH_TIPS', {
path: DB_PATH
}),
value: path.dirname(DB_PATH)
})
} else {
sendToolboxRes(event, {
status: IToolboxItemCheckStatus.ERROR,
msg: T('TOOLBOX_CHECK_GALLERY_FILE_BROKEN_TIPS'),
value: path.dirname(DB_PATH)
})
}
}
}
export const fixFileMap: IToolboxFixMap<
IToolboxItemType.IS_CONFIG_FILE_BROKEN | IToolboxItemType.IS_GALLERY_FILE_BROKEN
> = {
[IToolboxItemType.IS_CONFIG_FILE_BROKEN]: async () => {
try {
fs.unlinkSync(dbPathChecker())
} catch (e) {
// do nothing
}
return {
type: IToolboxItemType.IS_CONFIG_FILE_BROKEN,
status: IToolboxItemCheckStatus.SUCCESS
}
},
[IToolboxItemType.IS_GALLERY_FILE_BROKEN]: async () => {
try {
fs.unlinkSync(DB_PATH)
} catch (e) {
// do nothing
}
return {
type: IToolboxItemType.IS_GALLERY_FILE_BROKEN,
status: IToolboxItemCheckStatus.SUCCESS
}
}
}

View File

@ -0,0 +1,92 @@
import fs from 'fs-extra'
import { IToolboxItemCheckStatus, IToolboxItemType } from '~/universal/types/enum'
import { sendToolboxResWithType } from './utils'
import tunnel from 'tunnel'
import { dbPathChecker } from '~/main/apis/core/datastore/dbChecker'
import { IConfig } from 'piclist'
import axios, { AxiosRequestConfig } from 'axios'
import { T } from '~/main/i18n'
const getProxy = (proxyStr: string): AxiosRequestConfig['proxy'] | false => {
if (proxyStr) {
try {
const proxyOptions = new URL(proxyStr)
return {
host: proxyOptions.hostname,
port: parseInt(proxyOptions.port || '0', 10),
protocol: proxyOptions.protocol
}
} catch (e) {
}
}
return false
}
const sendToolboxRes = sendToolboxResWithType(IToolboxItemType.HAS_PROBLEM_WITH_PROXY)
export const checkProxyMap: IToolboxCheckerMap<
IToolboxItemType.HAS_PROBLEM_WITH_PROXY
> = {
[IToolboxItemType.HAS_PROBLEM_WITH_PROXY]: async (event) => {
sendToolboxRes(event, {
status: IToolboxItemCheckStatus.LOADING
})
const configFilePath = dbPathChecker()
if (fs.existsSync(configFilePath)) {
let config: IConfig | undefined
try {
config = await fs.readJSON(configFilePath) as IConfig
} catch (e) {
}
if (!config) {
return sendToolboxRes(event, {
status: IToolboxItemCheckStatus.SUCCESS,
msg: T('TOOLBOX_CHECK_PROXY_NO_PROXY_TIPS')
})
}
const proxy = config.picBed?.proxy
if (!proxy) {
return sendToolboxRes(event, {
status: IToolboxItemCheckStatus.SUCCESS,
msg: T('TOOLBOX_CHECK_PROXY_NO_PROXY_TIPS')
})
} else {
const proxyOptions = getProxy(proxy)
if (!proxyOptions) {
return sendToolboxRes(event, {
status: IToolboxItemCheckStatus.ERROR,
msg: T('TOOLBOX_CHECK_PROXY_PROXY_IS_NOT_CORRECT')
})
} else {
const httpsAgent = tunnel.httpsOverHttp({
proxy: {
host: proxyOptions.host,
port: proxyOptions.port
}
})
try {
await axios.get('https://www.google.com', {
httpsAgent
})
return sendToolboxRes(event, {
status: IToolboxItemCheckStatus.SUCCESS,
msg: T('TOOLBOX_CHECK_PROXY_SUCCESS_TIPS')
})
} catch (e) {
console.log(e)
return sendToolboxRes(event, {
status: IToolboxItemCheckStatus.ERROR,
msg: T('TOOLBOX_CHECK_PROXY_PROXY_IS_NOT_WORKING')
})
}
}
}
}
sendToolboxRes(event, {
status: IToolboxItemCheckStatus.SUCCESS,
msg: T('TOOLBOX_CHECK_PROXY_NO_PROXY_TIPS')
})
}
}

View File

@ -0,0 +1,48 @@
import { IRPCActionType, IToolboxItemType } from '~/universal/types/enum'
import { RPCRouter } from '../../router'
import { checkFileMap, fixFileMap } from './checkFile'
import { checkClipboardUploadMap, fixClipboardUploadMap } from './checkClipboardUpload'
import { checkProxyMap } from './checkProxy'
const toolboxRouter = new RPCRouter()
const toolboxCheckMap: Partial<IToolboxCheckerMap<IToolboxItemType>> = {
...checkFileMap,
...checkClipboardUploadMap,
...checkProxyMap
}
const toolboxFixMap: Partial<IToolboxFixMap<IToolboxItemType>> = {
...fixFileMap,
...fixClipboardUploadMap
}
toolboxRouter
.add(IRPCActionType.TOOLBOX_CHECK, async (args, event) => {
const [type] = args as IToolboxCheckArgs
if (type) {
const handler = toolboxCheckMap[type]
if (handler) {
handler(event)
}
} else {
// do check all
for (const key in toolboxCheckMap) {
const handler = toolboxCheckMap[key as IToolboxItemType]
if (handler) {
handler(event)
}
}
}
})
.add(IRPCActionType.TOOLBOX_CHECK_FIX, async (args, event) => {
const [type] = args as IToolboxCheckArgs
const handler = toolboxFixMap[type]
if (handler) {
return await handler(event)
}
})
export {
toolboxRouter
}

View File

@ -0,0 +1,9 @@
import { IpcMainEvent } from 'electron'
import { IRPCActionType, IToolboxItemType } from '~/universal/types/enum'
export const sendToolboxResWithType = (type: IToolboxItemType) => (event: IpcMainEvent, res?: Omit<IToolboxCheckRes, 'type'>) => {
return event.sender.send(IRPCActionType.TOOLBOX_CHECK_RES, {
...res,
type
})
}

View File

@ -0,0 +1,29 @@
<template>
<div class="toolbox-handler">
<ElButton
type="text"
@click="() => props.handler(value)"
>
{{ props.handlerText }}
</ElButton>
</div>
</template>
<script lang="ts" setup>
import { IToolboxItemCheckStatus } from '~/universal/types/enum'
interface IProps {
status: IToolboxItemCheckStatus
value: any
handlerText: string
handler: (value: any) => void | Promise<void>
}
const props = defineProps<IProps>()
</script>
<script lang="ts">
export default {
name: 'ToolboxHandler'
}
</script>
<style lang='stylus'>
</style>

View File

@ -0,0 +1,48 @@
<template>
<el-icon
:color="color"
class="toolbox-status-icon"
>
<template v-if="props.status === IToolboxItemCheckStatus.SUCCESS">
<SuccessFilled />
</template>
<template v-if="props.status === IToolboxItemCheckStatus.ERROR">
<CircleCloseFilled />
</template>
<template v-if="props.status === IToolboxItemCheckStatus.LOADING">
<Loading />
</template>
</el-icon>
</template>
<script lang="ts" setup>
import { CircleCloseFilled, Loading, SuccessFilled } from '@element-plus/icons-vue'
import { computed } from 'vue'
import { IToolboxItemCheckStatus } from '~/universal/types/enum'
interface IProps {
status: IToolboxItemCheckStatus
}
const props = defineProps<IProps>()
const color = computed(() => {
switch (props.status) {
case IToolboxItemCheckStatus.SUCCESS:
return '#67C23A'
case IToolboxItemCheckStatus.ERROR:
return '#F56C6C'
default:
return '#909399'
}
})
</script>
<script lang="ts">
export default {
name: 'ToolboxStatusIcon'
}
</script>
<style lang='stylus'>
.toolbox-status-icon {
margin-left: 8px;
}
</style>

View File

@ -0,0 +1,64 @@
<template>
<el-form-item>
<template #label>
<el-row align="middle">
{{ props.settingText }}
<template v-if="props.tooltips">
<el-tooltip
class="item"
effect="dark"
:content="props.tooltips"
placement="right"
>
<el-icon style="margin-left: 4px">
<QuestionFilled />
</el-icon>
</el-tooltip>
</template>
</el-row>
</template>
<el-switch
v-model="value"
:active-text="$T('SETTINGS_OPEN')"
:inactive-text="$T('SETTINGS_CLOSE')"
@change="handleChange"
/>
</el-form-item>
</template>
<script lang="ts" setup>
import { T as $T } from '@/i18n'
import { saveConfig } from '@/utils/dataSender'
import { ref, watch } from 'vue'
import { QuestionFilled } from '@element-plus/icons-vue'
interface IProps {
tooltips?: string
settingProps: string
settingText: string
defaultValue: boolean
}
const props = defineProps<IProps>()
// to fix v-model blank bug
watch(() => props.defaultValue, (v) => {
value.value = v
})
const value = ref<boolean>(props.defaultValue)
const emit = defineEmits(['change'])
const handleChange = (val: ICheckBoxValueType) => {
saveConfig(props.settingProps, val)
emit('change', val)
}
</script>
<script lang="ts">
export default {
name: 'CheckboxFormItem'
}
</script>
<style lang='stylus'>
</style>

View File

@ -0,0 +1,29 @@
import { ipcRenderer } from 'electron'
import { onUnmounted } from 'vue'
import { IRPCActionType } from '~/universal/types/enum'
export const useIPCOn = (channel: string, listener: IpcRendererListener) => {
ipcRenderer.on(channel, listener)
onUnmounted(() => {
ipcRenderer.removeListener(channel, listener)
})
}
export const useIPCOnce = (channel: string, listener: IpcRendererListener) => {
ipcRenderer.once(channel, listener)
onUnmounted(() => {
ipcRenderer.removeListener(channel, listener)
})
}
/**
* will auto removeListener when component unmounted
*/
export const useIPC = () => {
return {
on: (channel: IRPCActionType, listener: IpcRendererListener) => useIPCOn(channel, listener),
once: (channel: IRPCActionType, listener: IpcRendererListener) => useIPCOnce(channel, listener)
}
}

View File

@ -1068,7 +1068,7 @@
import { ElForm, ElMessage as $message, ElMessage, ElMessageBox, FormRules } from 'element-plus'
import { Reading, QuestionFilled } from '@element-plus/icons-vue'
import pkg from 'root/package.json'
import { PICGO_OPEN_FILE, OPEN_URL, GET_PICBEDS, HIDE_DOCK, RELOAD_APP } from '#/events/constants'
import { PICGO_OPEN_FILE, OPEN_URL, GET_PICBEDS, HIDE_DOCK } from '#/events/constants'
import {
ipcRenderer
} from 'electron'
@ -1078,11 +1078,12 @@ import { getLatestVersion } from '#/utils/getLatestVersion'
import { compare } from 'compare-versions'
import { STABLE_RELEASE_URL } from '#/utils/static'
import { computed, onBeforeMount, onBeforeUnmount, reactive, ref, toRaw } from 'vue'
import { getConfig, saveConfig, sendToMain } from '@/utils/dataSender'
import { getConfig, saveConfig, sendRPC, sendToMain } from '@/utils/dataSender'
import { useRouter } from 'vue-router'
import { SHORTKEY_PAGE } from '@/router/config'
import { IConfig, IBuildInCompressOptions, IBuildInWaterMarkOptions } from 'piclist'
import { invokeToMain } from '@/manage/utils/dataSender'
import { IRPCActionType } from '~/universal/types/enum'
const imageProcessDialogVisible = ref(false)
@ -1298,7 +1299,7 @@ function confirmSyncSetting () {
'settings.sync': sync.value
})
syncVisible.value = false
sendToMain(RELOAD_APP)
sendRPC(IRPCActionType.RELOAD_APP)
}
const version = pkg.version

View File

@ -207,7 +207,6 @@ import {
import { handleStreamlinePluginName } from '~/universal/utils/common'
import {
OPEN_URL,
RELOAD_APP,
PICGO_CONFIG_PLUGIN,
PICGO_HANDLE_PLUGIN_ING,
PICGO_TOGGLE_PLUGIN,
@ -216,9 +215,11 @@ import {
PICGO_HANDLE_PLUGIN_DONE
} from '#/events/constants'
import { computed, ref, onBeforeMount, onBeforeUnmount, watch, onMounted } from 'vue'
import { getConfig, saveConfig, sendToMain } from '@/utils/dataSender'
import { getConfig, saveConfig, sendRPC, sendToMain } from '@/utils/dataSender'
import { ElMessageBox } from 'element-plus'
import axios from 'axios'
import { IRPCActionType } from '~/universal/types/enum'
const $confirm = ElMessageBox.confirm
const searchText = ref('')
const pluginList = ref<IPicGoPlugin[]>([])
@ -411,7 +412,7 @@ function installPlugin (item: IPicGoPlugin) {
// }
function reloadApp () {
sendToMain(RELOAD_APP)
sendRPC(IRPCActionType.RELOAD_APP)
}
async function handleReload () {

View File

@ -0,0 +1,273 @@
<template>
<div class="toolbox">
<el-row>
<el-row
class="toolbox-header"
>
<el-row>
<img
class="toolbox-header__logo"
:src="defaultLogo"
>
<el-row class="toolbox-header__text">
<el-row class="toolbox-header__title">
{{ $T('TOOLBOX_TITLE') }}
</el-row>
<el-row class="toolbox-header__sub-title">
{{ $T('TOOLBOX_SUB_TITLE') }}
</el-row>
</el-row>
</el-row>
<el-row>
<template v-if="progress !== 100">
<el-button
type="primary"
round
:disabled="isLoading"
@click="handleCheck"
>
{{ $T('TOOLBOX_START_SCAN') }}
</el-button>
</template>
<template v-else-if="isAllSuccess">
<div class="toolbox-tips">
{{ $T('TOOLBOX_SUCCESS_TIPS') }}
</div>
</template>
<template v-else-if="!isAllSuccess">
<template v-if="canFixLength !== 0">
<el-button
type="primary"
round
@click="handleFix"
>
{{ $T('TOOLBOX_START_FIX') }}
</el-button>
</template>
<template v-else>
<div class="toolbox-cant-fix toolbox-tips">
{{ $T('TOOLBOX_CANT_AUTO_FIX') }}
<el-button
type="primary"
round
class="toolbox-cant-fix__btn"
@click="handleCheck"
>
{{ $T('TOOLBOX_RE_SCAN') }}
</el-button>
</div>
</template>
</template>
</el-row>
</el-row>
</el-row>
<el-row class="progress">
<el-progress
:percentage="progress"
:format="format"
/>
</el-row>
<el-collapse
v-model="activeTypes"
accordion
>
<el-collapse-item
v-for="(item, key) in fixList"
:key="key"
:name="key"
>
<template #title>
{{ item.title }} <toolbox-status-icon :status="item.status" />
</template>
<div class="toolbox-item-msg">
{{ item.msg || '' }}
<template v-if="item.handler && item.handlerText && item.value">
<toolbox-handler
:value="item.value"
:status="item.status"
:handler="item.handler"
:handler-text="item.handlerText"
/>
</template>
</div>
</el-collapse-item>
</el-collapse>
</div>
</template>
<script lang="ts" setup>
import { useIPC } from '@/hooks/useIPC'
import { sendRPC, triggerRPC } from '@/utils/dataSender'
import { ElMessageBox } from 'element-plus'
import { computed, reactive, ref } from 'vue'
import { IToolboxItemType, IToolboxItemCheckStatus, IRPCActionType } from '~/universal/types/enum'
import { T as $T } from '@/i18n'
import ToolboxStatusIcon from '@/components/ToolboxStatusIcon.vue'
import ToolboxHandler from '@/components/ToolboxHandler.vue'
const $confirm = ElMessageBox.confirm
const defaultLogo = ref(`file://${__static.replace(/\\/g, '/')}/roundLogo.png`)
const activeTypes = ref<IToolboxItemType[]>([])
const fixList = reactive<IToolboxMap>({
[IToolboxItemType.IS_CONFIG_FILE_BROKEN]: {
title: $T('TOOLBOX_CHECK_CONFIG_FILE_BROKEN'),
status: IToolboxItemCheckStatus.INIT,
handlerText: $T('SETTINGS_OPEN_CONFIG_FILE'),
handler (value: string) {
sendRPC(IRPCActionType.OPEN_FILE, value)
}
},
[IToolboxItemType.IS_GALLERY_FILE_BROKEN]: {
title: $T('TOOLBOX_CHECK_GALLERY_FILE_BROKEN'),
status: IToolboxItemCheckStatus.INIT
},
[IToolboxItemType.HAS_PROBLEM_WITH_CLIPBOARD_PIC_UPLOAD]: {
title: $T('TOOLBOX_CHECK_PROBLEM_WITH_CLIPBOARD_PIC_UPLOAD'), // picgo-image-clipboard folder
status: IToolboxItemCheckStatus.INIT,
handlerText: $T('OPEN_FILE_PATH'),
handler (value: string) {
sendRPC(IRPCActionType.OPEN_FILE, value)
}
},
[IToolboxItemType.HAS_PROBLEM_WITH_PROXY]: {
title: $T('TOOLBOX_CHECK_PROBLEM_WITH_PROXY'),
status: IToolboxItemCheckStatus.INIT,
hasNoFixMethod: true
}
})
const progress = computed(() => {
const total = Object.keys(fixList).length
const done = Object.keys(fixList).filter(key => {
const status = fixList[key as IToolboxItemType].status
return status !== IToolboxItemCheckStatus.INIT && status !== IToolboxItemCheckStatus.LOADING
}).length
return done / total * 100
})
const isAllSuccess = computed(() => {
return Object.keys(fixList).every(key => {
const status = fixList[key as IToolboxItemType].status
return status === IToolboxItemCheckStatus.SUCCESS
})
})
const isLoading = computed(() => {
return Object.keys(fixList).some(key => {
const status = fixList[key as IToolboxItemType].status
return status === IToolboxItemCheckStatus.LOADING
})
})
const canFixLength = computed(() => {
return Object.keys(fixList).filter(key => {
const status = fixList[key as IToolboxItemType].status
return status === IToolboxItemCheckStatus.ERROR && !fixList[key as IToolboxItemType].hasNoFixMethod
}).length
})
const format = (_percentage: number) => ''
const ipc = useIPC()
ipc.on(IRPCActionType.TOOLBOX_CHECK_RES, (_event: any, { type, msg = '', status, value = '' }: IToolboxCheckRes) => {
fixList[type].status = status
fixList[type].msg = msg
fixList[type].value = value
if (status === IToolboxItemCheckStatus.ERROR) {
activeTypes.value.push(type)
}
})
const handleCheck = () => {
activeTypes.value = []
Object.keys(fixList).forEach(key => {
fixList[key as IToolboxItemType].status = IToolboxItemCheckStatus.LOADING
fixList[key as IToolboxItemType].msg = ''
fixList[key as IToolboxItemType].value = ''
})
sendRPC(IRPCActionType.TOOLBOX_CHECK)
}
const handleFix = async () => {
const fixRes = await Promise.all(Object.keys(fixList).filter(key => {
const status = fixList[key as IToolboxItemType].status
return status === IToolboxItemCheckStatus.ERROR && !fixList[key as IToolboxItemType].hasNoFixMethod
}).map(async key => {
return triggerRPC<IToolboxCheckRes>(IRPCActionType.TOOLBOX_CHECK_FIX, key as IToolboxItemType)
}))
fixRes.filter(item => item !== null).forEach(item => {
if (item) {
fixList[item.type].status = item.status
fixList[item.type].msg = item.msg
fixList[item.type].value = item.value
}
})
$confirm($T('TOOLBOX_FIX_DONE_NEED_RELOAD'), $T('TIPS_NOTICE'), {
confirmButtonText: $T('CONFIRM'),
cancelButtonText: $T('CANCEL'),
type: 'info'
}).then(() => {
sendRPC(IRPCActionType.RELOAD_APP)
}).catch(() => {})
}
</script>
<script lang="ts">
export default {
name: 'ToolBoxPage'
}
</script>
<style lang='stylus'>
.toolbox
padding 0 40px
&-header
width 100%
color #eee
justify-content space-between
align-items center
padding 20px 0px
&__logo
width 64px
height 64px
margin-right 20px
&__text
flex-direction column
justify-content center
&__title
color #ddd
font-size 20px
margin-bottom 4px
&__sub-title
color #aaa
font-size 16px
.progress
width 100%
.el-progress--line
width 100%
.el-progress__text
min-width 0
.el-collapse
margin-top 20px
--el-collapse-border-color: #777;
--el-collapse-header-height: 48px;
--el-collapse-header-bg-color: transparent;
--el-collapse-header-text-color: #ddd;
--el-collapse-header-font-size: 13px;
--el-collapse-content-bg-color: transparent;
--el-collapse-content-font-size: 13px;
--el-collapse-content-text-color: #ddd;
&-item__content
padding-bottom: 12px
&-item-msg
color: #aaa
&-tips
padding: 12px 0
&-cant-fix
display flex
justify-content center
align-items center
&__btn
margin-left: 8px
</style>

View File

@ -14,3 +14,4 @@ export const MANAGE_LOGIN_PAGE = 'ManageLoginPage'
export const MANAGE_SETTING_PAGE = 'ManageSettingPage'
export const MANAGE_EMPTY_PAGE = 'ManageEmptyPage'
export const MANAGE_BUCKET_PAGE = 'ManageBucketPage'
export const TOOLBOX_CONFIG_PAGE = 'ToolBoxPage'

View File

@ -91,6 +91,11 @@ export default createRouter({
}
]
},
{
path: '/toolbox-page',
name: config.TOOLBOX_CONFIG_PAGE,
component: () => import(/* webpackChunkName: "ToolboxPage" */ '@/pages/Toolbox.vue')
},
{
path: '/:pathMatch(.*)*',
redirect: '/'

View File

@ -49,6 +49,19 @@ export function triggerRPC<T> (action: IRPCActionType, ...args: any[]): Promise<
})
}
/**
* send a rpc request & do not need to wait for the response
*
* or the response will be handled by other listener
*/
export function sendRPC (action: IRPCActionType, ...args: any[]): void {
const data = getRawData(args)
ipcRenderer.send(RPC_ACTIONS, action, data)
}
/**
* @deprecated will be replaced by sendRPC in the future
*/
export function sendToMain (channel: string, ...args: any[]) {
const data = getRawData(args)
ipcRenderer.send(channel, ...data)

View File

@ -17,3 +17,5 @@ declare interface IWindowManager {
deleteById: (id: number) => void
getAvailableWindow: () => BrowserWindow
}
type IpcRendererListener = (event: import('electron').IpcRendererEvent, ...args: any[]) => void

View File

@ -32,7 +32,8 @@ export enum IWindowList {
SETTING_WINDOW = 'SETTING_WINDOW',
TRAY_WINDOW = 'TRAY_WINDOW',
MINI_WINDOW = 'MINI_WINDOW',
RENAME_WINDOW = 'RENAME_WINDOW'
RENAME_WINDOW = 'RENAME_WINDOW',
TOOLBOX_WINDOW = 'TOOLBOX_WINDOW'
}
export enum IRemoteNoticeActionType {
@ -58,10 +59,39 @@ export enum IRemoteNoticeTriggerCount {
* renderer trigger action from main
*/
export enum IRPCActionType {
// config RPC
GET_PICBED_CONFIG_LIST = 'GET_PICBED_CONFIG_LIST',
DELETE_PICBED_CONFIG = 'DELETE_PICBED_CONFIG',
CHANGE_CURRENT_UPLOADER = 'CHANGE_CURRENT_UPLOADER',
SELECT_UPLOADER = 'SELECT_UPLOADER',
UPDATE_UPLOADER_CONFIG = 'UPDATE_UPLOADER_CONFIG',
RESET_UPLOADER_CONFIG = 'RESET_UPLOADER_CONFIG'
RESET_UPLOADER_CONFIG = 'RESET_UPLOADER_CONFIG',
// version rpc
GET_LATEST_VERSION = 'GET_LATEST_VERSION',
// toolbox rpc
TOOLBOX_CHECK = 'TOOLBOX_CHECK',
TOOLBOX_CHECK_RES = 'TOOLBOX_CHECK_RES',
TOOLBOX_CHECK_FIX = 'TOOLBOX_CHECK_FIX',
// system rpc
RELOAD_APP = 'RELOAD_APP',
OPEN_FILE = 'OPEN_FILE',
COPY_TEXT = 'COPY_TEXT',
SHOW_DOCK_ICON = 'SHOW_DOCK_ICON',
}
export enum IToolboxItemType {
IS_CONFIG_FILE_BROKEN = 'IS_CONFIG_FILE_BROKEN',
IS_GALLERY_FILE_BROKEN = 'IS_GALLERY_FILE_BROKEN',
HAS_PROBLEM_WITH_CLIPBOARD_PIC_UPLOAD = 'HAS_PROBLEM_WITH_CLIPBOARD_PIC_UPLOAD',
HAS_PROBLEM_WITH_PROXY = 'HAS_PROBLEM_WITH_PROXY',
}
export enum IToolboxItemCheckStatus {
INIT = 'init',
LOADING = 'loading',
SUCCESS = 'success',
ERROR = 'error',
}

View File

@ -28,6 +28,31 @@ interface ILocales {
CURRENT_PICBED: string
START_WATCH_CLIPBOARD: string
STOP_WATCH_CLIPBOARD: string
OPEN_TOOLBOX: string
TOOLBOX: string
TOOLBOX_TITLE: string
TOOLBOX_SUB_TITLE: string
TOOLBOX_CHECK_CONFIG_FILE_BROKEN: string
TOOLBOX_CHECK_GALLERY_FILE_BROKEN: string
TOOLBOX_CHECK_PROBLEM_WITH_CLIPBOARD_PIC_UPLOAD: string
TOOLBOX_CHECK_PROBLEM_WITH_PROXY: string
TOOLBOX_FIX_DONE_NEED_RELOAD: string
TOOLBOX_CANT_AUTO_FIX: string
TOOLBOX_START_SCAN: string
TOOLBOX_RE_SCAN: string
TOOLBOX_START_FIX: string
TOOLBOX_SUCCESS_TIPS: string
TOOLBOX_CHECK_CONFIG_FILE_PATH_TIPS: string
TOOLBOX_CHECK_CONFIG_FILE_BROKEN_TIPS: string
TOOLBOX_CHECK_GALLERY_FILE_PATH_TIPS: string
TOOLBOX_CHECK_GALLERY_FILE_BROKEN_TIPS: string
TOOLBOX_CHECK_PROXY_SUCCESS_TIPS: string
TOOLBOX_CHECK_PROXY_NO_PROXY_TIPS: string
TOOLBOX_CHECK_PROXY_PROXY_IS_NOT_CORRECT: string
TOOLBOX_CHECK_PROXY_PROXY_IS_NOT_WORKING: string
TOOLBOX_CHECK_CLIPBOARD_FILE_PATH_TIPS: string
TOOLBOX_CHECK_CLIPBOARD_FILE_PATH_NOT_EXIST_TIPS: string
TOOLBOX_CHECK_CLIPBOARD_FILE_PATH_ERROR_TIPS: string
CHOOSE_YOUR_DEFAULT_PICBED: string
UPLOAD_AREA: string
UPLOAD_VIEW_HINT: string
@ -61,6 +86,8 @@ interface ILocales {
COPY_LINK_SUCCEED: string
BATCH_COPY_LINK_SUCCEED: string
FILE_RENAME: string
COPY_FILE_PATH: string
OPEN_FILE_PATH: string
GALLERY_SYNC_DELETE: string
GALLERY_SYNC_DELETE_NOTICE_TITLE: string
GALLERY_SYNC_DELETE_NOTICE_SUCCEED: string

View File

@ -3,3 +3,41 @@ type IDeleteUploaderConfigArgs = [type: string, id: string]
type ISelectUploaderConfigArgs = [type: string, id: string]
type IUpdateUploaderConfigArgs = [type: string, id: string, config: IStringKeyMap]
type IResetUploaderConfigArgs = [type: string, id: string]
type IGetLatestVersionArgs = [isCheckBetaVersion: boolean]
type IToolboxCheckArgs = [type: import('./enum').IToolboxItemType]
type IOpenFileArgs = [filePath: string]
type ICopyTextArgs = [text: string]
type IShowDockIconArgs = [visible: boolean]
interface IRPCServer {
start: () => void
stop: () => void
use: (routes: IRPCRoutes) => void
}
type IRPCRoutes = Map<import('./enum').IRPCActionType, IRPCHandler<any>>
type IRPCHandler<T> = (args: any[], event: import('electron').IpcMainEvent) => Promise<T>
interface IRPCRouter {
add<T>(action: import('./enum').IRPCActionType, handler: IRPCHandler<T>): IRPCRouter
routes: () => IRPCRoutes
}
type IToolboxChecker<T = any> = (event: import('electron').IpcMainEvent) => Promise<T>
type IToolboxCheckerMap<T extends import('./enum').IToolboxItemType> = {
[type in T]: IToolboxChecker
}
type IToolboxFixMap<T extends import('./enum').IToolboxItemType> = {
[type in T]: IToolboxChecker<IToolboxCheckRes>
}
type IToolboxCheckRes = {
type: import('./enum').IToolboxItemType
status: import('./enum').IToolboxItemCheckStatus,
msg?: string
value?: any
}

View File

@ -25,3 +25,17 @@ interface ISettingForm {
interface IShortKeyMap {
[propName: string]: string
}
interface IToolboxItem {
title: string
status: import('#/types/enum').IToolboxItemCheckStatus
msg?: string
value?: any // for handler
hasNoFixMethod?: boolean
handler?: (value: any) => Promise<void> | void
handlerText?: string
}
type IToolboxMap = {
[id in import('#/types/enum').IToolboxItemType]: IToolboxItem
}

View File

@ -3226,6 +3226,13 @@
resolved "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.1.tgz#8f80dd965ad81f3e1bc26d6f5c727e132721ff40"
integrity sha512-Y0K95ThC3esLEYD6ZuqNek29lNX2EM1qxV8y2FTLUB0ff5wWrk7az+mLrnNFUnaXcgKye22+sFBRXOgpPILZNg==
"@types/tunnel@^0.0.3":
version "0.0.3"
resolved "https://registry.npmjs.org/@types/tunnel/-/tunnel-0.0.3.tgz#f109e730b072b3136347561fc558c9358bb8c6e9"
integrity sha512-sOUTGn6h1SfQ+gbgqC364jLFBw2lnFqkgF3q0WovEHRLMrVD1sd5aufqi/aJObLekJO+Aq5z646U4Oxy6shXMA==
dependencies:
"@types/node" "*"
"@types/uuid@^9.0.0":
version "9.0.0"
resolved "https://registry.npmmirror.com/@types/uuid/-/uuid-9.0.0.tgz#53ef263e5239728b56096b0a869595135b7952d2"