feat: add upgrade plugin support (halo-dev/console#663)

#### What type of PR is this?

/kind feature
/milestone 2.0

#### What this PR does / why we need it:

支持插件升级,适配 https://github.com/halo-dev/halo/pull/2624

#### Which issue(s) this PR fixes:

Fixes https://github.com/halo-dev/halo/issues/2551

#### Screenshots:
<img width="1663" alt="image" src="https://user-images.githubusercontent.com/21301288/197682557-7e37895e-a6b5-43d6-8d40-2a1c899b9ce1.png">
<img width="1662" alt="image" src="https://user-images.githubusercontent.com/21301288/197682572-4db39f09-efda-4928-9a6d-8593c7c0c790.png">


#### Special notes for your reviewer:

测试方式:

1. Halo 需要使用 https://github.com/halo-dev/halo/pull/2624 PR 的分支。
2. Console 需要 `pnpm install`
3. 修改已安装的插件,构建之后更新插件,检查是否更新成功。


#### Does this PR introduce a user-facing change?

```release-note
支持插件升级
```
pull/3445/head
Ryan Wang 2022-10-26 11:26:09 +08:00 committed by GitHub
parent 4ca853e159
commit a23c4318cc
5 changed files with 59 additions and 11 deletions

View File

@ -33,7 +33,7 @@
"@formkit/inputs": "^1.0.0-beta.11", "@formkit/inputs": "^1.0.0-beta.11",
"@formkit/themes": "^1.0.0-beta.11", "@formkit/themes": "^1.0.0-beta.11",
"@formkit/vue": "^1.0.0-beta.11", "@formkit/vue": "^1.0.0-beta.11",
"@halo-dev/api-client": "^0.0.38", "@halo-dev/api-client": "^0.0.39",
"@halo-dev/components": "workspace:*", "@halo-dev/components": "workspace:*",
"@halo-dev/console-shared": "workspace:*", "@halo-dev/console-shared": "workspace:*",
"@halo-dev/richtext-editor": "^0.0.0-alpha.8", "@halo-dev/richtext-editor": "^0.0.0-alpha.8",

View File

@ -13,7 +13,7 @@ importers:
'@formkit/inputs': ^1.0.0-beta.11 '@formkit/inputs': ^1.0.0-beta.11
'@formkit/themes': ^1.0.0-beta.11 '@formkit/themes': ^1.0.0-beta.11
'@formkit/vue': ^1.0.0-beta.11 '@formkit/vue': ^1.0.0-beta.11
'@halo-dev/api-client': ^0.0.38 '@halo-dev/api-client': ^0.0.39
'@halo-dev/components': workspace:* '@halo-dev/components': workspace:*
'@halo-dev/console-shared': workspace:* '@halo-dev/console-shared': workspace:*
'@halo-dev/richtext-editor': ^0.0.0-alpha.8 '@halo-dev/richtext-editor': ^0.0.0-alpha.8
@ -101,7 +101,7 @@ importers:
'@formkit/inputs': 1.0.0-beta.11 '@formkit/inputs': 1.0.0-beta.11
'@formkit/themes': 1.0.0-beta.11_tailwindcss@3.1.8 '@formkit/themes': 1.0.0-beta.11_tailwindcss@3.1.8
'@formkit/vue': 1.0.0-beta.11_k5hp3txgeyj6le63abiyc7wx3u '@formkit/vue': 1.0.0-beta.11_k5hp3txgeyj6le63abiyc7wx3u
'@halo-dev/api-client': 0.0.38 '@halo-dev/api-client': 0.0.39
'@halo-dev/components': link:packages/components '@halo-dev/components': link:packages/components
'@halo-dev/console-shared': link:packages/shared '@halo-dev/console-shared': link:packages/shared
'@halo-dev/richtext-editor': 0.0.0-alpha.8_vue@3.2.40 '@halo-dev/richtext-editor': 0.0.0-alpha.8_vue@3.2.40
@ -1892,8 +1892,8 @@ packages:
- windicss - windicss
dev: false dev: false
/@halo-dev/api-client/0.0.38: /@halo-dev/api-client/0.0.39:
resolution: {integrity: sha512-7Vlc/tXkpERi2xWxtoWOVtYbZi+sksrueBAj64gr0cAUOqRy7A82oJXpeabLKeJAjDNdQKZ7eL7CClnf9NJTEA==} resolution: {integrity: sha512-GuTTJDOj0PPMXo3KTiNYGACRUXqJKnjnApK303eNPWqVodgR3mJVLFTXwa+euAJOkcSG3KkB5OtUFAkZeHRbPA==}
dev: false dev: false
/@halo-dev/richtext-editor/0.0.0-alpha.8_vue@3.2.40: /@halo-dev/richtext-editor/0.0.0-alpha.8_vue@3.2.40:

View File

@ -13,7 +13,7 @@ import {
VSpace, VSpace,
} from "@halo-dev/components"; } from "@halo-dev/components";
import PluginListItem from "./components/PluginListItem.vue"; import PluginListItem from "./components/PluginListItem.vue";
import PluginInstallModal from "./components/PluginInstallModal.vue"; import PluginUploadModal from "./components/PluginUploadModal.vue";
import { onMounted, ref } from "vue"; import { onMounted, ref } from "vue";
import { apiClient } from "@/utils/api-client"; import { apiClient } from "@/utils/api-client";
import type { PluginList } from "@halo-dev/api-client"; import type { PluginList } from "@halo-dev/api-client";
@ -140,7 +140,7 @@ function handleSortItemChange(sortItem?: SortItem) {
} }
</script> </script>
<template> <template>
<PluginInstallModal <PluginUploadModal
v-if="currentUserHasPermission(['system:plugins:manage'])" v-if="currentUserHasPermission(['system:plugins:manage'])"
v-model:visible="pluginInstall" v-model:visible="pluginInstall"
@close="handleFetchPlugins" @close="handleFetchPlugins"
@ -306,7 +306,7 @@ function handleSortItemChange(sortItem?: SortItem) {
role="list" role="list"
> >
<li v-for="(plugin, index) in plugins.items" :key="index"> <li v-for="(plugin, index) in plugins.items" :key="index">
<PluginListItem :plugin="plugin" /> <PluginListItem :plugin="plugin" @reload="handleFetchPlugins" />
</li> </li>
</ul> </ul>

View File

@ -9,7 +9,8 @@ import {
VEntityField, VEntityField,
VAvatar, VAvatar,
} from "@halo-dev/components"; } from "@halo-dev/components";
import { toRefs } from "vue"; import PluginUploadModal from "./PluginUploadModal.vue";
import { ref, toRefs } from "vue";
import { usePluginLifeCycle } from "../composables/use-plugin"; import { usePluginLifeCycle } from "../composables/use-plugin";
import type { Plugin } from "@halo-dev/api-client"; import type { Plugin } from "@halo-dev/api-client";
import { formatDatetime } from "@/utils/date"; import { formatDatetime } from "@/utils/date";
@ -26,11 +27,26 @@ const props = withDefaults(
} }
); );
const emit = defineEmits<{
(event: "reload"): void;
}>();
const { plugin } = toRefs(props); const { plugin } = toRefs(props);
const upgradeModal = ref(false);
const { isStarted, changeStatus, uninstall } = usePluginLifeCycle(plugin); const { isStarted, changeStatus, uninstall } = usePluginLifeCycle(plugin);
const onUpgradeModalClose = () => {
emit("reload");
};
</script> </script>
<template> <template>
<PluginUploadModal
v-model:visible="upgradeModal"
:upgrade-plugin="plugin"
@close="onUpgradeModalClose"
/>
<VEntity> <VEntity>
<template #start> <template #start>
<VEntityField> <VEntityField>
@ -108,6 +124,14 @@ const { isStarted, changeStatus, uninstall } = usePluginLifeCycle(plugin);
v-if="currentUserHasPermission(['system:plugins:manage'])" v-if="currentUserHasPermission(['system:plugins:manage'])"
#dropdownItems #dropdownItems
> >
<VButton
v-close-popper
block
type="secondary"
@click="upgradeModal = true"
>
升级
</VButton>
<VButton v-close-popper block type="danger" @click="uninstall"> <VButton v-close-popper block type="danger" @click="uninstall">
卸载 卸载
</VButton> </VButton>

