refactor: abnormal status display of plugin management (#3945)

#### What type of PR is this?

/kind improvement
/area console
/milestone 2.6.x

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

重构 Console 端插件异常状态的判断和显示,改动如下:

1. 移除插件名称旁边的启用状态。
2. 切换按钮的状态是期望值,意思就是不与插件实际状态一致。
3. 小红点出现的时机为:插件的实际状态与期望状态不一致以及插件本身出了异常。
4. 插件详情页面支持横幅显示插件异常状态。

<img width="1358" alt="image" src="https://github.com/halo-dev/halo/assets/21301288/42408d1f-7975-4aef-9373-d828994501b3">
<img width="1383" alt="image" src="https://github.com/halo-dev/halo/assets/21301288/033efdef-470b-4570-94c1-da64d9ea0db9">

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

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

#### Special notes for your reviewer:

测试方式:

1. 想办法将插件状态变成异常,比如在开发环境将 runtime-mode 改为 deployment。
2. 检查 Console 端插件管理中的 UI 表现是否和上面的描述一致。

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

```release-note
重构 Console 插件管理的异常状态显示。
```
pull/3939/head^2
Ryan Wang 2023-05-17 11:54:15 +08:00 committed by GitHub
parent 017d5b8d8f
commit 8deea08231
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 35 additions and 43 deletions

View File

@ -1,9 +1,9 @@
<script lang="ts" setup> <script lang="ts" setup>
import { import {
VAlert,
VDescription, VDescription,
VDescriptionItem, VDescriptionItem,
VSwitch, VSwitch,
VTag,
} from "@halo-dev/components"; } from "@halo-dev/components";
import type { Ref } from "vue"; import type { Ref } from "vue";
import { computed, inject } from "vue"; import { computed, inject } from "vue";
@ -16,7 +16,7 @@ import { formatDatetime } from "@/utils/date";
import { useQuery } from "@tanstack/vue-query"; import { useQuery } from "@tanstack/vue-query";
const plugin = inject<Ref<Plugin | undefined>>("plugin"); const plugin = inject<Ref<Plugin | undefined>>("plugin");
const { changeStatus, isStarted } = usePluginLifeCycle(plugin); const { changeStatus } = usePluginLifeCycle(plugin);
interface RoleTemplateGroup { interface RoleTemplateGroup {
module: string | null | undefined; module: string | null | undefined;
@ -70,23 +70,25 @@ const pluginRoleTemplateGroups = computed<RoleTemplateGroup[]>(() => {
<h3 class="text-lg font-medium leading-6 text-gray-900"> <h3 class="text-lg font-medium leading-6 text-gray-900">
{{ $t("core.plugin.detail.header.title") }} {{ $t("core.plugin.detail.header.title") }}
</h3> </h3>
<p class="mt-1 flex max-w-2xl items-center gap-2">
<span class="text-sm text-gray-500">
{{ plugin?.spec.version }}
</span>
<VTag>
{{
isStarted
? $t("core.common.status.activated")
: $t("core.common.status.not_activated")
}}
</VTag>
</p>
</div> </div>
<div v-permission="['system:plugins:manage']"> <div v-permission="['system:plugins:manage']">
<VSwitch :model-value="isStarted" @change="changeStatus" /> <VSwitch :model-value="plugin?.spec.enabled" @change="changeStatus" />
</div> </div>
</div> </div>
<div
v-if="
plugin?.status?.phase === 'FAILED' &&
plugin?.status?.conditions?.length
"
class="w-full px-4 pb-2 sm:px-6"
>
<VAlert
type="error"
:title="plugin?.status?.conditions?.[0].reason"
:description="plugin?.status?.conditions?.[0].message"
:closable="false"
/>
</div>
<div class="border-t border-gray-200"> <div class="border-t border-gray-200">
<VDescription> <VDescription>
<VDescriptionItem <VDescriptionItem

View File

@ -1,8 +1,6 @@
<script lang="ts" setup> <script lang="ts" setup>
import { import {
VSpace,
VSwitch, VSwitch,
VTag,
VStatusDot, VStatusDot,
VEntity, VEntity,
VEntityField, VEntityField,
@ -42,7 +40,8 @@ const { plugin } = toRefs(props);
const upgradeModal = ref(false); const upgradeModal = ref(false);
const { isStarted, changeStatus, uninstall } = usePluginLifeCycle(plugin); const { getFailedMessage, changeStatus, uninstall } =
usePluginLifeCycle(plugin);
const onUpgradeModalClose = () => { const onUpgradeModalClose = () => {
emit("reload"); emit("reload");
@ -72,13 +71,6 @@ const handleResetSettingConfig = async () => {
}, },
}); });
}; };
const getFailedMessage = (plugin: Plugin) => {
if (plugin.status?.conditions?.length) {
const lastCondition = plugin.status.conditions[0];
return [lastCondition.reason, lastCondition.message].join(":");
}
};
</script> </script>
<template> <template>
<PluginUploadModal <PluginUploadModal
@ -104,28 +96,12 @@ const getFailedMessage = (plugin: Plugin) => {
name: 'PluginDetail', name: 'PluginDetail',
params: { name: plugin?.metadata.name }, params: { name: plugin?.metadata.name },
}" }"
> />
<template #extra>
<VSpace>
<VTag>
{{
isStarted
? $t("core.common.status.activated")
: $t("core.common.status.not_activated")
}}
</VTag>
</VSpace>
</template>
</VEntityField>
</template> </template>
<template #end> <template #end>
<VEntityField v-if="plugin?.status?.phase === 'FAILED'"> <VEntityField v-if="plugin?.status?.phase === 'FAILED'">
<template #description> <template #description>
<VStatusDot <VStatusDot v-tooltip="getFailedMessage()" state="error" animate />
v-tooltip="getFailedMessage(plugin)"
state="error"
animate
/>
</template> </template>
</VEntityField> </VEntityField>
<VEntityField v-if="plugin?.metadata.deletionTimestamp"> <VEntityField v-if="plugin?.metadata.deletionTimestamp">

View File

@ -8,6 +8,7 @@ import { useI18n } from "vue-i18n";
interface usePluginLifeCycleReturn { interface usePluginLifeCycleReturn {
isStarted: ComputedRef<boolean | undefined>; isStarted: ComputedRef<boolean | undefined>;
getFailedMessage: () => string | undefined;
changeStatus: () => void; changeStatus: () => void;
uninstall: (deleteExtensions?: boolean) => void; uninstall: (deleteExtensions?: boolean) => void;
} }
@ -23,6 +24,18 @@ export function usePluginLifeCycle(
); );
}); });
const getFailedMessage = () => {
if (!plugin?.value) return;
if (!isStarted.value) {
const lastCondition = plugin.value.status?.conditions?.[0];
return (
[lastCondition?.reason, lastCondition?.message].join(":") || "Unknown"
);
}
};
const changeStatus = () => { const changeStatus = () => {
if (!plugin?.value) return; if (!plugin?.value) return;
@ -135,6 +148,7 @@ export function usePluginLifeCycle(
return { return {
isStarted, isStarted,
getFailedMessage,
changeStatus, changeStatus,
uninstall, uninstall,
}; };