feat(FN-4050): add one-click install support for reports plugin

- Add reports plugin to bundled plugin resolver so it can be installed from packaged assets
- Expose reports plugin in dashboard plugin manager and server routes for one-click install flows
- Add CLI and dashboard test coverage for bundled install behavior and plugin route availability
- Update reports/plugin management/settings docs and include a changeset for @runfusion/fusion
This commit is contained in:
Fusion
2026-05-11 21:48:19 -07:00
committed by gsxdsm
parent 287ebaf102
commit 4a09924c56
11 changed files with 148 additions and 2 deletions

View File

@@ -517,6 +517,38 @@ describe("POST /api/plugins mode:install — bundled plugin path fallback", () =
);
});
it("installs bundled reports plugin when relative path misses cwd", async () => {
const bundledManifest = {
...VALID_MANIFEST,
id: "fusion-plugin-reports",
name: "Reports",
};
mockExistsSync.mockImplementation((p: string) => p.includes("fusion-plugin-reports/manifest.json"));
mockAccess.mockImplementation((p: string) => {
if (p.includes("fusion-plugin-reports")) return Promise.resolve();
return Promise.reject(new Error("not found"));
});
mockReadFile.mockResolvedValue(JSON.stringify(bundledManifest));
(pluginStore.registerPlugin as ReturnType<typeof vi.fn>).mockResolvedValue({
...INSTALLED_PLUGIN,
id: "fusion-plugin-reports",
name: "Reports",
});
const res = await REQUEST(buildApp(), "POST", "/api/plugins", {
mode: "install",
path: "./plugins/fusion-plugin-reports",
});
expect(res.status).toBe(201);
expect(pluginStore.registerPlugin).toHaveBeenCalledWith(
expect.objectContaining({
manifest: expect.objectContaining({ id: "fusion-plugin-reports" }),
path: expect.stringContaining("fusion-plugin-reports"),
}),
);
});
it("returns 404 with helpful message when local and bundled paths are unresolved", async () => {
mockExistsSync.mockReturnValue(false);
mockAccess.mockRejectedValue(new Error("not found"));