diff --git a/ui/console-src/modules/system/plugins/PluginDetail.vue b/ui/console-src/modules/system/plugins/PluginDetail.vue
index eeca579ed..c12735fed 100644
--- a/ui/console-src/modules/system/plugins/PluginDetail.vue
+++ b/ui/console-src/modules/system/plugins/PluginDetail.vue
@@ -1,123 +1,23 @@
 <script lang="ts" setup>
-// core libs
-import { consoleApiClient, coreApiClient } from "@halo-dev/api-client";
-import { computed, provide, ref } from "vue";
-import { useRoute } from "vue-router";
-
-// libs
-import { cloneDeep } from "lodash-es";
-
-// components
+import type { Plugin, Setting } from "@halo-dev/api-client";
 import { VAvatar, VCard, VPageHeader, VTabbar } from "@halo-dev/components";
-
-// types
-import { usePluginModuleStore } from "@/stores/plugin";
-import { usePermission } from "@/utils/permission";
-import type { Plugin, Setting, SettingForm } from "@halo-dev/api-client";
-import type { PluginTab } from "@halo-dev/console-shared";
-import { useQuery } from "@tanstack/vue-query";
-import { useRouteQuery } from "@vueuse/router";
 import type { Ref } from "vue";
-import { markRaw } from "vue";
-import { useI18n } from "vue-i18n";
-import DetailTab from "./tabs/Detail.vue";
-import SettingTab from "./tabs/Setting.vue";
-
-const { currentUserHasPermission } = usePermission();
-const { t } = useI18n();
-
-const initialTabs = ref<PluginTab[]>([
-  {
-    id: "detail",
-    label: t("core.plugin.tabs.detail"),
-    component: markRaw(DetailTab),
-  },
-]);
+import { provide, toRefs } from "vue";
+import { useRoute } from "vue-router";
+import { usePluginDetailTabs } from "./composables/use-plugin";
 
 const route = useRoute();
 
-const tabs = ref<PluginTab[]>(cloneDeep(initialTabs.value));
-const activeTab = useRouteQuery<string>("tab", tabs.value[0].id);
+const { name } = toRefs(route.params);
+
+const { plugin, setting, activeTab, tabs } = usePluginDetailTabs(
+  name as Ref<string | undefined>,
+  true
+);
 
 provide<Ref<string>>("activeTab", activeTab);
-
-const { data: plugin } = useQuery({
-  queryKey: ["plugin", route.params.name],
-  queryFn: async () => {
-    const { data } = await coreApiClient.plugin.plugin.getPlugin({
-      name: route.params.name as string,
-    });
-    return data;
-  },
-  async onSuccess(data) {
-    if (
-      !data.spec.settingName ||
-      !currentUserHasPermission(["system:plugins:manage"])
-    ) {
-      tabs.value = [...initialTabs.value, ...(await getTabsFromExtensions())];
-    }
-  },
-});
-
 provide<Ref<Plugin | undefined>>("plugin", plugin);
-
-const { data: setting } = useQuery({
-  queryKey: ["plugin-setting", plugin],
-  queryFn: async () => {
-    const { data } = await consoleApiClient.plugin.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,
-        ...(await getTabsFromExtensions()),
-        ...forms.map((item: SettingForm) => {
-          return {
-            id: item.group,
-            label: item.label || "",
-            component: markRaw(SettingTab),
-          };
-        }),
-      ] as PluginTab[];
-    }
-  },
-});
-
 provide<Ref<Setting | undefined>>("setting", setting);
-
-async function getTabsFromExtensions() {
-  const { pluginModuleMap } = usePluginModuleStore();
-
-  const currentPluginModule = pluginModuleMap[route.params.name as string];
-
-  if (!currentPluginModule) {
-    return [];
-  }
-
-  const callbackFunction =
-    currentPluginModule?.extensionPoints?.["plugin:self:tabs:create"];
-
-  if (typeof callbackFunction !== "function") {
-    return [];
-  }
-
-  const pluginTabs = await callbackFunction();
-
-  return pluginTabs.filter((tab) => {
-    return currentUserHasPermission(tab.permissions);
-  });
-}
 </script>
 <template>
   <VPageHeader :title="plugin?.spec?.displayName">