View File

@ -6,12 +6,14 @@ import type { Plugin } from "@halo-dev/api-client";
import { computed, ref } from "vue"; import { computed, ref } from "vue";
import type { AxiosResponse } from "axios"; import type { AxiosResponse } from "axios";
withDefaults( const props = withDefaults(
defineProps<{ defineProps<{
visible: boolean; visible: boolean;
upgradePlugin?: Plugin;
}>(), }>(),
{ {
visible: false, visible: false,
upgradePlugin: undefined,
} }
); );
@ -22,6 +24,12 @@ const emit = defineEmits<{
const FilePondUploadRef = ref(); const FilePondUploadRef = ref();
const modalTitle = computed(() => {
return props.upgradePlugin
? `升级插件(${props.upgradePlugin.spec.displayName}`
: "安装插件";
});
const handleVisibleChange = (visible: boolean) => { const handleVisibleChange = (visible: boolean) => {
emit("update:visible", visible); emit("update:visible", visible);
if (!visible) { if (!visible) {
@ -31,6 +39,16 @@ const handleVisibleChange = (visible: boolean) => {
}; };
const uploadHandler = computed(() => { const uploadHandler = computed(() => {
if (props.upgradePlugin) {
return (file, config) =>
apiClient.plugin.upgradePlugin(
{
name: props.upgradePlugin.metadata.name as string,
file: file,
},
config
);
}
return (file, config) => return (file, config) =>
apiClient.plugin.installPlugin( apiClient.plugin.installPlugin(
{ {
@ -41,6 +59,11 @@ const uploadHandler = computed(() => {
}); });
const onUploaded = async (response: AxiosResponse) => { const onUploaded = async (response: AxiosResponse) => {
if (props.upgradePlugin) {
handleVisibleChange(false);
return;
}
const plugin = response.data as Plugin; const plugin = response.data as Plugin;
handleVisibleChange(false); handleVisibleChange(false);
Dialog.success({ Dialog.success({
@ -71,10 +94,11 @@ const onUploaded = async (response: AxiosResponse) => {
<VModal <VModal
:visible="visible" :visible="visible"
:width="500" :width="500"
title="安装插件" :title="modalTitle"
@update:visible="handleVisibleChange" @update:visible="handleVisibleChange"
> >
<FilePondUpload <FilePondUpload
v-if="visible && uploadHandler"
ref="FilePondUploadRef" ref="FilePondUploadRef"
:allow-multiple="false" :allow-multiple="false"
:handler="uploadHandler" :handler="uploadHandler"