mirror of
https://github.com/l0ng-ai/openidea.git
synced 2026-11-06 00:07:50 +00:00
feat(vcs): resize the Push dialog's commits and changed files with a splitter
The commits list and the changed files tree had fixed heights, so a push with one commit and many files left the files in a small scroll area and empty space above the buttons. They now sit in a vertical split that fills the dialog body, and the divider position is remembered.
This commit is contained in:
@@ -129,15 +129,32 @@
|
||||
flex-direction: column;
|
||||
padding: 0 14px 14px;
|
||||
}
|
||||
/* Push dialog: commits above their changed files, split by a draggable divider; the pair fills the body. */
|
||||
.pushSplit {
|
||||
flex: 1;
|
||||
min-height: min(540px, 60vh);
|
||||
}
|
||||
/* The panel's own `height: 100%` doesn't resolve against a flex-basis height in WebKit: stretch instead. */
|
||||
.pushSplit .pushSplitPanel {
|
||||
height: auto;
|
||||
align-self: stretch;
|
||||
}
|
||||
.pushSplitPanel > .pushListWrap {
|
||||
min-height: 0;
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
/* Push dialogs: the outgoing commits' changed files below the commits, the diff beside them. */
|
||||
.pushChanges {
|
||||
flex: none;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
padding-top: 8px;
|
||||
}
|
||||
.pushChanges .comparison {
|
||||
height: min(360px, 45vh);
|
||||
flex: 1;
|
||||
height: auto;
|
||||
min-height: 0;
|
||||
padding: 0 14px 14px;
|
||||
}
|
||||
.pushChangesTitle {
|
||||
|
||||
@@ -5,7 +5,7 @@ import { call, commands } from "@/platform/ipc";
|
||||
import { tx } from "@/platform/i18n";
|
||||
import { workflowSettings } from "@/platform/workflowSettings";
|
||||
import { notifications } from "@/workbench/contributions";
|
||||
import { Checkbox, Dialog, Input, List, Select, Spinner, T, Tree } from "@/ui";
|
||||
import { Checkbox, Dialog, Input, List, Select, Spinner, SplitGroup, SplitHandle, SplitPanel, T, Tree } from "@/ui";
|
||||
import { ask } from "@/workbench/messages";
|
||||
import { openDialog } from "./dialogs";
|
||||
import { formatTime } from "./model";
|
||||
@@ -340,6 +340,11 @@ function PushDialog({ target: pushTarget, onClose }: { target: PushTarget; onClo
|
||||
const [commits, setCommits] = useState<Commit[] | null>(null);
|
||||
// The commit whose changes are shown; -1: all outgoing commits.
|
||||
const [shownCommit, setShownCommit] = useState(-1);
|
||||
const [pushSplit, setPushSplit] = useState(loadPushSplit);
|
||||
const keepPushSplit = (layout: Record<string, number>) => {
|
||||
setPushSplit(layout);
|
||||
savePushSplit(layout);
|
||||
};
|
||||
const shownCommits = useMemo(
|
||||
() => (commits && shownCommit >= 0 && commits[shownCommit] ? [commits[shownCommit]] : (commits ?? [])),
|
||||
[commits, shownCommit],
|
||||
@@ -440,6 +445,36 @@ function PushDialog({ target: pushTarget, onClose }: { target: PushTarget; onClo
|
||||
);
|
||||
};
|
||||
|
||||
const commitList = (
|
||||
<div className={styles.pushListWrap}>
|
||||
{error ? (
|
||||
<div className={styles.error}>{error}</div>
|
||||
) : !commits ? (
|
||||
<div className={styles.empty}>
|
||||
<Spinner size={14} />
|
||||
</div>
|
||||
) : (
|
||||
<List
|
||||
items={commits}
|
||||
getKey={(c) => c.id}
|
||||
activeIndex={shownCommit}
|
||||
onActiveChange={setShownCommit}
|
||||
rowHeight={22}
|
||||
aria-label="Outgoing commits"
|
||||
className={styles.boxList}
|
||||
empty={<span>{upstream ? tx("Everything is up to date") : tx("No commits")}</span>}
|
||||
renderItem={(c) => (
|
||||
<span className={styles.commitRow} style={{ flex: 1, padding: 0 }}>
|
||||
<span className={styles.commitHash}>{c.shortId}</span>
|
||||
<span className={styles.commitSubject}>{c.summary}</span>
|
||||
<span className={styles.commitMeta}>{c.author}</span>
|
||||
<span className={styles.commitMeta}>{formatTime(c.timeMs)}</span>
|
||||
</span>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
return (
|
||||
<Dialog
|
||||
open
|
||||
@@ -520,44 +555,56 @@ function PushDialog({ target: pushTarget, onClose }: { target: PushTarget; onClo
|
||||
)}
|
||||
{retarget && <span className={styles.hint}> {tx("New")}</span>}
|
||||
</div>
|
||||
<div className={styles.pushListWrap}>
|
||||
{error ? (
|
||||
<div className={styles.error}>{error}</div>
|
||||
) : !commits ? (
|
||||
<div className={styles.empty}>
|
||||
<Spinner size={14} />
|
||||
</div>
|
||||
) : (
|
||||
<List
|
||||
items={commits}
|
||||
getKey={(c) => c.id}
|
||||
activeIndex={shownCommit}
|
||||
onActiveChange={setShownCommit}
|
||||
rowHeight={22}
|
||||
aria-label="Outgoing commits"
|
||||
className={styles.boxList}
|
||||
empty={<span>{upstream ? tx("Everything is up to date") : tx("No commits")}</span>}
|
||||
renderItem={(c) => (
|
||||
<span className={styles.commitRow} style={{ flex: 1, padding: 0 }}>
|
||||
<span className={styles.commitHash}>{c.shortId}</span>
|
||||
<span className={styles.commitSubject}>{c.summary}</span>
|
||||
<span className={styles.commitMeta}>{c.author}</span>
|
||||
<span className={styles.commitMeta}>{formatTime(c.timeMs)}</span>
|
||||
</span>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<PushChanges
|
||||
key={pushChangesKey(repo, shownCommits)}
|
||||
repo={repo}
|
||||
commits={shownCommits}
|
||||
onShowAll={shownCommit >= 0 && (commits?.length ?? 0) > 1 ? () => setShownCommit(-1) : undefined}
|
||||
/>
|
||||
{commits?.length && !error ? (
|
||||
<SplitGroup
|
||||
orientation="vertical"
|
||||
id="vcs-push-split"
|
||||
className={styles.pushSplit}
|
||||
defaultLayout={pushSplit}
|
||||
onLayoutChanged={keepPushSplit}
|
||||
>
|
||||
<SplitPanel id="commits" minSize="72px" defaultSize="35%" className={styles.pushSplitPanel}>
|
||||
{commitList}
|
||||
</SplitPanel>
|
||||
<SplitHandle />
|
||||
<SplitPanel id="changes" minSize="160px" className={styles.pushSplitPanel}>
|
||||
<PushChanges
|
||||
key={pushChangesKey(repo, shownCommits)}
|
||||
repo={repo}
|
||||
commits={shownCommits}
|
||||
onShowAll={shownCommit >= 0 && commits.length > 1 ? () => setShownCommit(-1) : undefined}
|
||||
/>
|
||||
</SplitPanel>
|
||||
</SplitGroup>
|
||||
) : (
|
||||
commitList
|
||||
)}
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
const PUSH_SPLIT_KEY = "openidea.vcs.pushSplit";
|
||||
|
||||
/** Heights of the Push dialog's commits and changed files, as the splitter left them. */
|
||||
function loadPushSplit(): Record<string, number> | undefined {
|
||||
try {
|
||||
const v: unknown = JSON.parse(localStorage.getItem(PUSH_SPLIT_KEY) ?? "null");
|
||||
return v && typeof v === "object" && Object.values(v).every((n) => typeof n === "number")
|
||||
? (v as Record<string, number>)
|
||||
: undefined;
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function savePushSplit(layout: Record<string, number>) {
|
||||
try {
|
||||
localStorage.setItem(PUSH_SPLIT_KEY, JSON.stringify(layout));
|
||||
} catch {
|
||||
/* kept for this dialog only */
|
||||
}
|
||||
}
|
||||
|
||||
const SILENT_FORCE_PUSH_KEY = "openidea.vcs.silentForcePushTargets";
|
||||
|
||||
function silentForcePushTargets(): string[] {
|
||||
|
||||
Reference in New Issue
Block a user