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

@@ -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)