halo/ui/console-src/modules/system/plugins/PluginDetail.vue

155 lines
4.0 KiB
Vue
Raw Normal View History

<script lang="ts" setup>
// core libs
import { provide, ref, computed } from "vue";
import { useRoute } from "vue-router";
import { apiClient } from "@/utils/api-client";
// libs
import { cloneDeep } from "lodash-es";
// components
import { VCard, VPageHeader, VTabbar, VAvatar } from "@halo-dev/components";
// types
import type { Ref } from "vue";
import type { Plugin, Setting, SettingForm } from "@halo-dev/api-client";
import { usePermission } from "@/utils/permission";
import { useI18n } from "vue-i18n";
import { useQuery } from "@tanstack/vue-query";
import type { PluginTab } from "@halo-dev/console-shared";
import { markRaw } from "vue";
import DetailTab from "./tabs/Detail.vue";
import SettingTab from "./tabs/Setting.vue";
import { useRouteQuery } from "@vueuse/router";
import { usePluginModuleStore } from "@/stores/plugin";
const { currentUserHasPermission } = usePermission();
const { t } = useI18n();
const initialTabs = ref<PluginTab[]>([
{
id: "detail",
label: t("core.plugin.tabs.detail"),
component: markRaw(DetailTab),
},
]);
const route = useRoute();
const tabs = ref<PluginTab[]>(cloneDeep(initialTabs.value));
const activeTab = useRouteQuery<string>("tab", tabs.value[0].id);
provide<Ref<string>>("activeTab", activeTab);
const { data: plugin } = useQuery({
queryKey: ["plugin", route.params.name],
queryFn: async () => {
const { data } =
await apiClient.extension.plugin.getPluginHaloRunV1alpha1Plugin({
name: route.params.name as string,
});
return data;
},
onSuccess(data) {
fix: plugin extension tab cannot be displayed when only having plugin view permissions (#4746) <!-- Thanks for sending a pull request! Here are some tips for you: 1. 如果这是你的第一次,请阅读我们的贡献指南:<https://github.com/halo-dev/halo/blob/master/CONTRIBUTING.md>。 1. If this is your first time, please read our contributor guidelines: <https://github.com/halo-dev/halo/blob/master/CONTRIBUTING.md>. 2. 请根据你解决问题的类型为 Pull Request 添加合适的标签。 2. Please label this pull request according to what type of issue you are addressing, especially if this is a release targeted pull request. 3. 请确保你已经添加并运行了适当的测试。 3. Ensure you have added or ran the appropriate tests for your PR. --> #### What type of PR is this? /kind bug /area console <!-- 添加其中一个类别: Add one of the following kinds: /kind bug /kind cleanup /kind documentation /kind feature /kind improvement 适当添加其中一个或多个类别(可选): Optionally add one or more of the following kinds if applicable: /kind api-change /kind deprecation /kind failing-test /kind flake /kind regression --> #### What this PR does / why we need it: 修复用户仅拥有插件查看权限时,有setting的插件会导致无法加载插件扩展tab的问题 #### Which issue(s) this PR fixes: <!-- PR 合并时自动关闭 issue。 Automatically closes linked issue when PR is merged. 用法:`Fixes #<issue 号>`,或者 `Fixes (粘贴 issue 完整链接)` Usage: `Fixes #<issue number>`, or `Fixes (paste link of issue)`. --> Fixes #4732 #### Special notes for your reviewer: 1. 使用如下测试版 s3 插件 [plugin-s3-1.5.0-SNAPSHOT.jar.zip](https://github.com/halo-dev/halo/files/12914987/plugin-s3-1.5.0-SNAPSHOT.jar.zip) <https://github.com/longjuan/halo-plugin-s3os/tree/aaa> 2. 创建一个用户,仅赋予 S3 Link 权限(依赖于插件查看和附件管理权限) 3. 登录这个新用户,打开 s3 插件详情 4. 观察 关联S3文件 功能是否正常出现 #### Does this PR introduce a user-facing change? <!-- 如果当前 Pull Request 的修改不会造成用户侧的任何变更,在 `release-note` 代码块儿中填写 `NONE`。 否则请填写用户侧能够理解的 Release Note。如果当前 Pull Request 包含破坏性更新(Break Change), Release Note 需要以 `action required` 开头。 If no, just write "NONE" in the release-note block below. If yes, a release note is required: Enter your extended release note in the block below. If the PR requires additional action from users switching to the new release, include the string "action required". --> ```release-note 修复部分场景下插件详情的扩展 tab 不能正常显示的问题 ```
2023-10-19 05:32:25 +00:00
if (
!data.spec.settingName ||
!currentUserHasPermission(["system:plugins:manage"])
) {
tabs.value = [...initialTabs.value, ...getTabsFromExtensions()];
}
},
});
provide<Ref<Plugin | undefined>>("plugin", plugin);
const { data: setting } = useQuery({
queryKey: ["plugin-setting", plugin],
queryFn: async () => {
const { data } = await apiClient.plugin.fetchPluginSetting({
name: plugin.value?.metadata.name as string,
});
return data;
},
enabled: computed(() => {
return (
!!plugin.value &&
!!plugin.value.spec.settingName &&
currentUserHasPermission(["system:plugins:manage"])
);
}),
async onSuccess(data) {
if (data) {
const { forms } = data.spec;
tabs.value = [
...initialTabs.value,
...getTabsFromExtensions(),
...forms.map((item: SettingForm) => {
return {
id: item.group,
label: item.label || "",
component: markRaw(SettingTab),
};
}),
] as PluginTab[];
}
},
});
provide<Ref<Setting | undefined>>("setting", setting);
function getTabsFromExtensions(): PluginTab[] {
const { pluginModuleMap } = usePluginModuleStore();
const currentPluginModule = pluginModuleMap[route.params.name as string];
if (!currentPluginModule) {
return [];
}
const { extensionPoints } = currentPluginModule;
if (!extensionPoints?.["plugin:self:tabs:create"]) {
return [];
}
const pluginTabs = extensionPoints[
"plugin:self:tabs:create"
]() as PluginTab[];
return pluginTabs.filter((tab) => {
return currentUserHasPermission(tab.permissions);
});
}
</script>
<template>
<VPageHeader :title="plugin?.spec?.displayName">
<template #icon>
<VAvatar
v-if="plugin"
:src="plugin.status?.logo"
:alt="plugin.spec.displayName"
class="mr-2"
size="sm"
/>
</template>
</VPageHeader>
<div class="m-0 md:m-4">
<VCard :body-class="['!p-0', '!overflow-visible']">
<template #header>
<VTabbar
v-model:active-id="activeTab"
:items="tabs.map((item) => ({ id: item.id, label: item.label }))"
class="w-full !rounded-none"
type="outline"
></VTabbar>
</template>
<div class="rounded-b-base bg-white">
<template v-for="tab in tabs" :key="tab.id">
<component :is="tab.component" v-if="activeTab === tab.id" />
</template>
</div>
</VCard>
</div>
</template>