mirror of https://github.com/halo-dev/halo-admin
refactor: use new apis to refactor plugins management (#824)
#### What type of PR is this? /kind improvement /milestone 2.2.x #### What this PR does / why we need it: 使用新的 API 来管理插件,用于区分插件管理和配置相关的权限。适配:https://github.com/halo-dev/halo/pull/3142 #### Which issue(s) this PR fixes: Ref https://github.com/halo-dev/halo/issues/3069 #### Screenshots: #### Special notes for your reviewer: 测试方式: 1. Halo 需要切换到 https://github.com/halo-dev/halo/pull/3142 分支。 2. Console 需要 `pnpm install`。 1. 插件设置项,需要测试保存,安装新插件之后表单是否正常。 3. 创建一个角色,测试仅有管理/查看插件的角色,登录之后检查是否符合预期。 #### Does this PR introduce a user-facing change? ```release-note 重构 Console 端插件的设置表单逻辑。 ```pull/828/head^2
parent
ab888119ef
commit
62f8e2e703
|
@ -1,65 +1,67 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
// core libs
|
// core libs
|
||||||
import { computed, ref } from "vue";
|
import { inject, ref, type Ref } from "vue";
|
||||||
|
|
||||||
// hooks
|
// hooks
|
||||||
import { useSettingForm } from "@/composables/use-setting-form";
|
import { useSettingFormConvert } from "@/composables/use-setting-form";
|
||||||
import { apiClient } from "@/utils/api-client";
|
import { apiClient } from "@/utils/api-client";
|
||||||
|
|
||||||
// components
|
// components
|
||||||
import { VButton } from "@halo-dev/components";
|
import { VButton } from "@halo-dev/components";
|
||||||
|
|
||||||
// types
|
// types
|
||||||
import type { Plugin } from "@halo-dev/api-client";
|
import type { ConfigMap, Plugin, Setting } from "@halo-dev/api-client";
|
||||||
import { useRouteParams } from "@vueuse/router";
|
import { useRouteParams } from "@vueuse/router";
|
||||||
import type { FormKitSchemaCondition, FormKitSchemaNode } from "@formkit/core";
|
|
||||||
|
|
||||||
const name = useRouteParams<string>("name");
|
|
||||||
const group = useRouteParams<string>("group");
|
const group = useRouteParams<string>("group");
|
||||||
|
|
||||||
const plugin = ref<Plugin | undefined>();
|
const plugin = inject<Ref<Plugin | undefined>>("plugin");
|
||||||
|
const saving = ref(false);
|
||||||
|
const setting = ref<Setting>();
|
||||||
|
const configMap = ref<ConfigMap>();
|
||||||
|
|
||||||
const settingName = computed(() => plugin?.value?.spec.settingName);
|
const { configMapFormData, formSchema, convertToSave } = useSettingFormConvert(
|
||||||
const configMapName = computed(() => plugin?.value?.spec.configMapName);
|
|
||||||
|
|
||||||
const {
|
|
||||||
setting,
|
setting,
|
||||||
configMapFormData,
|
configMap,
|
||||||
saving,
|
group
|
||||||
handleFetchSettings,
|
);
|
||||||
handleFetchConfigMap,
|
|
||||||
handleSaveConfigMap,
|
|
||||||
} = useSettingForm(settingName, configMapName);
|
|
||||||
|
|
||||||
const formSchema = computed(() => {
|
const handleFetchSettings = async () => {
|
||||||
if (!setting.value) {
|
if (!plugin?.value) return;
|
||||||
return;
|
const { data } = await apiClient.plugin.fetchPluginSetting({
|
||||||
}
|
name: plugin.value.metadata.name,
|
||||||
const { forms } = setting.value.spec;
|
|
||||||
return forms.find((item) => item.group === group.value)?.formSchema as (
|
|
||||||
| FormKitSchemaCondition
|
|
||||||
| FormKitSchemaNode
|
|
||||||
)[];
|
|
||||||
});
|
|
||||||
|
|
||||||
const handleFetchPlugin = async () => {
|
|
||||||
try {
|
|
||||||
const { data } =
|
|
||||||
await apiClient.extension.plugin.getpluginHaloRunV1alpha1Plugin({
|
|
||||||
name: name.value,
|
|
||||||
});
|
});
|
||||||
plugin.value = data;
|
setting.value = data;
|
||||||
|
|
||||||
if (settingName.value && configMapName.value) {
|
|
||||||
await handleFetchSettings();
|
|
||||||
await handleFetchConfigMap();
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.error("Failed to fetch plugin and settings", e);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
await handleFetchPlugin();
|
const handleFetchConfigMap = async () => {
|
||||||
|
if (!plugin?.value) return;
|
||||||
|
const { data } = await apiClient.plugin.fetchPluginConfig({
|
||||||
|
name: plugin.value.metadata.name,
|
||||||
|
});
|
||||||
|
configMap.value = data;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSaveConfigMap = async () => {
|
||||||
|
saving.value = true;
|
||||||
|
const configMapToUpdate = convertToSave();
|
||||||
|
if (!configMapToUpdate || !plugin?.value) {
|
||||||
|
saving.value = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { data: newConfigMap } = await apiClient.plugin.updatePluginConfig({
|
||||||
|
name: plugin.value.metadata.name,
|
||||||
|
configMap: configMapToUpdate,
|
||||||
|
});
|
||||||
|
|
||||||
|
await handleFetchSettings();
|
||||||
|
configMap.value = newConfigMap;
|
||||||
|
saving.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
await handleFetchSettings();
|
||||||
|
await handleFetchConfigMap();
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<Transition mode="out-in" name="fade">
|
<Transition mode="out-in" name="fade">
|
||||||
|
@ -81,7 +83,7 @@ await handleFetchPlugin();
|
||||||
/>
|
/>
|
||||||
</FormKit>
|
</FormKit>
|
||||||
</div>
|
</div>
|
||||||
<div v-permission="['system:configmaps:manage']" class="pt-5">
|
<div v-permission="['system:plugins:manage']" class="pt-5">
|
||||||
<div class="flex justify-start">
|
<div class="flex justify-start">
|
||||||
<VButton
|
<VButton
|
||||||
:loading="saving"
|
:loading="saving"
|
||||||
|
|
|
@ -1,18 +1,14 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
// core libs
|
// core libs
|
||||||
import { computed, nextTick, onMounted, provide, ref, watch } from "vue";
|
import { nextTick, onMounted, provide, ref, watch } from "vue";
|
||||||
import { RouterView, useRoute, useRouter } from "vue-router";
|
import { RouterView, useRoute, useRouter } from "vue-router";
|
||||||
import { apiClient } from "@/utils/api-client";
|
import { apiClient } from "@/utils/api-client";
|
||||||
|
|
||||||
// libs
|
// libs
|
||||||
import cloneDeep from "lodash.clonedeep";
|
import cloneDeep from "lodash.clonedeep";
|
||||||
|
|
||||||
// hooks
|
|
||||||
import { useSettingForm } from "@/composables/use-setting-form";
|
|
||||||
|
|
||||||
// components
|
// components
|
||||||
import {
|
import {
|
||||||
VButton,
|
|
||||||
VCard,
|
VCard,
|
||||||
VPageHeader,
|
VPageHeader,
|
||||||
VTabbar,
|
VTabbar,
|
||||||
|
@ -23,7 +19,7 @@ import BasicLayout from "@/layouts/BasicLayout.vue";
|
||||||
|
|
||||||
// types
|
// types
|
||||||
import type { Ref } from "vue";
|
import type { Ref } from "vue";
|
||||||
import type { Plugin, SettingForm } from "@halo-dev/api-client";
|
import type { Plugin, Setting, SettingForm } from "@halo-dev/api-client";
|
||||||
import { usePermission } from "@/utils/permission";
|
import { usePermission } from "@/utils/permission";
|
||||||
import { usePluginLifeCycle } from "../composables/use-plugin";
|
import { usePluginLifeCycle } from "../composables/use-plugin";
|
||||||
|
|
||||||
|
@ -52,22 +48,15 @@ const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const plugin = ref<Plugin>();
|
const plugin = ref<Plugin>();
|
||||||
|
const setting = ref<Setting>();
|
||||||
const tabs = ref<PluginTab[]>(cloneDeep(initialTabs));
|
const tabs = ref<PluginTab[]>(cloneDeep(initialTabs));
|
||||||
const activeTab = ref<string>();
|
const activeTab = ref<string>();
|
||||||
|
|
||||||
provide<Ref<Plugin | undefined>>("plugin", plugin);
|
provide<Ref<Plugin | undefined>>("plugin", plugin);
|
||||||
provide<Ref<string | undefined>>("activeTab", activeTab);
|
provide<Ref<string | undefined>>("activeTab", activeTab);
|
||||||
|
|
||||||
const settingName = computed(() => plugin.value?.spec.settingName);
|
|
||||||
const configMapName = computed(() => plugin.value?.spec.configMapName);
|
|
||||||
|
|
||||||
const { isStarted } = usePluginLifeCycle(plugin);
|
const { isStarted } = usePluginLifeCycle(plugin);
|
||||||
|
|
||||||
const { setting, handleFetchSettings } = useSettingForm(
|
|
||||||
settingName,
|
|
||||||
configMapName
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleFetchPlugin = async () => {
|
const handleFetchPlugin = async () => {
|
||||||
try {
|
try {
|
||||||
const response =
|
const response =
|
||||||
|
@ -80,6 +69,14 @@ const handleFetchPlugin = async () => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleFetchSettings = async () => {
|
||||||
|
if (!plugin.value) return;
|
||||||
|
const { data } = await apiClient.plugin.fetchPluginSetting({
|
||||||
|
name: plugin.value?.metadata.name,
|
||||||
|
});
|
||||||
|
setting.value = data;
|
||||||
|
};
|
||||||
|
|
||||||
const handleTabChange = (id: string) => {
|
const handleTabChange = (id: string) => {
|
||||||
const tab = tabs.value.find((item) => item.id === id);
|
const tab = tabs.value.find((item) => item.id === id);
|
||||||
if (tab) {
|
if (tab) {
|
||||||
|
@ -110,7 +107,7 @@ const handleTriggerTabChange = () => {
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await handleFetchPlugin();
|
await handleFetchPlugin();
|
||||||
|
|
||||||
if (!currentUserHasPermission(["system:settings:view"])) {
|
if (!currentUserHasPermission(["system:plugins:manage"])) {
|
||||||
handleTriggerTabChange();
|
handleTriggerTabChange();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -161,9 +158,6 @@ watch([() => route.name, () => route.params], () => {
|
||||||
size="sm"
|
size="sm"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template #actions>
|
|
||||||
<VButton class="opacity-0" type="secondary">安装</VButton>
|
|
||||||
</template>
|
|
||||||
</VPageHeader>
|
</VPageHeader>
|
||||||
|
|
||||||
<div class="m-0 md:m-4">
|
<div class="m-0 md:m-4">
|
||||||
|
|
|
@ -56,7 +56,7 @@ export default definePlugin({
|
||||||
component: PluginSetting,
|
component: PluginSetting,
|
||||||
meta: {
|
meta: {
|
||||||
title: "插件设置",
|
title: "插件设置",
|
||||||
permissions: ["system:settings:view"],
|
permissions: ["system:plugins:manage"],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
Loading…
Reference in New Issue