diff --git a/ui/console-src/modules/system/plugins/components/PluginDetailModal.vue b/ui/console-src/modules/system/plugins/components/PluginDetailModal.vue
new file mode 100644
index 000000000..7d2a2c210
--- /dev/null
+++ b/ui/console-src/modules/system/plugins/components/PluginDetailModal.vue
@@ -0,0 +1,66 @@
+<script lang="ts" setup>
+import type { Plugin, Setting } from "@halo-dev/api-client";
+import { IconLink, VButton, VModal, VTabbar } from "@halo-dev/components";
+import { provide, ref, toRefs, type Ref } from "vue";
+import { usePluginDetailTabs } from "../composables/use-plugin";
+
+const props = withDefaults(defineProps<{ name: string }>(), {});
+
+const emit = defineEmits<{
+  (event: "close"): void;
+}>();
+
+const modal = ref<InstanceType<typeof VModal> | null>(null);
+
+const { name } = toRefs(props);
+
+const { plugin, setting, tabs, activeTab } = usePluginDetailTabs(name, false);
+
+provide<Ref<string>>("activeTab", activeTab);
+provide<Ref<Plugin | undefined>>("plugin", plugin);
+provide<Ref<Setting | undefined>>("setting", setting);
+</script>
+
+<template>
+  <VModal
+    ref="modal"
+    :title="plugin?.spec.displayName"
+    :centered="true"
+    :width="920"
+    height="calc(100vh - 20px)"
+    mount-to-body
+    @close="emit('close')"
+  >
+    <template #actions>
+      <span>
+        <RouterLink
+          :to="{
+            name: 'PluginDetail',
+            params: { name },
+          }"
+        >
+          <IconLink />
+        </RouterLink>
+      </span>
+    </template>
+    <VTabbar
+      v-model:active-id="activeTab"
+      :items="
+        tabs.map((tab) => {
+          return { label: tab.label, id: tab.id };
+        })
+      "
+      type="outline"
+    />
+    <div class="-m-4 mt-2">
+      <template v-for="tab in tabs" :key="tab.id">
+        <component :is="tab.component" v-if="activeTab === tab.id" />
+      </template>
+    </div>
+    <template #footer>
+      <VButton @click="modal?.close()">
+        {{ $t("core.common.buttons.close") }}
+      </VButton>
+    </template>
+  </VModal>
+</template>
diff --git a/ui/console-src/modules/system/plugins/components/extension-points/ExtensionDefinitionListItem.vue b/ui/console-src/modules/system/plugins/components/extension-points/ExtensionDefinitionListItem.vue
index 3c37f2a20..a73a09369 100644
--- a/ui/console-src/modules/system/plugins/components/extension-points/ExtensionDefinitionListItem.vue
+++ b/ui/console-src/modules/system/plugins/components/extension-points/ExtensionDefinitionListItem.vue
@@ -11,7 +11,8 @@ import {
   VEntityField,
 } from "@halo-dev/components";
 import { useQuery } from "@tanstack/vue-query";
-import { computed } from "vue";
+import { computed, ref } from "vue";
+import PluginDetailModal from "../PluginDetailModal.vue";
 
 const props = withDefaults(
   defineProps<{ extensionDefinition: ExtensionDefinition }>(),
@@ -36,9 +37,16 @@ const matchedPlugin = computed(() => {
       props.extensionDefinition.metadata.labels?.["plugin.halo.run/plugin-name"]
   );
 });
+
+const pluginDetailModalVisible = ref(false);
 </script>
 
 <template>
+  <PluginDetailModal
+    v-if="pluginDetailModalVisible && matchedPlugin"
+    :name="matchedPlugin.metadata.name"
+    @close="pluginDetailModalVisible = false"
+  />
   <VEntity>
     <template v-if="$slots['selection-indicator']" #checkbox>
       <slot name="selection-indicator" />
