From 30a21b98aa24f1a115e7f1c35da0a70b1247c73a Mon Sep 17 00:00:00 2001 From: garak95 <267723355+garak95@users.noreply.github.com> Date: Tue, 31 Mar 2026 01:47:11 +0100 Subject: [PATCH] Add context menu to revert folder --- src/main.ts | 30 +++++++++++++++++++++++------- src/modals.ts | 2 +- src/statusBadges.ts | 6 ++++++ 3 files changed, 30 insertions(+), 8 deletions(-) diff --git a/src/main.ts b/src/main.ts index 2987586..b1408b0 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,4 +1,4 @@ -import { EventRef, Menu, Notice, Platform, Plugin, TAbstractFile, TFile, FileSystemAdapter } from "obsidian"; +import { EventRef, Menu, Notice, Platform, Plugin, TAbstractFile, TFile, TFolder, FileSystemAdapter } from "obsidian"; import { AutoGitSettings, AutoGitSettingTab, DEFAULT_SETTINGS } from "./settings"; import { getChangedFiles, commitAll, push, pull, getConflictFiles, markConflictsResolved, revertAll, revertFile, getChangedFilesSync, commitSyncAndPushDetached, setGitDebug } from "./git"; import { renderTemplate } from "./template"; @@ -373,21 +373,37 @@ export default class AutoGitPlugin extends Plugin { this.registerEvent( this.app.workspace.on("file-menu", (menu, file) => { - if (!(file instanceof TFile)) return; + let filePaths = []; + if (file instanceof TFolder) { + const status = this.statusBadges?.getFolderStatus(file.path); + if (!status) return; + // We fetch all changes because if we only walked the current children we would miss deleted files... + const changedFiles = getChangedFilesSync(this.getVaultPath(), this.settings.gitPath); + const prefix = file.path + "/"; + for (const filePath of changedFiles) { + if (filePath.startsWith(prefix)) { + filePaths.push(filePath); + } + } + } else { + const status = this.statusBadges?.getStatus(file.path); + if (!status) return; + filePaths.push(file.path); + } - const filePath = file.path; - const status = this.statusBadges?.getStatus(filePath); - if (!status) return; + if (filePaths.length === 0) return; menu.addItem((item) => { item.setTitle(t().revertFileMenu) .setIcon("rotate-ccw") .onClick(() => { - new RevertConfirmModal(this.app, [filePath], () => { + new RevertConfirmModal(this.app, filePaths, () => { void (async () => { try { const cwd = this.getVaultPath(); - await revertFile(cwd, this.settings.gitPath, filePath); + for (const filePath of filePaths) { + await revertFile(cwd, this.settings.gitPath, filePath); + } new Notice(t().noticeFileReverted); void this.statusBadges?.refresh(); } catch (e) { diff --git a/src/modals.ts b/src/modals.ts index 451b48a..0791b1d 100644 --- a/src/modals.ts +++ b/src/modals.ts @@ -15,7 +15,7 @@ export class RevertConfirmModal extends Modal { const i18n = t(); const { contentEl } = this; - contentEl.createEl("h2", { text: i18n.revertConfirmTitle }); + this.setTitle(i18n.revertConfirmTitle); contentEl.createEl("p", { text: i18n.revertConfirmDesc }); const listEl = contentEl.createEl("ul", { cls: "revert-file-list" }); diff --git a/src/statusBadges.ts b/src/statusBadges.ts index 371e952..abe68f2 100644 --- a/src/statusBadges.ts +++ b/src/statusBadges.ts @@ -80,6 +80,12 @@ export class GitStatusBadgeManager { return this.fileStatuses.get(path) ?? ""; } + getFolderStatus(path: string): FileStatus { + if (!this.enabled || this.opts.shouldIgnore(path)) return ""; + if (this.conflicts.has(path)) return "U"; + return this.folderStatuses.get(path) ?? ""; + } + noteCreate(path: string): void { if (!this.enabled || this.opts.shouldIgnore(path)) return; if (!this.trackedLoaded) return;