fix(*): 插件工作流 - 统一启停状态并闭环校验生成链路
This commit is contained in:
@@ -13,6 +13,8 @@ import { isFrameNode, isNodeHiddenByCollapsedFrame } from "@/lib/canvas/canvas-f
|
||||
import { normalizeRunningHubCapability, type AiConfig } from "@/stores/use-config-store";
|
||||
import { useUserStore } from "@/stores/use-user-store";
|
||||
import { CanvasNodeType, type CanvasConnection, type CanvasNodeData, type CanvasNodeMetadata, type ConnectionHandle, type ContextMenuState, type Position, type ViewportTransform } from "@/types/canvas";
|
||||
import { workflowProviderPluginEnabled } from "@/lib/plugins/builtin/workflows";
|
||||
import { usePluginStore } from "@/stores/use-plugin-store";
|
||||
|
||||
type UseCanvasConnectionControllerOptions = {
|
||||
projectId: string;
|
||||
@@ -78,6 +80,7 @@ export function useCanvasConnectionController({
|
||||
}: UseCanvasConnectionControllerOptions) {
|
||||
const { message } = App.useApp();
|
||||
const tldrawLicenseKey = useUserStore((state) => state.drawingEngine.tldrawLicenseKey);
|
||||
const runtimeStatuses = usePluginStore((state) => state.runtimeStatuses);
|
||||
const [connectingParams, setConnectingParams] = useState<ConnectionHandle | null>(null);
|
||||
const [connectionTargetNodeId, setConnectionTargetNodeId] = useState<string | null>(null);
|
||||
const [connectionTargetAnchorRatio, setConnectionTargetAnchorRatio] = useState<number | undefined>();
|
||||
@@ -210,8 +213,13 @@ export function useCanvasConnectionController({
|
||||
? batchSourceNodeIds.length ? batchScriptPrompt : sourceNode?.type === CanvasNodeType.Text ? (sourceNode.metadata?.content || sourceNode.metadata?.prompt || "").trim() : ""
|
||||
: "";
|
||||
const selectedWorkflowProvider = nodeType === CanvasNodeType.Config
|
||||
? workflowProvider || (config.runningHub.enabled && config.runningHub.workflows.length ? "runninghub" : config.comfyBridge.enabled && config.comfyBridge.workflows.length ? "comfyui" : "runninghub")
|
||||
? workflowProvider || (workflowProviderPluginEnabled(runtimeStatuses, "runninghub") ? "runninghub" : workflowProviderPluginEnabled(runtimeStatuses, "comfyui") ? "comfyui" : undefined)
|
||||
: undefined;
|
||||
if (selectedWorkflowProvider && !workflowProviderPluginEnabled(runtimeStatuses, selectedWorkflowProvider)) {
|
||||
message.error(`${selectedWorkflowProvider === "runninghub" ? "RunningHub" : "ComfyUI"} 工作流插件未启用`);
|
||||
closeConnectionCreateMenu();
|
||||
return;
|
||||
}
|
||||
const runningHubWorkflow = selectedWorkflowProvider === "runninghub" ? selectRunningHubWorkflow(config) : undefined;
|
||||
const comfyBridgeWorkflow = selectedWorkflowProvider === "comfyui" ? selectComfyBridgeWorkflow(config) : undefined;
|
||||
const workflowCapability = selectedWorkflowProvider === "runninghub"
|
||||
@@ -338,10 +346,13 @@ export function useCanvasConnectionController({
|
||||
else if (nodeType !== CanvasNodeType.Text && nodeType !== CanvasNodeType.Script && nodeType !== CanvasNodeType.Audio) setDialogNodeId(newNode.id);
|
||||
closeConnectionCreateMenu();
|
||||
setConnecting(null);
|
||||
}, [closeConnectionCreateMenu, config, connectionsRef, defaultDrawingEngine, message, nodesRef, projectId, setConnecting, setConnections, setDialogNodeId, setDrawingNodeId, setNodes, setSelectedConnectionId, setSelectedNodeIds, tldrawLicenseKey]);
|
||||
}, [closeConnectionCreateMenu, config, connectionsRef, defaultDrawingEngine, message, nodesRef, projectId, runtimeStatuses, setConnecting, setConnections, setDialogNodeId, setDrawingNodeId, setNodes, setSelectedConnectionId, setSelectedNodeIds, tldrawLicenseKey]);
|
||||
|
||||
const getConnectionCreateDisabledReason = useCallback((type: CanvasNodeType.Image | CanvasNodeType.Text | CanvasNodeType.Script | CanvasNodeType.Video | CanvasNodeType.Audio | CanvasNodeType.Drawing | CanvasNodeType.Config, pending: PendingConnectionCreate, workflowProvider?: "runninghub" | "comfyui") => {
|
||||
const nodeType = type;
|
||||
if (nodeType === CanvasNodeType.Config) {
|
||||
if (workflowProvider && !workflowProviderPluginEnabled(runtimeStatuses, workflowProvider)) return `${workflowProvider === "runninghub" ? "RunningHub" : "ComfyUI"} 工作流插件未启用`;
|
||||
}
|
||||
if (pending.batchSourceNodeIds?.length) {
|
||||
if (nodeType === CanvasNodeType.Drawing || nodeType === CanvasNodeType.Config) return "批量连接暂不支持此节点类型";
|
||||
const pendingNode: CanvasNodeData = { id: "__pending-connection-node__", type: nodeType, title: "", position: pending.position, width: getNodeSpec(nodeType).width, height: getNodeSpec(nodeType).height };
|
||||
@@ -354,7 +365,7 @@ export function useCanvasConnectionController({
|
||||
const connection = normalizeConnection(pending.connection.nodeId, pendingNode.id, pendingNodes, pending.connection.handleType);
|
||||
if (!connection) return "当前节点类型不能这样连接";
|
||||
return canvasConnectionError(config, pendingNodes, connectionsRef.current, connection);
|
||||
}, [config, connectionsRef, nodesRef]);
|
||||
}, [config, connectionsRef, nodesRef, runtimeStatuses]);
|
||||
|
||||
const getConnectionDropTarget = useCallback((clientX: number, clientY: number, current: ConnectionHandle): ConnectionDropTarget => {
|
||||
const world = screenToCanvas(clientX, clientY);
|
||||
|
||||
@@ -14,6 +14,8 @@ import { isDrawingEngineAvailable, type CanvasDrawingEngine } from "@/lib/canvas
|
||||
import { useUserStore } from "@/stores/use-user-store";
|
||||
import { useEffectiveConfig } from "@/stores/use-config-store";
|
||||
import { createDefaultPortraitClearanceState, PORTRAIT_CLEARANCE_NODE_TYPE } from "@/lib/portrait-clearance/contracts";
|
||||
import { workflowProviderPluginEnabled } from "@/lib/plugins/builtin/workflows";
|
||||
import { usePluginStore } from "@/stores/use-plugin-store";
|
||||
|
||||
type CanvasClipboard = {
|
||||
nodes: CanvasNodeData[];
|
||||
@@ -58,6 +60,7 @@ export function useCanvasNodeOperations({
|
||||
const { message } = App.useApp();
|
||||
const effectiveConfig = useEffectiveConfig();
|
||||
const tldrawLicenseKey = useUserStore((state) => state.drawingEngine.tldrawLicenseKey);
|
||||
const runtimeStatuses = usePluginStore((state) => state.runtimeStatuses);
|
||||
const clipboardRef = useRef<CanvasClipboard | null>(null);
|
||||
const preferCopiedNodesRef = useRef(false);
|
||||
const markerWritePendingRef = useRef(false);
|
||||
@@ -131,13 +134,17 @@ export function useCanvasNodeOperations({
|
||||
return;
|
||||
}
|
||||
const selectedWorkflowProvider = type === CanvasNodeType.Config
|
||||
? workflowProvider || "runninghub"
|
||||
? workflowProvider || (workflowProviderPluginEnabled(runtimeStatuses, "runninghub") ? "runninghub" : workflowProviderPluginEnabled(runtimeStatuses, "comfyui") ? "comfyui" : undefined)
|
||||
: undefined;
|
||||
if (selectedWorkflowProvider && !workflowProviderPluginEnabled(runtimeStatuses, selectedWorkflowProvider)) {
|
||||
message.error(`${selectedWorkflowProvider === "runninghub" ? "RunningHub" : "ComfyUI"} 工作流插件未启用`);
|
||||
return;
|
||||
}
|
||||
const workflowTitle = type === CanvasNodeType.Config && selectedWorkflowProvider === "runninghub" ? "RunningHub 工作流" : type === CanvasNodeType.Config && selectedWorkflowProvider === "comfyui" ? "ComfyUI Bridge" : undefined;
|
||||
const metadata: CanvasNodeMetadata | undefined = type === CanvasNodeType.Drawing
|
||||
? { drawingEngine: defaultDrawingEngine }
|
||||
: type === CanvasNodeType.Config
|
||||
? { generationMode: "image", workflowProvider: selectedWorkflowProvider }
|
||||
? { generationMode: "image", workflowProvider: selectedWorkflowProvider || "model" }
|
||||
: type === PORTRAIT_CLEARANCE_NODE_TYPE
|
||||
? { portraitClearance: createDefaultPortraitClearanceState() }
|
||||
: undefined;
|
||||
@@ -146,7 +153,7 @@ export function useCanvasNodeOperations({
|
||||
commitNodes([...nodesRef.current, node]);
|
||||
selectNodes(new Set([node.id]));
|
||||
if (type !== CanvasNodeType.Text && type !== CanvasNodeType.Script && type !== CanvasNodeType.Audio && type !== CanvasNodeType.Frame && type !== CanvasNodeType.Drawing && type !== PORTRAIT_CLEARANCE_NODE_TYPE) setDialogNodeId(node.id);
|
||||
}, [commitNodes, defaultDrawingEngine, effectiveConfig.comfyBridge.enabled, effectiveConfig.comfyBridge.workflows.length, effectiveConfig.runningHub.enabled, effectiveConfig.runningHub.workflows.length, getCanvasCenter, message, nodesRef, selectNodes, setDialogNodeId, tldrawLicenseKey]);
|
||||
}, [commitNodes, defaultDrawingEngine, effectiveConfig.comfyBridge.enabled, effectiveConfig.comfyBridge.workflows.length, effectiveConfig.runningHub.enabled, effectiveConfig.runningHub.workflows.length, getCanvasCenter, message, nodesRef, runtimeStatuses, selectNodes, setDialogNodeId, tldrawLicenseKey]);
|
||||
|
||||
const createFolder = useCallback((position?: Position, linked?: { id: string; projectId: string; title: string; style: CanvasFolderStyle; theme: CanvasFolderTheme; createdAt: string }) => {
|
||||
const folder = createCanvasNode(CanvasNodeType.Frame, position || getCanvasCenter(), {
|
||||
|
||||
@@ -65,6 +65,8 @@ export default function PluginsPage() {
|
||||
const installations = usePluginStore((state) => state.installations);
|
||||
const ensurePlugin = usePluginStore((state) => state.ensurePlugin);
|
||||
const setEnabled = usePluginStore((state) => state.setEnabled);
|
||||
const setRuntimeStatuses = usePluginStore((state) => state.setRuntimeStatuses);
|
||||
const runtimeStatuses = usePluginStore((state) => state.runtimeStatuses);
|
||||
const updateConfig = usePluginStore((state) => state.updateConfig);
|
||||
const builtinPlugins = useMemo(() => listRegisteredPlugins(), []);
|
||||
const [backendPlugins, setBackendPlugins] = useState<BackendPlugin[]>([]);
|
||||
@@ -93,7 +95,8 @@ export default function PluginsPage() {
|
||||
const reloadBackendPlugins = async () => {
|
||||
setBackendPluginsLoading(true);
|
||||
try {
|
||||
setBackendPlugins(await fetchPlugins());
|
||||
const plugins = await fetchPlugins();
|
||||
setBackendPlugins(plugins);
|
||||
} catch (error) {
|
||||
message.error(error instanceof Error ? error.message : "读取插件中心失败");
|
||||
setBackendPlugins([]);
|
||||
@@ -107,7 +110,11 @@ export default function PluginsPage() {
|
||||
}, []);
|
||||
|
||||
const remotePlugins = useMemo(() => backendPlugins.map(toRegisteredPlugin), [backendPlugins]);
|
||||
const registeredPlugins = useMemo(() => [...builtinPlugins, ...remotePlugins], [builtinPlugins, remotePlugins]);
|
||||
const registeredPlugins = useMemo(() => {
|
||||
const byId = new Map(builtinPlugins.map((plugin) => [plugin.manifest.id, plugin]));
|
||||
for (const plugin of remotePlugins) byId.set(plugin.manifest.id, plugin);
|
||||
return [...byId.values()];
|
||||
}, [builtinPlugins, remotePlugins]);
|
||||
const backendPluginById = useMemo(() => new Map(backendPlugins.map((plugin) => [plugin.manifest.id, plugin])), [backendPlugins]);
|
||||
|
||||
const eagle = installations.find((item) => item.manifest.id === EAGLE_PLUGIN_ID);
|
||||
@@ -127,7 +134,8 @@ export default function PluginsPage() {
|
||||
const isSystemPlugin = plugin.source !== "uploaded";
|
||||
if (user?.role !== "admin" && !features.systemPluginsVisibleToUsers && isSystemPlugin) return false;
|
||||
const installation = installations.find((item) => item.manifest.id === plugin.manifest.id);
|
||||
const enabled = backendPluginById.get(plugin.manifest.id)?.status === "enabled" || Boolean(installation?.enabled);
|
||||
const remote = backendPluginById.get(plugin.manifest.id);
|
||||
const enabled = remote ? remote.status === "enabled" : Boolean(installation?.enabled);
|
||||
const manifest = plugin.manifest;
|
||||
const contributionKinds = contributionKindsFor(manifest);
|
||||
const searchableText = [manifest.name, manifest.description, manifest.author, manifest.id, ...contributionKinds.map((kind) => categoryLabels[kind] || kind)].filter(Boolean).join(" ").toLocaleLowerCase();
|
||||
@@ -186,20 +194,21 @@ export default function PluginsPage() {
|
||||
|
||||
const settingsPlugin = settingsPluginId ? registeredPlugins.find((plugin) => plugin.manifest.id === settingsPluginId) : undefined;
|
||||
const settingsInstallation = settingsPlugin ? installations.find((item) => item.manifest.id === settingsPlugin.manifest.id) : undefined;
|
||||
const settingsEnabled = settingsPlugin ? backendPluginById.get(settingsPlugin.manifest.id)?.status === "enabled" || Boolean(settingsInstallation?.enabled) : false;
|
||||
const settingsEnabled = settingsPlugin ? (backendPluginById.has(settingsPlugin.manifest.id) ? backendPluginById.get(settingsPlugin.manifest.id)?.status === "enabled" : Boolean(settingsInstallation?.enabled)) : false;
|
||||
const detailsPlugin = detailsPluginId ? registeredPlugins.find((plugin) => plugin.manifest.id === detailsPluginId) : undefined;
|
||||
|
||||
const hasPluginConfiguration = (plugin: RegisteredPlugin) => Boolean(plugin.manifest.configuration?.fields?.length);
|
||||
const canConfigurePlugin = (plugin: RegisteredPlugin) => hasPluginConfiguration(plugin) && user?.role === "admin";
|
||||
|
||||
const isPluginEnabled = (plugin: RegisteredPlugin, installation = installations.find((item) => item.manifest.id === plugin.manifest.id)) =>
|
||||
backendPluginById.get(plugin.manifest.id)?.status === "enabled" || Boolean(installation?.enabled);
|
||||
backendPluginById.has(plugin.manifest.id) ? backendPluginById.get(plugin.manifest.id)?.status === "enabled" : Boolean(installation?.enabled);
|
||||
|
||||
const togglePlugin = async (plugin: RegisteredPlugin, enabled: boolean) => {
|
||||
try {
|
||||
if (backendPluginById.has(plugin.manifest.id)) {
|
||||
const next = await setPluginEnabled(plugin.manifest.id, enabled);
|
||||
setBackendPlugins((items) => items.map((item) => (item.manifest.id === next.manifest.id ? next : item)));
|
||||
setRuntimeStatuses({ ...runtimeStatuses, [next.manifest.id]: next.status });
|
||||
} else {
|
||||
setEnabled(plugin.manifest.id, enabled);
|
||||
}
|
||||
|
||||
@@ -226,30 +226,34 @@ export function ChannelSettingsPane({ onOpenModels, onOpenRunningHub, onOpenComf
|
||||
<Button className="h-10 flex-1 sm:h-8 sm:flex-none" type="primary" icon={<Plus className="size-4" />} onClick={addChannel}>新增渠道</Button>
|
||||
</div>
|
||||
</div>
|
||||
<section className="settings-section mb-3">
|
||||
{onOpenRunningHub || onOpenComfyUI ? <section className="settings-section mb-3">
|
||||
<div className="mb-3">
|
||||
<h3 className="text-sm font-semibold">个人工作流渠道</h3>
|
||||
<p className="mt-1 text-xs text-foreground/55">RunningHub 和 ComfyUI 使用各自的工作流参数与执行通道,配置入口统一放在个人渠道中。</p>
|
||||
</div>
|
||||
<div className="grid gap-2 lg:grid-cols-2">
|
||||
<WorkflowChannelEntry
|
||||
icon={<Workflow className="size-4" />}
|
||||
title="RunningHub"
|
||||
description="云端工作流和 RunningHub App"
|
||||
status={runningHubReady ? `${config.runningHub.workflows.length} 个工作流已配置` : config.runningHub.enabled ? "待完成连接和工作流配置" : "未启用"}
|
||||
ready={runningHubReady}
|
||||
onOpen={onOpenRunningHub}
|
||||
/>
|
||||
<WorkflowChannelEntry
|
||||
icon={<MonitorUp className="size-4" />}
|
||||
title="ComfyUI"
|
||||
description="通过 Bridge 连接本机或远程 ComfyUI"
|
||||
status={comfyBridgeReady ? `${config.comfyBridge.workflows.length} 个工作流已配置` : config.comfyBridge.enabled ? "待选择 Bridge 和工作流" : "未启用"}
|
||||
ready={comfyBridgeReady}
|
||||
onOpen={onOpenComfyUI}
|
||||
/>
|
||||
{onOpenRunningHub ? (
|
||||
<WorkflowChannelEntry
|
||||
icon={<Workflow className="size-4" />}
|
||||
title="RunningHub"
|
||||
description="云端工作流和 RunningHub App"
|
||||
status={runningHubReady ? `${config.runningHub.workflows.length} 个工作流已配置` : config.runningHub.enabled ? "待完成连接和工作流配置" : "未启用"}
|
||||
ready={runningHubReady}
|
||||
onOpen={onOpenRunningHub}
|
||||
/>
|
||||
) : null}
|
||||
{onOpenComfyUI ? (
|
||||
<WorkflowChannelEntry
|
||||
icon={<MonitorUp className="size-4" />}
|
||||
title="ComfyUI"
|
||||
description="通过 Bridge 连接本机或远程 ComfyUI"
|
||||
status={comfyBridgeReady ? `${config.comfyBridge.workflows.length} 个工作流已配置` : config.comfyBridge.enabled ? "待选择 Bridge 和工作流" : "未启用"}
|
||||
ready={comfyBridgeReady}
|
||||
onOpen={onOpenComfyUI}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
</section>
|
||||
</section> : null}
|
||||
{userChannels.length ? (
|
||||
<div className="settings-channel-list space-y-2">
|
||||
{userChannels.map((channel) => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { App, Button, Form, Input, InputNumber, Select } from "antd";
|
||||
import { ArrowLeft, Boxes, Bug, Cloud, MessageSquareText, MonitorUp, RadioTower, SlidersHorizontal, SquareTerminal, Workflow } from "lucide-react";
|
||||
import { useEffect, useState, type ReactNode } from "react";
|
||||
import { useEffect, useMemo, useState, type ReactNode } from "react";
|
||||
import { useNavigate, useSearchParams } from "react-router";
|
||||
|
||||
import { UserOSSSettingsForm } from "@/components/layout/user-oss-settings-form";
|
||||
@@ -16,6 +16,8 @@ import { LocalCliSettings } from "./local-cli-settings";
|
||||
import { PromptPreferencesPane } from "./prompt-preferences-pane";
|
||||
import DiagnosticsPanel from "./diagnostics-panel";
|
||||
import { RunningHubSettingsPane } from "./runninghub-settings-pane";
|
||||
import { COMFYUI_PLUGIN_ID, RUNNINGHUB_PLUGIN_ID } from "@/lib/plugins/builtin/workflows";
|
||||
import { usePluginStore } from "@/stores/use-plugin-store";
|
||||
|
||||
type ConfigSectionKey = "local-cli" | "channels" | "models" | "runninghub" | "comfyui" | "preferences" | "prompts" | "storage" | "diagnostics";
|
||||
|
||||
@@ -41,7 +43,13 @@ export default function SettingsPage() {
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const requestedSection = searchParams.get("section");
|
||||
const customChannelsEnabled = useUserStore((state) => state.features.customChannelsEnabled);
|
||||
const initialSection = isConfigSection(requestedSection) ? requestedSection : customChannelsEnabled ? "channels" : "models";
|
||||
const runtimeStatuses = usePluginStore((state) => state.runtimeStatuses);
|
||||
const runningHubPluginEnabled = runtimeStatuses[RUNNINGHUB_PLUGIN_ID] === "enabled";
|
||||
const comfyUIPluginEnabled = runtimeStatuses[COMFYUI_PLUGIN_ID] === "enabled";
|
||||
const requestedSectionEnabled = requestedSection !== "runninghub" && requestedSection !== "comfyui"
|
||||
|| requestedSection === "runninghub" && runningHubPluginEnabled
|
||||
|| requestedSection === "comfyui" && comfyUIPluginEnabled;
|
||||
const initialSection = isConfigSection(requestedSection) && requestedSectionEnabled ? requestedSection : customChannelsEnabled ? "channels" : "models";
|
||||
const [activeTab, setActiveTab] = useState<ConfigSectionKey>(initialSection === "channels" && !customChannelsEnabled ? "models" : initialSection);
|
||||
const config = useConfigStore((state) => state.config);
|
||||
const effectiveConfig = useEffectiveConfig();
|
||||
@@ -49,15 +57,19 @@ export default function SettingsPage() {
|
||||
const shouldPromptContinue = searchParams.get("continue") === "1";
|
||||
const userId = useUserStore((state) => state.user?.id);
|
||||
const userChannels = config.channels.filter((channel) => channel.scope !== "system");
|
||||
const visibleConfigSections = customChannelsEnabled ? configSections : configSections.filter((section) => section.key !== "channels");
|
||||
const visibleConfigSections = useMemo(() => (customChannelsEnabled ? configSections : configSections.filter((section) => section.key !== "channels"))
|
||||
.filter((section) => section.key !== "runninghub" || runningHubPluginEnabled)
|
||||
.filter((section) => section.key !== "comfyui" || comfyUIPluginEnabled), [comfyUIPluginEnabled, customChannelsEnabled, runningHubPluginEnabled]);
|
||||
|
||||
const isVisibleConfigSection = (value: string | null): value is ConfigSectionKey => isConfigSection(value) && visibleConfigSections.some((section) => section.key === value);
|
||||
|
||||
useEffect(() => {
|
||||
if (isConfigSection(requestedSection) && (requestedSection !== "channels" || customChannelsEnabled)) {
|
||||
if (isVisibleConfigSection(requestedSection)) {
|
||||
setActiveTab(requestedSection);
|
||||
return;
|
||||
}
|
||||
if (!customChannelsEnabled) setActiveTab((current) => (current === "channels" ? "models" : current));
|
||||
}, [customChannelsEnabled, requestedSection]);
|
||||
setActiveTab((current) => visibleConfigSections.some((section) => section.key === current) ? current : customChannelsEnabled ? "channels" : "models");
|
||||
}, [customChannelsEnabled, requestedSection, visibleConfigSections]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!userId) return;
|
||||
@@ -71,6 +83,7 @@ export default function SettingsPage() {
|
||||
}, [message, userId]);
|
||||
|
||||
const selectSection = (section: ConfigSectionKey) => {
|
||||
if ((section === "runninghub" && !runningHubPluginEnabled) || (section === "comfyui" && !comfyUIPluginEnabled)) return;
|
||||
setActiveTab(section);
|
||||
const next = new URLSearchParams(searchParams);
|
||||
next.set("section", section);
|
||||
@@ -87,8 +100,8 @@ export default function SettingsPage() {
|
||||
}
|
||||
const hasReadyLocalRuntime = effectiveConfig.channels.some((channel) => channel.transport === "local-runtime" && channel.enabled !== false && Boolean(channel.localModels?.length));
|
||||
const workflowReady = Boolean(
|
||||
(config.runningHub.enabled && config.runningHub.workflowId.trim() && config.runningHub.baseUrl.trim() && config.runningHub.apiKey.trim())
|
||||
|| (config.comfyBridge.enabled && config.comfyBridge.bridgeId.trim() && config.comfyBridge.workflowId.trim()),
|
||||
(runningHubPluginEnabled && config.runningHub.enabled && config.runningHub.workflowId.trim() && config.runningHub.baseUrl.trim() && config.runningHub.apiKey.trim())
|
||||
|| (comfyUIPluginEnabled && config.comfyBridge.enabled && config.comfyBridge.bridgeId.trim() && config.comfyBridge.workflowId.trim()),
|
||||
);
|
||||
if (!effectiveConfig.channels.some(isChannelReady) && !hasReadyLocalRuntime && !workflowReady) {
|
||||
selectSection(customChannelsEnabled ? "channels" : "models");
|
||||
@@ -101,7 +114,7 @@ export default function SettingsPage() {
|
||||
|
||||
const panes: Record<ConfigSectionKey, ReactNode> = {
|
||||
"local-cli": <SettingsPane><LocalCliSettings /></SettingsPane>,
|
||||
channels: <SettingsPane><ChannelSettingsPane onOpenModels={() => selectSection("models")} onOpenRunningHub={() => selectSection("runninghub")} onOpenComfyUI={() => selectSection("comfyui")} /></SettingsPane>,
|
||||
channels: <SettingsPane><ChannelSettingsPane onOpenModels={() => selectSection("models")} onOpenRunningHub={runningHubPluginEnabled ? () => selectSection("runninghub") : undefined} onOpenComfyUI={comfyUIPluginEnabled ? () => selectSection("comfyui") : undefined} /></SettingsPane>,
|
||||
models: (
|
||||
<SettingsPane>
|
||||
<div className="settings-pane-header">
|
||||
|
||||
Reference in New Issue
Block a user