feat(webui): add guided setup flows
* feat(channels): add guided setup flows * test(channels): preserve setup config values * fix(channels): reflect saved setup state * refactor(channels): simplify setup state metadata * fix(channels): harden setup lifecycle * refactor(channels): centralize setup contracts * fix(channels): route setup actions through webui shim * fix(channels): adapt settings for compact screens * fix(models): preserve default preset display * feat(models): add curated Codex catalog * fix(webui): stop attached gateway on interrupt * fix(webui): simplify apps catalog * docs(webui): clarify apps and runtime features * feat(settings): add guided capability setup * fix(webui): harden setup and managed services * test: keep managed runtime checks portable * test: scope POSIX runtime coverage * fix(webui): simplify file settings * feat(files): bundle document reading * fix(webui): harden setup request boundaries * fix(webui): prevent channel setup status squeeze * fix(settings): group provider compatibility aliases * refactor(settings): remove redundant setup surfaces * fix(webui): harden guided setup lifecycle * fix(webui): preserve channel setup compatibility
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
import {
|
||||
configureChannel,
|
||||
createModelConfiguration,
|
||||
deleteSession,
|
||||
fetchFilePreview,
|
||||
fetchAutomations,
|
||||
fetchApiService,
|
||||
fetchCliApps,
|
||||
fetchInstalledCliApps,
|
||||
fetchMcpPresets,
|
||||
@@ -28,6 +30,11 @@ import {
|
||||
runCliAppAction,
|
||||
runMcpPresetAction,
|
||||
saveCustomMcpServer,
|
||||
startApiService,
|
||||
stopApiService,
|
||||
cancelChannelConnect,
|
||||
pollChannelConnect,
|
||||
startChannelConnect,
|
||||
updateAutomation,
|
||||
updateSidebarState,
|
||||
updateImageGenerationSettings,
|
||||
@@ -37,6 +44,7 @@ import {
|
||||
updateProviderSettings,
|
||||
updateSettings,
|
||||
updateWebSearchSettings,
|
||||
validateChannel,
|
||||
} from "@/lib/api";
|
||||
|
||||
describe("webui API helpers", () => {
|
||||
@@ -116,6 +124,82 @@ describe("webui API helpers", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("validates channel settings with form values", async () => {
|
||||
await validateChannel(
|
||||
"tok",
|
||||
"slack",
|
||||
{ "channels.slack.botToken": "xoxb-test" },
|
||||
{ instanceId: "default" },
|
||||
);
|
||||
|
||||
expect(fetch).toHaveBeenCalledWith(
|
||||
"/api/settings/channels/validate?name=slack&instance_id=default",
|
||||
expect.objectContaining({
|
||||
headers: expect.objectContaining({
|
||||
Authorization: "Bearer tok",
|
||||
"X-Nanobot-Channel-Values": JSON.stringify({
|
||||
"channels.slack.botToken": "xoxb-test",
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
);
|
||||
expect(fetch).not.toHaveBeenCalledWith(
|
||||
expect.anything(),
|
||||
expect.objectContaining({ method: "POST" }),
|
||||
);
|
||||
});
|
||||
|
||||
it("configures channels through the WebSocket HTTP shim", async () => {
|
||||
await configureChannel(
|
||||
"tok",
|
||||
"discord",
|
||||
{ "channels.discord.token": "saved-secret" },
|
||||
{ enable: true },
|
||||
);
|
||||
|
||||
expect(fetch).toHaveBeenCalledWith(
|
||||
"/api/settings/channels/configure?name=discord&enable=true",
|
||||
expect.objectContaining({
|
||||
headers: expect.objectContaining({
|
||||
Authorization: "Bearer tok",
|
||||
"X-Nanobot-Channel-Values": JSON.stringify({
|
||||
"channels.discord.token": "saved-secret",
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
);
|
||||
expect(fetch).not.toHaveBeenCalledWith(
|
||||
expect.anything(),
|
||||
expect.objectContaining({ method: "POST" }),
|
||||
);
|
||||
});
|
||||
|
||||
it("serializes channel QR connect helpers", async () => {
|
||||
await startChannelConnect("tok", "weixin", { force: true });
|
||||
expect(fetch).toHaveBeenLastCalledWith(
|
||||
"/api/settings/channels/weixin/connect/start?force=true",
|
||||
expect.objectContaining({
|
||||
headers: { Authorization: "Bearer tok" },
|
||||
}),
|
||||
);
|
||||
|
||||
await pollChannelConnect("tok", "weixin", "session+/=");
|
||||
expect(fetch).toHaveBeenLastCalledWith(
|
||||
"/api/settings/channels/weixin/connect/poll?session_id=session%2B%2F%3D",
|
||||
expect.objectContaining({
|
||||
headers: { Authorization: "Bearer tok" },
|
||||
}),
|
||||
);
|
||||
|
||||
await cancelChannelConnect("tok", "weixin", "session+/=");
|
||||
expect(fetch).toHaveBeenLastCalledWith(
|
||||
"/api/settings/channels/weixin/connect/cancel?session_id=session%2B%2F%3D",
|
||||
expect.objectContaining({
|
||||
headers: { Authorization: "Bearer tok" },
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("serializes workspace automation actions", async () => {
|
||||
await runAutomationAction("tok", "disable", "job 1/2");
|
||||
|
||||
@@ -478,6 +562,44 @@ describe("webui API helpers", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("manages the API service capability", async () => {
|
||||
await fetchApiService("tok");
|
||||
expect(fetch).toHaveBeenCalledWith(
|
||||
"/api/settings/api-service",
|
||||
expect.objectContaining({ headers: { Authorization: "Bearer tok" } }),
|
||||
);
|
||||
|
||||
await startApiService("tok", { host: "127.0.0.1", port: 8900, timeout: 120 });
|
||||
expect(fetch).toHaveBeenCalledWith(
|
||||
"/api/settings/api-service/start?host=127.0.0.1&port=8900&timeout=120",
|
||||
expect.objectContaining({ headers: { Authorization: "Bearer tok" } }),
|
||||
);
|
||||
|
||||
await startApiService(
|
||||
"tok",
|
||||
{ host: "0.0.0.0", port: 8900, timeout: 120, apiKey: "secret-token" },
|
||||
);
|
||||
expect(fetch).toHaveBeenCalledWith(
|
||||
"/api/settings/api-service/start?host=0.0.0.0&port=8900&timeout=120",
|
||||
expect.objectContaining({
|
||||
headers: {
|
||||
Authorization: "Bearer tok",
|
||||
"X-Nanobot-API-Service-Values": JSON.stringify({ api_key: "secret-token" }),
|
||||
},
|
||||
}),
|
||||
);
|
||||
expect(fetch).not.toHaveBeenCalledWith(
|
||||
expect.stringContaining("secret-token"),
|
||||
expect.anything(),
|
||||
);
|
||||
|
||||
await stopApiService("tok");
|
||||
expect(fetch).toHaveBeenCalledWith(
|
||||
"/api/settings/api-service/stop",
|
||||
expect.objectContaining({ headers: { Authorization: "Bearer tok" } }),
|
||||
);
|
||||
});
|
||||
|
||||
it("reads MCP presets and serializes actions", async () => {
|
||||
vi.mocked(fetch).mockResolvedValueOnce({
|
||||
ok: true,
|
||||
|
||||
Reference in New Issue
Block a user