дзеркало
https://github.com/l0ng-ai/openidea.git
синхронізовано 2026-11-08 19:02:17 +02:00
Closes #1950 Plugins can declare `detail = true` on a tree or list view (any tool-window side, grouped or not) to show the selected item's detail-provider tabs beside the list. The pane follows selection and refresh, clears stale content when the item, project or remote host changes, shows an empty state when nothing is selected, and remembers its resizable divider. Services keeps its single split. Released WIT and IPC shapes are unchanged. Verified on macOS in light and dark themes. Co-authored-by: arnaud-ritti <[email protected]>
83 рядки
2.8 KiB
TypeScript
83 рядки
2.8 KiB
TypeScript
import { useState } from "react";
|
|
import { createRoot } from "react-dom/client";
|
|
import type { ProjectInfo, RemoteSession, View } from "../src/bindings";
|
|
import { createMemoryPluginsBackend, setPluginsBackend } from "../src/features/plugins/backend";
|
|
import { PluginView } from "../src/features/plugins/views/PluginView";
|
|
import { bumpView } from "../src/features/plugins/views/viewStore";
|
|
import { useProject } from "../src/platform/project";
|
|
import { useRemote } from "../src/platform/remote";
|
|
import "../src/styles/tokens.css";
|
|
|
|
const remote = (config: string): RemoteSession => ({
|
|
target: { kind: "ssh", config },
|
|
root: "/same",
|
|
host: config,
|
|
os: "linux",
|
|
commands: [],
|
|
});
|
|
useProject.setState({ project: { root: "/same" } as ProjectInfo });
|
|
useRemote.setState({ session: remote("one") });
|
|
|
|
let removed = false;
|
|
let revision = 0;
|
|
let selected = "";
|
|
setPluginsBackend({
|
|
...createMemoryPluginsBackend([]),
|
|
renderView: async (_p, view): Promise<View> => ({
|
|
toolbar: [
|
|
{ id: "remove", label: "Remove alpha", icon: null, enabled: true },
|
|
{ id: "refresh", label: "Refresh details", icon: null, enabled: true },
|
|
],
|
|
status: null,
|
|
body: {
|
|
kind: view === "tree" ? "tree" : "list",
|
|
value: (removed ? ["beta"] : ["alpha", "beta"]).map((key) => ({
|
|
key,
|
|
label: key,
|
|
icon: null,
|
|
detail: null,
|
|
parent: null,
|
|
expanded: false,
|
|
expandable: false,
|
|
})),
|
|
},
|
|
}),
|
|
viewEvent: async (_p, view, event) => {
|
|
if (event.kind === "select") selected = event.key;
|
|
if (event.kind === "button") {
|
|
if (event.id === "remove") removed = true;
|
|
revision++;
|
|
bumpView("fixture", view);
|
|
}
|
|
},
|
|
serviceDetail: async (_p, view, key) => {
|
|
if (selected !== key) throw new Error("select was not handled");
|
|
return [
|
|
{ id: "info", label: "Info", body: { kind: "text", value: `${view}: ${key}\nRevision ${revision}` } },
|
|
{ id: "summary", label: "Summary", body: { kind: "message", value: `Selected ${key}` } },
|
|
];
|
|
},
|
|
});
|
|
function Fixture() {
|
|
const kind = new URLSearchParams(location.search).get("kind") === "tree" ? "tree" : "list";
|
|
const [shown, setShown] = useState(true);
|
|
const [host, setHost] = useState("one");
|
|
return (
|
|
<>
|
|
<button onClick={() => setShown((value) => !value)}>Toggle view</button>
|
|
<button
|
|
onClick={() => {
|
|
const next = host === "one" ? "two" : "one";
|
|
useRemote.setState({ session: remote(next) });
|
|
setHost(next);
|
|
}}
|
|
>
|
|
Switch remote host
|
|
</button>
|
|
<output aria-label="Remote host">{host}</output>
|
|
<div style={{ height: 400, width: 900 }}>{shown && <PluginView pluginId="fixture" view={kind} detail />}</div>
|
|
</>
|
|
);
|
|
}
|
|
createRoot(document.getElementById("root")!).render(<Fixture />);
|