@caozeal/dsh-next-git 0.1.5 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -9
- package/assets/screenshots/01-changes.png +0 -0
- package/assets/screenshots/02-commit-graph.png +0 -0
- package/assets/screenshots/03-word-level-diff.png +0 -0
- package/assets/screenshots/04-branches.png +0 -0
- package/assets/screenshots/05-graph-multibranch.png +0 -0
- package/assets/screenshots/06-fullscreen.png +0 -0
- package/assets/screenshots/README.md +24 -0
- package/lib/client.js +513 -13
- package/package.json +3 -1
- package/screenshots.json +8 -0
- package/src/ai-commit.js +65 -22
- package/src/ai-conflict.js +159 -0
- package/src/operations.js +355 -6
package/lib/client.js
CHANGED
|
@@ -64,6 +64,26 @@ window.__ModuleLoader__.load({
|
|
|
64
64
|
'changes.unstageAll': '全部取消暂存',
|
|
65
65
|
'changes.stage': '暂存',
|
|
66
66
|
'changes.unstage': '取消暂存',
|
|
67
|
+
'changes.discard': '丢弃改动',
|
|
68
|
+
'changes.discardUntracked': '删除文件',
|
|
69
|
+
'changes.discardConfirm': '丢弃 {path} 的改动?此操作不可恢复。',
|
|
70
|
+
'changes.discardUntrackedConfirm': '删除未跟踪文件 {path}?此操作不可恢复。',
|
|
71
|
+
'changes.discardStagedConfirm': '丢弃 {path} 的暂存与工作区改动?此操作不可恢复。',
|
|
72
|
+
'conflict.resolve': '解决冲突',
|
|
73
|
+
'conflict.title': '冲突解决',
|
|
74
|
+
'conflict.hintPlaceholder': '补充说明(可选),例如「版本号取上游」',
|
|
75
|
+
'conflict.ai': 'AI 生成解决建议',
|
|
76
|
+
'conflict.regenerate': '重新生成',
|
|
77
|
+
'conflict.takeOurs': '取当前分支',
|
|
78
|
+
'conflict.takeTheirs': '取对方分支',
|
|
79
|
+
'conflict.apply': '应用并标记已解决',
|
|
80
|
+
'conflict.discard': '放弃',
|
|
81
|
+
'conflict.empty': '先生成建议,或直接取某一侧;生成过程不会改动文件',
|
|
82
|
+
'conflict.generating': '正在生成解决建议…',
|
|
83
|
+
'conflict.preview': 'AI 建议的解决结果 · 确认后才会写入文件',
|
|
84
|
+
'conflict.model': '由 {model} 生成',
|
|
85
|
+
'conflict.remaining': '还剩 {n} 个冲突文件',
|
|
86
|
+
'conflict.noBase': 'add/add 冲突,没有共同祖先版本',
|
|
67
87
|
'commit.title': '提交信息',
|
|
68
88
|
'commit.placeholder': '填写提交信息,或先点「AI 生成信息」',
|
|
69
89
|
'commit.hintPlaceholder': '给 AI 的补充说明(可选)',
|
|
@@ -75,6 +95,13 @@ window.__ModuleLoader__.load({
|
|
|
75
95
|
'commit.push': '提交并推送',
|
|
76
96
|
'commit.messageRequired': '请先填写提交信息',
|
|
77
97
|
'commit.empty': '没有可提交的暂存变更',
|
|
98
|
+
'commit.prompt': 'AI 提示词',
|
|
99
|
+
'commit.promptTitle': '自定义 AI 提交提示词',
|
|
100
|
+
'commit.promptHint': '留空使用默认提示词。这里只改「怎么写」,diff 与文件列表始终会传给模型。',
|
|
101
|
+
'commit.promptSave': '保存',
|
|
102
|
+
'commit.promptReset': '恢复默认',
|
|
103
|
+
'commit.promptCancel': '取消',
|
|
104
|
+
'commit.promptCustom': '自定义提示词',
|
|
78
105
|
'tabs.changes': '变更',
|
|
79
106
|
'tabs.graph': '提交图',
|
|
80
107
|
'tabs.branches': '分支',
|
|
@@ -112,6 +139,17 @@ window.__ModuleLoader__.load({
|
|
|
112
139
|
'status.branchCreated': '已创建分支 {branch}',
|
|
113
140
|
'status.branchDeleted': '已删除分支 {branch}',
|
|
114
141
|
'status.deleteConfirm': '确定删除分支 {branch}?',
|
|
142
|
+
'status.discardOk': '已丢弃 {path}',
|
|
143
|
+
'status.stashSaveOk': '已 stash 当前改动',
|
|
144
|
+
'status.stashPopOk': '已恢复 stash@{n}',
|
|
145
|
+
'status.stashDropOk': '已删除 stash@{n}',
|
|
146
|
+
'status.promptSaved': '提示词已保存',
|
|
147
|
+
'status.promptReset': '已恢复默认提示词',
|
|
148
|
+
'status.resolveOk': '已解决 {path}',
|
|
149
|
+
'status.resolveAllOk': '全部冲突已解决,可以提交了',
|
|
150
|
+
'status.takeOursOk': '已取当前分支版本',
|
|
151
|
+
'status.takeTheirsOk': '已取对方分支版本',
|
|
152
|
+
'status.conflictApplied': '已应用解决结果',
|
|
115
153
|
'status.aiModel': '由 {model} 生成',
|
|
116
154
|
'status.aiFallback': '模型输出不可用,已生成降级文案',
|
|
117
155
|
'toast.error': '失败',
|
|
@@ -131,6 +169,14 @@ window.__ModuleLoader__.load({
|
|
|
131
169
|
'status.aiModelEdit': '由 {model} 生成,可继续编辑',
|
|
132
170
|
'status.ready': '就绪',
|
|
133
171
|
'changes.stagedCount': '已暂存 {n}',
|
|
172
|
+
'stash.title': 'Stash',
|
|
173
|
+
'stash.empty': '没有 stash 记录',
|
|
174
|
+
'stash.placeholder': 'stash 说明(可选)',
|
|
175
|
+
'stash.save': '暂存改动',
|
|
176
|
+
'stash.pop': '恢复',
|
|
177
|
+
'stash.drop': '删除',
|
|
178
|
+
'stash.popConfirm': '恢复 stash@{n} 并从列表移除?',
|
|
179
|
+
'stash.dropConfirm': '删除 stash@{n}?此操作不可恢复。',
|
|
134
180
|
'changes.conflictBanner': '存在 {n} 个冲突文件,解决后再提交',
|
|
135
181
|
'branch.selectTitle': '切换分支',
|
|
136
182
|
'header.refreshing': '刷新中…',
|
|
@@ -175,6 +221,26 @@ window.__ModuleLoader__.load({
|
|
|
175
221
|
'changes.unstageAll': 'Unstage all',
|
|
176
222
|
'changes.stage': 'Stage',
|
|
177
223
|
'changes.unstage': 'Unstage',
|
|
224
|
+
'changes.discard': 'Discard changes',
|
|
225
|
+
'changes.discardUntracked': 'Delete file',
|
|
226
|
+
'changes.discardConfirm': 'Discard changes to {path}? This cannot be undone.',
|
|
227
|
+
'changes.discardUntrackedConfirm': 'Delete untracked file {path}? This cannot be undone.',
|
|
228
|
+
'changes.discardStagedConfirm': 'Discard staged and working-tree changes to {path}? This cannot be undone.',
|
|
229
|
+
'conflict.resolve': 'Resolve conflict',
|
|
230
|
+
'conflict.title': 'Resolve conflict',
|
|
231
|
+
'conflict.hintPlaceholder': 'Optional hint, e.g. "take the upstream version"',
|
|
232
|
+
'conflict.ai': 'Generate a resolution',
|
|
233
|
+
'conflict.regenerate': 'Regenerate',
|
|
234
|
+
'conflict.takeOurs': 'Take ours',
|
|
235
|
+
'conflict.takeTheirs': 'Take theirs',
|
|
236
|
+
'conflict.apply': 'Apply and mark resolved',
|
|
237
|
+
'conflict.discard': 'Discard',
|
|
238
|
+
'conflict.empty': 'Generate a suggestion, or take one side; generating never touches the file',
|
|
239
|
+
'conflict.generating': 'Generating a resolution…',
|
|
240
|
+
'conflict.preview': 'AI suggestion · nothing is written until you apply',
|
|
241
|
+
'conflict.model': 'Generated by {model}',
|
|
242
|
+
'conflict.remaining': '{n} conflicted file(s) left',
|
|
243
|
+
'conflict.noBase': 'add/add conflict; no common ancestor',
|
|
178
244
|
'commit.title': 'Commit message',
|
|
179
245
|
'commit.placeholder': 'Write a commit message, or generate one with AI',
|
|
180
246
|
'commit.hintPlaceholder': 'Optional hint for the AI',
|
|
@@ -186,6 +252,13 @@ window.__ModuleLoader__.load({
|
|
|
186
252
|
'commit.push': 'Commit & push',
|
|
187
253
|
'commit.messageRequired': 'Commit message is required',
|
|
188
254
|
'commit.empty': 'Nothing staged to commit',
|
|
255
|
+
'commit.prompt': 'AI prompt',
|
|
256
|
+
'commit.promptTitle': 'Custom AI commit prompt',
|
|
257
|
+
'commit.promptHint': 'Leave empty to use the default. This only changes how it writes; the diff and file list are always sent.',
|
|
258
|
+
'commit.promptSave': 'Save',
|
|
259
|
+
'commit.promptReset': 'Reset to default',
|
|
260
|
+
'commit.promptCancel': 'Cancel',
|
|
261
|
+
'commit.promptCustom': 'Custom prompt',
|
|
189
262
|
'tabs.changes': 'Changes',
|
|
190
263
|
'tabs.graph': 'Graph',
|
|
191
264
|
'tabs.branches': 'Branches',
|
|
@@ -223,6 +296,17 @@ window.__ModuleLoader__.load({
|
|
|
223
296
|
'status.branchCreated': 'Created branch {branch}',
|
|
224
297
|
'status.branchDeleted': 'Deleted branch {branch}',
|
|
225
298
|
'status.deleteConfirm': 'Delete branch {branch}?',
|
|
299
|
+
'status.discardOk': 'Discarded {path}',
|
|
300
|
+
'status.stashSaveOk': 'Stashed current changes',
|
|
301
|
+
'status.stashPopOk': 'Restored stash@{n}',
|
|
302
|
+
'status.stashDropOk': 'Dropped stash@{n}',
|
|
303
|
+
'status.promptSaved': 'Prompt saved',
|
|
304
|
+
'status.promptReset': 'Restored the default prompt',
|
|
305
|
+
'status.resolveOk': 'Resolved {path}',
|
|
306
|
+
'status.resolveAllOk': 'All conflicts resolved; ready to commit',
|
|
307
|
+
'status.takeOursOk': 'Took the ours side',
|
|
308
|
+
'status.takeTheirsOk': 'Took the theirs side',
|
|
309
|
+
'status.conflictApplied': 'Resolution applied',
|
|
226
310
|
'status.aiModel': 'Generated by {model}',
|
|
227
311
|
'status.aiFallback': 'Model output unusable; used a fallback message',
|
|
228
312
|
'toast.error': 'Failed',
|
|
@@ -242,6 +326,14 @@ window.__ModuleLoader__.load({
|
|
|
242
326
|
'status.aiModelEdit': 'Generated by {model}; edit as needed',
|
|
243
327
|
'status.ready': 'Ready',
|
|
244
328
|
'changes.stagedCount': '{n} staged',
|
|
329
|
+
'stash.title': 'Stash',
|
|
330
|
+
'stash.empty': 'No stash entries',
|
|
331
|
+
'stash.placeholder': 'Stash message (optional)',
|
|
332
|
+
'stash.save': 'Stash changes',
|
|
333
|
+
'stash.pop': 'Restore',
|
|
334
|
+
'stash.drop': 'Drop',
|
|
335
|
+
'stash.popConfirm': 'Restore stash@{n} and remove it from the list?',
|
|
336
|
+
'stash.dropConfirm': 'Drop stash@{n}? This cannot be undone.',
|
|
245
337
|
'changes.conflictBanner': '{n} conflicted file(s); resolve them before committing',
|
|
246
338
|
'branch.selectTitle': 'Switch branch',
|
|
247
339
|
'header.refreshing': 'Refreshing…',
|
|
@@ -411,6 +503,20 @@ window.__ModuleLoader__.load({
|
|
|
411
503
|
.gm-file:hover .gm-act, .gm-file:focus-within .gm-act, .gm-branch:hover .gm-act { opacity:1; }
|
|
412
504
|
.gm-act:hover { transform:scale(1.12); }
|
|
413
505
|
@media (hover:none) { .gm-act { opacity:1; } }
|
|
506
|
+
.gm-resolution { display:flex; flex-direction:column; gap:7px; padding:10px 12px 14px; }
|
|
507
|
+
.gm-res-head { display:flex; align-items:center; gap:6px; color:var(--gm-blue); }
|
|
508
|
+
.gm-res-title { font-size:11px; font-weight:700; letter-spacing:.04em; text-transform:uppercase; }
|
|
509
|
+
.gm-res-path { font: 600 12px ui-monospace, SFMono-Regular, Menlo, monospace; color:var(--gm-fg);
|
|
510
|
+
padding:2px 0; word-break:break-all; }
|
|
511
|
+
.gm-res-note { font-size:11px; color:var(--gm-dim); line-height:1.6; }
|
|
512
|
+
/* .gm-input 默认 flex:1 1 100px,在纵向 flex 里会被拉成 100px 高,这里压回去 */
|
|
513
|
+
.gm-resolution .gm-input { flex:none; width:100%; height:28px; }
|
|
514
|
+
.gm-res-code { margin-top:4px; border-radius:10px; background:var(--gm-blue-06);
|
|
515
|
+
border:1px solid var(--gm-blue-12); padding:6px 0; overflow:auto; max-height:46vh; }
|
|
516
|
+
.gm-res-line { display:flex; gap:8px; font: 11.5px/1.65 ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
517
|
+
white-space:pre; padding:0 8px; }
|
|
518
|
+
.gm-res-line .no { width:34px; text-align:right; color:var(--gm-dim); flex:none; user-select:none; }
|
|
519
|
+
.gm-res-line .tx { color:var(--gm-fg); }
|
|
414
520
|
.gm-conflict-bar { margin:9px 10px 2px; padding:6px 10px; border-radius:10px; font-size:11px; font-weight:600;
|
|
415
521
|
color:var(--gm-err); background:color-mix(in srgb, var(--gm-err) 8%, transparent);
|
|
416
522
|
border:1px solid color-mix(in srgb, var(--gm-err) 28%, transparent); }
|
|
@@ -482,6 +588,11 @@ window.__ModuleLoader__.load({
|
|
|
482
588
|
.gm-commit::before { content:''; position:absolute; top:0; left:0; right:0; height:3px;
|
|
483
589
|
background:linear-gradient(90deg, var(--gm-cyan), var(--gm-blue) 45%, transparent 90%); }
|
|
484
590
|
.gm-commit-head { display:flex; align-items:center; gap:6px; }
|
|
591
|
+
.gm-prompt { display:flex; flex-direction:column; gap:5px; padding:8px; border-radius:10px;
|
|
592
|
+
background:var(--gm-blue-06); border:1px solid var(--gm-blue-12); }
|
|
593
|
+
.gm-prompt .gm-section { padding:0; }
|
|
594
|
+
.gm-prompt-text { min-height:96px; max-height:180px; font-size:11px;
|
|
595
|
+
font-family:ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
|
|
485
596
|
.gm-commit-title { font-size:10.5px; font-weight:700; letter-spacing:.05em; text-transform:uppercase;
|
|
486
597
|
color:var(--gm-blue); }
|
|
487
598
|
.gm-textarea { width:100%; min-height:46px; max-height:140px; padding:7px 9px; border-radius:10px;
|
|
@@ -607,6 +718,9 @@ window.__ModuleLoader__.load({
|
|
|
607
718
|
commit: ['M12 4a8 8 0 1 0 0 16 8 8 0 0 0 0-16z', 'M8.5 12l2.5 2.5L16 9.5'],
|
|
608
719
|
file: ['M6 3h8l4 4v14H6z', 'M14 3v5h5'],
|
|
609
720
|
branch: ['M6 4v9', 'M6 17m-2 0a2 2 0 1 0 4 0a2 2 0 1 0-4 0', 'M18 6m-2 0a2 2 0 1 0 4 0a2 2 0 1 0-4 0', 'M18 8v1a6 6 0 0 1-6 6H8'],
|
|
721
|
+
trash: ['M4 7h16', 'M9 7V4h6v3', 'M6 7l1 14h10l1-14', 'M10 11v6', 'M14 11v6'],
|
|
722
|
+
gear: ['M12 15a3 3 0 1 0 0-6 3 3 0 0 0 0 6z', 'M19.4 15a1.7 1.7 0 0 0 .3 1.9l.1.1a2 2 0 1 1-2.8 2.8l-.1-.1a1.7 1.7 0 0 0-1.9-.3 1.7 1.7 0 0 0-1 1.5V21a2 2 0 1 1-4 0v-.1A1.7 1.7 0 0 0 9 19.4a1.7 1.7 0 0 0-1.9.3l-.1.1a2 2 0 1 1-2.8-2.8l.1-.1a1.7 1.7 0 0 0 .3-1.9 1.7 1.7 0 0 0-1.5-1H3a2 2 0 1 1 0-4h.1A1.7 1.7 0 0 0 4.6 9a1.7 1.7 0 0 0-.3-1.9l-.1-.1a2 2 0 1 1 2.8-2.8l.1.1a1.7 1.7 0 0 0 1.9.3H9a1.7 1.7 0 0 0 1-1.5V3a2 2 0 1 1 4 0v.1a1.7 1.7 0 0 0 1 1.5 1.7 1.7 0 0 0 1.9-.3l.1-.1a2 2 0 1 1 2.8 2.8l-.1.1a1.7 1.7 0 0 0-.3 1.9V9a1.7 1.7 0 0 0 1.5 1H21a2 2 0 1 1 0 4h-.1a1.7 1.7 0 0 0-1.5 1z'],
|
|
723
|
+
stash: ['M4 5h16v4H4z', 'M6 9v10h12V9', 'M10 13h4'],
|
|
610
724
|
}
|
|
611
725
|
|
|
612
726
|
function Icon(props) {
|
|
@@ -790,6 +904,15 @@ window.__ModuleLoader__.load({
|
|
|
790
904
|
newBranchOpen: false,
|
|
791
905
|
newBranchName: '',
|
|
792
906
|
newBranchFrom: '',
|
|
907
|
+
// 自定义 AI 提示词编辑态。promptDraft 是编辑中的草稿,
|
|
908
|
+
// 只有点保存才写回 git config,避免边打字边写盘。
|
|
909
|
+
promptOpen: false,
|
|
910
|
+
promptDraft: '',
|
|
911
|
+
stashMessage: '',
|
|
912
|
+
// 冲突解决:resolution 非空时「差异」页切到解决视图。
|
|
913
|
+
// suggested 为 null 表示还没生成,用户可以先选边或让 AI 生成。
|
|
914
|
+
resolution: null,
|
|
915
|
+
conflictHint: '',
|
|
793
916
|
})
|
|
794
917
|
var toastTimer = null
|
|
795
918
|
var loadToken = 0
|
|
@@ -909,6 +1032,10 @@ window.__ModuleLoader__.load({
|
|
|
909
1032
|
}
|
|
910
1033
|
|
|
911
1034
|
function setNewBranchName(value) { set({ newBranchName: value }) }
|
|
1035
|
+
function setStashMessage(value) {
|
|
1036
|
+
set({ stashMessage: String(value || '') })
|
|
1037
|
+
}
|
|
1038
|
+
|
|
912
1039
|
function setNewBranchFrom(value) { set({ newBranchFrom: value }) }
|
|
913
1040
|
|
|
914
1041
|
async function runBusy(label, operation) {
|
|
@@ -981,6 +1108,181 @@ window.__ModuleLoader__.load({
|
|
|
981
1108
|
}
|
|
982
1109
|
}
|
|
983
1110
|
|
|
1111
|
+
/**
|
|
1112
|
+
* 丢弃改动。分组的语义决定用哪个后端模式:
|
|
1113
|
+
* unstaged → worktree(只回退工作区)
|
|
1114
|
+
* untracked → untracked(删除文件)
|
|
1115
|
+
* staged → all(连暂存区一起回退)
|
|
1116
|
+
* 三种都不可恢复,所以一律先 window.confirm。
|
|
1117
|
+
*/
|
|
1118
|
+
async function discard(group, entry) {
|
|
1119
|
+
var cwd = store.get().cwd
|
|
1120
|
+
if (!cwd || !entry || !entry.path) return
|
|
1121
|
+
var mode = group === 'untracked' ? 'untracked' : group === 'staged' ? 'all' : 'worktree'
|
|
1122
|
+
var key = group === 'untracked'
|
|
1123
|
+
? 'changes.discardUntrackedConfirm'
|
|
1124
|
+
: group === 'staged' ? 'changes.discardStagedConfirm' : 'changes.discardConfirm'
|
|
1125
|
+
if (typeof window !== 'undefined' && typeof window.confirm === 'function') {
|
|
1126
|
+
if (!window.confirm(tr(key, { path: entry.path }))) return
|
|
1127
|
+
}
|
|
1128
|
+
var result = await runBusy('discard', function () {
|
|
1129
|
+
return rpc('discard', { cwd: cwd, paths: [entry.path], mode: mode })
|
|
1130
|
+
})
|
|
1131
|
+
if (result !== null) {
|
|
1132
|
+
toast('ok', tr('status.discardOk', { path: entry.path }), result.output)
|
|
1133
|
+
set({ selected: null, diff: null })
|
|
1134
|
+
await refresh()
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
async function stashSave() {
|
|
1139
|
+
var state = store.get()
|
|
1140
|
+
var cwd = state.cwd
|
|
1141
|
+
if (!cwd) return
|
|
1142
|
+
var params = { cwd: cwd }
|
|
1143
|
+
var message = String(state.stashMessage || '').trim()
|
|
1144
|
+
if (message !== '') params.message = message
|
|
1145
|
+
// 未跟踪文件默认不进 stash;有未跟踪改动时一并存起来,否则用户会以为「全存了」
|
|
1146
|
+
var status = state.snapshot && state.snapshot.status ? state.snapshot.status : null
|
|
1147
|
+
if (status && status.untracked && status.untracked.length > 0) params.includeUntracked = true
|
|
1148
|
+
var result = await runBusy('stash', function () { return rpc('stashPush', params) })
|
|
1149
|
+
if (result !== null) {
|
|
1150
|
+
set({ stashMessage: '' })
|
|
1151
|
+
toast('ok', tr('status.stashSaveOk'), result.output)
|
|
1152
|
+
await refresh()
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
async function stashPop(index) {
|
|
1157
|
+
var cwd = store.get().cwd
|
|
1158
|
+
if (!cwd) return
|
|
1159
|
+
if (typeof window !== 'undefined' && typeof window.confirm === 'function') {
|
|
1160
|
+
if (!window.confirm(tr('stash.popConfirm', { n: index }))) return
|
|
1161
|
+
}
|
|
1162
|
+
var result = await runBusy('stash', function () { return rpc('stashPop', { cwd: cwd, index: index }) })
|
|
1163
|
+
if (result !== null) {
|
|
1164
|
+
toast('ok', tr('status.stashPopOk', { n: index }), result.output)
|
|
1165
|
+
await refresh()
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
async function stashDrop(index) {
|
|
1170
|
+
var cwd = store.get().cwd
|
|
1171
|
+
if (!cwd) return
|
|
1172
|
+
if (typeof window !== 'undefined' && typeof window.confirm === 'function') {
|
|
1173
|
+
if (!window.confirm(tr('stash.dropConfirm', { n: index }))) return
|
|
1174
|
+
}
|
|
1175
|
+
var result = await runBusy('stash', function () { return rpc('stashDrop', { cwd: cwd, index: index }) })
|
|
1176
|
+
if (result !== null) {
|
|
1177
|
+
toast('ok', tr('status.stashDropOk', { n: index }), result.output)
|
|
1178
|
+
await refresh()
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
function openPrompt() {
|
|
1183
|
+
var snapshot = store.get().snapshot
|
|
1184
|
+
set({ promptOpen: true, promptDraft: snapshot && snapshot.commitPrompt ? snapshot.commitPrompt : '' })
|
|
1185
|
+
}
|
|
1186
|
+
|
|
1187
|
+
function closePrompt() {
|
|
1188
|
+
set({ promptOpen: false, promptDraft: '' })
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
function setPromptDraft(value) {
|
|
1192
|
+
set({ promptDraft: String(value || '') })
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
async function savePrompt() {
|
|
1196
|
+
var state = store.get()
|
|
1197
|
+
var cwd = state.cwd
|
|
1198
|
+
if (!cwd) return
|
|
1199
|
+
var result = await runBusy('prompt', function () {
|
|
1200
|
+
return rpc('setCommitPrompt', { cwd: cwd, prompt: String(state.promptDraft || '') })
|
|
1201
|
+
})
|
|
1202
|
+
if (result !== null) {
|
|
1203
|
+
set({ promptOpen: false, promptDraft: '' })
|
|
1204
|
+
toast('ok', tr('status.promptSaved'))
|
|
1205
|
+
await refresh()
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
async function resetPrompt() {
|
|
1210
|
+
var cwd = store.get().cwd
|
|
1211
|
+
if (!cwd) return
|
|
1212
|
+
var result = await runBusy('prompt', function () {
|
|
1213
|
+
return rpc('setCommitPrompt', { cwd: cwd, prompt: '' })
|
|
1214
|
+
})
|
|
1215
|
+
if (result !== null) {
|
|
1216
|
+
set({ promptOpen: false, promptDraft: '' })
|
|
1217
|
+
toast('ok', tr('status.promptReset'))
|
|
1218
|
+
await refresh()
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
// ------------------------------------------------------------ 冲突解决
|
|
1223
|
+
|
|
1224
|
+
function openResolution(entry) {
|
|
1225
|
+
if (!entry || !entry.path) return
|
|
1226
|
+
set({
|
|
1227
|
+
resolution: { path: entry.path, suggested: null, model: null, loading: false, hasBase: true },
|
|
1228
|
+
conflictHint: '',
|
|
1229
|
+
activeTab: 'diff',
|
|
1230
|
+
selected: { kind: 'file', group: 'conflicted', path: entry.path },
|
|
1231
|
+
})
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
function closeResolution() {
|
|
1235
|
+
set({ resolution: null, conflictHint: '' })
|
|
1236
|
+
}
|
|
1237
|
+
|
|
1238
|
+
function setConflictHint(value) {
|
|
1239
|
+
set({ conflictHint: String(value || '') })
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
async function aiResolve() {
|
|
1243
|
+
var state = store.get()
|
|
1244
|
+
var resolution = state.resolution
|
|
1245
|
+
if (!state.cwd || !resolution || resolution.loading) return
|
|
1246
|
+
set({ resolution: { path: resolution.path, suggested: resolution.suggested, model: resolution.model, loading: true, hasBase: resolution.hasBase } })
|
|
1247
|
+
var result = await runBusy('aiConflict', function () {
|
|
1248
|
+
return rpc('aiConflict', { cwd: state.cwd, path: resolution.path, hint: String(state.conflictHint || '').trim() })
|
|
1249
|
+
})
|
|
1250
|
+
if (result !== null) {
|
|
1251
|
+
set({ resolution: { path: resolution.path, suggested: result.suggested, model: result.model, loading: false, hasBase: result.hasBase } })
|
|
1252
|
+
} else {
|
|
1253
|
+
set({ resolution: { path: resolution.path, suggested: resolution.suggested, model: resolution.model, loading: false, hasBase: resolution.hasBase } })
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1257
|
+
async function applyResolution() {
|
|
1258
|
+
var state = store.get()
|
|
1259
|
+
var resolution = state.resolution
|
|
1260
|
+
if (!state.cwd || !resolution || !resolution.suggested) return
|
|
1261
|
+
var result = await runBusy('applyConflict', function () {
|
|
1262
|
+
return rpc('applyConflict', { cwd: state.cwd, path: resolution.path, content: resolution.suggested })
|
|
1263
|
+
})
|
|
1264
|
+
if (result !== null) {
|
|
1265
|
+
set({ resolution: null, conflictHint: '' })
|
|
1266
|
+
toast('ok', result.unmerged === 0 ? tr('status.resolveAllOk') : tr('status.conflictApplied'), result.output)
|
|
1267
|
+
await refresh()
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
async function takeConflictSide(side) {
|
|
1272
|
+
var state = store.get()
|
|
1273
|
+
var resolution = state.resolution
|
|
1274
|
+
if (!state.cwd || !resolution) return
|
|
1275
|
+
var result = await runBusy('takeSide', function () {
|
|
1276
|
+
return rpc('takeSide', { cwd: state.cwd, path: resolution.path, side: side })
|
|
1277
|
+
})
|
|
1278
|
+
if (result !== null) {
|
|
1279
|
+
set({ resolution: null, conflictHint: '' })
|
|
1280
|
+
var label = side === 'ours' ? tr('status.takeOursOk') : tr('status.takeTheirsOk')
|
|
1281
|
+
toast('ok', result.unmerged === 0 ? tr('status.resolveAllOk') : label, result.output)
|
|
1282
|
+
await refresh()
|
|
1283
|
+
}
|
|
1284
|
+
}
|
|
1285
|
+
|
|
984
1286
|
async function switchBranch(name) {
|
|
985
1287
|
var cwd = store.get().cwd
|
|
986
1288
|
if (!cwd || !name) return
|
|
@@ -1105,6 +1407,22 @@ window.__ModuleLoader__.load({
|
|
|
1105
1407
|
setNewBranch: setNewBranch,
|
|
1106
1408
|
setNewBranchName: setNewBranchName,
|
|
1107
1409
|
setNewBranchFrom: setNewBranchFrom,
|
|
1410
|
+
discard: discard,
|
|
1411
|
+
stashSave: stashSave,
|
|
1412
|
+
stashPop: stashPop,
|
|
1413
|
+
stashDrop: stashDrop,
|
|
1414
|
+
setStashMessage: setStashMessage,
|
|
1415
|
+
openPrompt: openPrompt,
|
|
1416
|
+
closePrompt: closePrompt,
|
|
1417
|
+
setPromptDraft: setPromptDraft,
|
|
1418
|
+
savePrompt: savePrompt,
|
|
1419
|
+
resetPrompt: resetPrompt,
|
|
1420
|
+
openResolution: openResolution,
|
|
1421
|
+
closeResolution: closeResolution,
|
|
1422
|
+
setConflictHint: setConflictHint,
|
|
1423
|
+
aiResolve: aiResolve,
|
|
1424
|
+
applyResolution: applyResolution,
|
|
1425
|
+
takeConflictSide: takeConflictSide,
|
|
1108
1426
|
clearToast: clearToast,
|
|
1109
1427
|
}
|
|
1110
1428
|
}
|
|
@@ -1162,16 +1480,41 @@ window.__ModuleLoader__.load({
|
|
|
1162
1480
|
h('span', { className: 'gm-fpath' },
|
|
1163
1481
|
parts.dir ? h('span', { className: 'gm-dir' }, parts.dir) : null,
|
|
1164
1482
|
parts.base),
|
|
1165
|
-
h('
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1483
|
+
h('span', { className: 'gm-row', style: { gap: '2px' } },
|
|
1484
|
+
// 冲突文件不给「暂存」:git add 会把带 <<<<<<< 的文件直接标记为已解决。
|
|
1485
|
+
// 唯一入口是「解决」,由 applyConflict / takeSide 负责清掉冲突标记。
|
|
1486
|
+
props.group === 'conflicted'
|
|
1487
|
+
? h('button', {
|
|
1488
|
+
type: 'button',
|
|
1489
|
+
className: 'gm-btn icon sm ghost gm-act',
|
|
1490
|
+
title: tr('conflict.resolve'),
|
|
1491
|
+
onClick: function (event) {
|
|
1492
|
+
event.stopPropagation()
|
|
1493
|
+
props.onResolve(entry)
|
|
1494
|
+
},
|
|
1495
|
+
}, h(Icon, { name: 'ai', size: 12 }))
|
|
1496
|
+
: h('button', {
|
|
1497
|
+
type: 'button',
|
|
1498
|
+
className: 'gm-btn icon sm ghost gm-act',
|
|
1499
|
+
title: staged ? tr('changes.unstage') : tr('changes.stage'),
|
|
1500
|
+
onClick: function (event) {
|
|
1501
|
+
event.stopPropagation()
|
|
1502
|
+
if (staged) props.onUnstage(entry)
|
|
1503
|
+
else props.onStage(entry)
|
|
1504
|
+
},
|
|
1505
|
+
}, h(Icon, { name: staged ? 'minus' : 'plus', size: 12 })),
|
|
1506
|
+
// 冲突文件不给「丢弃」:那等于放弃冲突解决状态,语义上容易误伤
|
|
1507
|
+
props.onDiscard && props.group !== 'conflicted'
|
|
1508
|
+
? h('button', {
|
|
1509
|
+
type: 'button',
|
|
1510
|
+
className: 'gm-btn icon sm ghost gm-act',
|
|
1511
|
+
title: props.group === 'untracked' ? tr('changes.discardUntracked') : tr('changes.discard'),
|
|
1512
|
+
onClick: function (event) {
|
|
1513
|
+
event.stopPropagation()
|
|
1514
|
+
props.onDiscard(entry)
|
|
1515
|
+
},
|
|
1516
|
+
}, h(Icon, { name: 'trash', size: 12 }))
|
|
1517
|
+
: null))
|
|
1175
1518
|
}))
|
|
1176
1519
|
}
|
|
1177
1520
|
|
|
@@ -1194,6 +1537,8 @@ window.__ModuleLoader__.load({
|
|
|
1194
1537
|
onSelect: function (entry) { props.actions.selectFile(group, entry) },
|
|
1195
1538
|
onStage: function (entry) { props.actions.stage(group, entry) },
|
|
1196
1539
|
onUnstage: function (entry) { props.actions.unstage(group, entry) },
|
|
1540
|
+
onDiscard: function (entry) { props.actions.discard(group, entry) },
|
|
1541
|
+
onResolve: function (entry) { props.actions.openResolution(entry) },
|
|
1197
1542
|
})
|
|
1198
1543
|
}
|
|
1199
1544
|
var empty = !conflicted.length && !staged.length && !unstaged.length && !untracked.length
|
|
@@ -1226,6 +1571,29 @@ window.__ModuleLoader__.load({
|
|
|
1226
1571
|
}
|
|
1227
1572
|
}
|
|
1228
1573
|
return h('div', { className: 'gm-commit' },
|
|
1574
|
+
state.promptOpen
|
|
1575
|
+
? h('div', { className: 'gm-prompt' },
|
|
1576
|
+
h('div', { className: 'gm-section' },
|
|
1577
|
+
h('span', null, tr('commit.promptTitle')),
|
|
1578
|
+
h('span', { className: 'gm-spacer' }),
|
|
1579
|
+
h('button', {
|
|
1580
|
+
type: 'button',
|
|
1581
|
+
className: 'gm-btn icon sm ghost',
|
|
1582
|
+
title: tr('commit.promptCancel'),
|
|
1583
|
+
onClick: props.onClosePrompt,
|
|
1584
|
+
}, h(Icon, { name: 'close', size: 12 }))),
|
|
1585
|
+
h('textarea', {
|
|
1586
|
+
className: 'gm-textarea gm-prompt-text',
|
|
1587
|
+
value: state.promptDraft,
|
|
1588
|
+
placeholder: tr('commit.promptHint'),
|
|
1589
|
+
onChange: function (event) { props.onPromptDraft(event.target.value) },
|
|
1590
|
+
}),
|
|
1591
|
+
h('div', { className: 'gm-hint' }, tr('commit.promptHint')),
|
|
1592
|
+
h('div', { className: 'gm-actions' },
|
|
1593
|
+
h(Btn, { label: tr('commit.promptReset'), small: true, ghost: true, disabled: !!busy, onClick: props.onResetPrompt }),
|
|
1594
|
+
h('span', { className: 'gm-spacer' }),
|
|
1595
|
+
h(Btn, { label: tr('commit.promptSave'), small: true, variant: 'primary', disabled: !!busy, onClick: props.onSavePrompt })))
|
|
1596
|
+
: null,
|
|
1229
1597
|
h('div', { className: 'gm-commit-head' },
|
|
1230
1598
|
h(WhaleGlyph, { size: 22 }),
|
|
1231
1599
|
h('span', { className: 'gm-commit-title' }, tr('commit.title')),
|
|
@@ -1254,8 +1622,17 @@ window.__ModuleLoader__.load({
|
|
|
1254
1622
|
className: busy === 'ai' ? 'gm-ai-busy' : undefined,
|
|
1255
1623
|
disabled: !!busy || !state.cwd,
|
|
1256
1624
|
onClick: props.onGenerate,
|
|
1625
|
+
}),
|
|
1626
|
+
h(Btn, {
|
|
1627
|
+
icon: 'gear',
|
|
1628
|
+
title: tr('commit.prompt'),
|
|
1629
|
+
disabled: !!busy || !state.cwd,
|
|
1630
|
+
onClick: props.onOpenPrompt,
|
|
1257
1631
|
})),
|
|
1258
1632
|
h('div', { className: 'gm-actions' },
|
|
1633
|
+
state.snapshot && state.snapshot.commitPrompt
|
|
1634
|
+
? h('span', { className: 'gm-badge brand', title: state.snapshot.commitPrompt }, tr('commit.promptCustom'))
|
|
1635
|
+
: null,
|
|
1259
1636
|
state.aiModel
|
|
1260
1637
|
? h('span', { className: 'gm-ai-line gm-hint', title: tr('status.aiModel', { model: state.aiModel }) },
|
|
1261
1638
|
state.aiFallback ? tr('status.aiFallback') : tr('status.aiModelEdit', { model: state.aiModel }))
|
|
@@ -1498,8 +1875,88 @@ window.__ModuleLoader__.load({
|
|
|
1498
1875
|
})
|
|
1499
1876
|
}
|
|
1500
1877
|
|
|
1878
|
+
/**
|
|
1879
|
+
* 冲突解决视图。
|
|
1880
|
+
* 生成阶段完全不碰磁盘,只有点「应用」才写文件 —— 模型给错了最多白看一次。
|
|
1881
|
+
*/
|
|
1882
|
+
function ResolutionView(props) {
|
|
1883
|
+
var state = props.state
|
|
1884
|
+
var resolution = state.resolution
|
|
1885
|
+
var busy = !!state.busy
|
|
1886
|
+
var suggested = resolution.suggested
|
|
1887
|
+
var lines = suggested ? suggested.replace(/\n$/, '').split('\n') : []
|
|
1888
|
+
var visible = lines.slice(0, 400)
|
|
1889
|
+
var actions = props.actions
|
|
1890
|
+
return h('div', { className: 'gm-scroll' },
|
|
1891
|
+
h('div', { className: 'gm-content-inner gm-resolution' },
|
|
1892
|
+
h('div', { className: 'gm-res-head' },
|
|
1893
|
+
h(Icon, { name: 'ai', size: 14 }),
|
|
1894
|
+
h('span', { className: 'gm-res-title' }, tr('conflict.title')),
|
|
1895
|
+
h('span', { className: 'gm-spacer' }),
|
|
1896
|
+
h('button', {
|
|
1897
|
+
type: 'button',
|
|
1898
|
+
className: 'gm-btn icon sm ghost',
|
|
1899
|
+
title: tr('conflict.discard'),
|
|
1900
|
+
onClick: function () { actions.closeResolution() },
|
|
1901
|
+
}, h(Icon, { name: 'close', size: 12 }))),
|
|
1902
|
+
h('div', { className: 'gm-res-path' }, resolution.path),
|
|
1903
|
+
resolution.loading
|
|
1904
|
+
? h('div', { className: 'gm-res-note' }, tr('conflict.generating'))
|
|
1905
|
+
: suggested
|
|
1906
|
+
? h('div', { className: 'gm-res-note' },
|
|
1907
|
+
tr('conflict.preview'),
|
|
1908
|
+
resolution.model ? ' · ' + tr('conflict.model', { model: resolution.model }) : '')
|
|
1909
|
+
: h('div', { className: 'gm-res-note' }, tr('conflict.empty')),
|
|
1910
|
+
h('input', {
|
|
1911
|
+
className: 'gm-input',
|
|
1912
|
+
value: state.conflictHint,
|
|
1913
|
+
placeholder: tr('conflict.hintPlaceholder'),
|
|
1914
|
+
disabled: busy,
|
|
1915
|
+
onChange: function (event) { actions.setConflictHint(event.target.value) },
|
|
1916
|
+
onKeyDown: function (event) { if (event.key === 'Enter') actions.aiResolve() },
|
|
1917
|
+
}),
|
|
1918
|
+
h('div', { className: 'gm-actions' },
|
|
1919
|
+
h(Btn, {
|
|
1920
|
+
icon: 'ai',
|
|
1921
|
+
label: suggested ? tr('conflict.regenerate') : tr('conflict.ai'),
|
|
1922
|
+
small: true,
|
|
1923
|
+
variant: 'primary',
|
|
1924
|
+
disabled: busy || resolution.loading,
|
|
1925
|
+
onClick: actions.aiResolve,
|
|
1926
|
+
}),
|
|
1927
|
+
h(Btn, {
|
|
1928
|
+
label: tr('conflict.takeOurs'),
|
|
1929
|
+
small: true,
|
|
1930
|
+
disabled: busy || resolution.loading,
|
|
1931
|
+
onClick: function () { actions.takeConflictSide('ours') },
|
|
1932
|
+
}),
|
|
1933
|
+
h(Btn, {
|
|
1934
|
+
label: tr('conflict.takeTheirs'),
|
|
1935
|
+
small: true,
|
|
1936
|
+
disabled: busy || resolution.loading,
|
|
1937
|
+
onClick: function () { actions.takeConflictSide('theirs') },
|
|
1938
|
+
})),
|
|
1939
|
+
suggested
|
|
1940
|
+
? h('div', { className: 'gm-actions' },
|
|
1941
|
+
h(Btn, { label: tr('conflict.apply'), small: true, variant: 'primary', disabled: busy, onClick: actions.applyResolution }),
|
|
1942
|
+
h(Btn, { label: tr('conflict.discard'), small: true, ghost: true, disabled: busy, onClick: function () { actions.closeResolution() } }))
|
|
1943
|
+
: null,
|
|
1944
|
+
suggested
|
|
1945
|
+
? h('div', { className: 'gm-res-code' }, visible.map(function (line, index) {
|
|
1946
|
+
return h('div', { key: 'rl:' + index, className: 'gm-res-line' },
|
|
1947
|
+
h('span', { className: 'no' }, String(index + 1)),
|
|
1948
|
+
h('span', { className: 'tx' }, line === '' ? ' ' : line))
|
|
1949
|
+
}))
|
|
1950
|
+
: null,
|
|
1951
|
+
suggested && lines.length > visible.length
|
|
1952
|
+
? h('div', { className: 'gm-res-note' }, tr('diff.truncated'))
|
|
1953
|
+
: null))
|
|
1954
|
+
}
|
|
1955
|
+
|
|
1501
1956
|
function DiffView(props) {
|
|
1502
1957
|
var state = props.state
|
|
1958
|
+
// 解决视图优先:它是「差异」页的一个特殊态,不额外占一个 tab。
|
|
1959
|
+
if (state.resolution) return h(ResolutionView, { state: state, actions: props.actions })
|
|
1503
1960
|
var diff = state.diff
|
|
1504
1961
|
if (state.diffLoading) return h(EmptyState, { spinner: true, title: tr('status.loading') })
|
|
1505
1962
|
if (!diff) return h(EmptyState, { title: tr('diff.empty') })
|
|
@@ -1539,6 +1996,7 @@ window.__ModuleLoader__.load({
|
|
|
1539
1996
|
var branches = state.snapshot && state.snapshot.branches ? state.snapshot.branches : []
|
|
1540
1997
|
var locals = branches.filter(function (branch) { return branch.kind === 'local' })
|
|
1541
1998
|
var remotes = branches.filter(function (branch) { return branch.kind === 'remote' })
|
|
1999
|
+
var stashes = state.snapshot && state.snapshot.stashes ? state.snapshot.stashes : []
|
|
1542
2000
|
function group(title, items, allowDelete) {
|
|
1543
2001
|
if (items.length === 0) return null
|
|
1544
2002
|
return h('div', null,
|
|
@@ -1564,13 +2022,42 @@ window.__ModuleLoader__.load({
|
|
|
1564
2022
|
: null))
|
|
1565
2023
|
}))
|
|
1566
2024
|
}
|
|
2025
|
+
// stash 放在分支页:它和分支一样是「当前工作放哪儿」的操作,
|
|
2026
|
+
// 而不是某次提交的内容。后端 snapshot 早就解析了 stashes,这里才真正用上。
|
|
2027
|
+
function stashSection() {
|
|
2028
|
+
return h('div', null,
|
|
2029
|
+
h('div', { className: 'gm-section' },
|
|
2030
|
+
h('span', null, tr('stash.title')),
|
|
2031
|
+
h('span', { className: 'gm-section-count' }, String(stashes.length))),
|
|
2032
|
+
h('div', { className: 'gm-row', style: { padding: '0 10px 6px' } },
|
|
2033
|
+
h('input', {
|
|
2034
|
+
className: 'gm-input',
|
|
2035
|
+
value: state.stashMessage,
|
|
2036
|
+
placeholder: tr('stash.placeholder'),
|
|
2037
|
+
onChange: function (event) { props.onStashMessage(event.target.value) },
|
|
2038
|
+
onKeyDown: function (event) { if (event.key === 'Enter') props.onStashSave() },
|
|
2039
|
+
}),
|
|
2040
|
+
h(Btn, { label: tr('stash.save'), small: true, disabled: !!state.busy, onClick: props.onStashSave })),
|
|
2041
|
+
stashes.length === 0
|
|
2042
|
+
? h('div', { className: 'gm-hint', style: { padding: '0 12px 8px' } }, tr('stash.empty'))
|
|
2043
|
+
: stashes.map(function (item) {
|
|
2044
|
+
return h('div', { key: 'stash:' + item.index, className: 'gm-branch' },
|
|
2045
|
+
h(Icon, { name: 'stash', size: 12 }),
|
|
2046
|
+
h('span', { className: 'gm-badge' }, 'stash@{' + item.index + '}'),
|
|
2047
|
+
h('span', { className: 'gm-bmeta' }, item.message || ''),
|
|
2048
|
+
h('span', { className: 'gm-row gm-act', style: { gap: '4px', flex: 'none' } },
|
|
2049
|
+
h(Btn, { label: tr('stash.pop'), small: true, disabled: !!state.busy, onClick: function () { props.onStashPop(item.index) } }),
|
|
2050
|
+
h(Btn, { label: tr('stash.drop'), small: true, ghost: true, disabled: !!state.busy, onClick: function () { props.onStashDrop(item.index) } })))
|
|
2051
|
+
}))
|
|
2052
|
+
}
|
|
1567
2053
|
return h('div', { className: 'gm-scroll' },
|
|
1568
2054
|
h('div', { className: 'gm-content-inner' },
|
|
1569
2055
|
group(tr('branch.local'), locals, true),
|
|
1570
2056
|
group(tr('branch.remote'), remotes, false),
|
|
1571
2057
|
locals.length === 0 && remotes.length === 0
|
|
1572
2058
|
? h(EmptyState, { title: tr('branch.empty') })
|
|
1573
|
-
: null
|
|
2059
|
+
: null,
|
|
2060
|
+
stashSection()))
|
|
1574
2061
|
}
|
|
1575
2062
|
|
|
1576
2063
|
function StatusBar(props) {
|
|
@@ -1629,8 +2116,16 @@ window.__ModuleLoader__.load({
|
|
|
1629
2116
|
var content
|
|
1630
2117
|
if (state.activeTab === 'changes') content = h(ChangesPane, { state: state, actions: props.actions })
|
|
1631
2118
|
else if (state.activeTab === 'graph') content = h(GraphView, { state: state, onSelectCommit: props.actions.selectCommit })
|
|
1632
|
-
else if (state.activeTab === 'branches') content = h(BranchesView, {
|
|
1633
|
-
|
|
2119
|
+
else if (state.activeTab === 'branches') content = h(BranchesView, {
|
|
2120
|
+
state: state,
|
|
2121
|
+
onSwitch: props.actions.switchBranch,
|
|
2122
|
+
onDelete: props.actions.deleteBranch,
|
|
2123
|
+
onStashSave: props.actions.stashSave,
|
|
2124
|
+
onStashPop: props.actions.stashPop,
|
|
2125
|
+
onStashDrop: props.actions.stashDrop,
|
|
2126
|
+
onStashMessage: props.actions.setStashMessage,
|
|
2127
|
+
})
|
|
2128
|
+
else content = h(DiffView, { state: state, actions: props.actions })
|
|
1634
2129
|
return h('div', { className: 'gm-root' },
|
|
1635
2130
|
panelStyle(),
|
|
1636
2131
|
h(CompactTopBar, {
|
|
@@ -1665,6 +2160,11 @@ window.__ModuleLoader__.load({
|
|
|
1665
2160
|
onHint: props.actions.setAiHint,
|
|
1666
2161
|
onGenerate: props.actions.generateMessage,
|
|
1667
2162
|
onCommit: function (andPush) { props.actions.commit(andPush) },
|
|
2163
|
+
onOpenPrompt: props.actions.openPrompt,
|
|
2164
|
+
onClosePrompt: props.actions.closePrompt,
|
|
2165
|
+
onPromptDraft: props.actions.setPromptDraft,
|
|
2166
|
+
onSavePrompt: props.actions.savePrompt,
|
|
2167
|
+
onResetPrompt: props.actions.resetPrompt,
|
|
1668
2168
|
})
|
|
1669
2169
|
: null)
|
|
1670
2170
|
}
|