Keep Settings runtime navigation synchronized with installed runtime plugins. - Filter runtime sections to installed plugins while preserving disabled installed runtimes - Refresh runtime navigation after plugin lifecycle events and direct plugin mutations - Add Settings coverage and document runtime visibility behavior Files changed: .changeset/fn-8520-runtime-sidebar.md | 7 +++ docs/dashboard-guide.md | 2 +- .../dashboard/app/components/PluginManager.tsx | 10 +++- .../dashboard/app/components/SettingsModal.tsx | 70 +++++++++++++++++++++- .../__tests__/SettingsModal.general.test.tsx | 58 ++++++++++++++++++ .../__tests__/SettingsModal.test-harness.tsx | 2 + .../components/__tests__/settings-mobile.test.tsx | 1 + .../settings/sections/PluginsSection.tsx | 6 +- 8 files changed, 149 insertions(+), 7 deletions(-) Fusion-Task-Id: FN-8520 Fusion-Task-Lineage: 914ae503-e1b0-4051-bc01-4da950bf55b3 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
40 lines
3.2 KiB
TypeScript
40 lines
3.2 KiB
TypeScript
import { lazy, Suspense } from "react";
|
|
import { PluginSlot } from "../../PluginSlot";
|
|
import type { ToastType } from "../../../hooks/useToast";
|
|
import { useTranslation } from "react-i18next";
|
|
const PluginManager = lazy(() => import("../../PluginManager").then((m) => ({ default: m.PluginManager })));
|
|
const PiExtensionsManager = lazy(() => import("../../PiExtensionsManager").then((m) => ({ default: m.PiExtensionsManager })));
|
|
export type PluginsSubsectionId = "fusion-plugins" | "pi-extensions";
|
|
export interface PluginsSectionProps {
|
|
projectId?: string;
|
|
addToast: (message: string, type?: ToastType) => void;
|
|
activePluginsSubsection: PluginsSubsectionId;
|
|
setActivePluginsSubsection: (id: PluginsSubsectionId) => void;
|
|
/** Invalidates Settings-owned runtime navigation after a direct mutation. */
|
|
onPluginsChanged?: () => void;
|
|
}
|
|
export function PluginsSection({ projectId, addToast, activePluginsSubsection, setActivePluginsSubsection, onPluginsChanged, }: PluginsSectionProps) {
|
|
const { t } = useTranslation("app");
|
|
return (<>
|
|
<h4 className="settings-section-heading">{t("settings.plugins.plugins", "Plugins")}</h4>
|
|
<div className="settings-plugins-subsection-toggle" role="tablist" aria-label={t("settings.plugins.pluginManagerType", "Plugin manager type")}>
|
|
<button type="button" id="plugins-tab-fusion-plugins" role="tab" aria-controls="plugins-panel-fusion-plugins" aria-selected={activePluginsSubsection === "fusion-plugins"} tabIndex={activePluginsSubsection === "fusion-plugins" ? 0 : -1} className={`settings-plugins-subsection-btn${activePluginsSubsection === "fusion-plugins" ? " active" : ""}`} onClick={() => setActivePluginsSubsection("fusion-plugins")}>{t("settings.plugins.fusionPlugins", " Fusion Plugins ")}</button>
|
|
<button type="button" id="plugins-tab-pi-extensions" role="tab" aria-controls="plugins-panel-pi-extensions" aria-selected={activePluginsSubsection === "pi-extensions"} tabIndex={activePluginsSubsection === "pi-extensions" ? 0 : -1} className={`settings-plugins-subsection-btn${activePluginsSubsection === "pi-extensions" ? " active" : ""}`} onClick={() => setActivePluginsSubsection("pi-extensions")}>{t("settings.plugins.piExtensions", " Pi Extensions ")}</button>
|
|
</div>
|
|
<div id="plugins-panel-fusion-plugins" role="tabpanel" aria-labelledby="plugins-tab-fusion-plugins" className="settings-plugins-subsection-panel" hidden={activePluginsSubsection !== "fusion-plugins"}>
|
|
{activePluginsSubsection === "fusion-plugins" && (<>
|
|
<Suspense fallback={null}>
|
|
<PluginManager addToast={addToast} projectId={projectId} onPluginsChanged={onPluginsChanged}/>
|
|
</Suspense>
|
|
<PluginSlot slotId="settings-section" projectId={projectId}/>
|
|
</>)}
|
|
</div>
|
|
<div id="plugins-panel-pi-extensions" role="tabpanel" aria-labelledby="plugins-tab-pi-extensions" className="settings-plugins-subsection-panel" hidden={activePluginsSubsection !== "pi-extensions"}>
|
|
{activePluginsSubsection === "pi-extensions" && (<Suspense fallback={null}>
|
|
<PiExtensionsManager addToast={addToast} projectId={projectId}/>
|
|
</Suspense>)}
|
|
</div>
|
|
</>);
|
|
}
|
|
export default PluginsSection;
|