fix(plugins): PR #493 - 合并分类修复并保留本地插件删减
This commit is contained in:
@@ -10,9 +10,11 @@ import { EditorTranscription } from "./editor-transcription";
|
||||
import { EditorExport } from "./editor-export";
|
||||
import { EditorAiAssistant } from "./editor-ai-assistant";
|
||||
|
||||
export const EDITOR_SHELL_PLUGIN_ID = "editor-shell";
|
||||
|
||||
const manifest: PluginManifestV2 = {
|
||||
apiVersion: "yingce.plugin/v2",
|
||||
id: "editor-shell",
|
||||
id: EDITOR_SHELL_PLUGIN_ID,
|
||||
name: "剪辑工作台",
|
||||
version: "0.1.0",
|
||||
description: "注册时间线、预览、检查器、素材、字幕、转写、导出和 AI 编辑八个工作台插槽。",
|
||||
|
||||
27
web/src/lib/plugins/official-applications.ts
Normal file
27
web/src/lib/plugins/official-applications.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { ART_CRITIQUE_PLUGIN_ID } from "@/lib/art-critique/contracts";
|
||||
import { EAGLE_PLUGIN_ID } from "@/lib/plugins/builtin/eagle";
|
||||
import { PROMPT_OPTIMIZER_PLUGIN_ID } from "@/lib/plugins/builtin/prompt-optimizer";
|
||||
import { RUNNINGHUB_PLUGIN_ID } from "@/lib/plugins/builtin/workflows";
|
||||
|
||||
import { EDITOR_SHELL_PLUGIN_ID } from "./builtin/editor/editor-shell";
|
||||
|
||||
/**
|
||||
* 官方“应用型”插件清单:这些插件在管理页按用户自主启停处理,而不是系统协议。
|
||||
*
|
||||
* 之前管理页、用户插件页和后端各自维护一份清单,管理页漏掉 AI 审美分析和剪辑
|
||||
* 工作台,导致二者被误判为系统协议并在管理页显示“已停用”。这里收敛为唯一来源。
|
||||
*/
|
||||
export const OFFICIAL_APPLICATION_PLUGIN_IDS = [
|
||||
RUNNINGHUB_PLUGIN_ID,
|
||||
EAGLE_PLUGIN_ID,
|
||||
PROMPT_OPTIMIZER_PLUGIN_ID,
|
||||
ART_CRITIQUE_PLUGIN_ID,
|
||||
EDITOR_SHELL_PLUGIN_ID,
|
||||
] as const;
|
||||
|
||||
const officialApplicationIdSet = new Set<string>(OFFICIAL_APPLICATION_PLUGIN_IDS);
|
||||
|
||||
/** 判断插件是否为官方应用型插件(用户可在插件页自主启停)。 */
|
||||
export function isOfficialApplicationPluginId(pluginId: string) {
|
||||
return officialApplicationIdSet.has(pluginId);
|
||||
}
|
||||
@@ -8,8 +8,8 @@ import { useEffect, useMemo, useState } from "react";
|
||||
import { PaginationBar } from "@/components/layout/workspace-page";
|
||||
import "@/lib/plugins/builtin";
|
||||
import { EAGLE_PLUGIN_ID } from "@/lib/plugins/builtin/eagle";
|
||||
import { PROMPT_OPTIMIZER_PLUGIN_ID } from "@/lib/plugins/builtin/prompt-optimizer";
|
||||
import { RUNNINGHUB_PLUGIN_ID } from "@/lib/plugins/builtin/workflows";
|
||||
import { isOfficialApplicationPluginId } from "@/lib/plugins/official-applications";
|
||||
import { listRegisteredPlugins } from "@/lib/plugins/plugin-registry";
|
||||
import type { PluginManifest, PluginManifestV2 } from "@/lib/plugins/plugin-types";
|
||||
import { fetchAdminPlugins, setPluginPlatformAvailability, uninstallPlugin, uploadPlugin, type AdminPluginState, type BackendPlugin, type PluginManagement } from "@/services/api/plugins";
|
||||
@@ -26,8 +26,6 @@ type AdminPluginItem = {
|
||||
error?: string;
|
||||
};
|
||||
|
||||
const officialApplicationIds = new Set([RUNNINGHUB_PLUGIN_ID, EAGLE_PLUGIN_ID, PROMPT_OPTIMIZER_PLUGIN_ID]);
|
||||
|
||||
export default function AdminPluginsPage() {
|
||||
const { message, modal } = App.useApp();
|
||||
const [plugins, setPlugins] = useState<BackendPlugin[]>([]);
|
||||
@@ -362,7 +360,7 @@ function PluginBrandIcon({ pluginId }: { pluginId: string }) {
|
||||
function mergePlugins(remote: BackendPlugin[]): AdminPluginItem[] {
|
||||
const byId = new Map<string, AdminPluginItem>();
|
||||
for (const plugin of listRegisteredPlugins()) {
|
||||
const application = officialApplicationIds.has(plugin.manifest.id);
|
||||
const application = isOfficialApplicationPluginId(plugin.manifest.id);
|
||||
byId.set(plugin.manifest.id, {
|
||||
manifest: plugin.manifest,
|
||||
source: plugin.source || "bundled",
|
||||
|
||||
@@ -10,7 +10,7 @@ import "@/lib/plugins/builtin";
|
||||
import { EAGLE_PLUGIN_ID } from "@/lib/plugins/builtin/eagle";
|
||||
import { PROMPT_OPTIMIZER_PLUGIN_ID } from "@/lib/plugins/builtin/prompt-optimizer";
|
||||
import { RUNNINGHUB_PLUGIN_ID } from "@/lib/plugins/builtin/workflows";
|
||||
import { ART_CRITIQUE_PLUGIN_ID } from "@/lib/art-critique/contracts";
|
||||
import { isOfficialApplicationPluginId } from "@/lib/plugins/official-applications";
|
||||
import type { PluginManifest, PluginManifestV2, RegisteredPlugin } from "@/lib/plugins/plugin-types";
|
||||
import { getEagleLibrary, type EagleFolder } from "@/services/api/eagle";
|
||||
import { fetchPlugins, setUserPluginEnabled, type BackendPlugin, type PluginState } from "@/services/api/plugins";
|
||||
@@ -141,7 +141,7 @@ export default function PluginsPage() {
|
||||
const normalizedSearch = search.trim().toLocaleLowerCase();
|
||||
return registeredPlugins.filter((plugin) => {
|
||||
const state = pluginStates[plugin.manifest.id];
|
||||
const isApplicationPlugin = backendPluginById.get(plugin.manifest.id)?.management.kind === "application" || isOfficialApplicationPlugin(plugin.manifest.id);
|
||||
const isApplicationPlugin = backendPluginById.get(plugin.manifest.id)?.management.kind === "application" || isOfficialApplicationPluginId(plugin.manifest.id);
|
||||
if (user?.role !== "admin" && !features.systemPluginsVisibleToUsers && !isApplicationPlugin) return false;
|
||||
const installation = installations.find((item) => item.manifest.id === plugin.manifest.id);
|
||||
const enabled = state?.effectiveEnabled ?? Boolean(installation?.enabled);
|
||||
@@ -185,7 +185,7 @@ export default function PluginsPage() {
|
||||
}, [pluginSections, scrollTarget]);
|
||||
|
||||
const categoryCounts = useMemo(() => {
|
||||
const visiblePlugins = registeredPlugins.filter((plugin) => user?.role === "admin" || features.systemPluginsVisibleToUsers || isOfficialApplicationPlugin(plugin.manifest.id));
|
||||
const visiblePlugins = registeredPlugins.filter((plugin) => user?.role === "admin" || features.systemPluginsVisibleToUsers || isOfficialApplicationPluginId(plugin.manifest.id));
|
||||
const counts: Record<string, number> = { all: visiblePlugins.length, text: 0, image: 0, video: 0, audio: 0, payment: 0, other: 0 };
|
||||
for (const plugin of visiblePlugins) {
|
||||
for (const section of protocolSectionMeta) {
|
||||
@@ -626,14 +626,10 @@ function toRegisteredPlugin(plugin: BackendPlugin): RegisteredPlugin {
|
||||
return { manifest: plugin.manifest, source: plugin.source };
|
||||
}
|
||||
|
||||
function isOfficialApplicationPlugin(pluginId: string) {
|
||||
return [RUNNINGHUB_PLUGIN_ID, EAGLE_PLUGIN_ID, PROMPT_OPTIMIZER_PLUGIN_ID, ART_CRITIQUE_PLUGIN_ID].includes(pluginId);
|
||||
}
|
||||
|
||||
function pluginSourceLabel(plugin: RegisteredPlugin, state?: PluginState) {
|
||||
if (plugin.source === "uploaded") return "自定义插件";
|
||||
if (plugin.source === "system") return "系统插件";
|
||||
if (state?.canToggle || isOfficialApplicationPlugin(plugin.manifest.id)) return "官方插件";
|
||||
if (state?.canToggle || isOfficialApplicationPluginId(plugin.manifest.id)) return "官方插件";
|
||||
return "系统插件";
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user