mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-10-25 17:22:27 +08:00
Installed apps on the apps page can be reordered by dragging the handle that appears at the start of a row on hover, the same way provider cards are sorted. Only the installed section is sortable: where a missing app sits does not matter, and while the first probe has not finished it is not yet known which section a row belongs to. There is a single order for all apps, saved as `appOrder` in the device-level settings.json next to `visibleApps` (not cloud-synced). The sidebar and the app opened by default follow it. Each section shows the order filtered by install state, so an app keeps its relative position when it moves between sections. Apps missing from a saved order, such as ones added in a later version, are inserted after their default predecessor; unknown ids are ignored. The dragged row is kept inside its section's list box, which clips overflow for the rounded corners, so it cannot disappear mid-drag.
59 lines
1.9 KiB
TypeScript
59 lines
1.9 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import {
|
|
APP_IDS,
|
|
orderAppIds,
|
|
isAdditiveAppId,
|
|
SKILLS_APP_IDS,
|
|
MCP_APP_IDS,
|
|
isProxyAppId,
|
|
} from "@/config/appConfig";
|
|
|
|
describe("appConfig provider lifecycle", () => {
|
|
it.each(["opencode", "openclaw", "hermes", "pi", "mcode", "kimi"])(
|
|
"classifies %s as additive",
|
|
(appId) => {
|
|
expect(isAdditiveAppId(appId)).toBe(true);
|
|
},
|
|
);
|
|
|
|
it.each(["claude", "claude-desktop", "codex", "gemini", "grokbuild"])(
|
|
"does not classify %s as additive",
|
|
(appId) => {
|
|
expect(isAdditiveAppId(appId)).toBe(false);
|
|
},
|
|
);
|
|
});
|
|
|
|
// Antigravity shares management UI, but has independent configuration and no CCS proxy.
|
|
describe("Antigravity capabilities", () => {
|
|
it("supports skills and MCP with direct provider switching", () => {
|
|
expect(SKILLS_APP_IDS).toContain("agy");
|
|
expect(MCP_APP_IDS).toContain("agy");
|
|
expect(isAdditiveAppId("agy")).toBe(false);
|
|
expect(isProxyAppId("agy")).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe("orderAppIds", () => {
|
|
it("falls back to the default order when nothing is saved", () => {
|
|
expect(orderAppIds(undefined)).toEqual(APP_IDS);
|
|
expect(orderAppIds([])).toEqual(APP_IDS);
|
|
});
|
|
|
|
it("keeps the saved order and drops unknown or repeated ids", () => {
|
|
const saved = [...APP_IDS].reverse();
|
|
expect(orderAppIds(["future-app", ...saved, "claude"])).toEqual(saved);
|
|
});
|
|
|
|
it("puts an app missing from the saved order after its default predecessor", () => {
|
|
const saved = APP_IDS.filter((app) => app !== "kimi");
|
|
const [first, ...rest] = saved;
|
|
// 把 mcode(kimi 默认的前一个)挪到最后,kimi 应跟着它
|
|
const moved = [first, ...rest.filter((app) => app !== "mcode"), "mcode"];
|
|
expect(orderAppIds(moved)).toEqual([...moved, "kimi"]);
|
|
expect(orderAppIds(APP_IDS.filter((app) => app !== "claude"))[0]).toBe(
|
|
"claude",
|
|
);
|
|
});
|
|
});
|