дзеркало
https://github.com/l0ng-ai/openidea.git
синхронізовано 2026-11-09 03:05:40 +02:00
feat(github): pull request tool window, timeline and review flow (#477)
Replaces the Pull Requests tool window with a full review workflow on top of gh's authentication. - List with search, quick filters and paging; a tab per pull request and a New Pull Request tab. - Details: commit picker, changes tree with viewed state, CI and reviewer status, merge, close and reopen. - Timeline editor: comments, review threads, reactions and suggested changes. - Review in the diff viewer and, for the checked-out branch, in the editor (review mode). - New generic vcs extension points: registerDiffViewerProvider, lineInlays, reviewGutter, branch widget extensions; new vcs_merge_base and gh_api commands. - CSP: img-src allows https://avatars.githubusercontent.com for avatars. Fixed while testing against a real repository: remotes behind an SSH host alias, mergeability stuck on UNKNOWN, Apply Locally staying disabled after a checkout, relative links navigating the app's page, and review inlays wider than the pane. Co-authored-by: imacross <[email protected]>
Цей коміт міститься в:
1 джерело
696377acc2
коміт
059fd8a69b
192 files changed
+23668
-2076
No files matched your search
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* Content tabs of the Pull Requests tool window (IntelliJ's `ReviewToolwindowTabsManager`):
|
||||
* the list tab (not closable), one `#N` tab per opened pull request and the "New Pull
|
||||
* Request" tab, each opened at most once. Also the list's selection, which actions such as
|
||||
* Checkout Pull Request… use.
|
||||
*/
|
||||
import { create } from "zustand";
|
||||
import { setContext } from "@/platform/context";
|
||||
|
||||
export type GhTab = { kind: "pr"; number: number } | { kind: "create" };
|
||||
export type GhTabId = "list" | `pr:${number}` | "create";
|
||||
|
||||
interface TabsState {
|
||||
tabs: GhTab[];
|
||||
active: GhTabId;
|
||||
/** The pull request selected in the list. */
|
||||
listSelection: number | null;
|
||||
}
|
||||
|
||||
export const useGhTabs = create<TabsState>(() => ({ tabs: [], active: "list", listSelection: null }));
|
||||
|
||||
export const tabId = (t: GhTab): GhTabId => (t.kind === "pr" ? `pr:${t.number}` : "create");
|
||||
|
||||
/** Opens (or selects) the `#N` tab. */
|
||||
export function openPullRequestTab(number: number) {
|
||||
useGhTabs.setState((s) => ({
|
||||
tabs: s.tabs.some((t) => t.kind === "pr" && t.number === number) ? s.tabs : [...s.tabs, { kind: "pr", number }],
|
||||
active: `pr:${number}`,
|
||||
}));
|
||||
}
|
||||
|
||||
/** Opens (or selects) the "New Pull Request at {repo}" tab. */
|
||||
export function openCreateTab() {
|
||||
useGhTabs.setState((s) => ({
|
||||
tabs: s.tabs.some((t) => t.kind === "create") ? s.tabs : [...s.tabs, { kind: "create" }],
|
||||
active: "create",
|
||||
}));
|
||||
}
|
||||
|
||||
export function selectTab(id: GhTabId) {
|
||||
useGhTabs.setState({ active: id });
|
||||
}
|
||||
|
||||
/** Closes a `#N` or the New Pull Request tab; the tab before it becomes active. */
|
||||
export function closeTab(id: GhTabId) {
|
||||
if (id === "list") return;
|
||||
useGhTabs.setState((s) => {
|
||||
const i = s.tabs.findIndex((t) => tabId(t) === id);
|
||||
if (i < 0) return s;
|
||||
const tabs = s.tabs.filter((_, j) => j !== i);
|
||||
const before = tabs[i - 1];
|
||||
const active = s.active === id ? (before ? tabId(before) : "list") : s.active;
|
||||
return { tabs, active };
|
||||
});
|
||||
}
|
||||
|
||||
export function setListSelection(number: number | null) {
|
||||
useGhTabs.setState({ listSelection: number });
|
||||
}
|
||||
|
||||
/** The pull request of the active `#N` tab, else the list's selection. */
|
||||
export function contextPullRequest(): number | null {
|
||||
const s = useGhTabs.getState();
|
||||
const m = /^pr:(\d+)$/.exec(s.active);
|
||||
return m ? Number(m[1]) : s.listSelection;
|
||||
}
|
||||
|
||||
/** Another repository or project: only the list tab stays. */
|
||||
export function resetTabs() {
|
||||
useGhTabs.setState({ tabs: [], active: "list", listSelection: null });
|
||||
}
|
||||
|
||||
/** `githubPrTab`: `list`, `pr` or `create`, for the tab-specific shortcuts (Refresh). */
|
||||
useGhTabs.subscribe((s) => setContext("githubPrTab", s.active.startsWith("pr:") ? "pr" : s.active));
|
||||
Reference in new issue
Заблокувати користувача