дзеркало
https://github.com/l0ng-ai/openidea.git
синхронізовано 2026-11-09 03:05:40 +02:00
feat(plugins): support secondary split on [[contributes.views]] (#2185)
Plugin tool windows could only target the primary split of their dock, because the view was never registered as secondary. An optional secondary = true on [[contributes.views]], gated to plugin API 1.3, places a view in Left Bottom, Right Bottom or Bottom Right. Existing plugins stay where they are, and a user's saved layout wins. Co-authored-by: dengliu <[email protected]>
Цей коміт міститься в:
1 джерело
067feac89c
коміт
3dae4ef729
5 files changed
+115
-4
No files matched your search
@@ -5,6 +5,7 @@ import userEvent from "@testing-library/user-event";
|
||||
import { setLocale, tx } from "@/platform/i18n";
|
||||
import { setContext, useContextKeys } from "@/platform/context";
|
||||
import { provideToolWindowService, useContributions } from "@/workbench/contributions";
|
||||
import { loadToolWindowLayout, moveToolWindow, resetToolWindowLayout, slotOfId } from "@/workbench/toolwindows/store";
|
||||
import { registerWindowView, revealWindowView, type WindowView } from "../views/viewWindows";
|
||||
|
||||
const disposers: (() => void)[] = [];
|
||||
@@ -173,6 +174,48 @@ it("retains an opened tab's local state while switching tabs", async () => {
|
||||
expect(input).toHaveValue("retain this draft");
|
||||
});
|
||||
|
||||
it("keeps views primary unless secondary is explicitly true in every dock", () => {
|
||||
for (const location of ["left", "right", "bottom"] as const) {
|
||||
for (const secondary of [undefined, false, true]) {
|
||||
for (const header of [undefined, "none"] as const) {
|
||||
const id = `${location}-${secondary}-${header}`;
|
||||
add("split", { id, location, secondary, header });
|
||||
expect(useContributions.getState().toolWindows.get(`plugin.split.${id}`)?.secondary).toBe(secondary === true);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it("uses the first group member's split even when hidden", () => {
|
||||
add("spring", { id: "routes", group: "framework", secondary: true, when: "plugin.spring.ready" });
|
||||
add("spring", { id: "beans", group: "framework", secondary: false });
|
||||
expect(useContributions.getState().toolWindows.get(id)?.secondary).toBe(true);
|
||||
setContext("plugin.spring.ready", true);
|
||||
expect(useContributions.getState().toolWindows.get(id)?.secondary).toBe(true);
|
||||
});
|
||||
|
||||
it("preserves a user's moved placement across registration and layout reload", () => {
|
||||
localStorage.clear();
|
||||
resetToolWindowLayout();
|
||||
loadToolWindowLayout("/plugin-split-test");
|
||||
try {
|
||||
const view = add("split", { id: "panel", location: "right", secondary: true });
|
||||
const id = "plugin.split.panel";
|
||||
expect(slotOfId(id)).toBe("right-split");
|
||||
moveToolWindow(id, "right");
|
||||
view.setIcon("folder");
|
||||
loadToolWindowLayout("/plugin-split-test");
|
||||
expect(slotOfId(id)).toBe("right");
|
||||
moveToolWindow(id, "bottom-split");
|
||||
view.setIcon("plugin");
|
||||
loadToolWindowLayout("/plugin-split-test");
|
||||
expect(slotOfId(id)).toBe("bottom-split");
|
||||
} finally {
|
||||
resetToolWindowLayout();
|
||||
localStorage.clear();
|
||||
}
|
||||
});
|
||||
|
||||
it("discards a conditionally hidden tab and keeps it lazy when it becomes available again", async () => {
|
||||
setContext("plugin.spring.ready", true);
|
||||
add("spring", { id: "routes", title: "Routes", group: "framework" });
|
||||
|
||||
@@ -17,6 +17,8 @@ export interface WindowView {
|
||||
id: string;
|
||||
title: string;
|
||||
location: ToolWindowAnchor;
|
||||
secondary?: boolean;
|
||||
header?: "default" | "none" | null;
|
||||
group?: string | null;
|
||||
when?: string | null;
|
||||
}
|
||||
@@ -105,7 +107,9 @@ function refresh(id: string, group: WindowGroup) {
|
||||
members,
|
||||
selected: selected ?? members[0]?.decl.id ?? null,
|
||||
});
|
||||
const signature = first && members.length ? JSON.stringify([first.decl.title, first.decl.location, first.icon]) : "";
|
||||
const secondary = first?.decl.secondary === true;
|
||||
const signature =
|
||||
first && members.length ? JSON.stringify([first.decl.title, first.decl.location, secondary, first.icon]) : "";
|
||||
if (signature === group.signature) return;
|
||||
group.dispose();
|
||||
group.signature = signature;
|
||||
@@ -116,6 +120,7 @@ function refresh(id: string, group: WindowGroup) {
|
||||
title: first.decl.title,
|
||||
verbatim: true,
|
||||
anchor: first.decl.location,
|
||||
secondary,
|
||||
icon: first.icon,
|
||||
order: 900,
|
||||
component: first.decl.group ? group.component : first.component,
|
||||
|
||||
Reference in new issue
Заблокувати користувача