@@ -61,15 +69,12 @@ const matchedPlugin = computed(() => {
     <template v-if="matchedPlugin" #end>
       <VEntityField>
         <template #description>
-          <RouterLink
+          <div
             class="cursor-pointer rounded p-1 text-gray-600 transition-all hover:text-blue-600 group-hover:bg-gray-200/60"
-            :to="{
-              name: 'PluginDetail',
-              params: { name: matchedPlugin?.metadata.name },
-            }"
+            @click.prevent="pluginDetailModalVisible = true"
           >
             <IconSettings />
-          </RouterLink>
+          </div>
         </template>
       </VEntityField>
     </template>
diff --git a/ui/console-src/modules/system/plugins/components/extension-points/ExtensionDefinitionSingletonView.vue b/ui/console-src/modules/system/plugins/components/extension-points/ExtensionDefinitionSingletonView.vue
index e1457d028..02586b788 100644
--- a/ui/console-src/modules/system/plugins/components/extension-points/ExtensionDefinitionSingletonView.vue
+++ b/ui/console-src/modules/system/plugins/components/extension-points/ExtensionDefinitionSingletonView.vue
@@ -131,6 +131,7 @@ async function onExtensionChange(e: Event) {
           <label
             class="cursor-pointer transition-all"
             :class="{ 'pointer-events-none opacity-50': isSubmitting }"
+            @click.stop
           >
             <ExtensionDefinitionListItem :extension-definition="item">
               <template #selection-indicator>
diff --git a/ui/console-src/modules/system/plugins/tabs/Detail.vue b/ui/console-src/modules/system/plugins/components/tabs/Detail.vue
similarity index 96%
rename from ui/console-src/modules/system/plugins/tabs/Detail.vue
rename to ui/console-src/modules/system/plugins/components/tabs/Detail.vue
index 0078abd70..0a3a3939d 100644
--- a/ui/console-src/modules/system/plugins/tabs/Detail.vue
+++ b/ui/console-src/modules/system/plugins/components/tabs/Detail.vue
@@ -2,6 +2,7 @@
 import { rbacAnnotations } from "@/constants/annotations";
 import { pluginLabels, roleLabels } from "@/constants/labels";
 import { formatDatetime } from "@/utils/date";
+import { usePermission } from "@/utils/permission";
 import {
   PluginStatusPhaseEnum,
   coreApiClient,
@@ -18,8 +19,10 @@ import {
 import { useQuery } from "@tanstack/vue-query";
 import type { Ref } from "vue";
 import { computed, inject, ref } from "vue";
-import PluginConditionsModal from "../components/PluginConditionsModal.vue";
-import { usePluginLifeCycle } from "../composables/use-plugin";
+import { usePluginLifeCycle } from "../../composables/use-plugin";
+import PluginConditionsModal from "../PluginConditionsModal.vue";
+
+const { currentUserHasPermission } = usePermission();
 
 const plugin = inject<Ref<Plugin | undefined>>("plugin");
 const { changeStatus, changingStatus } = usePluginLifeCycle(plugin);
@@ -45,7 +48,11 @@ const { data: pluginRoleTemplates } = useQuery({
     return data.items;
   },
   cacheTime: 0,
-  enabled: computed(() => !!plugin?.value?.metadata.name),
+  enabled: computed(
+    () =>
+      !!plugin?.value?.metadata.name &&
+      currentUserHasPermission(["system:roles:view"])
+  ),
 });
 
 const pluginRoleTemplateGroups = computed<RoleTemplateGroup[]>(() => {
diff --git a/ui/console-src/modules/system/plugins/tabs/Setting.vue b/ui/console-src/modules/system/plugins/components/tabs/Setting.vue
similarity index 95%
rename from ui/console-src/modules/system/plugins/tabs/Setting.vue
rename to ui/console-src/modules/system/plugins/components/tabs/Setting.vue
index bd5bdf575..460a82f5b 100644
--- a/ui/console-src/modules/system/plugins/tabs/Setting.vue
+++ b/ui/console-src/modules/system/plugins/components/tabs/Setting.vue
@@ -1,19 +1,11 @@
 <script lang="ts" setup>
-// core libs
-import { computed, inject, ref, type Ref } from "vue";
-
-// hooks
-import { useSettingFormConvert } from "@console/composables/use-setting-form";
-import { consoleApiClient } from "@halo-dev/api-client";
-
-// components
-import { Toast, VButton } from "@halo-dev/components";
-
-// types
 import StickyBlock from "@/components/sticky-block/StickyBlock.vue";
+import { useSettingFormConvert } from "@console/composables/use-setting-form";
 import type { ConfigMap, Plugin, Setting } from "@halo-dev/api-client";
+import { consoleApiClient } from "@halo-dev/api-client";
+import { Toast, VButton } from "@halo-dev/components";
 import { useQuery, useQueryClient } from "@tanstack/vue-query";
-import { toRaw } from "vue";
+import { computed, inject, ref, toRaw, type Ref } from "vue";
 import { useI18n } from "vue-i18n";
 
 const { t } = useI18n();
diff --git a/ui/console-src/modules/system/plugins/composables/use-plugin.ts b/ui/console-src/modules/system/plugins/composables/use-plugin.ts
index 0a562f74d..0c01c9cea 100644
--- a/ui/console-src/modules/system/plugins/composables/use-plugin.ts
+++ b/ui/console-src/modules/system/plugins/composables/use-plugin.ts
@@ -1,15 +1,21 @@
+import { usePluginModuleStore } from "@/stores/plugin";
+import { usePermission } from "@/utils/permission";
 import {
   PluginStatusPhaseEnum,
   consoleApiClient,
   coreApiClient,
   type Plugin,
+  type SettingForm,
 } from "@halo-dev/api-client";
-import type { ComputedRef, Ref } from "vue";
-import { computed } from "vue";
-
 import { Dialog, Toast } from "@halo-dev/components";
-import { useMutation } from "@tanstack/vue-query";
+import type { PluginTab } from "@halo-dev/console-shared";
+import { useMutation, useQuery } from "@tanstack/vue-query";
+import { useRouteQuery } from "@vueuse/router";
+import type { ComputedRef, Ref } from "vue";
+import { computed, markRaw, ref } from "vue";
 import { useI18n } from "vue-i18n";
+import DetailTab from "../components/tabs/Detail.vue";
+import SettingTab from "../components/tabs/Setting.vue";
 
 interface usePluginLifeCycleReturn {
   isStarted: ComputedRef<boolean | undefined>;
@@ -270,3 +276,105 @@ export function usePluginBatchOperations(names: Ref<string[]>) {
 
   return { handleUninstallInBatch, handleChangeStatusInBatch };
 }
+
+export function usePluginDetailTabs(
+  pluginName: Ref<string | undefined>,
+  recordsActiveTab: boolean
+) {
+  const { currentUserHasPermission } = usePermission();
+  const { t } = useI18n();
+
+  const initialTabs = [
+    {
+      id: "detail",
+      label: t("core.plugin.tabs.detail"),
+      component: markRaw(DetailTab),
+    },
+  ];
+
+  const tabs = ref<PluginTab[]>(initialTabs);
+  const activeTab = recordsActiveTab
+    ? useRouteQuery<string>("tab", tabs.value[0].id)
+    : ref(tabs.value[0].id);
+
+  const { data: plugin } = useQuery({
+    queryKey: ["plugin", pluginName],
+    queryFn: async () => {
+      const { data } = await coreApiClient.plugin.plugin.getPlugin({
+        name: pluginName.value as string,
+      });
+      return data;
+    },
+    async onSuccess(data) {
+      if (
+        !data.spec.settingName ||
+        !currentUserHasPermission(["system:plugins:manage"])
+      ) {
+        tabs.value = [...initialTabs, ...(await getTabsFromExtensions())];
+      }
+    },
+  });
+
+  const { data: setting } = useQuery({
+    queryKey: ["plugin-setting", plugin],
+    queryFn: async () => {
+      const { data } = await consoleApiClient.plugin.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,
+          ...(await getTabsFromExtensions()),
+          ...forms.map((item: SettingForm) => {
+            return {
+              id: item.group,
+              label: item.label || "",
+              component: markRaw(SettingTab),
+            };
+          }),
+        ] as PluginTab[];
+      }
+    },
+  });
+
+  async function getTabsFromExtensions() {
+    const { pluginModuleMap } = usePluginModuleStore();
+
+    const currentPluginModule = pluginModuleMap[pluginName.value as string];
+
+    if (!currentPluginModule) {
+      return [];
+    }
+
+    const callbackFunction =
+      currentPluginModule?.extensionPoints?.["plugin:self:tabs:create"];
+
+    if (typeof callbackFunction !== "function") {
+      return [];
+    }
+
+    const pluginTabs = await callbackFunction();
+
+    return pluginTabs.filter((tab) => {
+      return currentUserHasPermission(tab.permissions);
+    });
+  }
+
+  return {
+    plugin,
+    setting,
+    tabs,
+    activeTab,
+  };
+}
diff --git a/ui/console-src/modules/system/plugins/module.ts b/ui/console-src/modules/system/plugins/module.ts
index 105f11d6f..ef511aac1 100644
--- a/ui/console-src/modules/system/plugins/module.ts
+++ b/ui/console-src/modules/system/plugins/module.ts
@@ -6,9 +6,12 @@ import type { RouteRecordRaw } from "vue-router";
 import PluginDetail from "./PluginDetail.vue";
 import PluginExtensionPointSettings from "./PluginExtensionPointSettings.vue";
 import PluginList from "./PluginList.vue";
+import PluginDetailModal from "./components/PluginDetailModal.vue";
 
 export default definePlugin({
-  components: {},
+  components: {
+    PluginDetailModal,
+  },
   routes: [
     {
       path: "/plugins",