@co0ontty/wand 1.41.4 → 1.43.0
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/dist/build-info.json +3 -3
- package/dist/server.js +40 -18
- package/dist/update-helper.d.ts +18 -0
- package/dist/update-helper.js +238 -0
- package/dist/web-ui/content/scripts.js +331 -446
- package/dist/web-ui/content/styles.css +202 -180
- package/dist/web-ui/embedded-assets.d.ts +1 -1
- package/dist/web-ui/embedded-assets.js +3 -3
- package/package.json +1 -1
|
@@ -284,19 +284,11 @@
|
|
|
284
284
|
quickCommitSubmitting: false,
|
|
285
285
|
quickCommitGenerating: false,
|
|
286
286
|
quickCommitError: "",
|
|
287
|
-
|
|
288
|
-
// Pushing is a separate, standalone action — never bundled into the commit button.
|
|
289
|
-
quickCommitForm: { customMessage: "", tag: "", tagEdited: false, commitMode: "commit-tag" },
|
|
290
|
-
// Which inline panel/dropdown is open. Only one can be open at a time, so a
|
|
291
|
-
// single field beats juggling three sibling booleans with mutual-exclusion code.
|
|
292
|
-
// Values: null | "action" | "push" | "tag-head".
|
|
293
|
-
quickCommitOpenMenu: null,
|
|
294
|
-
quickCommitTagHeadForm: { tag: "", push: false },
|
|
295
|
-
quickCommitTagHeadSubmitting: false,
|
|
296
|
-
quickCommitTagHeadGenerating: false,
|
|
297
|
-
quickCommitTagHeadError: "",
|
|
287
|
+
quickCommitForm: { customMessage: "", tag: "", tagEdited: false },
|
|
298
288
|
quickCommitPushing: false,
|
|
299
289
|
quickCommitPushError: "",
|
|
290
|
+
quickCommitResult: null,
|
|
291
|
+
quickCommitDragAction: "commit",
|
|
300
292
|
// Telegram 风格的"贴底"状态:true = 用户当前贴在底部,新消息会自然出现;
|
|
301
293
|
// false = 用户向上滚了,未读会累积到气泡里,不会自动滚他们的视图。
|
|
302
294
|
chatStickToBottom: true,
|
|
@@ -2249,19 +2241,50 @@
|
|
|
2249
2241
|
}
|
|
2250
2242
|
|
|
2251
2243
|
var quickCommitEscHandler = null;
|
|
2252
|
-
var
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2244
|
+
var quickCommitDragCleanup = null;
|
|
2245
|
+
var quickCommitDragState = null;
|
|
2246
|
+
|
|
2247
|
+
function normalizeQuickCommitAction(value) {
|
|
2248
|
+
if (value === "commit-tag" || value === "commit-tag-push") return value;
|
|
2249
|
+
return "commit";
|
|
2250
|
+
}
|
|
2251
|
+
|
|
2252
|
+
function getQuickCommitActionMeta(action) {
|
|
2253
|
+
action = normalizeQuickCommitAction(action);
|
|
2254
|
+
if (action === "commit-tag-push") {
|
|
2255
|
+
return {
|
|
2256
|
+
action: action,
|
|
2257
|
+
label: "Commit + Tag + Push",
|
|
2258
|
+
verb: "提交、打 Tag 并推送",
|
|
2259
|
+
withTag: true,
|
|
2260
|
+
push: true,
|
|
2261
|
+
tone: "push",
|
|
2262
|
+
};
|
|
2263
|
+
}
|
|
2264
|
+
if (action === "commit-tag") {
|
|
2265
|
+
return {
|
|
2266
|
+
action: action,
|
|
2267
|
+
label: "Commit + Tag",
|
|
2268
|
+
verb: "提交并打 Tag",
|
|
2269
|
+
withTag: true,
|
|
2270
|
+
push: false,
|
|
2271
|
+
tone: "tag",
|
|
2272
|
+
};
|
|
2273
|
+
}
|
|
2274
|
+
return {
|
|
2275
|
+
action: "commit",
|
|
2276
|
+
label: "Commit",
|
|
2277
|
+
verb: "仅提交",
|
|
2278
|
+
withTag: false,
|
|
2279
|
+
push: false,
|
|
2280
|
+
tone: "commit",
|
|
2281
|
+
};
|
|
2262
2282
|
}
|
|
2263
|
-
|
|
2264
|
-
|
|
2283
|
+
|
|
2284
|
+
function getQuickCommitActionFromRatio(ratio) {
|
|
2285
|
+
if (ratio >= 0.74) return "commit-tag-push";
|
|
2286
|
+
if (ratio >= 0.38) return "commit-tag";
|
|
2287
|
+
return "commit";
|
|
2265
2288
|
}
|
|
2266
2289
|
|
|
2267
2290
|
function openQuickCommitModal() {
|
|
@@ -2274,16 +2297,11 @@
|
|
|
2274
2297
|
tag: "",
|
|
2275
2298
|
// Whether the user has manually edited the tag (so we stop auto-overwriting it).
|
|
2276
2299
|
tagEdited: false,
|
|
2277
|
-
// "commit-tag" → commit + version tag; "commit" → commit only.
|
|
2278
|
-
commitMode: readSavedCommitMode(),
|
|
2279
2300
|
};
|
|
2280
|
-
state.quickCommitOpenMenu = null;
|
|
2281
|
-
state.quickCommitTagHeadForm = { tag: "", push: false };
|
|
2282
|
-
state.quickCommitTagHeadSubmitting = false;
|
|
2283
|
-
state.quickCommitTagHeadGenerating = false;
|
|
2284
|
-
state.quickCommitTagHeadError = "";
|
|
2285
2301
|
state.quickCommitPushing = false;
|
|
2286
2302
|
state.quickCommitPushError = "";
|
|
2303
|
+
state.quickCommitResult = null;
|
|
2304
|
+
state.quickCommitDragAction = "commit";
|
|
2287
2305
|
closeWorktreeMergeModal();
|
|
2288
2306
|
closeSessionModal();
|
|
2289
2307
|
closeSettingsModal();
|
|
@@ -2296,33 +2314,11 @@
|
|
|
2296
2314
|
}
|
|
2297
2315
|
if (quickCommitEscHandler) document.removeEventListener("keydown", quickCommitEscHandler);
|
|
2298
2316
|
quickCommitEscHandler = function(e) {
|
|
2299
|
-
if (e.key === "Escape" && state.quickCommitOpen && !state.quickCommitSubmitting && !state.
|
|
2300
|
-
// First Esc closes any open dropdown; second closes the modal.
|
|
2301
|
-
if (state.quickCommitOpenMenu) {
|
|
2302
|
-
state.quickCommitOpenMenu = null;
|
|
2303
|
-
rerenderQuickCommitModal();
|
|
2304
|
-
return;
|
|
2305
|
-
}
|
|
2317
|
+
if (e.key === "Escape" && state.quickCommitOpen && !state.quickCommitSubmitting && !state.quickCommitPushing) {
|
|
2306
2318
|
closeQuickCommitModal();
|
|
2307
2319
|
}
|
|
2308
2320
|
};
|
|
2309
2321
|
document.addEventListener("keydown", quickCommitEscHandler);
|
|
2310
|
-
if (quickCommitDocClickHandler) document.removeEventListener("click", quickCommitDocClickHandler, true);
|
|
2311
|
-
quickCommitDocClickHandler = function(e) {
|
|
2312
|
-
if (!state.quickCommitOpen) return;
|
|
2313
|
-
// tag-head is an inline drawer, not a dropdown — clicking outside shouldn't close it.
|
|
2314
|
-
if (state.quickCommitOpenMenu !== "action" && state.quickCommitOpenMenu !== "push") return;
|
|
2315
|
-
var modalEl = document.getElementById("quick-commit-modal");
|
|
2316
|
-
if (!modalEl) return;
|
|
2317
|
-
var t = e.target;
|
|
2318
|
-
while (t && t !== modalEl) {
|
|
2319
|
-
if (t.dataset && (t.dataset.qcDropdownToggle || t.dataset.qcDropdownMenu)) return;
|
|
2320
|
-
t = t.parentNode;
|
|
2321
|
-
}
|
|
2322
|
-
state.quickCommitOpenMenu = null;
|
|
2323
|
-
rerenderQuickCommitModal();
|
|
2324
|
-
};
|
|
2325
|
-
document.addEventListener("click", quickCommitDocClickHandler, true);
|
|
2326
2322
|
loadGitStatus(state.selectedId, { force: true }).then(function() {
|
|
2327
2323
|
if (!state.quickCommitOpen) return;
|
|
2328
2324
|
// Seed the tag field with the locally-derived suggestion so a tag is
|
|
@@ -2339,7 +2335,8 @@
|
|
|
2339
2335
|
state.quickCommitOpen = false;
|
|
2340
2336
|
state.quickCommitSubmitting = false;
|
|
2341
2337
|
state.quickCommitError = "";
|
|
2342
|
-
state.
|
|
2338
|
+
state.quickCommitResult = null;
|
|
2339
|
+
state.quickCommitDragAction = "commit";
|
|
2343
2340
|
var modal = document.getElementById("quick-commit-modal");
|
|
2344
2341
|
if (modal) modal.classList.add("hidden");
|
|
2345
2342
|
if (focusTrapHandler) {
|
|
@@ -2350,9 +2347,9 @@
|
|
|
2350
2347
|
document.removeEventListener("keydown", quickCommitEscHandler);
|
|
2351
2348
|
quickCommitEscHandler = null;
|
|
2352
2349
|
}
|
|
2353
|
-
if (
|
|
2354
|
-
|
|
2355
|
-
|
|
2350
|
+
if (quickCommitDragCleanup) {
|
|
2351
|
+
quickCommitDragCleanup();
|
|
2352
|
+
quickCommitDragCleanup = null;
|
|
2356
2353
|
}
|
|
2357
2354
|
if (lastFocusedElement && typeof lastFocusedElement.focus === "function") {
|
|
2358
2355
|
lastFocusedElement.focus();
|
|
@@ -2362,6 +2359,10 @@
|
|
|
2362
2359
|
function rerenderQuickCommitModal() {
|
|
2363
2360
|
var modal = document.getElementById("quick-commit-modal");
|
|
2364
2361
|
if (!modal) return;
|
|
2362
|
+
if (quickCommitDragCleanup) {
|
|
2363
|
+
quickCommitDragCleanup();
|
|
2364
|
+
quickCommitDragCleanup = null;
|
|
2365
|
+
}
|
|
2365
2366
|
var html = renderQuickCommitModal();
|
|
2366
2367
|
var temp = document.createElement("div");
|
|
2367
2368
|
temp.innerHTML = html;
|
|
@@ -2377,8 +2378,6 @@
|
|
|
2377
2378
|
var cancelBtn = document.getElementById("quick-commit-cancel-btn");
|
|
2378
2379
|
if (cancelBtn) cancelBtn.addEventListener("click", closeQuickCommitModal);
|
|
2379
2380
|
|
|
2380
|
-
var submitBtn = document.getElementById("quick-commit-submit-btn");
|
|
2381
|
-
if (submitBtn) submitBtn.addEventListener("click", submitQuickCommit);
|
|
2382
2381
|
var aiBtn = document.getElementById("quick-commit-ai-btn");
|
|
2383
2382
|
if (aiBtn) aiBtn.addEventListener("click", generateCommitMessageAI);
|
|
2384
2383
|
var msgEl = document.getElementById("quick-commit-message");
|
|
@@ -2390,7 +2389,7 @@
|
|
|
2390
2389
|
msgEl.addEventListener("keydown", function(e) {
|
|
2391
2390
|
if ((e.metaKey || e.ctrlKey) && e.key === "Enter") {
|
|
2392
2391
|
e.preventDefault();
|
|
2393
|
-
submitQuickCommit();
|
|
2392
|
+
submitQuickCommit("commit");
|
|
2394
2393
|
}
|
|
2395
2394
|
});
|
|
2396
2395
|
}
|
|
@@ -2403,114 +2402,136 @@
|
|
|
2403
2402
|
tagInput.addEventListener("keydown", function(e) {
|
|
2404
2403
|
if (e.key === "Enter") {
|
|
2405
2404
|
e.preventDefault();
|
|
2406
|
-
submitQuickCommit();
|
|
2405
|
+
submitQuickCommit("commit-tag");
|
|
2407
2406
|
}
|
|
2408
2407
|
});
|
|
2409
2408
|
}
|
|
2410
2409
|
|
|
2411
|
-
var
|
|
2412
|
-
if (
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
rerenderQuickCommitModal();
|
|
2410
|
+
var pushAfterBtn = document.getElementById("quick-commit-push-after-btn");
|
|
2411
|
+
if (pushAfterBtn) pushAfterBtn.addEventListener("click", function() {
|
|
2412
|
+
var result = state.quickCommitResult || {};
|
|
2413
|
+
submitPushOnly({ pushCommits: true, pushTags: !!result.tagName, closeOnSuccess: true });
|
|
2416
2414
|
});
|
|
2417
|
-
var actionMenu = document.getElementById("quick-commit-action-menu");
|
|
2418
|
-
if (actionMenu) {
|
|
2419
|
-
var actionItems = actionMenu.querySelectorAll("[data-qc-commit-mode]");
|
|
2420
|
-
for (var i = 0; i < actionItems.length; i++) {
|
|
2421
|
-
(function(btn) {
|
|
2422
|
-
btn.addEventListener("click", function() {
|
|
2423
|
-
// Keep what the user typed before the re-render.
|
|
2424
|
-
var liveTag = document.getElementById("quick-commit-tag");
|
|
2425
|
-
if (liveTag && !liveTag.disabled) state.quickCommitForm.tag = liveTag.value;
|
|
2426
|
-
var value = btn.getAttribute("data-qc-commit-mode");
|
|
2427
|
-
if (value === "commit" || value === "commit-tag") {
|
|
2428
|
-
state.quickCommitForm.commitMode = value;
|
|
2429
|
-
saveCommitMode(value);
|
|
2430
|
-
}
|
|
2431
|
-
state.quickCommitOpenMenu = null;
|
|
2432
|
-
rerenderQuickCommitModal();
|
|
2433
|
-
if (value === "commit-tag") {
|
|
2434
|
-
var inp = document.getElementById("quick-commit-tag");
|
|
2435
|
-
if (inp) setTimeout(function() { inp.focus(); var v = inp.value; inp.value = ""; inp.value = v; }, 0);
|
|
2436
|
-
}
|
|
2437
|
-
});
|
|
2438
|
-
})(actionItems[i]);
|
|
2439
|
-
}
|
|
2440
|
-
}
|
|
2441
2415
|
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2416
|
+
attachQuickCommitDrag();
|
|
2417
|
+
}
|
|
2418
|
+
|
|
2419
|
+
function updateQuickCommitDragVisual(action, ratio) {
|
|
2420
|
+
action = normalizeQuickCommitAction(action);
|
|
2421
|
+
state.quickCommitDragAction = action;
|
|
2422
|
+
var track = document.getElementById("quick-commit-drag-track");
|
|
2423
|
+
if (!track) return;
|
|
2424
|
+
var meta = getQuickCommitActionMeta(action);
|
|
2425
|
+
var progress = typeof ratio === "number"
|
|
2426
|
+
? Math.max(0, Math.min(1, ratio))
|
|
2427
|
+
: (action === "commit-tag-push" ? 1 : (action === "commit-tag" ? 0.5 : 0));
|
|
2428
|
+
track.setAttribute("data-action", action);
|
|
2429
|
+
track.style.setProperty("--qc-progress", (progress * 100).toFixed(1) + "%");
|
|
2430
|
+
var knob = document.getElementById("quick-commit-drag-action");
|
|
2431
|
+
if (knob) {
|
|
2432
|
+
var maxX = Math.max(0, track.clientWidth - knob.offsetWidth - 14);
|
|
2433
|
+
track.style.setProperty("--qc-knob-x", (maxX * progress).toFixed(1) + "px");
|
|
2434
|
+
}
|
|
2435
|
+
var label = document.getElementById("quick-commit-drag-label");
|
|
2436
|
+
if (label) label.textContent = state.quickCommitSubmitting ? "执行中..." : meta.label;
|
|
2437
|
+
var stages = track.querySelectorAll("[data-qc-stage]");
|
|
2438
|
+
var order = { "commit": 0, "commit-tag": 1, "commit-tag-push": 2 };
|
|
2439
|
+
for (var i = 0; i < stages.length; i++) {
|
|
2440
|
+
var stageAction = stages[i].getAttribute("data-qc-stage");
|
|
2441
|
+
var passed = order[stageAction] <= order[action];
|
|
2442
|
+
stages[i].classList.toggle("is-active", stageAction === action);
|
|
2443
|
+
stages[i].classList.toggle("is-passed", passed);
|
|
2444
|
+
}
|
|
2445
|
+
}
|
|
2446
|
+
|
|
2447
|
+
function attachQuickCommitDrag() {
|
|
2448
|
+
var track = document.getElementById("quick-commit-drag-track");
|
|
2449
|
+
var knob = document.getElementById("quick-commit-drag-action");
|
|
2450
|
+
if (!track || !knob) return;
|
|
2451
|
+
updateQuickCommitDragVisual(state.quickCommitDragAction || "commit");
|
|
2452
|
+
|
|
2453
|
+
var onPointerDown = function(e) {
|
|
2454
|
+
if (knob.disabled || isQuickCommitOpInFlight()) return;
|
|
2455
|
+
var rect = track.getBoundingClientRect();
|
|
2456
|
+
quickCommitDragState = {
|
|
2457
|
+
pointerId: e.pointerId,
|
|
2458
|
+
rect: rect,
|
|
2459
|
+
moved: false,
|
|
2460
|
+
action: "commit",
|
|
2461
|
+
};
|
|
2462
|
+
knob.setPointerCapture(e.pointerId);
|
|
2463
|
+
track.classList.add("is-dragging");
|
|
2464
|
+
updateQuickCommitDragVisual("commit", 0);
|
|
2465
|
+
e.preventDefault();
|
|
2466
|
+
};
|
|
2467
|
+
var onPointerMove = function(e) {
|
|
2468
|
+
if (!quickCommitDragState || quickCommitDragState.pointerId !== e.pointerId) return;
|
|
2469
|
+
var rect = quickCommitDragState.rect;
|
|
2470
|
+
var ratio = rect.width > 0 ? (e.clientX - rect.left) / rect.width : 0;
|
|
2471
|
+
ratio = Math.max(0, Math.min(1, ratio));
|
|
2472
|
+
if (Math.abs(e.clientX - rect.left) > 6) quickCommitDragState.moved = true;
|
|
2473
|
+
var action = getQuickCommitActionFromRatio(ratio);
|
|
2474
|
+
quickCommitDragState.action = action;
|
|
2475
|
+
updateQuickCommitDragVisual(action, ratio);
|
|
2476
|
+
};
|
|
2477
|
+
var finish = function(e, cancelled) {
|
|
2478
|
+
if (!quickCommitDragState) return;
|
|
2479
|
+
var current = quickCommitDragState;
|
|
2480
|
+
quickCommitDragState = null;
|
|
2481
|
+
track.classList.remove("is-dragging");
|
|
2482
|
+
try {
|
|
2483
|
+
if (typeof knob.releasePointerCapture === "function") knob.releasePointerCapture(current.pointerId);
|
|
2484
|
+
} catch (err) { /* ignored */ }
|
|
2485
|
+
if (cancelled) {
|
|
2486
|
+
updateQuickCommitDragVisual("commit");
|
|
2487
|
+
return;
|
|
2453
2488
|
}
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2489
|
+
var action = current.moved ? current.action : "commit";
|
|
2490
|
+
updateQuickCommitDragVisual(action);
|
|
2491
|
+
submitQuickCommit(action);
|
|
2492
|
+
if (e && typeof e.preventDefault === "function") e.preventDefault();
|
|
2493
|
+
};
|
|
2494
|
+
var onPointerUp = function(e) {
|
|
2495
|
+
if (!quickCommitDragState || quickCommitDragState.pointerId !== e.pointerId) return;
|
|
2496
|
+
finish(e, false);
|
|
2497
|
+
};
|
|
2498
|
+
var onPointerCancel = function(e) {
|
|
2499
|
+
if (!quickCommitDragState || quickCommitDragState.pointerId !== e.pointerId) return;
|
|
2500
|
+
finish(e, true);
|
|
2501
|
+
};
|
|
2502
|
+
var onKeyDown = function(e) {
|
|
2503
|
+
if (knob.disabled || isQuickCommitOpInFlight()) return;
|
|
2504
|
+
if (e.key === "ArrowRight") {
|
|
2505
|
+
e.preventDefault();
|
|
2506
|
+
var next = state.quickCommitDragAction === "commit"
|
|
2507
|
+
? "commit-tag"
|
|
2508
|
+
: (state.quickCommitDragAction === "commit-tag" ? "commit-tag-push" : "commit-tag-push");
|
|
2509
|
+
updateQuickCommitDragVisual(next);
|
|
2510
|
+
} else if (e.key === "ArrowLeft") {
|
|
2511
|
+
e.preventDefault();
|
|
2512
|
+
var prev = state.quickCommitDragAction === "commit-tag-push"
|
|
2513
|
+
? "commit-tag"
|
|
2514
|
+
: (state.quickCommitDragAction === "commit-tag" ? "commit" : "commit");
|
|
2515
|
+
updateQuickCommitDragVisual(prev);
|
|
2516
|
+
} else if (e.key === "Enter" || e.key === " ") {
|
|
2517
|
+
e.preventDefault();
|
|
2518
|
+
submitQuickCommit(state.quickCommitDragAction || "commit");
|
|
2458
2519
|
}
|
|
2459
|
-
}
|
|
2460
|
-
var tagHeadCancel = document.getElementById("quick-commit-tag-head-cancel");
|
|
2461
|
-
if (tagHeadCancel) tagHeadCancel.addEventListener("click", function() {
|
|
2462
|
-
if (state.quickCommitOpenMenu === "tag-head") state.quickCommitOpenMenu = null;
|
|
2463
|
-
state.quickCommitTagHeadError = "";
|
|
2464
|
-
rerenderQuickCommitModal();
|
|
2465
|
-
});
|
|
2466
|
-
var tagHeadInput = document.getElementById("quick-commit-tag-head-input");
|
|
2467
|
-
if (tagHeadInput) {
|
|
2468
|
-
tagHeadInput.addEventListener("input", function() {
|
|
2469
|
-
state.quickCommitTagHeadForm.tag = tagHeadInput.value;
|
|
2470
|
-
});
|
|
2471
|
-
tagHeadInput.addEventListener("keydown", function(e) {
|
|
2472
|
-
if (e.key === "Enter") {
|
|
2473
|
-
e.preventDefault();
|
|
2474
|
-
submitTagHead(false);
|
|
2475
|
-
}
|
|
2476
|
-
});
|
|
2477
|
-
}
|
|
2478
|
-
var tagHeadAi = document.getElementById("quick-commit-tag-head-ai");
|
|
2479
|
-
if (tagHeadAi) tagHeadAi.addEventListener("click", generateTagHeadAI);
|
|
2480
|
-
var tagHeadPushCb = document.getElementById("quick-commit-tag-head-push");
|
|
2481
|
-
if (tagHeadPushCb) tagHeadPushCb.addEventListener("change", function() {
|
|
2482
|
-
state.quickCommitTagHeadForm.push = tagHeadPushCb.checked;
|
|
2483
|
-
});
|
|
2484
|
-
var tagHeadSubmit = document.getElementById("quick-commit-tag-head-submit");
|
|
2485
|
-
if (tagHeadSubmit) tagHeadSubmit.addEventListener("click", function() {
|
|
2486
|
-
submitTagHead(false);
|
|
2487
|
-
});
|
|
2520
|
+
};
|
|
2488
2521
|
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
for (var j = 0; j < pushItems.length; j++) {
|
|
2503
|
-
(function(btn) {
|
|
2504
|
-
btn.addEventListener("click", function() {
|
|
2505
|
-
var value = btn.getAttribute("data-qc-push");
|
|
2506
|
-
state.quickCommitOpenMenu = null;
|
|
2507
|
-
if (value === "commits") submitPushOnly({ pushCommits: true, pushTags: false });
|
|
2508
|
-
else if (value === "tags") submitPushOnly({ pushCommits: false, pushTags: true });
|
|
2509
|
-
else if (value === "both") submitPushOnly({ pushCommits: true, pushTags: true });
|
|
2510
|
-
});
|
|
2511
|
-
})(pushItems[j]);
|
|
2512
|
-
}
|
|
2513
|
-
}
|
|
2522
|
+
knob.addEventListener("pointerdown", onPointerDown);
|
|
2523
|
+
knob.addEventListener("pointermove", onPointerMove);
|
|
2524
|
+
knob.addEventListener("pointerup", onPointerUp);
|
|
2525
|
+
knob.addEventListener("pointercancel", onPointerCancel);
|
|
2526
|
+
knob.addEventListener("keydown", onKeyDown);
|
|
2527
|
+
quickCommitDragCleanup = function() {
|
|
2528
|
+
knob.removeEventListener("pointerdown", onPointerDown);
|
|
2529
|
+
knob.removeEventListener("pointermove", onPointerMove);
|
|
2530
|
+
knob.removeEventListener("pointerup", onPointerUp);
|
|
2531
|
+
knob.removeEventListener("pointercancel", onPointerCancel);
|
|
2532
|
+
knob.removeEventListener("keydown", onKeyDown);
|
|
2533
|
+
quickCommitDragState = null;
|
|
2534
|
+
};
|
|
2514
2535
|
}
|
|
2515
2536
|
|
|
2516
2537
|
function generateCommitMessageAI() {
|
|
@@ -2548,8 +2569,7 @@
|
|
|
2548
2569
|
// recommendation is actually applied on commit.
|
|
2549
2570
|
if (aiTag) {
|
|
2550
2571
|
if (!state.quickCommitForm.tagEdited) state.quickCommitForm.tag = aiTag;
|
|
2551
|
-
state.
|
|
2552
|
-
saveCommitMode("commit-tag");
|
|
2572
|
+
state.quickCommitDragAction = "commit-tag";
|
|
2553
2573
|
}
|
|
2554
2574
|
})
|
|
2555
2575
|
.catch(function(error) {
|
|
@@ -2561,14 +2581,15 @@
|
|
|
2561
2581
|
});
|
|
2562
2582
|
}
|
|
2563
2583
|
|
|
2564
|
-
function submitQuickCommit() {
|
|
2584
|
+
function submitQuickCommit(action) {
|
|
2565
2585
|
if (!state.selectedId || state.quickCommitSubmitting) return;
|
|
2566
2586
|
var msgEl = document.getElementById("quick-commit-message");
|
|
2567
2587
|
if (msgEl) state.quickCommitForm.customMessage = msgEl.value;
|
|
2568
2588
|
var tagEl = document.getElementById("quick-commit-tag");
|
|
2569
2589
|
if (tagEl) state.quickCommitForm.tag = tagEl.value;
|
|
2570
2590
|
var form = state.quickCommitForm || {};
|
|
2571
|
-
var
|
|
2591
|
+
var meta = getQuickCommitActionMeta(action || state.quickCommitDragAction || "commit");
|
|
2592
|
+
var withTag = meta.withTag;
|
|
2572
2593
|
var userTag = withTag ? (form.tag || "").trim() : "";
|
|
2573
2594
|
var message = (form.customMessage || "").trim();
|
|
2574
2595
|
if (!message) {
|
|
@@ -2576,17 +2597,28 @@
|
|
|
2576
2597
|
rerenderQuickCommitModal();
|
|
2577
2598
|
return;
|
|
2578
2599
|
}
|
|
2579
|
-
|
|
2580
|
-
|
|
2600
|
+
var before = {
|
|
2601
|
+
branch: (state.gitStatus || {}).branch || "",
|
|
2602
|
+
commitHash: (state.gitStatus || {}).lastCommit && (state.gitStatus || {}).lastCommit.shortHash
|
|
2603
|
+
? (state.gitStatus || {}).lastCommit.shortHash
|
|
2604
|
+
: ((state.gitStatus || {}).head ? (state.gitStatus || {}).head.substring(0, 7) : ""),
|
|
2605
|
+
commitSubject: (state.gitStatus || {}).lastCommit && (state.gitStatus || {}).lastCommit.subject
|
|
2606
|
+
? (state.gitStatus || {}).lastCommit.subject
|
|
2607
|
+
: "",
|
|
2608
|
+
tag: (state.gitStatus || {}).latestTag || "",
|
|
2609
|
+
};
|
|
2581
2610
|
var payload = {
|
|
2582
2611
|
autoMessage: false,
|
|
2583
2612
|
customMessage: message,
|
|
2584
2613
|
tag: userTag,
|
|
2585
2614
|
autoTag: !!(withTag && !userTag),
|
|
2586
|
-
push:
|
|
2615
|
+
push: !!meta.push
|
|
2587
2616
|
};
|
|
2588
2617
|
state.quickCommitSubmitting = true;
|
|
2589
2618
|
state.quickCommitError = "";
|
|
2619
|
+
state.quickCommitPushError = "";
|
|
2620
|
+
state.quickCommitResult = null;
|
|
2621
|
+
state.quickCommitDragAction = meta.action;
|
|
2590
2622
|
rerenderQuickCommitModal();
|
|
2591
2623
|
fetch("/api/sessions/" + encodeURIComponent(state.selectedId) + "/quick-commit", {
|
|
2592
2624
|
method: "POST",
|
|
@@ -2607,99 +2639,35 @@
|
|
|
2607
2639
|
? "已先提交 " + subCommits.length + " 个 submodule(" + subCommits.map(function(c) { return c.path; }).join("、") + "),"
|
|
2608
2640
|
: "";
|
|
2609
2641
|
var base = subPrefix + "已提交" + (hash ? " " + hash : "") + (tagName ? ",已打 Tag " + tagName : "");
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
if (!state.selectedId || state.quickCommitTagHeadGenerating) return;
|
|
2626
|
-
var inp = document.getElementById("quick-commit-tag-head-input");
|
|
2627
|
-
if (inp) state.quickCommitTagHeadForm.tag = inp.value;
|
|
2628
|
-
state.quickCommitTagHeadGenerating = true;
|
|
2629
|
-
state.quickCommitTagHeadError = "";
|
|
2630
|
-
rerenderQuickCommitModal();
|
|
2631
|
-
// Reuse the existing generator — it stages and asks for {message, tag}.
|
|
2632
|
-
// We only consume `suggestedTag` here.
|
|
2633
|
-
fetch("/api/sessions/" + encodeURIComponent(state.selectedId) + "/generate-commit-message", {
|
|
2634
|
-
method: "POST",
|
|
2635
|
-
credentials: "same-origin",
|
|
2636
|
-
headers: { "Content-Type": "application/json" },
|
|
2637
|
-
body: JSON.stringify({})
|
|
2638
|
-
})
|
|
2639
|
-
.then(function(res) { return res.json().then(function(data) { return { ok: res.ok, data: data }; }); })
|
|
2640
|
-
.then(function(result) {
|
|
2641
|
-
if (!result.ok) throw new Error((result.data && result.data.error) || "AI 生成失败。");
|
|
2642
|
-
var aiTag = (result.data && typeof result.data.suggestedTag === "string") ? result.data.suggestedTag.trim() : "";
|
|
2643
|
-
var currentTag = (state.quickCommitTagHeadForm.tag || "").trim();
|
|
2644
|
-
if (!currentTag && aiTag) {
|
|
2645
|
-
state.quickCommitTagHeadForm.tag = aiTag;
|
|
2646
|
-
} else if (!aiTag) {
|
|
2647
|
-
throw new Error("AI 没有给出 tag 建议。");
|
|
2648
|
-
}
|
|
2649
|
-
})
|
|
2650
|
-
.catch(function(error) {
|
|
2651
|
-
state.quickCommitTagHeadError = (error && error.message) || "AI 生成失败。";
|
|
2652
|
-
})
|
|
2653
|
-
.finally(function() {
|
|
2654
|
-
state.quickCommitTagHeadGenerating = false;
|
|
2655
|
-
if (state.quickCommitOpen) rerenderQuickCommitModal();
|
|
2656
|
-
});
|
|
2657
|
-
}
|
|
2658
|
-
|
|
2659
|
-
// Tag the existing HEAD without making a new commit.
|
|
2660
|
-
function submitTagHead(silent) {
|
|
2661
|
-
if (!state.selectedId || state.quickCommitTagHeadSubmitting) return;
|
|
2662
|
-
var inp = document.getElementById("quick-commit-tag-head-input");
|
|
2663
|
-
if (inp) state.quickCommitTagHeadForm.tag = inp.value;
|
|
2664
|
-
var tag = (state.quickCommitTagHeadForm.tag || "").trim();
|
|
2665
|
-
if (!tag) {
|
|
2666
|
-
state.quickCommitTagHeadError = "请填写 tag 名称,或点击 AI 建议。";
|
|
2667
|
-
rerenderQuickCommitModal();
|
|
2668
|
-
return;
|
|
2669
|
-
}
|
|
2670
|
-
state.quickCommitTagHeadSubmitting = true;
|
|
2671
|
-
state.quickCommitTagHeadError = "";
|
|
2672
|
-
rerenderQuickCommitModal();
|
|
2673
|
-
fetch("/api/sessions/" + encodeURIComponent(state.selectedId) + "/git/tag-head", {
|
|
2674
|
-
method: "POST",
|
|
2675
|
-
credentials: "same-origin",
|
|
2676
|
-
headers: { "Content-Type": "application/json" },
|
|
2677
|
-
body: JSON.stringify({ tag: tag, push: !!state.quickCommitTagHeadForm.push })
|
|
2678
|
-
})
|
|
2679
|
-
.then(function(res) { return res.json().then(function(data) { return { ok: res.ok, data: data }; }); })
|
|
2680
|
-
.then(function(result) {
|
|
2681
|
-
if (!result.ok) throw new Error((result.data && result.data.error) || "打 tag 失败。");
|
|
2682
|
-
var data = result.data || {};
|
|
2683
|
-
var name = data.tag && data.tag.name ? data.tag.name : tag;
|
|
2684
|
-
var pushed = !!data.pushed;
|
|
2685
|
-
var pushErr = data.pushError;
|
|
2686
|
-
var base = "已为 HEAD 打 tag " + name;
|
|
2687
|
-
if (state.quickCommitTagHeadForm.push && pushErr) {
|
|
2688
|
-
if (typeof showToast === "function") showToast(base + ";push tag 失败:" + pushErr, "error");
|
|
2642
|
+
state.quickCommitResult = {
|
|
2643
|
+
action: meta.action,
|
|
2644
|
+
pushed: !!data.pushed,
|
|
2645
|
+
pushError: data.pushError || "",
|
|
2646
|
+
commitHash: hash,
|
|
2647
|
+
commitMessage: data.commit && data.commit.message ? data.commit.message : message,
|
|
2648
|
+
tagName: tagName,
|
|
2649
|
+
oldTag: before.tag,
|
|
2650
|
+
oldCommitHash: before.commitHash,
|
|
2651
|
+
oldCommitSubject: before.commitSubject,
|
|
2652
|
+
submoduleCount: subCommits.length,
|
|
2653
|
+
};
|
|
2654
|
+
if (meta.push && !data.pushError) {
|
|
2655
|
+
if (typeof showToast === "function") showToast(base + ",已推送。", "success");
|
|
2656
|
+
closeQuickCommitModal();
|
|
2689
2657
|
} else {
|
|
2690
|
-
if (typeof showToast === "function")
|
|
2658
|
+
if (typeof showToast === "function") {
|
|
2659
|
+
showToast(base + (data.pushError ? ";push 失败:" + data.pushError : "。"), data.pushError ? "error" : "success");
|
|
2660
|
+
}
|
|
2661
|
+
if (state.selectedId) loadGitStatus(state.selectedId, { force: true }).then(function() {
|
|
2662
|
+
if (state.quickCommitOpen) rerenderQuickCommitModal();
|
|
2663
|
+
});
|
|
2691
2664
|
}
|
|
2692
|
-
if (state.quickCommitOpenMenu === "tag-head") state.quickCommitOpenMenu = null;
|
|
2693
|
-
state.quickCommitTagHeadForm = { tag: "", push: false };
|
|
2694
|
-
if (state.selectedId) loadGitStatus(state.selectedId, { force: true }).then(function() {
|
|
2695
|
-
if (state.quickCommitOpen) rerenderQuickCommitModal();
|
|
2696
|
-
});
|
|
2697
2665
|
})
|
|
2698
2666
|
.catch(function(error) {
|
|
2699
|
-
state.
|
|
2667
|
+
state.quickCommitError = (error && error.message) || "快捷提交失败。";
|
|
2700
2668
|
})
|
|
2701
2669
|
.finally(function() {
|
|
2702
|
-
state.
|
|
2670
|
+
state.quickCommitSubmitting = false;
|
|
2703
2671
|
if (state.quickCommitOpen) rerenderQuickCommitModal();
|
|
2704
2672
|
});
|
|
2705
2673
|
}
|
|
@@ -2708,6 +2676,7 @@
|
|
|
2708
2676
|
if (!state.selectedId || state.quickCommitPushing) return;
|
|
2709
2677
|
var pushCommits = !!(opts && opts.pushCommits);
|
|
2710
2678
|
var pushTags = !!(opts && opts.pushTags);
|
|
2679
|
+
var closeOnSuccess = !!(opts && opts.closeOnSuccess);
|
|
2711
2680
|
if (!pushCommits && !pushTags) return;
|
|
2712
2681
|
state.quickCommitPushing = true;
|
|
2713
2682
|
state.quickCommitPushError = "";
|
|
@@ -2733,9 +2702,15 @@
|
|
|
2733
2702
|
if (data.pushedTags) parts.push("tags");
|
|
2734
2703
|
var label = parts.length ? parts.join(" 和 ") : "(无内容)";
|
|
2735
2704
|
if (typeof showToast === "function") showToast("已推送 " + label, "success");
|
|
2736
|
-
if (state.
|
|
2737
|
-
|
|
2738
|
-
|
|
2705
|
+
if (state.quickCommitResult) state.quickCommitResult.pushed = true;
|
|
2706
|
+
if (closeOnSuccess) {
|
|
2707
|
+
closeQuickCommitModal();
|
|
2708
|
+
if (state.selectedId) loadGitStatus(state.selectedId, { force: true });
|
|
2709
|
+
} else if (state.selectedId) {
|
|
2710
|
+
loadGitStatus(state.selectedId, { force: true }).then(function() {
|
|
2711
|
+
if (state.quickCommitOpen) rerenderQuickCommitModal();
|
|
2712
|
+
});
|
|
2713
|
+
}
|
|
2739
2714
|
})
|
|
2740
2715
|
.catch(function(error) {
|
|
2741
2716
|
state.quickCommitPushError = (error && error.message) || "推送失败。";
|
|
@@ -2800,213 +2775,110 @@
|
|
|
2800
2775
|
}
|
|
2801
2776
|
|
|
2802
2777
|
function isQuickCommitOpInFlight() {
|
|
2803
|
-
return state.quickCommitSubmitting || state.
|
|
2804
|
-
}
|
|
2805
|
-
|
|
2806
|
-
function renderQuickCommitCommitButton(hasChanges) {
|
|
2807
|
-
var f = state.quickCommitForm;
|
|
2808
|
-
var withTag = f.commitMode === "commit-tag";
|
|
2809
|
-
var label;
|
|
2810
|
-
if (state.quickCommitSubmitting) label = "提交中…";
|
|
2811
|
-
else label = withTag ? "提交并打 Tag" : "提交";
|
|
2812
|
-
var disabled = !hasChanges || isQuickCommitOpInFlight();
|
|
2813
|
-
var menuOpen = state.quickCommitOpenMenu === "action";
|
|
2814
|
-
var caretActive = menuOpen ? " is-active" : "";
|
|
2815
|
-
var menuItems = [
|
|
2816
|
-
{ value: "commit-tag", label: "提交并打 Tag", desc: "创建 commit,并为它打一个版本 Tag" },
|
|
2817
|
-
{ value: "commit", label: "仅提交", desc: "只创建 commit,不打 Tag" }
|
|
2818
|
-
];
|
|
2819
|
-
var menuHtml = menuItems.map(function(item) {
|
|
2820
|
-
var sel = f.commitMode === item.value ? " is-selected" : "";
|
|
2821
|
-
return '<button type="button" class="qc-dropdown-item' + sel + '" data-qc-commit-mode="' + item.value + '" role="menuitemradio" aria-checked="' + (f.commitMode === item.value ? 'true' : 'false') + '">' +
|
|
2822
|
-
'<span class="qc-dropdown-item-main"><span class="qc-dropdown-check" aria-hidden="true">' +
|
|
2823
|
-
(f.commitMode === item.value ? '<svg viewBox="0 0 16 16" width="13" height="13"><path d="M13 4.5l-6 6L3 7" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg>' : '') +
|
|
2824
|
-
'</span><span class="qc-dropdown-item-title">' + escapeHtml(item.label) + '</span></span>' +
|
|
2825
|
-
'<span class="qc-dropdown-item-desc">' + escapeHtml(item.desc) + '</span>' +
|
|
2826
|
-
'</button>';
|
|
2827
|
-
}).join("");
|
|
2828
|
-
return '<div class="qc-split-button">' +
|
|
2829
|
-
'<button id="quick-commit-submit-btn" class="btn btn-primary qc-split-main" type="button"' + (disabled ? ' disabled' : '') + '>' +
|
|
2830
|
-
escapeHtml(label) +
|
|
2831
|
-
'</button>' +
|
|
2832
|
-
'<button id="quick-commit-action-caret" class="btn btn-primary qc-split-caret' + caretActive + '" type="button" data-qc-dropdown-toggle="action"' + (disabled ? ' disabled' : '') + ' aria-haspopup="menu" aria-expanded="' + (menuOpen ? 'true' : 'false') + '" aria-label="切换提交方式">' +
|
|
2833
|
-
'<svg viewBox="0 0 12 12" width="10" height="10" aria-hidden="true"><path d="M2 4l4 4 4-4" stroke="currentColor" stroke-width="1.6" fill="none" stroke-linecap="round" stroke-linejoin="round"/></svg>' +
|
|
2834
|
-
'</button>' +
|
|
2835
|
-
(menuOpen ?
|
|
2836
|
-
'<div id="quick-commit-action-menu" class="qc-dropdown-menu" data-qc-dropdown-menu="action" role="menu">' + menuHtml + '</div>' : '') +
|
|
2837
|
-
'</div>';
|
|
2778
|
+
return state.quickCommitSubmitting || state.quickCommitPushing;
|
|
2838
2779
|
}
|
|
2839
2780
|
|
|
2840
|
-
function
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
if (!hasUpstream) {
|
|
2850
|
-
chips.push('<span class="qc-chip qc-chip--warn" title="当前分支没有 upstream,将首次推送时自动设置">无 upstream</span>');
|
|
2851
|
-
} else if (!chips.length) {
|
|
2852
|
-
chips.push('<span class="qc-chip qc-chip--clean">与远端同步</span>');
|
|
2853
|
-
}
|
|
2854
|
-
return '<div class="qc-status-chips">' + chips.join("") + '</div>';
|
|
2781
|
+
function renderQuickCommitPair(label, fromHtml, toHtml, extraClass) {
|
|
2782
|
+
return '<div class="qc-pair' + (extraClass ? ' ' + extraClass : '') + '">' +
|
|
2783
|
+
'<div class="qc-pair-label">' + escapeHtml(label) + '</div>' +
|
|
2784
|
+
'<div class="qc-pair-flow">' +
|
|
2785
|
+
'<div class="qc-pair-value qc-pair-value--from">' + fromHtml + '</div>' +
|
|
2786
|
+
'<div class="qc-pair-arrow" aria-hidden="true">→</div>' +
|
|
2787
|
+
'<div class="qc-pair-value qc-pair-value--to">' + toHtml + '</div>' +
|
|
2788
|
+
'</div>' +
|
|
2789
|
+
'</div>';
|
|
2855
2790
|
}
|
|
2856
2791
|
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
var
|
|
2860
|
-
var
|
|
2861
|
-
var
|
|
2862
|
-
return '<div class="qc-
|
|
2863
|
-
'<div class="qc-tag-
|
|
2864
|
-
|
|
2865
|
-
'<
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
'
|
|
2870
|
-
'<
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
'<button type="button" id="quick-commit-tag-head-cancel" class="btn btn-ghost btn-sm"' + (submitting ? ' disabled' : '') + '>收起</button>' +
|
|
2875
|
-
'<button type="button" id="quick-commit-tag-head-submit" class="btn btn-secondary btn-sm"' + (submitting ? ' disabled' : '') + '>' + (submitting ? '打 Tag 中…' : '打 Tag') + '</button>' +
|
|
2792
|
+
function renderQuickCommitDragControl(hasChanges) {
|
|
2793
|
+
var action = normalizeQuickCommitAction(state.quickCommitDragAction || "commit");
|
|
2794
|
+
var meta = getQuickCommitActionMeta(action);
|
|
2795
|
+
var disabled = !hasChanges || isQuickCommitOpInFlight();
|
|
2796
|
+
var label = state.quickCommitSubmitting ? "执行中..." : meta.label;
|
|
2797
|
+
return '<div class="qc-drag-wrap">' +
|
|
2798
|
+
'<div id="quick-commit-drag-track" class="qc-drag-track" data-action="' + escapeHtml(action) + '" style="--qc-progress: ' + (action === "commit-tag-push" ? "100%" : (action === "commit-tag" ? "50%" : "0%")) + ';">' +
|
|
2799
|
+
'<div class="qc-drag-progress" aria-hidden="true"></div>' +
|
|
2800
|
+
'<div class="qc-drag-stages" aria-hidden="true">' +
|
|
2801
|
+
'<span class="qc-drag-stage is-active is-passed" data-qc-stage="commit">Commit</span>' +
|
|
2802
|
+
'<span class="qc-drag-stage' + (action !== "commit" ? ' is-passed' : '') + (action === "commit-tag" ? ' is-active' : '') + '" data-qc-stage="commit-tag">Tag</span>' +
|
|
2803
|
+
'<span class="qc-drag-stage' + (action === "commit-tag-push" ? ' is-active is-passed' : '') + '" data-qc-stage="commit-tag-push">Push</span>' +
|
|
2804
|
+
'</div>' +
|
|
2805
|
+
'<button id="quick-commit-drag-action" class="qc-drag-action" type="button"' + (disabled ? ' disabled' : '') + ' aria-label="' + escapeHtml(meta.verb) + '">' +
|
|
2806
|
+
'<span id="quick-commit-drag-label">' + escapeHtml(label) + '</span>' +
|
|
2807
|
+
'<svg viewBox="0 0 24 24" width="16" height="16" aria-hidden="true"><path d="M5 12h14"/><path d="M13 6l6 6-6 6" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>' +
|
|
2808
|
+
'</button>' +
|
|
2876
2809
|
'</div>' +
|
|
2877
2810
|
'</div>';
|
|
2878
2811
|
}
|
|
2879
2812
|
|
|
2880
|
-
function
|
|
2881
|
-
var
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
var
|
|
2890
|
-
var
|
|
2891
|
-
var
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
}).join("");
|
|
2904
|
-
return '<div class="qc-split-button qc-split-button--secondary">' +
|
|
2905
|
-
'<button id="quick-commit-push-btn" class="btn btn-secondary qc-split-main" type="button"' + (disabled ? ' disabled' : '') + '>' +
|
|
2906
|
-
escapeHtml(mainLabel) +
|
|
2907
|
-
'</button>' +
|
|
2908
|
-
'<button id="quick-commit-push-caret" class="btn btn-secondary qc-split-caret' + caretActive + '" type="button" data-qc-dropdown-toggle="push"' + (disabled ? ' disabled' : '') + ' aria-haspopup="menu" aria-expanded="' + (menuOpen ? 'true' : 'false') + '" aria-label="更多推送方式">' +
|
|
2909
|
-
'<svg viewBox="0 0 12 12" width="10" height="10" aria-hidden="true"><path d="M2 4l4 4 4-4" stroke="currentColor" stroke-width="1.6" fill="none" stroke-linecap="round" stroke-linejoin="round"/></svg>' +
|
|
2910
|
-
'</button>' +
|
|
2911
|
-
(menuOpen ?
|
|
2912
|
-
'<div id="quick-commit-push-menu" class="qc-dropdown-menu qc-dropdown-menu--right" data-qc-dropdown-menu="push" role="menu">' + menuHtml + '</div>' : '') +
|
|
2913
|
-
'</div>';
|
|
2813
|
+
function renderQuickCommitResultPanel() {
|
|
2814
|
+
var r = state.quickCommitResult;
|
|
2815
|
+
if (!r) return "";
|
|
2816
|
+
var oldCommit = r.oldCommitHash
|
|
2817
|
+
? '<code>' + escapeHtml(r.oldCommitHash) + '</code>' + (r.oldCommitSubject ? '<span>' + escapeHtml(r.oldCommitSubject) + '</span>' : '')
|
|
2818
|
+
: '<span class="qc-muted">无</span>';
|
|
2819
|
+
var newCommit = r.commitHash
|
|
2820
|
+
? '<code>' + escapeHtml(r.commitHash) + '</code><span>' + escapeHtml(r.commitMessage || "") + '</span>'
|
|
2821
|
+
: '<span class="qc-muted">无</span>';
|
|
2822
|
+
var oldTag = r.oldTag ? '<code>' + escapeHtml(r.oldTag) + '</code>' : '<span class="qc-muted">无 tag</span>';
|
|
2823
|
+
var newTag = r.tagName ? '<code>' + escapeHtml(r.tagName) + '</code>' : '<span class="qc-muted">未打 tag</span>';
|
|
2824
|
+
var pushButton = r.pushed
|
|
2825
|
+
? '<span class="qc-result-pushed">已推送</span>'
|
|
2826
|
+
: '<button id="quick-commit-push-after-btn" class="btn btn-primary btn-sm" type="button"' + (state.quickCommitPushing ? ' disabled' : '') + '>' + (state.quickCommitPushing ? '推送中...' : 'Push & Close') + '</button>';
|
|
2827
|
+
return '<section class="qc-result-panel">' +
|
|
2828
|
+
renderQuickCommitPair("Commit", oldCommit, newCommit, "") +
|
|
2829
|
+
renderQuickCommitPair("Tag", oldTag, newTag, "qc-pair--tag") +
|
|
2830
|
+
(r.pushError || state.quickCommitPushError ? '<p class="error-message">' + escapeHtml(r.pushError || state.quickCommitPushError) + '</p>' : '') +
|
|
2831
|
+
'<div class="qc-result-actions">' +
|
|
2832
|
+
'<button id="quick-commit-cancel-btn" class="btn btn-ghost btn-sm" type="button">关闭</button>' +
|
|
2833
|
+
pushButton +
|
|
2834
|
+
'</div>' +
|
|
2835
|
+
'</section>';
|
|
2914
2836
|
}
|
|
2915
2837
|
|
|
2916
2838
|
function renderQuickCommitModal() {
|
|
2917
2839
|
var s = state.gitStatus || {};
|
|
2918
|
-
var f = state.quickCommitForm || { customMessage: "", tag: "", tagEdited: false
|
|
2840
|
+
var f = state.quickCommitForm || { customMessage: "", tag: "", tagEdited: false };
|
|
2919
2841
|
var hasChanges = (s.modifiedCount || 0) > 0;
|
|
2920
|
-
var
|
|
2921
|
-
var
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
if (
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
'<
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
'<div class="qc-tag-field' + (withTag ? '' : ' is-off') + '">' +
|
|
2949
|
-
'<span class="qc-tag-field-label" title="' + (withTag ? '这次提交会打上这个版本 Tag' : '当前为「仅提交」,不会打 Tag') + '">Tag</span>' +
|
|
2950
|
-
'<input type="text" id="quick-commit-tag" class="field-input qc-tag-field-input" placeholder="版本号,如 v1.2.0" value="' + escapeHtml(f.tag || "") + '"' + ((!withTag || state.quickCommitSubmitting) ? ' disabled' : '') + '>' +
|
|
2951
|
-
(withTag ? '' : '<span class="qc-tag-field-note">仅提交</span>') +
|
|
2952
|
-
'</div>' +
|
|
2953
|
-
(state.quickCommitError ? '<p class="error-message">' + escapeHtml(state.quickCommitError) + '</p>' : '') +
|
|
2954
|
-
'<div class="qc-section-actions">' +
|
|
2955
|
-
'<button id="quick-commit-cancel-btn" class="btn btn-ghost btn-sm" type="button">取消</button>' +
|
|
2956
|
-
'<div class="qc-action-group">' +
|
|
2957
|
-
renderQuickCommitCommitButton(hasChanges) +
|
|
2958
|
-
renderQuickCommitPushButton(s) +
|
|
2959
|
-
'</div>' +
|
|
2960
|
-
'</div>' +
|
|
2961
|
-
'</section>';
|
|
2962
|
-
}
|
|
2963
|
-
// When clean, we skip the big "changes" card entirely — a small green
|
|
2964
|
-
// indicator in the header subtitle is enough of a signal (see below).
|
|
2965
|
-
|
|
2966
|
-
// Section 2: repo status + secondary actions (always show when there's at least one commit)
|
|
2967
|
-
var section2 = "";
|
|
2968
|
-
if (!s.initialCommit && s.isGit !== false) {
|
|
2969
|
-
var lc = s.lastCommit || {};
|
|
2970
|
-
var headLine = lc.shortHash ? lc.shortHash + " · " + (lc.subject || "") : (s.head ? s.head.substring(0, 7) : "(no commit)");
|
|
2971
|
-
var upstreamLine = s.upstream ? escapeHtml(s.branch || "") + " → " + escapeHtml(s.upstream) : escapeHtml(s.branch || "(no branch)") + " · 无 upstream";
|
|
2972
|
-
var tagHeadOpen = state.quickCommitOpenMenu === "tag-head";
|
|
2973
|
-
section2 = '<section class="qc-section qc-section--repo">' +
|
|
2974
|
-
'<div class="qc-section-head"><span class="qc-section-title">仓库 · 同步</span><span class="qc-section-meta">' + upstreamLine + '</span></div>' +
|
|
2975
|
-
'<div class="qc-head-card">' +
|
|
2976
|
-
'<span class="qc-head-label">HEAD</span>' +
|
|
2977
|
-
'<code class="qc-head-text">' + escapeHtml(headLine) + '</code>' +
|
|
2978
|
-
'</div>' +
|
|
2979
|
-
renderQuickCommitStatusChips(s) +
|
|
2980
|
-
(tagHeadOpen ? renderQuickCommitTagHeadPanel() : '') +
|
|
2981
|
-
'<div class="qc-section-actions qc-section-actions--secondary">' +
|
|
2982
|
-
'<button id="quick-commit-tag-head-toggle" class="btn btn-secondary btn-sm qc-tag-head-btn' + (tagHeadOpen ? ' is-open' : '') + '" type="button"' + (state.quickCommitPushing ? ' disabled' : '') + ' title="给当前最新提交(HEAD)打 Tag,不会创建新提交">' +
|
|
2983
|
-
'<svg viewBox="0 0 16 16" width="14" height="14" aria-hidden="true"><path d="M2 2h6.5l5 5-5.5 5.5L2 7.5V2z" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linejoin="round"/><circle cx="5" cy="5" r="1" fill="currentColor"/></svg>' +
|
|
2984
|
-
'<span>' + (tagHeadOpen ? '收起' : '为当前提交打 Tag') + '</span>' +
|
|
2985
|
-
'</button>' +
|
|
2986
|
-
// Push lives in the commit footer when there are changes; show it here otherwise.
|
|
2987
|
-
(hasChanges ? '' : renderQuickCommitPushButton(s)) +
|
|
2988
|
-
'</div>' +
|
|
2989
|
-
'</section>';
|
|
2990
|
-
}
|
|
2991
|
-
|
|
2992
|
-
var subtitleHtml = subParts.map(escapeHtml).join(" · ");
|
|
2993
|
-
// Small "clean" badge shown inline in the header subtitle (replaces the old empty-state card).
|
|
2994
|
-
var cleanBadge = (!hasChanges && s.isGit !== false)
|
|
2995
|
-
? '<span class="qc-clean-badge" title="工作区干净,没有待提交的改动"><svg viewBox="0 0 16 16" width="11" height="11" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M13 4.5l-6 6L3 7"/></svg>干净</span>'
|
|
2996
|
-
: '';
|
|
2997
|
-
|
|
2842
|
+
var genBusy = state.quickCommitGenerating;
|
|
2843
|
+
var lc = s.lastCommit || {};
|
|
2844
|
+
var oldCommitHtml = lc.shortHash
|
|
2845
|
+
? '<code>' + escapeHtml(lc.shortHash) + '</code><span>' + escapeHtml(lc.subject || "") + '</span>'
|
|
2846
|
+
: (s.head ? '<code>' + escapeHtml(s.head.substring(0, 7)) + '</code>' : '<span class="qc-muted">无 commit</span>');
|
|
2847
|
+
var oldTagHtml = s.latestTag ? '<code>' + escapeHtml(s.latestTag) + '</code>' : '<span class="qc-muted">无 tag</span>';
|
|
2848
|
+
var newTagHtml = '<input type="text" id="quick-commit-tag" class="field-input qc-tag-field-input" placeholder="v1.2.0" value="' + escapeHtml(f.tag || "") + '"' + (state.quickCommitSubmitting ? ' disabled' : '') + '>';
|
|
2849
|
+
var nextCommitHtml = '<textarea id="quick-commit-message" class="field-input qc-message-input" rows="3" placeholder="New commit message" ' + (state.quickCommitSubmitting ? 'disabled' : '') + '>' + escapeHtml(f.customMessage || "") + '</textarea>';
|
|
2850
|
+
var subtitleParts = [];
|
|
2851
|
+
subtitleParts.push(s.branch || "(no branch)");
|
|
2852
|
+
subtitleParts.push(hasChanges ? ((s.modifiedCount || 0) + " 个改动") : "工作区干净");
|
|
2853
|
+
if (typeof s.ahead === "number" && s.ahead > 0) subtitleParts.push("↑" + s.ahead);
|
|
2854
|
+
if (typeof s.behind === "number" && s.behind > 0) subtitleParts.push("↓" + s.behind);
|
|
2855
|
+
var formPanel = state.quickCommitResult ? "" : '<section class="qc-release-panel">' +
|
|
2856
|
+
'<div class="qc-message-header">' +
|
|
2857
|
+
'<span class="qc-section-title">New</span>' +
|
|
2858
|
+
'<button type="button" id="quick-commit-ai-btn" class="btn btn-ghost btn-sm qc-ai-btn"' + (genBusy ? ' disabled' : '') + ' title="AI 生成 commit message 与 tag">' +
|
|
2859
|
+
'<svg viewBox="0 0 16 16" width="13" height="13" aria-hidden="true"><path d="M8 1.5l1.4 3.6L13 6.5 9.4 7.9 8 11.5 6.6 7.9 3 6.5l3.6-1.4L8 1.5zM12.5 10.5l.7 1.8 1.8.7-1.8.7-.7 1.8-.7-1.8-1.8-.7 1.8-.7.7-1.8z" fill="currentColor"/></svg>' +
|
|
2860
|
+
'<span>' + (genBusy ? '生成中...' : 'AI') + '</span>' +
|
|
2861
|
+
'</button>' +
|
|
2862
|
+
'</div>' +
|
|
2863
|
+
renderQuickCommitPair("Commit", oldCommitHtml, nextCommitHtml, "qc-pair--commit") +
|
|
2864
|
+
renderQuickCommitPair("Tag", oldTagHtml, newTagHtml, "qc-pair--tag") +
|
|
2865
|
+
(state.quickCommitError ? '<p class="error-message">' + escapeHtml(state.quickCommitError) + '</p>' : '') +
|
|
2866
|
+
renderQuickCommitDragControl(hasChanges) +
|
|
2867
|
+
'<div class="qc-modal-actions"><button id="quick-commit-cancel-btn" class="btn btn-ghost btn-sm" type="button">取消</button></div>' +
|
|
2868
|
+
'</section>';
|
|
2869
|
+
var resultPanel = renderQuickCommitResultPanel();
|
|
2998
2870
|
return '<section id="quick-commit-modal" class="modal-backdrop' + (state.quickCommitOpen ? '' : ' hidden') + '">' +
|
|
2999
2871
|
'<div class="modal quick-commit-modal" role="dialog" aria-labelledby="quick-commit-title">' +
|
|
3000
2872
|
'<div class="modal-header">' +
|
|
3001
2873
|
'<div>' +
|
|
3002
2874
|
'<h2 id="quick-commit-title" class="modal-title">快捷提交</h2>' +
|
|
3003
|
-
'<p class="modal-subtitle">' +
|
|
2875
|
+
'<p class="modal-subtitle">' + escapeHtml(subtitleParts.join(" · ")) + '</p>' +
|
|
3004
2876
|
'</div>' +
|
|
3005
2877
|
'<button id="quick-commit-close-btn" class="btn btn-ghost btn-icon modal-close-btn" type="button" aria-label="关闭"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" aria-hidden="true"><line x1="6" y1="6" x2="18" y2="18"/><line x1="18" y1="6" x2="6" y2="18"/></svg></button>' +
|
|
3006
2878
|
'</div>' +
|
|
3007
2879
|
'<div class="modal-body">' +
|
|
3008
|
-
|
|
3009
|
-
|
|
2880
|
+
formPanel +
|
|
2881
|
+
resultPanel +
|
|
3010
2882
|
'</div>' +
|
|
3011
2883
|
'</div>' +
|
|
3012
2884
|
'</section>';
|
|
@@ -8444,9 +8316,16 @@
|
|
|
8444
8316
|
rows: 36,
|
|
8445
8317
|
autoResize: true,
|
|
8446
8318
|
cursorBlink: false,
|
|
8447
|
-
onData: function(
|
|
8448
|
-
|
|
8449
|
-
|
|
8319
|
+
onData: function() {
|
|
8320
|
+
// 物理键盘进 PTY 只允许在「终端交互(键盘透传)」开启时发生,而开启态那条
|
|
8321
|
+
// 路径由 captureTerminalInput(document keydown capture)独占处理——所以
|
|
8322
|
+
// wterm 自身的 onData 一律不再直接发:
|
|
8323
|
+
// · 关闭态(默认):用户点一下终端会触发 wterm 内部 _onClickFocus,让它的
|
|
8324
|
+
// 隐藏输入元素拿到焦点;之后敲的每个键都从 onData 冒出来。旧代码在这里
|
|
8325
|
+
// 直接 queueDirectInput,于是"没开透传也漏键进 PTY"(反复误触的根因)。
|
|
8326
|
+
// · 开启态:captureTerminalInput 已接管全部按键,onData 再发就是双份重复。
|
|
8327
|
+
// 两种状态都让路。要发命令请先开透传开关,或直接用输入框。
|
|
8328
|
+
return;
|
|
8450
8329
|
},
|
|
8451
8330
|
onResize: function(cols, rows) {
|
|
8452
8331
|
sendTerminalResize(cols, rows);
|
|
@@ -11322,7 +11201,9 @@
|
|
|
11322
11201
|
msgEl.classList.remove("hidden");
|
|
11323
11202
|
}
|
|
11324
11203
|
updateBtn.classList.add("hidden");
|
|
11325
|
-
if (data.
|
|
11204
|
+
if (data.detachedUpdate) {
|
|
11205
|
+
showRestartOverlay();
|
|
11206
|
+
} else if (data.restartRequired !== false) {
|
|
11326
11207
|
performRestart(null, msgEl);
|
|
11327
11208
|
} else {
|
|
11328
11209
|
// \u670d\u52a1\u7aef\u660e\u786e\u8868\u793a\u4e0d\u9700\u8981\u91cd\u542f\uff0c\u4fdd\u7559\u624b\u52a8\u91cd\u542f\u6309\u94ae
|
|
@@ -22089,6 +21970,10 @@
|
|
|
22089
21970
|
setSubtitle((data.message || "\u66f4\u65b0\u5b8c\u6210") + "\uff0c\u6b63\u5728\u91cd\u542f\u670d\u52a1\u2026");
|
|
22090
21971
|
setStatus("");
|
|
22091
21972
|
if (actionLabel) actionLabel.textContent = "\u6b63\u5728\u91cd\u542f\u2026";
|
|
21973
|
+
if (data.detachedUpdate) {
|
|
21974
|
+
showRestartOverlay();
|
|
21975
|
+
return;
|
|
21976
|
+
}
|
|
22092
21977
|
if (data.restartRequired === false) {
|
|
22093
21978
|
setProgress(false);
|
|
22094
21979
|
card.classList.remove("is-busy");
|
|
@@ -22174,7 +22059,7 @@
|
|
|
22174
22059
|
document.body.appendChild(overlay);
|
|
22175
22060
|
|
|
22176
22061
|
var attempts = 0;
|
|
22177
|
-
var maxAttempts =
|
|
22062
|
+
var maxAttempts = 180; // 180 * 2s = 6min; beta git installs can be slow
|
|
22178
22063
|
var timer = setInterval(function() {
|
|
22179
22064
|
attempts++;
|
|
22180
22065
|
fetch("/api/config", { credentials: "same-origin" })
|