From 3306b1f881c4d950059479bd94fe3bcd9dc226ab Mon Sep 17 00:00:00 2001 From: Ryan Wang Date: Mon, 27 Nov 2023 21:33:31 +0800 Subject: [PATCH] feat: add support for displaying enabled plugins on actuator page (#4897) --- .../modules/system/actuator/Actuator.vue | 265 +++++++++++++----- console/src/locales/en.yaml | 6 +- console/src/locales/zh-CN.yaml | 6 +- console/src/locales/zh-TW.yaml | 6 +- 4 files changed, 212 insertions(+), 71 deletions(-) diff --git a/console/console-src/modules/system/actuator/Actuator.vue b/console/console-src/modules/system/actuator/Actuator.vue index 4f166bb7ed..28415cedc8 100644 --- a/console/console-src/modules/system/actuator/Actuator.vue +++ b/console/console-src/modules/system/actuator/Actuator.vue @@ -9,49 +9,80 @@ import { Toast, VDescription, VDescriptionItem, + VTag, + VLoading, } from "@halo-dev/components"; -import { computed, onMounted, ref } from "vue"; +import { computed } from "vue"; import type { Info, GlobalInfo, Startup } from "@/types"; import axios from "axios"; import { formatDatetime } from "@/utils/date"; import { useClipboard } from "@vueuse/core"; import { useI18n } from "vue-i18n"; +import { useThemeStore } from "@console/stores/theme"; +import type { Plugin } from "@halo-dev/api-client"; +import { apiClient } from "@/utils/api-client"; +import { useQuery } from "@tanstack/vue-query"; +import { usePermission } from "@/utils/permission"; const { t } = useI18n(); +const themeStore = useThemeStore(); +const { currentUserHasPermission } = usePermission(); -const info = ref(); -const globalInfo = ref(); -const startup = ref(); +const { data: info } = useQuery({ + queryKey: ["system-info"], + queryFn: async () => { + const { data } = await axios.get( + `${import.meta.env.VITE_API_URL}/actuator/info`, + { + withCredentials: true, + } + ); + return data; + }, + retry: 0, +}); -const handleFetchActuatorInfo = async () => { - const { data } = await axios.get( - `${import.meta.env.VITE_API_URL}/actuator/info`, - { - withCredentials: true, - } - ); - info.value = data; -}; +const { data: globalInfo } = useQuery({ + queryKey: ["system-global-info"], + queryFn: async () => { + const { data } = await axios.get( + `${import.meta.env.VITE_API_URL}/actuator/globalinfo`, + { + withCredentials: true, + } + ); + return data; + }, + retry: 0, +}); -const handleFetchActuatorGlobalInfo = async () => { - const { data } = await axios.get( - `${import.meta.env.VITE_API_URL}/actuator/globalinfo`, - { - withCredentials: true, - } - ); - globalInfo.value = data; -}; +const { data: startup } = useQuery({ + queryKey: ["system-startup-info"], + queryFn: async () => { + const { data } = await axios.get( + `${import.meta.env.VITE_API_URL}/actuator/startup`, + { + withCredentials: true, + } + ); + return data; + }, + retry: 0, +}); -const handleFetchActuatorStartup = async () => { - const { data } = await axios.get( - `${import.meta.env.VITE_API_URL}/actuator/startup`, - { - withCredentials: true, - } - ); - startup.value = data; -}; +const { data: plugins, isLoading: isPluginsLoading } = useQuery({ + queryKey: ["enabled-plugins"], + queryFn: async () => { + const { data } = await apiClient.plugin.listPlugins({ + page: 0, + size: 0, + enabled: true, + }); + + return data.items; + }, + enabled: computed(() => currentUserHasPermission(["system:plugins:view"])), +}); const isExternalUrlValid = computed(() => { if (!globalInfo.value?.useAbsolutePermalink) { @@ -67,43 +98,101 @@ const isExternalUrlValid = computed(() => { return url.host === currentHost && url.protocol === currentProtocol; }); -onMounted(() => { - handleFetchActuatorInfo(); - handleFetchActuatorGlobalInfo(); - handleFetchActuatorStartup(); -}); - // copy system information to clipboard const { copy, isSupported } = useClipboard({ legacy: true }); +interface CopyItem { + label: string; + value?: string; + href?: string; + children?: CopyItem[]; +} + const handleCopy = () => { if (!isSupported.value) { Toast.warning(t("core.actuator.actions.copy.toast_browser_not_supported")); return; } - const text = ` -- ${t("core.actuator.copy_results.external_url", { - external_url: globalInfo.value?.externalUrl, - })} -- ${t("core.actuator.copy_results.start_time", { - start_time: formatDatetime(startup.value?.timeline.startTime), - })} -- ${t("core.actuator.fields.version", { version: info.value?.build?.version })} -- ${t("core.actuator.copy_results.build_time", { - build_time: formatDatetime(info.value?.build?.time), - })} -- Git Commit:${info.value?.git?.commit.id} -- Java:${info.value?.java.runtime.name} / ${info.value?.java.runtime.version} -- ${t("core.actuator.copy_results.database", { - database: [info.value?.database.name, info.value?.database.version].join( - " / " - ), - })} -- ${t("core.actuator.copy_results.os", { - os: [info.value?.os.name, info.value?.os.version].join(" / "), - })} - `; + const copyItems: CopyItem[] = [ + { + label: t("core.actuator.fields.external_url"), + value: globalInfo.value?.externalUrl || "", + }, + { + label: t("core.actuator.fields.start_time"), + value: formatDatetime(startup.value?.timeline.startTime) || "", + }, + { + label: t("core.actuator.fields.version"), + value: info.value?.build?.version || "", + }, + { + label: t("core.actuator.fields.build_time"), + value: formatDatetime(info.value?.build?.time) || "", + }, + { + label: "Git Commit", + value: info.value?.git?.commit.id || "", + }, + { + label: "Java", + value: + [info.value?.java.runtime.name, info.value?.java.runtime.version] + .filter(Boolean) + .join(" / ") + .trim() || "", + }, + { + label: t("core.actuator.fields.database"), + value: + [info.value?.database.name, info.value?.database.version] + .filter(Boolean) + .join(" / ") || "", + }, + { + label: t("core.actuator.fields.os"), + value: + [info.value?.os.name, info.value?.os.version] + .filter(Boolean) + .join(" / ") || "", + }, + { + label: t("core.actuator.fields.activated_theme"), + value: themeStore.activatedTheme?.spec.displayName || "", + href: + themeStore.activatedTheme?.spec.repo || + themeStore.activatedTheme?.spec.homepage, + }, + { + label: t("core.actuator.fields.enabled_plugins"), + children: plugins.value?.map((plugin) => ({ + value: plugin.spec.displayName, + href: plugin.spec.repo || plugin.spec.homepage, + })) as CopyItem[], + }, + ]; + + const text = copyItems + .map((item) => { + if (item.children?.length) { + const childrenText = item.children + .map( + (child) => + ` - ${ + child.href ? `[${child.value}](${child.href})` : child.value + }` + ) + .filter(Boolean) + .join("\n"); + return `- ${item.label}:\n${childrenText}`; + } else { + return `- ${item.label}: ${ + item.href ? `[${item.value}](${item.href})` : item.value || "" + }`; + } + }) + .join("\n"); copy(text); @@ -182,17 +271,55 @@ const handleDownloadLogfile = () => { + v-if="themeStore.activatedTheme" + :label="$t('core.actuator.fields.activated_theme')" + > + + + {{ themeStore.activatedTheme.spec.displayName }} + + + v-permission="['system:plugins:view']" + :label="$t('core.actuator.fields.enabled_plugins')" + > + + + {{ $t("core.common.text.none") }} + +
+ + + {{ plugin.spec.displayName }} + +
+
@@ -249,6 +376,14 @@ const handleDownloadLogfile = () => { {{ info.os.name }} {{ info.os.version }} / {{ info.os.arch }} + +