Merge branch 'opt/light_mode'
This commit is contained in:
+154
-1
@@ -22,9 +22,11 @@
|
||||
import FileHistoryPanel from "./lib/components/FileHistoryPanel.svelte";
|
||||
import GlobalSearchDialog from "./lib/components/GlobalSearchDialog.svelte";
|
||||
import HistoryPanel from "./lib/components/HistoryPanel.svelte";
|
||||
import InteractiveRebaseDialog from "./lib/components/InteractiveRebaseDialog.svelte";
|
||||
import LinePatchDialog from "./lib/components/LinePatchDialog.svelte";
|
||||
import NewBranchDialog from "./lib/components/NewBranchDialog.svelte";
|
||||
import RenameBranchDialog from "./lib/components/RenameBranchDialog.svelte";
|
||||
import ReflogDialog from "./lib/components/ReflogDialog.svelte";
|
||||
import RepoLoadingOverlay from "./lib/components/RepoLoadingOverlay.svelte";
|
||||
import ResolveDialog from "./lib/components/ResolveDialog.svelte";
|
||||
import StashPanel from "./lib/components/StashPanel.svelte";
|
||||
@@ -62,6 +64,8 @@
|
||||
listTags,
|
||||
listCommits,
|
||||
listFileHistory,
|
||||
listInteractiveRebaseCommits,
|
||||
listReflog,
|
||||
listRepositoryFiles,
|
||||
mergeBranch,
|
||||
openRepoInExplorer,
|
||||
@@ -83,9 +87,11 @@
|
||||
resolveConflict,
|
||||
resolveConflictSide,
|
||||
restoreFileFromCommit,
|
||||
restoreReflogEntry,
|
||||
restoreFiles,
|
||||
restoreToCommit,
|
||||
searchCodeIntroductions,
|
||||
startInteractiveRebase,
|
||||
setSyncBadge,
|
||||
stageFiles,
|
||||
stashApply,
|
||||
@@ -119,6 +125,9 @@
|
||||
LocalModelOption,
|
||||
PatchApplyAction,
|
||||
PreparedResolution,
|
||||
RebaseCommit,
|
||||
RebasePlanItem,
|
||||
ReflogEntry,
|
||||
StoredCredential,
|
||||
} from "./lib/types";
|
||||
|
||||
@@ -254,6 +263,15 @@
|
||||
let deleteBranchForce = false;
|
||||
let compareSelectOpen = false;
|
||||
let compareDialogOpen = false;
|
||||
let interactiveRebaseOpen = false;
|
||||
let interactiveRebaseBase = "";
|
||||
let interactiveRebaseCommits: RebaseCommit[] = [];
|
||||
let interactiveRebaseLoading = false;
|
||||
let interactiveRebaseError = "";
|
||||
let reflogOpen = false;
|
||||
let reflogEntries: ReflogEntry[] = [];
|
||||
let reflogLoading = false;
|
||||
let reflogError = "";
|
||||
let selectedDiffPath = "";
|
||||
let diffHighlightQuery = "";
|
||||
let pendingRestoreFile: { commit: GitCommit; file: GitCommitFile } | null = null;
|
||||
@@ -654,7 +672,7 @@
|
||||
}
|
||||
|
||||
async function autoRefreshTick() {
|
||||
if (!autoRefreshEnabled || activeView !== "repository" || !activeRepoPath || isBusy || autoRefreshInFlight || resolveDialogOpen || compareDialogOpen || compareSelectOpen || newBranchCommit || globalSearchOpen) return;
|
||||
if (!autoRefreshEnabled || activeView !== "repository" || !activeRepoPath || isBusy || autoRefreshInFlight || resolveDialogOpen || compareDialogOpen || compareSelectOpen || interactiveRebaseOpen || reflogOpen || newBranchCommit || globalSearchOpen) return;
|
||||
const path = activeRepoPath;
|
||||
autoRefreshInFlight = true;
|
||||
try {
|
||||
@@ -1580,6 +1598,13 @@
|
||||
comparison = null;
|
||||
compareSelectOpen = false;
|
||||
compareDialogOpen = false;
|
||||
interactiveRebaseOpen = false;
|
||||
interactiveRebaseBase = "";
|
||||
interactiveRebaseCommits = [];
|
||||
interactiveRebaseError = "";
|
||||
reflogOpen = false;
|
||||
reflogEntries = [];
|
||||
reflogError = "";
|
||||
selectedDiffPath = "";
|
||||
pendingRestoreFile = null;
|
||||
newBranchCommit = null;
|
||||
@@ -2250,6 +2275,99 @@
|
||||
});
|
||||
}
|
||||
|
||||
function preferredInteractiveRebaseBase(): string {
|
||||
const candidates = [status?.upstream, "origin/main", "main", "origin/master", "master"]
|
||||
.filter((value): value is string => Boolean(value) && value !== status?.current_branch);
|
||||
for (const candidate of candidates) {
|
||||
if (branches.some((branch) => branch.name === candidate)) return candidate;
|
||||
}
|
||||
return branches.find((branch) => !branch.current)?.name ?? "";
|
||||
}
|
||||
|
||||
async function loadInteractiveRebaseRange(base: string) {
|
||||
interactiveRebaseBase = base;
|
||||
interactiveRebaseCommits = [];
|
||||
interactiveRebaseError = "";
|
||||
if (!activeRepoPath || !base) return;
|
||||
interactiveRebaseLoading = true;
|
||||
try {
|
||||
const result = await listInteractiveRebaseCommits(activeRepoPath, base);
|
||||
if (interactiveRebaseBase === base) interactiveRebaseCommits = result;
|
||||
} catch (error) {
|
||||
if (interactiveRebaseBase === base) interactiveRebaseError = errorToMessage(error);
|
||||
} finally {
|
||||
if (interactiveRebaseBase === base) interactiveRebaseLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
function openInteractiveRebase() {
|
||||
if (!hasRepository || rebaseInProgress || cherryPickInProgress || isBusy) return;
|
||||
interactiveRebaseOpen = true;
|
||||
const base = preferredInteractiveRebaseBase();
|
||||
void loadInteractiveRebaseRange(base);
|
||||
trackEvent("interactive_rebase_opened");
|
||||
}
|
||||
|
||||
async function runInteractiveRebase(plan: RebasePlanItem[]) {
|
||||
if (!activeRepoPath || !interactiveRebaseBase || isBusy) return;
|
||||
interactiveRebaseError = "";
|
||||
await runOperation("Starting interactive rebase", async () => {
|
||||
applyStatus(await startInteractiveRebase(activeRepoPath, interactiveRebaseBase, plan));
|
||||
interactiveRebaseOpen = false;
|
||||
await refreshBranchList(activeRepoPath);
|
||||
await refreshCommitHistory(activeRepoPath);
|
||||
await refreshExplorerFiles(activeRepoPath);
|
||||
await refreshFileHistory(activeRepoPath);
|
||||
trackEvent("interactive_rebase_started", { commits: plan.length });
|
||||
});
|
||||
if (interactiveRebaseOpen && errorMessage) interactiveRebaseError = errorMessage;
|
||||
}
|
||||
|
||||
async function openReflog() {
|
||||
if (!hasRepository || isBusy) return;
|
||||
reflogOpen = true;
|
||||
reflogEntries = [];
|
||||
reflogError = "";
|
||||
reflogLoading = true;
|
||||
try {
|
||||
reflogEntries = await listReflog(activeRepoPath, 300);
|
||||
trackEvent("reflog_opened", { entries: reflogEntries.length });
|
||||
} catch (error) {
|
||||
reflogError = errorToMessage(error);
|
||||
} finally {
|
||||
reflogLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function previewReflogEntry(entry: ReflogEntry) {
|
||||
if (!activeRepoPath || isBusy) return;
|
||||
await runOperation("Previewing reflog entry", async () => {
|
||||
const result = await compareCommits(activeRepoPath, entry.hash, "HEAD");
|
||||
comparison = result;
|
||||
selectedDiffPath = result.files[0]?.path ?? "";
|
||||
diffHighlightQuery = "";
|
||||
pendingRestoreFile = null;
|
||||
reflogOpen = false;
|
||||
compareDialogOpen = true;
|
||||
trackEvent("reflog_previewed", { files: result.files.length });
|
||||
});
|
||||
}
|
||||
|
||||
async function recoverReflogEntry(entry: ReflogEntry, branch: string) {
|
||||
if (!activeRepoPath || !branch.trim() || isBusy) return;
|
||||
reflogError = "";
|
||||
await runOperation("Restoring reflog entry", async () => {
|
||||
applyStatus(await restoreReflogEntry(activeRepoPath, entry.hash, branch.trim()));
|
||||
reflogOpen = false;
|
||||
await refreshBranchList(activeRepoPath);
|
||||
await refreshCommitHistory(activeRepoPath);
|
||||
await refreshExplorerFiles(activeRepoPath);
|
||||
await refreshFileHistory(activeRepoPath);
|
||||
trackEvent("reflog_recovered");
|
||||
});
|
||||
if (reflogOpen && errorMessage) reflogError = errorMessage;
|
||||
}
|
||||
|
||||
async function createNewTag(name: string, message: string) {
|
||||
const trimmed = name.trim();
|
||||
if (!activeRepoPath || !trimmed) return;
|
||||
@@ -3337,6 +3455,8 @@
|
||||
else if (event.key === "Escape" && newBranchCommit) newBranchCommit = null;
|
||||
else if (event.key === "Escape" && renameBranchTarget) renameBranchTarget = null;
|
||||
else if (event.key === "Escape" && deleteBranchTarget) closeDeleteBranchDialog();
|
||||
else if (event.key === "Escape" && interactiveRebaseOpen && !isBusy) interactiveRebaseOpen = false;
|
||||
else if (event.key === "Escape" && reflogOpen && !isBusy) reflogOpen = false;
|
||||
else if (event.key === "Escape" && compareSelectOpen) compareSelectOpen = false;
|
||||
else if (event.key === "Escape" && globalSearchOpen) closeGlobalSearchDialog();
|
||||
}
|
||||
@@ -3374,6 +3494,8 @@
|
||||
onRefresh={refreshRepo}
|
||||
onSearch={openGlobalSearchDialog}
|
||||
onCompare={openCompareSelect}
|
||||
onInteractiveRebase={openInteractiveRebase}
|
||||
onReflog={openReflog}
|
||||
onOpenInExplorer={openActiveRepoInExplorer}
|
||||
onToggleAutoRefresh={toggleAutoRefresh}
|
||||
onOpenSettings={() => { appSettingsOpen = true; }}
|
||||
@@ -4093,6 +4215,37 @@
|
||||
/>
|
||||
{/if}
|
||||
|
||||
<!-- Compare: pick the two commits to diff -->
|
||||
{#if interactiveRebaseOpen}
|
||||
<InteractiveRebaseDialog
|
||||
{branches}
|
||||
currentBranch={status?.current_branch ?? ""}
|
||||
base={interactiveRebaseBase}
|
||||
commits={interactiveRebaseCommits}
|
||||
isLoading={interactiveRebaseLoading}
|
||||
{isBusy}
|
||||
{operation}
|
||||
error={interactiveRebaseError}
|
||||
onBaseChange={loadInteractiveRebaseRange}
|
||||
onStart={runInteractiveRebase}
|
||||
onClose={() => { if (!isBusy) interactiveRebaseOpen = false; }}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
{#if reflogOpen}
|
||||
<ReflogDialog
|
||||
entries={reflogEntries}
|
||||
currentHash={reflogEntries.find((entry) => entry.selector === "HEAD@{0}")?.hash ?? ""}
|
||||
isLoading={reflogLoading}
|
||||
{isBusy}
|
||||
{operation}
|
||||
error={reflogError}
|
||||
onPreview={previewReflogEntry}
|
||||
onRestore={recoverReflogEntry}
|
||||
onClose={() => { if (!isBusy) reflogOpen = false; }}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
<!-- Compare: pick the two commits to diff -->
|
||||
{#if compareSelectOpen}
|
||||
<CompareSelectDialog
|
||||
|
||||
Reference in New Issue
Block a user