mirror of https://github.com/halo-dev/halo
perf: improve plugin detail and settings page
parent
bcd997231a
commit
088196e6ae
|
@ -1,3 +1,2 @@
|
|||
export { default as BlankLayout } from "./BlankLayout.vue";
|
||||
export { default as BasicLayout } from "./BasicLayout.vue";
|
||||
export { default as PluginLayout } from "./PluginLayout.vue";
|
||||
|
|
|
@ -8,7 +8,7 @@ import { pluginLabels } from "@/constants/labels";
|
|||
import { rbacAnnotations } from "@/constants/annotations";
|
||||
import { usePluginLifeCycle } from "./composables/use-plugin";
|
||||
|
||||
const plugin = inject<Ref<Plugin>>("plugin", ref({} as Plugin));
|
||||
const plugin = inject<Ref<Plugin | undefined>>("plugin");
|
||||
const { changeStatus, isStarted } = usePluginLifeCycle(plugin);
|
||||
|
||||
interface RoleTemplateGroup {
|
||||
|
@ -23,7 +23,7 @@ const handleFetchRoles = async () => {
|
|||
const { data } = await apiClient.extension.role.listv1alpha1Role({
|
||||
page: 0,
|
||||
size: 0,
|
||||
labelSelector: [`${pluginLabels.NAME}=${plugin.value.metadata.name}`],
|
||||
labelSelector: [`${pluginLabels.NAME}=${plugin?.value?.metadata.name}`],
|
||||
});
|
||||
pluginRoleTemplates.value = data.items;
|
||||
} catch (e) {
|
||||
|
@ -51,7 +51,7 @@ const pluginRoleTemplateGroups = computed<RoleTemplateGroup[]>(() => {
|
|||
});
|
||||
|
||||
watchEffect(() => {
|
||||
if (plugin.value.metadata?.name) {
|
||||
if (plugin?.value) {
|
||||
handleFetchRoles();
|
||||
}
|
||||
});
|
||||
|
@ -62,7 +62,7 @@ watchEffect(() => {
|
|||
<div>
|
||||
<h3 class="text-lg font-medium leading-6 text-gray-900">插件信息</h3>
|
||||
<p class="mt-1 flex max-w-2xl items-center gap-2 text-sm text-gray-500">
|
||||
<span>{{ plugin?.spec?.version }}</span>
|
||||
<span>{{ plugin?.spec.version }}</span>
|
||||
<VTag>
|
||||
{{ isStarted ? "已启用" : "未启用" }}
|
||||
</VTag>
|
||||
|
@ -79,7 +79,7 @@ watchEffect(() => {
|
|||
>
|
||||
<dt class="text-sm font-medium text-gray-900">名称</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||
{{ plugin?.spec?.displayName }}
|
||||
{{ plugin?.spec.displayName }}
|
||||
</dd>
|
||||
</div>
|
||||
<div
|
||||
|
@ -87,7 +87,7 @@ watchEffect(() => {
|
|||
>
|
||||
<dt class="text-sm font-medium text-gray-900">版本</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||
{{ plugin?.spec?.version }}
|
||||
{{ plugin?.spec.version }}
|
||||
</dd>
|
||||
</div>
|
||||
<div
|
||||
|
@ -95,7 +95,7 @@ watchEffect(() => {
|
|||
>
|
||||
<dt class="text-sm font-medium text-gray-900">Halo 版本要求</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||
{{ plugin?.spec?.requires }}
|
||||
{{ plugin?.spec.requires }}
|
||||
</dd>
|
||||
</div>
|
||||
<div
|
||||
|
@ -103,8 +103,8 @@ watchEffect(() => {
|
|||
>
|
||||
<dt class="text-sm font-medium text-gray-900">提供方</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||
<a :href="plugin?.spec?.homepage" target="_blank">
|
||||
{{ plugin?.spec?.author }}
|
||||
<a :href="plugin?.spec.homepage" target="_blank">
|
||||
{{ plugin?.spec.author }}
|
||||
</a>
|
||||
</dd>
|
||||
</div>
|
||||
|
@ -114,7 +114,7 @@ watchEffect(() => {
|
|||
<dt class="text-sm font-medium text-gray-900">协议</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||
<ul
|
||||
v-if="plugin?.spec?.license && plugin?.spec?.license.length"
|
||||
v-if="plugin?.spec.license && plugin?.spec.license.length"
|
||||
class="list-inside list-disc"
|
||||
>
|
||||
<li v-for="(license, index) in plugin.spec.license" :key="index">
|
||||
|
@ -132,7 +132,7 @@ watchEffect(() => {
|
|||
class="bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-6 sm:gap-4 sm:px-6"
|
||||
>
|
||||
<dt class="text-sm font-medium text-gray-900">模型定义</dt>
|
||||
<dd class="mt-1 sm:col-span-2 sm:mt-0">
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||
<span>无</span>
|
||||
</dd>
|
||||
</div>
|
||||
|
|
|
@ -1,22 +1,24 @@
|
|||
<script lang="ts" setup>
|
||||
// core libs
|
||||
import { computed, inject, ref, watchEffect } from "vue";
|
||||
import { computed, ref } from "vue";
|
||||
|
||||
// hooks
|
||||
import { useSettingForm } from "@halo-dev/admin-shared";
|
||||
import { apiClient, useSettingForm } from "@halo-dev/admin-shared";
|
||||
|
||||
// components
|
||||
import { VButton } from "@halo-dev/components";
|
||||
|
||||
// types
|
||||
import type { Ref } from "vue";
|
||||
import type { Plugin } from "@halo-dev/api-client";
|
||||
import { useRouteParams } from "@vueuse/router";
|
||||
|
||||
const plugin = inject<Ref<Plugin>>("plugin", ref({} as Plugin));
|
||||
const group = inject<Ref<string | undefined>>("activeTab");
|
||||
const name = useRouteParams<string>("name");
|
||||
const group = useRouteParams<string>("group");
|
||||
|
||||
const settingName = computed(() => plugin.value.spec?.settingName);
|
||||
const configMapName = computed(() => plugin.value.spec?.configMapName);
|
||||
const plugin = ref<Plugin | undefined>();
|
||||
|
||||
const settingName = computed(() => plugin?.value?.spec.settingName);
|
||||
const configMapName = computed(() => plugin?.value?.spec.configMapName);
|
||||
|
||||
const {
|
||||
settings,
|
||||
|
@ -31,16 +33,28 @@ const formSchema = computed(() => {
|
|||
if (!settings?.value?.spec) {
|
||||
return;
|
||||
}
|
||||
return settings.value.spec.find((item) => item.group === group?.value)
|
||||
return settings.value.spec.find((item) => item.group === group.value)
|
||||
?.formSchema;
|
||||
});
|
||||
|
||||
watchEffect(async () => {
|
||||
if (settingName.value && configMapName.value) {
|
||||
await handleFetchSettings();
|
||||
await handleFetchConfigMap();
|
||||
const handleFetchPlugin = async () => {
|
||||
try {
|
||||
const { data } =
|
||||
await apiClient.extension.plugin.getpluginHaloRunV1alpha1Plugin({
|
||||
name: name.value,
|
||||
});
|
||||
plugin.value = data;
|
||||
|
||||
if (settingName.value && configMapName.value) {
|
||||
await handleFetchSettings();
|
||||
await handleFetchConfigMap();
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Failed to fetch plugin and settings", e);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
await handleFetchPlugin();
|
||||
</script>
|
||||
<template>
|
||||
<div class="bg-white p-4 sm:px-6">
|
||||
|
|
|
@ -13,10 +13,10 @@ import { formatDatetime } from "@/utils/date";
|
|||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
plugin: Plugin | null;
|
||||
plugin?: Plugin;
|
||||
}>(),
|
||||
{
|
||||
plugin: null,
|
||||
plugin: undefined,
|
||||
}
|
||||
);
|
||||
|
||||
|
|
|
@ -12,18 +12,18 @@ interface usePluginLifeCycleReturn {
|
|||
}
|
||||
|
||||
export function usePluginLifeCycle(
|
||||
plugin: Ref<Plugin | null>
|
||||
plugin?: Ref<Plugin | undefined>
|
||||
): usePluginLifeCycleReturn {
|
||||
const dialog = useDialog();
|
||||
|
||||
const isStarted = computed(() => {
|
||||
return (
|
||||
plugin.value?.status?.phase === "STARTED" && plugin.value?.spec.enabled
|
||||
plugin?.value?.status?.phase === "STARTED" && plugin.value?.spec.enabled
|
||||
);
|
||||
});
|
||||
|
||||
const changeStatus = () => {
|
||||
if (!plugin.value) return;
|
||||
if (!plugin?.value) return;
|
||||
|
||||
const pluginToUpdate = cloneDeep(plugin.value);
|
||||
|
||||
|
@ -46,7 +46,7 @@ export function usePluginLifeCycle(
|
|||
};
|
||||
|
||||
const uninstall = () => {
|
||||
if (!plugin.value) return;
|
||||
if (!plugin?.value) return;
|
||||
|
||||
const { enabled } = plugin.value.spec;
|
||||
|
||||
|
|
|
@ -1,23 +1,23 @@
|
|||
<script lang="ts" setup>
|
||||
// core libs
|
||||
import { computed, onMounted, provide, ref, watch } from "vue";
|
||||
import { computed, nextTick, onMounted, provide, ref, watch } from "vue";
|
||||
import { RouterView, useRoute, useRouter } from "vue-router";
|
||||
import { apiClient } from "../utils/api-client";
|
||||
import { apiClient } from "@halo-dev/admin-shared";
|
||||
|
||||
// libs
|
||||
import cloneDeep from "lodash.clonedeep";
|
||||
|
||||
// hooks
|
||||
import { useSettingForm } from "../composables";
|
||||
import { useSettingForm } from "@halo-dev/admin-shared";
|
||||
|
||||
// components
|
||||
import { VButton, VCard, VPageHeader, VTabbar } from "@halo-dev/components";
|
||||
import { BasicLayout } from "../layouts";
|
||||
import { BasicLayout } from "@halo-dev/admin-shared";
|
||||
|
||||
// types
|
||||
import type { Ref } from "vue";
|
||||
import type { Plugin } from "@halo-dev/api-client";
|
||||
import type { FormKitSettingSpec } from "../types/formkit";
|
||||
import type { FormKitSettingSpec } from "@halo-dev/admin-shared";
|
||||
|
||||
interface PluginTab {
|
||||
id: string;
|
||||
|
@ -41,15 +41,15 @@ const initialTabs: PluginTab[] = [
|
|||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
|
||||
const plugin = ref<Plugin>({} as Plugin);
|
||||
const plugin = ref<Plugin>();
|
||||
const tabs = ref<PluginTab[]>(cloneDeep(initialTabs));
|
||||
const activeTab = ref<string>();
|
||||
|
||||
provide<Ref<Plugin>>("plugin", plugin);
|
||||
provide<Ref<Plugin | undefined>>("plugin", plugin);
|
||||
provide<Ref<string | undefined>>("activeTab", activeTab);
|
||||
|
||||
const settingName = computed(() => plugin.value.spec?.settingName);
|
||||
const configMapName = computed(() => plugin.value.spec?.configMapName);
|
||||
const settingName = computed(() => plugin.value?.spec.settingName);
|
||||
const configMapName = computed(() => plugin.value?.spec.configMapName);
|
||||
|
||||
const { settings, handleFetchSettings } = useSettingForm(
|
||||
settingName,
|
||||
|
@ -71,15 +71,16 @@ const handleFetchPlugin = async () => {
|
|||
const handleTabChange = (id: string) => {
|
||||
const tab = tabs.value.find((item) => item.id === id);
|
||||
if (tab) {
|
||||
activeTab.value = tab.id;
|
||||
router.push(tab.route);
|
||||
}
|
||||
};
|
||||
|
||||
const onTabChange = (routeName: string) => {
|
||||
if (routeName === "PluginSetting") {
|
||||
const handleTriggerTabChange = () => {
|
||||
if (route.name === "PluginSetting") {
|
||||
const tab = tabs.value.find((tab) => {
|
||||
return (
|
||||
tab.route.name === routeName &&
|
||||
tab.route.name === route.name &&
|
||||
tab.route.params?.group === route.params.group
|
||||
);
|
||||
});
|
||||
|
@ -87,7 +88,7 @@ const onTabChange = (routeName: string) => {
|
|||
activeTab.value = tab.id;
|
||||
return;
|
||||
}
|
||||
router.push({ name: "PluginDetail" });
|
||||
handleTabChange(tabs.value[0].id);
|
||||
return;
|
||||
}
|
||||
const tab = tabs.value.find((tab) => tab.route.name === route.name);
|
||||
|
@ -99,6 +100,7 @@ onMounted(async () => {
|
|||
await handleFetchSettings();
|
||||
|
||||
tabs.value = cloneDeep(initialTabs);
|
||||
|
||||
if (settings.value && settings.value.spec) {
|
||||
tabs.value = [
|
||||
...tabs.value,
|
||||
|
@ -115,16 +117,16 @@ onMounted(async () => {
|
|||
};
|
||||
}),
|
||||
] as PluginTab[];
|
||||
onTabChange(route.name as string);
|
||||
}
|
||||
|
||||
await nextTick();
|
||||
|
||||
handleTriggerTabChange();
|
||||
});
|
||||
|
||||
watch(
|
||||
() => route.name,
|
||||
async (newRouteName) => {
|
||||
onTabChange(newRouteName as string);
|
||||
}
|
||||
);
|
||||
watch([() => route.name, () => route.params], () => {
|
||||
handleTriggerTabChange();
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
<BasicLayout>
|
||||
|
@ -150,7 +152,18 @@ watch(
|
|||
</template>
|
||||
</VCard>
|
||||
<div>
|
||||
<RouterView :key="activeTab" />
|
||||
<RouterView :key="activeTab" v-slot="{ Component }">
|
||||
<template v-if="Component">
|
||||
<Suspense>
|
||||
<component :is="Component"></component>
|
||||
<template #fallback>
|
||||
<div class="flex h-32 w-full justify-center bg-white">
|
||||
<span class="text-sm text-gray-600">加载中...</span>
|
||||
</div>
|
||||
</template>
|
||||
</Suspense>
|
||||
</template>
|
||||
</RouterView>
|
||||
</div>
|
||||
</div>
|
||||
</BasicLayout>
|
|
@ -1,9 +1,5 @@
|
|||
import {
|
||||
BasicLayout,
|
||||
BlankLayout,
|
||||
definePlugin,
|
||||
PluginLayout,
|
||||
} from "@halo-dev/admin-shared";
|
||||
import { BasicLayout, BlankLayout, definePlugin } from "@halo-dev/admin-shared";
|
||||
import PluginLayout from "./layouts/PluginLayout.vue";
|
||||
import PluginList from "./PluginList.vue";
|
||||
import PluginSetting from "./PluginSetting.vue";
|
||||
import PluginDetail from "./PluginDetail.vue";
|
||||
|
|
Loading…
Reference in New Issue