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>
import {
VAlert,
VDescription,
VDescriptionItem,
VSwitch,
VTag,
} from "@halo-dev/components";
import type { Ref } from "vue";
import { computed, inject } from "vue";
@ -16,7 +16,7 @@ import { formatDatetime } from "@/utils/date";
import { useQuery } from "@tanstack/vue-query";
const plugin = inject<Ref<Plugin | undefined>>("plugin");
const { changeStatus, isStarted } = usePluginLifeCycle(plugin);
const { changeStatus } = usePluginLifeCycle(plugin);
interface RoleTemplateGroup {
module: string | null | undefined;
@ -70,23 +70,25 @@ const pluginRoleTemplateGroups = computed<RoleTemplateGroup[]>(() => {
<h3 class="text-lg font-medium leading-6 text-gray-900">
{{ $t("core.plugin.detail.header.title") }}
</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 v-permission="['system:plugins:manage']">
<VSwitch :model-value="isStarted" @change="changeStatus" />
<VSwitch :model-value="plugin?.spec.enabled" @change="changeStatus" />
</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">
<VDescription>
<VDescriptionItem

View File

@ -1,8 +1,6 @@
<script lang="ts" setup>
import {
VSpace,
VSwitch,
VTag,
VStatusDot,
VEntity,
VEntityField,
@ -42,7 +40,8 @@ const { plugin } = toRefs(props);
const upgradeModal = ref(false);
const { isStarted, changeStatus, uninstall } = usePluginLifeCycle(plugin);
const { getFailedMessage, changeStatus, uninstall } =
usePluginLifeCycle(plugin);
const onUpgradeModalClose = () => {
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>
<template>
<PluginUploadModal
@ -104,28 +96,12 @@ const getFailedMessage = (plugin: Plugin) => {
name: 'PluginDetail',
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 #end>
<VEntityField v-if="plugin?.status?.phase === 'FAILED'">
<template #description>
<VStatusDot
v-tooltip="getFailedMessage(plugin)"
state="error"
animate
/>
<VStatusDot v-tooltip="getFailedMessage()" state="error" animate />
</template>
</VEntityField>
<VEntityField v-if="plugin?.metadata.deletionTimestamp">

View File

@ -8,6 +8,7 @@ import { useI18n } from "vue-i18n";
interface usePluginLifeCycleReturn {
isStarted: ComputedRef<boolean | undefined>;
getFailedMessage: () => string | undefined;
changeStatus: () => 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 = () => {
if (!plugin?.value) return;
@ -135,6 +148,7 @@ export function usePluginLifeCycle(
return {
isStarted,
getFailedMessage,
changeStatus,
uninstall,
};