Skip to content

Commit 708041f

Browse files
committed
Add ribbon button with Git actions menu (pull, commit, push, revert)
1 parent d7b87f0 commit 708041f

File tree

5 files changed

+113
-6
lines changed

5 files changed

+113
-6
lines changed

main.js

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/git.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,11 @@ export async function setRemoteUrl(cwd: string, gitPath: string, url: string): P
144144
}
145145
}
146146

147+
export async function revertAll(cwd: string, gitPath: string): Promise<void> {
148+
await runGit({ cwd, gitPath, args: ["checkout", "--", "."] });
149+
await runGit({ cwd, gitPath, args: ["clean", "-fd"] });
150+
}
151+
147152
export type FileStatus = "M" | "A" | "R" | "U" | "?" | "";
148153

149154
export async function getFileStatuses(cwd: string, gitPath: string): Promise<Map<string, FileStatus>> {

src/i18n.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,16 @@ type Translations = {
3333
showStatusBadgeName: string;
3434
showStatusBadgeDesc: string;
3535

36+
showRibbonButtonName: string;
37+
showRibbonButtonDesc: string;
38+
ribbonMenuPull: string;
39+
ribbonMenuCommit: string;
40+
ribbonMenuPush: string;
41+
ribbonMenuCommitAndPush: string;
42+
ribbonMenuRevertAll: string;
43+
noticeReverted: string;
44+
noticeRevertFailed: (msg: string) => string;
45+
3646
// Repository
3747
repoStatusName: string;
3848
repoNotInitialized: string;
@@ -108,6 +118,16 @@ const en: Translations = {
108118
showStatusBadgeName: "Show git status in file explorer",
109119
showStatusBadgeDesc: "Display colored dots next to changed files and folders.",
110120

121+
showRibbonButtonName: "Show ribbon button",
122+
showRibbonButtonDesc: "Add a ribbon icon for quick Git actions.",
123+
ribbonMenuPull: "Pull",
124+
ribbonMenuCommit: "Commit",
125+
ribbonMenuPush: "Push",
126+
ribbonMenuCommitAndPush: "Commit and push",
127+
ribbonMenuRevertAll: "Revert all changes",
128+
noticeReverted: "GitAutoCommit: All changes reverted.",
129+
noticeRevertFailed: (msg) => `GitAutoCommit: Revert failed - ${msg}`,
130+
111131
repoStatusName: "Repository status",
112132
repoNotInitialized: "Not a git repository",
113133
repoInitialized: "Git repository initialized",
@@ -180,6 +200,16 @@ const zhCN: Translations = {
180200
showStatusBadgeName: "在文件列表显示 Git 状态",
181201
showStatusBadgeDesc: "在变动的文件和文件夹旁显示彩色圆点。",
182202

203+
showRibbonButtonName: "显示侧边栏按钮",
204+
showRibbonButtonDesc: "添加快捷 Git 操作按钮。",
205+
ribbonMenuPull: "拉取",
206+
ribbonMenuCommit: "提交",
207+
ribbonMenuPush: "推送",
208+
ribbonMenuCommitAndPush: "提交并推送",
209+
ribbonMenuRevertAll: "还原所有修改",
210+
noticeReverted: "GitAutoCommit: 已还原所有修改。",
211+
noticeRevertFailed: (msg) => `GitAutoCommit: 还原失败 - ${msg}`,
212+
183213
repoStatusName: "仓库状态",
184214
repoNotInitialized: "尚未初始化为 Git 仓库",
185215
repoInitialized: "Git 仓库已初始化",

src/main.ts

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { EventRef, Notice, Platform, Plugin, TAbstractFile, TFile, FileSystemAdapter } from "obsidian";
1+
import { EventRef, Menu, Notice, Platform, Plugin, TAbstractFile, TFile, FileSystemAdapter } from "obsidian";
22
import { AutoGitSettings, AutoGitSettingTab, DEFAULT_SETTINGS } from "./settings";
3-
import { getChangedFiles, commitAll, push, pull, getFileStatuses, getConflictFiles, markConflictsResolved, FileStatus } from "./git";
3+
import { getChangedFiles, commitAll, push, pull, getFileStatuses, getConflictFiles, markConflictsResolved, revertAll, FileStatus } from "./git";
44
import { renderTemplate } from "./template";
55
import { t } from "./i18n";
66

@@ -16,10 +16,12 @@ export default class AutoGitPlugin extends Plugin {
1616
private conflictFiles: Set<string> = new Set();
1717
private _hasConflicts = false;
1818
private resolveConflictCommand: { id: string } | null = null;
19+
private ribbonIconEl: HTMLElement | null = null;
1920

2021
async onload() {
2122
await this.loadSettings();
2223
this.addSettingTab(new AutoGitSettingTab(this.app, this));
24+
this.updateRibbonButton();
2325

2426
this.addCommand({
2527
id: "commit-now",
@@ -70,6 +72,10 @@ export default class AutoGitPlugin extends Plugin {
7072
if (this.statusRefreshInterval) {
7173
window.clearInterval(this.statusRefreshInterval);
7274
}
75+
if (this.ribbonIconEl) {
76+
this.ribbonIconEl.remove();
77+
this.ribbonIconEl = null;
78+
}
7379
}
7480

7581
async loadSettings() {
@@ -230,6 +236,59 @@ export default class AutoGitPlugin extends Plugin {
230236
}
231237
}
232238

239+
updateRibbonButton() {
240+
if (this.settings.showRibbonButton && !Platform.isMobileApp) {
241+
if (!this.ribbonIconEl) {
242+
this.ribbonIconEl = this.addRibbonIcon("git-branch", "Git", (evt) => {
243+
this.showRibbonMenu(evt);
244+
});
245+
}
246+
} else if (this.ribbonIconEl) {
247+
this.ribbonIconEl.remove();
248+
this.ribbonIconEl = null;
249+
}
250+
}
251+
252+
private showRibbonMenu(evt: MouseEvent) {
253+
const i18n = t();
254+
const menu = new Menu();
255+
256+
menu.addItem((item) =>
257+
item.setTitle(i18n.ribbonMenuPull).setIcon("download").onClick(() => void this.doPull())
258+
);
259+
menu.addItem((item) =>
260+
item.setTitle(i18n.ribbonMenuCommit).setIcon("check").onClick(() => void this.runCommit("manual"))
261+
);
262+
menu.addItem((item) =>
263+
item.setTitle(i18n.ribbonMenuPush).setIcon("upload").onClick(() => void this.doPush())
264+
);
265+
menu.addItem((item) =>
266+
item.setTitle(i18n.ribbonMenuCommitAndPush).setIcon("upload").onClick(async () => {
267+
const committed = await this.runCommit("manual");
268+
if (committed) {
269+
await this.doPush();
270+
}
271+
})
272+
);
273+
menu.addSeparator();
274+
menu.addItem((item) =>
275+
item.setTitle(i18n.ribbonMenuRevertAll).setIcon("rotate-ccw").onClick(() => void this.doRevert())
276+
);
277+
278+
menu.showAtMouseEvent(evt);
279+
}
280+
281+
private async doRevert() {
282+
try {
283+
const cwd = this.getVaultPath();
284+
await revertAll(cwd, this.settings.gitPath);
285+
new Notice(t().noticeReverted);
286+
this.refreshStatusBadges();
287+
} catch (e) {
288+
new Notice(t().noticeRevertFailed((e as Error).message));
289+
}
290+
}
291+
233292
private async doPull() {
234293
if (Platform.isMobileApp) {
235294
new Notice(t().noticeMobileNotSupported);

src/settings.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export interface AutoGitSettings {
1313
gitPath: string;
1414
ignoreObsidianDir: boolean;
1515
showStatusBadge: boolean;
16+
showRibbonButton: boolean;
1617
}
1718

1819
export const DEFAULT_SETTINGS: AutoGitSettings = {
@@ -25,6 +26,7 @@ export const DEFAULT_SETTINGS: AutoGitSettings = {
2526
gitPath: "git",
2627
ignoreObsidianDir: true,
2728
showStatusBadge: true,
29+
showRibbonButton: true,
2830
};
2931

3032
export class AutoGitSettingTab extends PluginSettingTab {
@@ -144,6 +146,17 @@ export class AutoGitSettingTab extends PluginSettingTab {
144146
})
145147
);
146148

149+
new Setting(containerEl)
150+
.setName(i18n.showRibbonButtonName)
151+
.setDesc(i18n.showRibbonButtonDesc)
152+
.addToggle((toggle) =>
153+
toggle.setValue(this.plugin.settings.showRibbonButton).onChange(async (value) => {
154+
this.plugin.settings.showRibbonButton = value;
155+
await this.plugin.saveSettings();
156+
this.plugin.updateRibbonButton();
157+
})
158+
);
159+
147160
new Setting(containerEl)
148161
.setName(i18n.gitPathName)
149162
.setDesc(i18n.gitPathDesc)

0 commit comments

Comments
 (0)