dsh-diff-approval 0.2.0 → 0.4.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/README.md +20 -5
- package/README.zh.md +20 -5
- package/docs/images/pending-panel.png +0 -0
- package/docs/images/pending-panel.zh.png +0 -0
- package/lib/client.js +624 -275
- package/lib/index.js +302 -30
- package/lib/types/client/PendingPanel.d.ts +2 -2
- package/lib/types/client/highlight.d.ts +2 -0
- package/lib/types/client/locales.d.ts +18 -2
- package/lib/types/client/port.d.ts +3 -1
- package/lib/types/client/slots.d.ts +3 -1
- package/lib/types/client/store.d.ts +3 -0
- package/lib/types/index.d.ts +21 -9
- package/lib/types/open.d.ts +17 -0
- package/lib/types/persist.d.ts +10 -0
- package/lib/types/types.d.ts +7 -0
- package/package.json +4 -2
package/lib/client.js
CHANGED
|
@@ -11333,6 +11333,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
11333
11333
|
xml_default,
|
|
11334
11334
|
yaml_default
|
|
11335
11335
|
];
|
|
11336
|
+
/** Supported grammar ids, in picker order, for the viewer's language selector. */
|
|
11337
|
+
const HIGHLIGHT_LANGS = [...new Set(LANGS.flat().map((lang) => lang.name))];
|
|
11336
11338
|
/** All token colors resolve through `--shiki-*` custom properties (theme package sheets). */
|
|
11337
11339
|
const cssVariablesTheme = createCssVariablesTheme({
|
|
11338
11340
|
name: "css-variables",
|
|
@@ -11485,7 +11487,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
11485
11487
|
* @param path - the path to shorten.
|
|
11486
11488
|
* @returns the segment after the final separator.
|
|
11487
11489
|
*/
|
|
11488
|
-
function basenameOf(path) {
|
|
11490
|
+
function basenameOf$1(path) {
|
|
11489
11491
|
const normalized = path.replaceAll("\\", "/");
|
|
11490
11492
|
return normalized.slice(normalized.lastIndexOf("/") + 1);
|
|
11491
11493
|
}
|
|
@@ -11497,8 +11499,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
11497
11499
|
* @returns the display path for a copied reference.
|
|
11498
11500
|
*/
|
|
11499
11501
|
function copyDisplayPath(path, files) {
|
|
11500
|
-
const base = basenameOf(path);
|
|
11501
|
-
return files.some((file) => file.path !== path && basenameOf(file.path) === base) ? path : base;
|
|
11502
|
+
const base = basenameOf$1(path);
|
|
11503
|
+
return files.some((file) => file.path !== path && basenameOf$1(file.path) === base) ? path : base;
|
|
11502
11504
|
}
|
|
11503
11505
|
/**
|
|
11504
11506
|
* Format one line range as a reference suffix: a single line number, or the
|
|
@@ -11522,8 +11524,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
11522
11524
|
return `${copyDisplayPath(path, files)}:${lineRangeLabel(start, end)}`;
|
|
11523
11525
|
}
|
|
11524
11526
|
//#endregion
|
|
11525
|
-
//#region \0dsh-css
|
|
11526
|
-
const css = ".
|
|
11527
|
+
//#region \0dsh-css:/home/runner/work/dsh-diff-approval/dsh-diff-approval/src/client/PendingPanel.module.css.mjs
|
|
11528
|
+
const css = ".F1KBNa_layer{flex:none;align-items:center;width:calc(100% + 8px);height:34px;margin:4px -4px;display:flex;position:relative}.F1KBNa_footerButtons{align-items:center;width:100%;display:flex}.F1KBNa_badge{box-sizing:border-box;width:100%;height:34px;color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border:none;border-radius:12px;align-items:center;gap:8px;padding:6px 2px 6px 10px;font-family:inherit;font-size:14px;line-height:22px;display:flex;overflow:hidden}.F1KBNa_badge:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_badge[data-active]{background:var(--dsw-alias-interactive-bg-hover-solid)}.F1KBNa_badgeLabel{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.F1KBNa_badgeCount{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;flex:none;margin-left:auto;margin-right:6px;font-size:12px;line-height:16px}.F1KBNa_layer.F1KBNa_rail{width:36px;height:36px;margin:8px 0 10px}.F1KBNa_rail .F1KBNa_badge{border-radius:50%;justify-content:center;gap:0;width:36px;height:36px;padding:0}.F1KBNa_rail .F1KBNa_badgeLabel{display:none}.F1KBNa_rail .F1KBNa_badgeCount{box-sizing:border-box;background:var(--dsw-alias-state-business-primary);min-width:18px;height:18px;color:var(--dsw-alias-label-primary-foreground);font-variant-numeric:tabular-nums;border-radius:9px;justify-content:center;align-items:center;padding:0 4px;font-size:11px;line-height:18px;display:flex;position:absolute;top:-3px;right:-7px}.F1KBNa_panel{z-index:30;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);width:auto;max-width:none;box-shadow:var(--dsw-shadow-lv2);--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);border-radius:12px;flex-direction:column;display:flex;position:fixed;inset:8px 8px 128px;overflow:hidden}.F1KBNa_header{box-sizing:border-box;border-bottom:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);flex:none;justify-content:space-between;align-items:center;min-height:44px;padding:10px 12px;display:flex}.F1KBNa_states{flex:1;min-height:0;padding:4px 12px 12px;overflow-y:auto}.F1KBNa_split{flex:1;align-items:stretch;min-height:0;display:flex}.F1KBNa_fileList{box-sizing:border-box;border-right:1px solid var(--dsw-alias-border-l2);flex:none;width:240px;min-height:0;padding:4px 8px 12px;overflow-y:auto}.F1KBNa_resizeHandle{cursor:col-resize;background:0 0;flex:none;width:5px;margin:0 -2px}.F1KBNa_resizeHandle:hover{background:var(--dsw-alias-border-l2)}.F1KBNa_detail{flex-direction:column;flex:1;min-width:0;min-height:0;display:flex}.F1KBNa_detailEmpty{color:var(--dsw-alias-label-tertiary);text-align:center;flex:1;justify-content:center;align-items:center;margin:0;padding:24px;font-size:12px;line-height:18px;display:flex}.F1KBNa_title{color:var(--dsw-alias-label-primary);font-size:13px;font-weight:500;line-height:20px}.F1KBNa_note,.F1KBNa_readError,.F1KBNa_hint{color:var(--dsw-alias-label-tertiary);margin:4px 0;font-size:12px;line-height:18px}.F1KBNa_readError{color:var(--dsw-alias-state-error-primary)}.F1KBNa_group{color:var(--dsw-alias-label-tertiary);margin:8px 0 4px;font-size:12px;font-weight:500;line-height:16px}.F1KBNa_rows{margin:0;padding:0;list-style:none}.F1KBNa_row{border:1px solid #0000;border-radius:10px;margin:2px 0}.F1KBNa_rowHead{width:100%;color:var(--dsw-alias-label-primary);font:inherit;text-align:left;cursor:pointer;background:0 0;border:none;border-radius:10px;align-items:baseline;gap:8px;padding:6px 8px;display:flex}.F1KBNa_rowHead:hover{background:var(--dsw-alias-interactive-bg-hover-solid)}.F1KBNa_rowHead[data-selected]{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_rowPath{text-overflow:ellipsis;white-space:nowrap;min-width:0;font:var(--dsw-font-markdown-code-block);overflow:hidden}.F1KBNa_kindTag{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-tertiary);white-space:nowrap;border-radius:6px;flex:none;padding:1px 6px;font-size:11px;line-height:14px}.F1KBNa_kindHint{color:var(--dsw-alias-label-tertiary);flex:none;font-size:12px;line-height:16px}.F1KBNa_divergedHint,.F1KBNa_missingHint{border-bottom:1px solid var(--dsw-alias-border-l2);margin:0;padding:6px 8px;font-size:12px;line-height:18px}.F1KBNa_missing{border:1px solid var(--dsw-alias-state-warn-primary);color:var(--dsw-alias-state-warn-label,var(--dsw-alias-state-warn-primary));white-space:nowrap;border-radius:6px;flex:none;padding:1px 6px;font-size:11px;line-height:14px}.F1KBNa_missingHint{color:var(--dsw-alias-state-warn-label,var(--dsw-alias-state-warn-primary))}.F1KBNa_rowMeta{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;flex:none;gap:6px;margin-left:auto;font-size:12px;line-height:16px;display:inline-flex}.F1KBNa_addCount{color:color-mix(in srgb, var(--dsw-alias-state-success-primary) 60%, var(--dsw-alias-label-primary))}.F1KBNa_delCount{color:color-mix(in srgb, var(--dsw-alias-state-error-primary) 60%, var(--dsw-alias-label-primary))}.F1KBNa_diff{background:var(--dsw-alias-markdown-code-block);flex-direction:column;flex:1;min-height:0;display:flex;position:relative;overflow:hidden}.F1KBNa_diffHeader{border-bottom:1px solid var(--dsw-alias-border-l2);align-items:center;gap:8px;padding:6px 8px;display:flex}.F1KBNa_diffPath{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--dsw-alias-label-primary);font:var(--dsw-font-markdown-code-block);flex:1;font-size:12px;line-height:18px;overflow:hidden}.F1KBNa_diffActions{border-bottom:1px solid var(--dsw-alias-border-l2);align-items:center;gap:8px;padding:6px 8px;display:flex}.F1KBNa_diffStats{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;font-size:12px;line-height:16px}.F1KBNa_flexSpacer{flex:1}.F1KBNa_action{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border-radius:8px;padding:3px 12px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_action:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_action:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.F1KBNa_iconAction{justify-content:center;align-items:center;padding:4px 6px;display:inline-flex}.F1KBNa_close{cursor:pointer;width:28px;height:28px;color:var(--dsw-alias-label-tertiary);background:0 0;border:none;border-radius:28px;justify-content:center;align-items:center;padding:0;display:inline-flex}.F1KBNa_close:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_diffBody{min-height:0;font:var(--dsw-font-markdown-code-block);flex:1;padding:8px 10px;overflow:auto}.F1KBNa_lines{border-spacing:0;width:max-content;min-width:100%;display:table}.F1KBNa_line{display:table-row}.F1KBNa_gutter{box-sizing:border-box;text-align:right;width:44px;color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;user-select:none;padding-right:10px;display:table-cell}.F1KBNa_code{white-space:pre;display:table-cell}.F1KBNa_context{color:var(--dsw-alias-label-primary)}.F1KBNa_del{background-color:color-mix(in srgb, var(--dsw-alias-state-error-primary) 12%, transparent)}.F1KBNa_add{background-color:color-mix(in srgb, var(--dsw-alias-state-success-primary) 10%, transparent)}.F1KBNa_statusBar{box-sizing:border-box;border-top:1px solid var(--dsw-alias-border-l2);height:34px;color:var(--dsw-alias-label-tertiary);font-family:var(--dsw-font-markdown-code-block);font-variant-numeric:tabular-nums;flex:none;align-items:center;padding:0 8px;font-size:12px;line-height:18px;display:flex}.F1KBNa_statusAction{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);white-space:nowrap;cursor:pointer;background:0 0;border-radius:8px;padding:3px 12px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_statusAction:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_langSelect{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border-radius:8px;flex:none;align-items:center;gap:4px;padding:3px 12px;font-family:inherit;font-size:12px;line-height:18px;display:inline-flex}.F1KBNa_langSelect:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_langLabel{text-overflow:ellipsis;white-space:nowrap;max-width:140px;overflow:hidden}";
|
|
11527
11529
|
const tagId = "dsh-diff-approval/PendingPanel.module.css";
|
|
11528
11530
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
11529
11531
|
const tag = document.createElement("style");
|
|
@@ -11533,49 +11535,62 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
11533
11535
|
document.head.appendChild(tag);
|
|
11534
11536
|
}
|
|
11535
11537
|
var PendingPanel_module_css_default = {
|
|
11536
|
-
"
|
|
11537
|
-
"
|
|
11538
|
-
"
|
|
11539
|
-
"
|
|
11540
|
-
"
|
|
11541
|
-
"
|
|
11542
|
-
"
|
|
11543
|
-
"
|
|
11544
|
-
"
|
|
11545
|
-
"
|
|
11546
|
-
"
|
|
11547
|
-
"
|
|
11548
|
-
"
|
|
11549
|
-
"
|
|
11550
|
-
"
|
|
11551
|
-
"
|
|
11552
|
-
"
|
|
11553
|
-
"
|
|
11554
|
-
"
|
|
11555
|
-
"
|
|
11556
|
-
"
|
|
11557
|
-
"
|
|
11558
|
-
"
|
|
11559
|
-
"
|
|
11560
|
-
"
|
|
11561
|
-
"
|
|
11562
|
-
"
|
|
11563
|
-
"
|
|
11564
|
-
"
|
|
11565
|
-
"
|
|
11566
|
-
"
|
|
11567
|
-
"
|
|
11568
|
-
"
|
|
11569
|
-
"
|
|
11570
|
-
"
|
|
11571
|
-
"
|
|
11572
|
-
"
|
|
11573
|
-
"
|
|
11574
|
-
"
|
|
11538
|
+
"lines": "F1KBNa_lines",
|
|
11539
|
+
"badge": "F1KBNa_badge",
|
|
11540
|
+
"readError": "F1KBNa_readError",
|
|
11541
|
+
"hint": "F1KBNa_hint",
|
|
11542
|
+
"diffStats": "F1KBNa_diffStats",
|
|
11543
|
+
"flexSpacer": "F1KBNa_flexSpacer",
|
|
11544
|
+
"code": "F1KBNa_code",
|
|
11545
|
+
"close": "F1KBNa_close",
|
|
11546
|
+
"diffPath": "F1KBNa_diffPath",
|
|
11547
|
+
"split": "F1KBNa_split",
|
|
11548
|
+
"missingHint": "F1KBNa_missingHint",
|
|
11549
|
+
"add": "F1KBNa_add",
|
|
11550
|
+
"diffBody": "F1KBNa_diffBody",
|
|
11551
|
+
"rowHead": "F1KBNa_rowHead",
|
|
11552
|
+
"diffActions": "F1KBNa_diffActions",
|
|
11553
|
+
"kindHint": "F1KBNa_kindHint",
|
|
11554
|
+
"badgeLabel": "F1KBNa_badgeLabel",
|
|
11555
|
+
"fileList": "F1KBNa_fileList",
|
|
11556
|
+
"rowMeta": "F1KBNa_rowMeta",
|
|
11557
|
+
"del": "F1KBNa_del",
|
|
11558
|
+
"langSelect": "F1KBNa_langSelect",
|
|
11559
|
+
"langLabel": "F1KBNa_langLabel",
|
|
11560
|
+
"title": "F1KBNa_title",
|
|
11561
|
+
"context": "F1KBNa_context",
|
|
11562
|
+
"rows": "F1KBNa_rows",
|
|
11563
|
+
"divergedHint": "F1KBNa_divergedHint",
|
|
11564
|
+
"states": "F1KBNa_states",
|
|
11565
|
+
"statusAction": "F1KBNa_statusAction",
|
|
11566
|
+
"kindTag": "F1KBNa_kindTag",
|
|
11567
|
+
"footerButtons": "F1KBNa_footerButtons",
|
|
11568
|
+
"gutter": "F1KBNa_gutter",
|
|
11569
|
+
"addCount": "F1KBNa_addCount",
|
|
11570
|
+
"line": "F1KBNa_line",
|
|
11571
|
+
"statusBar": "F1KBNa_statusBar",
|
|
11572
|
+
"detail": "F1KBNa_detail",
|
|
11573
|
+
"missing": "F1KBNa_missing",
|
|
11574
|
+
"resizeHandle": "F1KBNa_resizeHandle",
|
|
11575
|
+
"diffHeader": "F1KBNa_diffHeader",
|
|
11576
|
+
"group": "F1KBNa_group",
|
|
11577
|
+
"rail": "F1KBNa_rail",
|
|
11578
|
+
"iconAction": "F1KBNa_iconAction",
|
|
11579
|
+
"header": "F1KBNa_header",
|
|
11580
|
+
"row": "F1KBNa_row",
|
|
11581
|
+
"delCount": "F1KBNa_delCount",
|
|
11582
|
+
"action": "F1KBNa_action",
|
|
11583
|
+
"detailEmpty": "F1KBNa_detailEmpty",
|
|
11584
|
+
"badgeCount": "F1KBNa_badgeCount",
|
|
11585
|
+
"layer": "F1KBNa_layer",
|
|
11586
|
+
"rowPath": "F1KBNa_rowPath",
|
|
11587
|
+
"panel": "F1KBNa_panel",
|
|
11588
|
+
"note": "F1KBNa_note",
|
|
11589
|
+
"diff": "F1KBNa_diff"
|
|
11575
11590
|
};
|
|
11576
11591
|
//#endregion
|
|
11577
11592
|
//#region lib/types/client/PendingPanel.js
|
|
11578
|
-
/** Sidebar-foot pending-edit review action and the
|
|
11593
|
+
/** Sidebar-foot pending-edit review action and the split review panel it opens. */
|
|
11579
11594
|
/**
|
|
11580
11595
|
* How often the panel re-reads the pending list. An external plugin cannot
|
|
11581
11596
|
* register on the host's forwarded-event allowlist, so polling is its change
|
|
@@ -11583,6 +11598,29 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
11583
11598
|
* even with the panel closed. The read is one small RPC per second.
|
|
11584
11599
|
*/
|
|
11585
11600
|
const POLL_INTERVAL_MS = 1e3;
|
|
11601
|
+
/** Panel bottom offset when the composer cannot be measured, in px. */
|
|
11602
|
+
const FALLBACK_BOTTOM_PX = 128;
|
|
11603
|
+
/** Gap kept between the composer's top edge and the panel bottom, in px. */
|
|
11604
|
+
const COMPOSER_GAP_PX = 12;
|
|
11605
|
+
/** The harness composer seat (conversation scroll body + seat div). */
|
|
11606
|
+
const SCROLL_SELECTOR = "[data-conversation-scroll]";
|
|
11607
|
+
const SEAT_SELECTOR = "[data-composer-seat]";
|
|
11608
|
+
/** Seat height ui-conversation publishes for floating controls (its own seat observer). */
|
|
11609
|
+
const COMPOSER_HEIGHT_VAR = "--dsh-composer-height";
|
|
11610
|
+
/** Interactive composer/approval cards; clicking these keeps the panel open.
|
|
11611
|
+
Deliberately the cards themselves, not the seat: the approval frame's wide
|
|
11612
|
+
side gutters are blank space, so a click there must still close. */
|
|
11613
|
+
const KEEP_OPEN_SELECTOR = "[data-composer-card],[data-question-key] > *,[data-plan-review-key] > *";
|
|
11614
|
+
/** Seat counts as docked when its bottom is this close to the window bottom. */
|
|
11615
|
+
const DOCKED_TOLERANCE_PX = 48;
|
|
11616
|
+
/** File-list pane width bounds for the manual split drag, in px. */
|
|
11617
|
+
const MIN_LIST_WIDTH_PX = 160;
|
|
11618
|
+
const MAX_LIST_WIDTH_PX = 560;
|
|
11619
|
+
/** The trailing file-name segment of a path, used for row display. */
|
|
11620
|
+
function basenameOf(path) {
|
|
11621
|
+
const index = Math.max(path.lastIndexOf("/"), path.lastIndexOf("\\"));
|
|
11622
|
+
return index < 0 ? path : path.slice(index + 1);
|
|
11623
|
+
}
|
|
11586
11624
|
/** The diff body's row class per line kind. */
|
|
11587
11625
|
const ROW_CLASS = {
|
|
11588
11626
|
context: PendingPanel_module_css_default.context,
|
|
@@ -11610,19 +11648,144 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
11610
11648
|
});
|
|
11611
11649
|
return blocks;
|
|
11612
11650
|
}
|
|
11613
|
-
|
|
11614
|
-
|
|
11651
|
+
/** The diff-row index containing a node, or undefined. */
|
|
11652
|
+
function rowIndexAt(node) {
|
|
11653
|
+
if (node === null) return void 0;
|
|
11654
|
+
const row = (node instanceof Element ? node : node.parentElement)?.closest("[data-diff-row]");
|
|
11655
|
+
if (row === null || row === void 0) return void 0;
|
|
11656
|
+
const index = Number(row.dataset.diffRow);
|
|
11657
|
+
return Number.isFinite(index) ? index : void 0;
|
|
11658
|
+
}
|
|
11659
|
+
/** Character offset of a selection boundary within its line's code text. */
|
|
11660
|
+
function lineOffsetAt(node, offset) {
|
|
11661
|
+
const code = (node instanceof Element ? node : node.parentElement)?.closest("[data-diff-code]");
|
|
11662
|
+
if (code === null || code === void 0) return 0;
|
|
11663
|
+
let before = 0;
|
|
11664
|
+
const walker = document.createTreeWalker(code, NodeFilter.SHOW_TEXT);
|
|
11665
|
+
let current = walker.nextNode();
|
|
11666
|
+
while (current !== null) {
|
|
11667
|
+
if (current === node) return before + offset;
|
|
11668
|
+
if (node instanceof Element && node.contains(current)) break;
|
|
11669
|
+
before += current.length;
|
|
11670
|
+
current = walker.nextNode();
|
|
11671
|
+
}
|
|
11672
|
+
if (node instanceof Element) {
|
|
11673
|
+
const children = [...node.childNodes];
|
|
11674
|
+
for (let i = 0; i < Math.min(offset, children.length); i++) {
|
|
11675
|
+
const inner = document.createTreeWalker(children[i], NodeFilter.SHOW_TEXT);
|
|
11676
|
+
let text = inner.nextNode();
|
|
11677
|
+
while (text !== null) {
|
|
11678
|
+
before += text.length;
|
|
11679
|
+
text = inner.nextNode();
|
|
11680
|
+
}
|
|
11681
|
+
}
|
|
11682
|
+
}
|
|
11683
|
+
return before;
|
|
11684
|
+
}
|
|
11685
|
+
/** Length of the code text on the line holding a node. */
|
|
11686
|
+
function lineLengthAt(node) {
|
|
11687
|
+
return ((node instanceof Element ? node : node.parentElement)?.closest("[data-diff-code]"))?.textContent?.length ?? 0;
|
|
11688
|
+
}
|
|
11689
|
+
/**
|
|
11690
|
+
* Derive the selected diff-row range from a native text selection. A
|
|
11691
|
+
* boundary sitting exactly at a line edge contributes no content: a start at
|
|
11692
|
+
* the line's end skips to the next line, an end at the line's start falls
|
|
11693
|
+
* back to the previous line.
|
|
11694
|
+
*/
|
|
11695
|
+
function rowRangeOf(selection) {
|
|
11696
|
+
if (selection === null || selection.isCollapsed || selection.rangeCount === 0) return void 0;
|
|
11697
|
+
const range = selection.getRangeAt(0);
|
|
11698
|
+
let start = rowIndexAt(range.startContainer);
|
|
11699
|
+
let end = rowIndexAt(range.endContainer);
|
|
11700
|
+
if (start === void 0 || end === void 0) return void 0;
|
|
11701
|
+
if (lineOffsetAt(range.startContainer, range.startOffset) >= lineLengthAt(range.startContainer)) start += 1;
|
|
11702
|
+
if (lineOffsetAt(range.endContainer, range.endOffset) === 0) end -= 1;
|
|
11703
|
+
if (start > end) return void 0;
|
|
11704
|
+
return {
|
|
11705
|
+
start,
|
|
11706
|
+
end
|
|
11707
|
+
};
|
|
11708
|
+
}
|
|
11709
|
+
/** One row of the file list: the clickable head in the left pane. */
|
|
11710
|
+
function PendingFileRow({ file, selected, t, onSelect }) {
|
|
11711
|
+
const stats = (0, react.useMemo)(() => computeWholeFileDiff(file.oldText, file.newText), [file.oldText, file.newText]);
|
|
11712
|
+
return (0, react_jsx_runtime.jsx)("li", {
|
|
11713
|
+
className: PendingPanel_module_css_default.row,
|
|
11714
|
+
children: (0, react_jsx_runtime.jsxs)("button", {
|
|
11715
|
+
type: "button",
|
|
11716
|
+
className: PendingPanel_module_css_default.rowHead,
|
|
11717
|
+
"data-selected": selected || void 0,
|
|
11718
|
+
onClick: () => {
|
|
11719
|
+
onSelect(file.id);
|
|
11720
|
+
},
|
|
11721
|
+
children: [
|
|
11722
|
+
(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
11723
|
+
label: file.path,
|
|
11724
|
+
delayMs: 500,
|
|
11725
|
+
maxWidth: 560,
|
|
11726
|
+
children: (0, react_jsx_runtime.jsx)("span", {
|
|
11727
|
+
className: PendingPanel_module_css_default.rowPath,
|
|
11728
|
+
children: basenameOf(file.path)
|
|
11729
|
+
})
|
|
11730
|
+
}),
|
|
11731
|
+
file.kind === "create" && (0, react_jsx_runtime.jsx)("span", {
|
|
11732
|
+
className: PendingPanel_module_css_default.kindTag,
|
|
11733
|
+
children: t("row.create")
|
|
11734
|
+
}),
|
|
11735
|
+
file.missing && (0, react_jsx_runtime.jsx)("span", {
|
|
11736
|
+
className: PendingPanel_module_css_default.missing,
|
|
11737
|
+
title: t("panel.missingHint"),
|
|
11738
|
+
children: t("panel.missing")
|
|
11739
|
+
}),
|
|
11740
|
+
(0, react_jsx_runtime.jsxs)("span", {
|
|
11741
|
+
className: PendingPanel_module_css_default.rowMeta,
|
|
11742
|
+
children: [(0, react_jsx_runtime.jsx)("span", {
|
|
11743
|
+
className: PendingPanel_module_css_default.addCount,
|
|
11744
|
+
children: t("row.added", { added: stats.added })
|
|
11745
|
+
}), (0, react_jsx_runtime.jsx)("span", {
|
|
11746
|
+
className: PendingPanel_module_css_default.delCount,
|
|
11747
|
+
children: t("row.removed", { removed: stats.removed })
|
|
11748
|
+
})]
|
|
11749
|
+
})
|
|
11750
|
+
]
|
|
11751
|
+
})
|
|
11752
|
+
});
|
|
11753
|
+
}
|
|
11754
|
+
/** The selected file's diff, actions, jump controls, and copy toolbar. */
|
|
11755
|
+
function PendingDiff({ file, files, busy, t, onKeep, onRevert, onOpen }) {
|
|
11756
|
+
const [langOverride, setLangOverride] = (0, react.useState)(void 0);
|
|
11757
|
+
const [langMenuOpen, setLangMenuOpen] = (0, react.useState)(false);
|
|
11758
|
+
const langMenuItems = (0, react.useMemo)(() => [{
|
|
11759
|
+
id: "",
|
|
11760
|
+
label: t("action.langAuto")
|
|
11761
|
+
}, ...HIGHLIGHT_LANGS.map((language) => ({
|
|
11762
|
+
id: language,
|
|
11763
|
+
label: language
|
|
11764
|
+
}))], [t]);
|
|
11765
|
+
const detectedLang = (0, react.useMemo)(() => langFromPath(file.path), [file.path]);
|
|
11766
|
+
const lang = (0, react.useMemo)(() => langOverride ?? detectedLang, [detectedLang, langOverride]);
|
|
11767
|
+
const langLabel = langOverride ?? (detectedLang === void 0 ? t("action.langAuto") : t("action.langAutoDetected", { lang: detectedLang }));
|
|
11615
11768
|
const model = (0, react.useMemo)(() => {
|
|
11616
|
-
if (!selected) return void 0;
|
|
11617
11769
|
const diff = computeWholeFileDiff(file.oldText, file.newText);
|
|
11618
11770
|
return {
|
|
11619
11771
|
diff,
|
|
11620
|
-
blocks: changeBlocksOf(diff)
|
|
11621
|
-
|
|
11622
|
-
|
|
11772
|
+
blocks: changeBlocksOf(diff)
|
|
11773
|
+
};
|
|
11774
|
+
}, [file.oldText, file.newText]);
|
|
11775
|
+
const [runs, setRuns] = (0, react.useState)(void 0);
|
|
11776
|
+
(0, react.useEffect)(() => {
|
|
11777
|
+
setRuns(void 0);
|
|
11778
|
+
const timer = window.setTimeout(() => {
|
|
11779
|
+
setRuns({
|
|
11780
|
+
oldRuns: highlightLines(file.oldText, lang),
|
|
11781
|
+
newRuns: highlightLines(file.newText, lang)
|
|
11782
|
+
});
|
|
11783
|
+
}, 0);
|
|
11784
|
+
return () => {
|
|
11785
|
+
window.clearTimeout(timer);
|
|
11623
11786
|
};
|
|
11624
11787
|
}, [
|
|
11625
|
-
|
|
11788
|
+
file.id,
|
|
11626
11789
|
file.oldText,
|
|
11627
11790
|
file.newText,
|
|
11628
11791
|
lang
|
|
@@ -11630,24 +11793,24 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
11630
11793
|
const rowRefs = (0, react.useRef)(/* @__PURE__ */ new Map());
|
|
11631
11794
|
const bodyRef = (0, react.useRef)(null);
|
|
11632
11795
|
const [focus, setFocus] = (0, react.useState)(0);
|
|
11633
|
-
const [
|
|
11634
|
-
const [range, setRange] = (0, react.useState)();
|
|
11796
|
+
const [selection, setSelection] = (0, react.useState)(void 0);
|
|
11635
11797
|
const [copied, setCopied] = (0, react.useState)(false);
|
|
11636
11798
|
(0, react.useEffect)(() => {
|
|
11637
11799
|
setFocus(0);
|
|
11638
|
-
|
|
11639
|
-
|
|
11800
|
+
setSelection(void 0);
|
|
11801
|
+
setLangOverride(void 0);
|
|
11802
|
+
setLangMenuOpen(false);
|
|
11640
11803
|
setCopied(false);
|
|
11641
|
-
}, [file.id
|
|
11804
|
+
}, [file.id]);
|
|
11642
11805
|
(0, react.useEffect)(() => {
|
|
11643
|
-
if (model
|
|
11806
|
+
if (model.blocks.length === 0) return;
|
|
11644
11807
|
const block = model.blocks[focus];
|
|
11645
11808
|
if (block === void 0) return;
|
|
11646
11809
|
rowRefs.current.get(block.start)?.scrollIntoView({ block: "center" });
|
|
11647
11810
|
}, [model, focus]);
|
|
11648
11811
|
const jump = (direction) => {
|
|
11649
11812
|
setFocus((current) => {
|
|
11650
|
-
if (model
|
|
11813
|
+
if (model.blocks.length === 0) return current;
|
|
11651
11814
|
if (direction === -1) return (current - 1 + model.blocks.length) % model.blocks.length;
|
|
11652
11815
|
const bodyRect = bodyRef.current?.getBoundingClientRect();
|
|
11653
11816
|
for (let index = current + 1; index < model.blocks.length; index++) {
|
|
@@ -11663,220 +11826,251 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
11663
11826
|
if (element === null) rowRefs.current.delete(index);
|
|
11664
11827
|
else rowRefs.current.set(index, element);
|
|
11665
11828
|
};
|
|
11666
|
-
|
|
11667
|
-
|
|
11668
|
-
|
|
11669
|
-
|
|
11670
|
-
|
|
11671
|
-
|
|
11672
|
-
}
|
|
11673
|
-
|
|
11674
|
-
|
|
11675
|
-
|
|
11676
|
-
});
|
|
11677
|
-
};
|
|
11678
|
-
const rowMouseEnter = (index) => () => {
|
|
11679
|
-
setDrag((current) => {
|
|
11680
|
-
if (current === void 0) return current;
|
|
11681
|
-
const next = {
|
|
11682
|
-
...current,
|
|
11683
|
-
end: index
|
|
11684
|
-
};
|
|
11685
|
-
setRange({
|
|
11686
|
-
start: Math.min(next.anchor, next.end),
|
|
11687
|
-
end: Math.max(next.anchor, next.end)
|
|
11688
|
-
});
|
|
11689
|
-
return next;
|
|
11690
|
-
});
|
|
11691
|
-
};
|
|
11692
|
-
const endDrag = () => {
|
|
11693
|
-
setDrag((current) => {
|
|
11694
|
-
if (current === void 0) return void 0;
|
|
11695
|
-
setRange({
|
|
11696
|
-
start: Math.min(current.anchor, current.end),
|
|
11697
|
-
end: Math.max(current.anchor, current.end)
|
|
11698
|
-
});
|
|
11699
|
-
});
|
|
11700
|
-
};
|
|
11701
|
-
const selection = drag === void 0 && range !== void 0 && model !== void 0 ? range : void 0;
|
|
11702
|
-
const selectionTop = (() => {
|
|
11703
|
-
if (selection === void 0) return 0;
|
|
11704
|
-
const row = rowRefs.current.get(selection.start);
|
|
11705
|
-
const body = bodyRef.current;
|
|
11706
|
-
if (row === void 0 || body === null) return 0;
|
|
11707
|
-
const bodyTop = body.offsetTop;
|
|
11708
|
-
const rowTop = bodyTop + row.getBoundingClientRect().top - body.getBoundingClientRect().top;
|
|
11709
|
-
const clamped = Math.max(rowTop - 36, bodyTop);
|
|
11710
|
-
return Math.min(clamped, Math.max(bodyTop, bodyTop + body.clientHeight - 36));
|
|
11711
|
-
})();
|
|
11712
|
-
const copySelection = async () => {
|
|
11713
|
-
if (selection === void 0 || model === void 0) return;
|
|
11829
|
+
(0, react.useEffect)(() => {
|
|
11830
|
+
const update = () => setSelection(rowRangeOf(window.getSelection()));
|
|
11831
|
+
document.addEventListener("selectionchange", update);
|
|
11832
|
+
update();
|
|
11833
|
+
return () => {
|
|
11834
|
+
document.removeEventListener("selectionchange", update);
|
|
11835
|
+
};
|
|
11836
|
+
}, [file.id]);
|
|
11837
|
+
const selectionReference = (() => {
|
|
11838
|
+
if (selection === void 0) return void 0;
|
|
11714
11839
|
const lineNumbers = model.diff.rows.slice(selection.start, selection.end + 1).map((row) => row.newLine ?? row.oldLine).filter((number) => number !== void 0);
|
|
11715
|
-
if (lineNumbers.length === 0) return;
|
|
11716
|
-
|
|
11840
|
+
if (lineNumbers.length === 0) return void 0;
|
|
11841
|
+
return referenceOf(file.path, files, Math.min(...lineNumbers), Math.max(...lineNumbers));
|
|
11842
|
+
})();
|
|
11843
|
+
const copySelection = (0, react.useCallback)(async () => {
|
|
11844
|
+
if (selectionReference === void 0) return;
|
|
11845
|
+
if (!await (0, _deepseek_ai_dsh_client_ui_primitives.writeClipboard)(selectionReference)) return;
|
|
11717
11846
|
setCopied(true);
|
|
11718
11847
|
window.setTimeout(() => {
|
|
11719
11848
|
setCopied(false);
|
|
11720
11849
|
}, 1500);
|
|
11721
|
-
};
|
|
11850
|
+
}, [selectionReference]);
|
|
11851
|
+
(0, react.useEffect)(() => {
|
|
11852
|
+
const onKeyDown = (event) => {
|
|
11853
|
+
if (!(event.ctrlKey || event.metaKey) || event.altKey || event.shiftKey) return;
|
|
11854
|
+
if (event.key.toLowerCase() !== "l") return;
|
|
11855
|
+
if (selectionReference === void 0) return;
|
|
11856
|
+
event.preventDefault();
|
|
11857
|
+
copySelection();
|
|
11858
|
+
};
|
|
11859
|
+
document.addEventListener("keydown", onKeyDown);
|
|
11860
|
+
return () => {
|
|
11861
|
+
document.removeEventListener("keydown", onKeyDown);
|
|
11862
|
+
};
|
|
11863
|
+
}, [copySelection]);
|
|
11722
11864
|
/** One line's text: token spans when highlighted, plain text otherwise. */
|
|
11723
11865
|
const renderLine = (row) => {
|
|
11724
11866
|
const lineNumber = row.kind === "del" ? row.oldLine : row.newLine;
|
|
11725
|
-
const
|
|
11726
|
-
|
|
11727
|
-
|
|
11867
|
+
const sideRuns = row.kind === "del" ? runs?.oldRuns : runs?.newRuns;
|
|
11868
|
+
const lineRuns = lineNumber === void 0 ? void 0 : sideRuns?.[lineNumber - 1];
|
|
11869
|
+
if (lineRuns === void 0 || lineRuns.length === 0) return row.text === "" ? "\xA0" : row.text;
|
|
11870
|
+
return lineRuns.map((span, index) => (0, react_jsx_runtime.jsx)("span", {
|
|
11728
11871
|
style: span.style,
|
|
11729
11872
|
children: span.text
|
|
11730
11873
|
}, index));
|
|
11731
11874
|
};
|
|
11732
|
-
const focusedBlock = model
|
|
11875
|
+
const focusedBlock = model.blocks.length > 0 ? model.blocks[focus] : void 0;
|
|
11733
11876
|
const inFocusedBlock = (index) => focusedBlock !== void 0 && index >= focusedBlock.start && index <= focusedBlock.end;
|
|
11734
|
-
return (0, react_jsx_runtime.jsxs)("
|
|
11735
|
-
className: PendingPanel_module_css_default.
|
|
11736
|
-
|
|
11737
|
-
|
|
11738
|
-
|
|
11739
|
-
|
|
11740
|
-
|
|
11741
|
-
|
|
11742
|
-
|
|
11743
|
-
|
|
11744
|
-
|
|
11745
|
-
|
|
11746
|
-
|
|
11747
|
-
|
|
11748
|
-
|
|
11749
|
-
|
|
11750
|
-
|
|
11751
|
-
|
|
11752
|
-
|
|
11753
|
-
|
|
11754
|
-
|
|
11755
|
-
|
|
11756
|
-
|
|
11757
|
-
|
|
11758
|
-
|
|
11759
|
-
|
|
11760
|
-
|
|
11761
|
-
|
|
11762
|
-
|
|
11763
|
-
|
|
11764
|
-
|
|
11765
|
-
|
|
11766
|
-
|
|
11767
|
-
|
|
11768
|
-
|
|
11769
|
-
|
|
11770
|
-
|
|
11771
|
-
|
|
11772
|
-
|
|
11877
|
+
return (0, react_jsx_runtime.jsxs)("div", {
|
|
11878
|
+
className: PendingPanel_module_css_default.diff,
|
|
11879
|
+
"data-diff-approval-diff": true,
|
|
11880
|
+
children: [
|
|
11881
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
11882
|
+
className: PendingPanel_module_css_default.diffHeader,
|
|
11883
|
+
children: [
|
|
11884
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
11885
|
+
className: PendingPanel_module_css_default.diffPath,
|
|
11886
|
+
children: file.path
|
|
11887
|
+
}),
|
|
11888
|
+
(0, react_jsx_runtime.jsx)("button", {
|
|
11889
|
+
type: "button",
|
|
11890
|
+
className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.iconAction}`,
|
|
11891
|
+
"data-diff-open": true,
|
|
11892
|
+
"aria-label": t("action.openFile"),
|
|
11893
|
+
title: t("action.openFile"),
|
|
11894
|
+
onClick: () => {
|
|
11895
|
+
onOpen(file.sessionId, file.id, "open");
|
|
11896
|
+
},
|
|
11897
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconBrowseOutline16, { size: 14 })
|
|
11898
|
+
}),
|
|
11899
|
+
(0, react_jsx_runtime.jsx)("button", {
|
|
11900
|
+
type: "button",
|
|
11901
|
+
className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.iconAction}`,
|
|
11902
|
+
"data-diff-reveal": true,
|
|
11903
|
+
"aria-label": t("action.revealFile"),
|
|
11904
|
+
title: t("action.revealFile"),
|
|
11905
|
+
onClick: () => {
|
|
11906
|
+
onOpen(file.sessionId, file.id, "reveal");
|
|
11907
|
+
},
|
|
11908
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconFolderOpenOutline16, { size: 14 })
|
|
11909
|
+
})
|
|
11910
|
+
]
|
|
11911
|
+
}),
|
|
11912
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
11913
|
+
className: PendingPanel_module_css_default.diffActions,
|
|
11914
|
+
children: [
|
|
11915
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
11916
|
+
className: PendingPanel_module_css_default.diffStats,
|
|
11917
|
+
children: t("panel.stats", {
|
|
11918
|
+
added: model.diff.added,
|
|
11919
|
+
removed: model.diff.removed
|
|
11920
|
+
})
|
|
11921
|
+
}),
|
|
11922
|
+
file.kind === "create" && (0, react_jsx_runtime.jsx)("span", {
|
|
11923
|
+
className: PendingPanel_module_css_default.kindHint,
|
|
11924
|
+
children: t("panel.createHint")
|
|
11925
|
+
}),
|
|
11926
|
+
model.blocks.length > 0 && (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)("button", {
|
|
11927
|
+
type: "button",
|
|
11928
|
+
className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.iconAction}`,
|
|
11929
|
+
"data-diff-prev": true,
|
|
11930
|
+
"aria-label": t("action.prevDiff"),
|
|
11931
|
+
title: t("action.prevDiff"),
|
|
11932
|
+
disabled: busy,
|
|
11933
|
+
onClick: () => {
|
|
11934
|
+
jump(-1);
|
|
11935
|
+
},
|
|
11936
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronUpOutline14, { size: 14 })
|
|
11937
|
+
}), (0, react_jsx_runtime.jsx)("button", {
|
|
11938
|
+
type: "button",
|
|
11939
|
+
className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.iconAction}`,
|
|
11940
|
+
"data-diff-next": true,
|
|
11941
|
+
"aria-label": t("action.nextDiff"),
|
|
11942
|
+
title: t("action.nextDiff"),
|
|
11943
|
+
disabled: busy,
|
|
11944
|
+
onClick: () => {
|
|
11945
|
+
jump(1);
|
|
11946
|
+
},
|
|
11947
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { size: 14 })
|
|
11948
|
+
})] }),
|
|
11949
|
+
(0, react_jsx_runtime.jsx)("span", { className: PendingPanel_module_css_default.flexSpacer }),
|
|
11950
|
+
(0, react_jsx_runtime.jsx)("button", {
|
|
11951
|
+
type: "button",
|
|
11952
|
+
className: PendingPanel_module_css_default.action,
|
|
11953
|
+
"data-diff-keep": true,
|
|
11954
|
+
disabled: busy,
|
|
11955
|
+
onClick: () => {
|
|
11956
|
+
onKeep(file.sessionId, file.id);
|
|
11957
|
+
},
|
|
11958
|
+
children: busy ? t("action.busy") : t("action.keep")
|
|
11959
|
+
}),
|
|
11960
|
+
(0, react_jsx_runtime.jsx)("button", {
|
|
11961
|
+
type: "button",
|
|
11962
|
+
className: PendingPanel_module_css_default.action,
|
|
11963
|
+
"data-diff-revert": true,
|
|
11964
|
+
disabled: busy,
|
|
11965
|
+
onClick: () => {
|
|
11966
|
+
onRevert(file.sessionId, file.id);
|
|
11967
|
+
},
|
|
11968
|
+
children: busy ? t("action.busy") : t("action.revert")
|
|
11969
|
+
})
|
|
11970
|
+
]
|
|
11971
|
+
}),
|
|
11972
|
+
file.missing && (0, react_jsx_runtime.jsx)("p", {
|
|
11973
|
+
className: PendingPanel_module_css_default.missingHint,
|
|
11974
|
+
children: t("panel.missingHint")
|
|
11975
|
+
}),
|
|
11976
|
+
(0, react_jsx_runtime.jsx)("div", {
|
|
11977
|
+
className: PendingPanel_module_css_default.diffBody,
|
|
11978
|
+
ref: bodyRef,
|
|
11979
|
+
children: (0, react_jsx_runtime.jsx)("div", {
|
|
11980
|
+
className: PendingPanel_module_css_default.lines,
|
|
11981
|
+
children: model.diff.rows.map((row, index) => (0, react_jsx_runtime.jsxs)("div", {
|
|
11982
|
+
ref: registerRow(index),
|
|
11983
|
+
className: `${PendingPanel_module_css_default.line} ${ROW_CLASS[row.kind]}`,
|
|
11984
|
+
"data-diff-line": row.kind,
|
|
11985
|
+
"data-diff-row": index,
|
|
11986
|
+
"data-diff-focused": inFocusedBlock(index) ? "" : void 0,
|
|
11987
|
+
children: [
|
|
11988
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
11989
|
+
className: PendingPanel_module_css_default.gutter,
|
|
11990
|
+
children: row.oldLine ?? ""
|
|
11991
|
+
}),
|
|
11992
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
11993
|
+
className: PendingPanel_module_css_default.gutter,
|
|
11994
|
+
children: row.newLine ?? ""
|
|
11995
|
+
}),
|
|
11996
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
11997
|
+
className: PendingPanel_module_css_default.code,
|
|
11998
|
+
"data-diff-code": true,
|
|
11999
|
+
children: renderLine(row)
|
|
11773
12000
|
})
|
|
11774
|
-
|
|
11775
|
-
|
|
11776
|
-
|
|
11777
|
-
|
|
11778
|
-
|
|
11779
|
-
|
|
11780
|
-
|
|
11781
|
-
|
|
11782
|
-
|
|
11783
|
-
|
|
11784
|
-
|
|
11785
|
-
|
|
11786
|
-
|
|
11787
|
-
children: t("action.prevDiff")
|
|
11788
|
-
}), (0, react_jsx_runtime.jsx)("button", {
|
|
12001
|
+
]
|
|
12002
|
+
}, index))
|
|
12003
|
+
})
|
|
12004
|
+
}),
|
|
12005
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
12006
|
+
className: PendingPanel_module_css_default.statusBar,
|
|
12007
|
+
"data-diff-status-bar": true,
|
|
12008
|
+
children: [
|
|
12009
|
+
selectionReference === void 0 ? null : (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
12010
|
+
label: copied ? t("action.copied") : `${t("action.copyHint")} (Ctrl+L)`,
|
|
12011
|
+
side: "top",
|
|
12012
|
+
delayMs: 300,
|
|
12013
|
+
children: (0, react_jsx_runtime.jsx)("button", {
|
|
11789
12014
|
type: "button",
|
|
11790
|
-
className: PendingPanel_module_css_default.
|
|
11791
|
-
"data-diff-
|
|
11792
|
-
|
|
11793
|
-
|
|
11794
|
-
jump(1);
|
|
12015
|
+
className: PendingPanel_module_css_default.statusAction,
|
|
12016
|
+
"data-diff-copy": true,
|
|
12017
|
+
onMouseDown: (event) => {
|
|
12018
|
+
event.preventDefault();
|
|
11795
12019
|
},
|
|
11796
|
-
children: t("action.nextDiff")
|
|
11797
|
-
})] }),
|
|
11798
|
-
(0, react_jsx_runtime.jsx)("span", { className: PendingPanel_module_css_default.flexSpacer }),
|
|
11799
|
-
(0, react_jsx_runtime.jsx)("button", {
|
|
11800
|
-
type: "button",
|
|
11801
|
-
className: PendingPanel_module_css_default.action,
|
|
11802
|
-
"data-diff-keep": true,
|
|
11803
|
-
disabled: busy,
|
|
11804
12020
|
onClick: () => {
|
|
11805
|
-
|
|
12021
|
+
copySelection();
|
|
11806
12022
|
},
|
|
11807
|
-
children:
|
|
11808
|
-
})
|
|
11809
|
-
|
|
12023
|
+
children: copied ? t("action.copied") : selectionReference
|
|
12024
|
+
})
|
|
12025
|
+
}),
|
|
12026
|
+
(0, react_jsx_runtime.jsx)("span", { className: PendingPanel_module_css_default.flexSpacer }),
|
|
12027
|
+
(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Menu, {
|
|
12028
|
+
open: langMenuOpen,
|
|
12029
|
+
portal: true,
|
|
12030
|
+
compact: true,
|
|
12031
|
+
align: "end",
|
|
12032
|
+
items: langMenuItems,
|
|
12033
|
+
selectedId: langOverride ?? "",
|
|
12034
|
+
onSelect: (id) => {
|
|
12035
|
+
setLangOverride(id === "" ? void 0 : id);
|
|
12036
|
+
setLangMenuOpen(false);
|
|
12037
|
+
},
|
|
12038
|
+
onClose: () => {
|
|
12039
|
+
setLangMenuOpen(false);
|
|
12040
|
+
},
|
|
12041
|
+
anchor: (0, react_jsx_runtime.jsxs)("button", {
|
|
11810
12042
|
type: "button",
|
|
11811
|
-
className: PendingPanel_module_css_default.
|
|
11812
|
-
"data-diff-
|
|
11813
|
-
|
|
12043
|
+
className: PendingPanel_module_css_default.langSelect,
|
|
12044
|
+
"data-diff-lang": true,
|
|
12045
|
+
"aria-label": t("action.langSelect"),
|
|
12046
|
+
title: t("action.langSelect"),
|
|
11814
12047
|
onClick: () => {
|
|
11815
|
-
|
|
12048
|
+
setLangMenuOpen((value) => !value);
|
|
11816
12049
|
},
|
|
11817
|
-
children:
|
|
12050
|
+
children: [(0, react_jsx_runtime.jsx)("span", {
|
|
12051
|
+
className: PendingPanel_module_css_default.langLabel,
|
|
12052
|
+
children: langLabel
|
|
12053
|
+
}), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { size: 12 })]
|
|
11818
12054
|
})
|
|
11819
|
-
]
|
|
11820
|
-
}),
|
|
11821
|
-
file.missing && (0, react_jsx_runtime.jsx)("p", {
|
|
11822
|
-
className: PendingPanel_module_css_default.missingHint,
|
|
11823
|
-
children: t("panel.missingHint")
|
|
11824
|
-
}),
|
|
11825
|
-
(0, react_jsx_runtime.jsx)("div", {
|
|
11826
|
-
className: PendingPanel_module_css_default.diffBody,
|
|
11827
|
-
ref: bodyRef,
|
|
11828
|
-
children: (0, react_jsx_runtime.jsx)("div", {
|
|
11829
|
-
className: PendingPanel_module_css_default.lines,
|
|
11830
|
-
children: model.diff.rows.map((row, index) => (0, react_jsx_runtime.jsxs)("div", {
|
|
11831
|
-
ref: registerRow(index),
|
|
11832
|
-
className: `${PendingPanel_module_css_default.line} ${ROW_CLASS[row.kind]}`,
|
|
11833
|
-
"data-diff-line": row.kind,
|
|
11834
|
-
"data-diff-focused": inFocusedBlock(index) ? "" : void 0,
|
|
11835
|
-
onMouseDown: rowMouseDown(index),
|
|
11836
|
-
onMouseEnter: rowMouseEnter(index),
|
|
11837
|
-
children: [
|
|
11838
|
-
(0, react_jsx_runtime.jsx)("span", {
|
|
11839
|
-
className: PendingPanel_module_css_default.gutter,
|
|
11840
|
-
children: row.oldLine ?? ""
|
|
11841
|
-
}),
|
|
11842
|
-
(0, react_jsx_runtime.jsx)("span", {
|
|
11843
|
-
className: PendingPanel_module_css_default.gutter,
|
|
11844
|
-
children: row.newLine ?? ""
|
|
11845
|
-
}),
|
|
11846
|
-
(0, react_jsx_runtime.jsx)("span", {
|
|
11847
|
-
className: PendingPanel_module_css_default.code,
|
|
11848
|
-
children: renderLine(row)
|
|
11849
|
-
})
|
|
11850
|
-
]
|
|
11851
|
-
}, index))
|
|
11852
12055
|
})
|
|
11853
|
-
|
|
11854
|
-
|
|
11855
|
-
|
|
11856
|
-
style: { top: selectionTop },
|
|
11857
|
-
"data-diff-selection-toolbar": true,
|
|
11858
|
-
children: (0, react_jsx_runtime.jsx)("button", {
|
|
11859
|
-
type: "button",
|
|
11860
|
-
className: PendingPanel_module_css_default.toolbarButton,
|
|
11861
|
-
"data-diff-copy": true,
|
|
11862
|
-
onClick: () => {
|
|
11863
|
-
copySelection();
|
|
11864
|
-
},
|
|
11865
|
-
children: copied ? t("action.copied") : t("action.copyRange")
|
|
11866
|
-
})
|
|
11867
|
-
})
|
|
11868
|
-
]
|
|
11869
|
-
})]
|
|
12056
|
+
]
|
|
12057
|
+
})
|
|
12058
|
+
]
|
|
11870
12059
|
});
|
|
11871
12060
|
}
|
|
11872
12061
|
/** Render the pending-edit review panel and its unified footer action. */
|
|
11873
|
-
function PendingPanel({ wide, useSessions, usePending, onRefresh, onKeep, onRevert, t }) {
|
|
12062
|
+
function PendingPanel({ wide, useSessions, usePending, onRefresh, onKeep, onRevert, onOpen, t }) {
|
|
11874
12063
|
const current = useSessions((state) => state.current);
|
|
11875
12064
|
const snapshot = usePending((snapshot) => snapshot);
|
|
11876
12065
|
const [open, setOpen] = (0, react.useState)(false);
|
|
11877
12066
|
const [selected, setSelected] = (0, react.useState)("");
|
|
11878
12067
|
/** Pending count captured at open time; auto-close needs a list that emptied. */
|
|
11879
12068
|
const [openedCount, setOpenedCount] = (0, react.useState)(0);
|
|
12069
|
+
/** Bottom offset tracking the chat composer's top edge so the input stays visible. */
|
|
12070
|
+
const [bottomPx, setBottomPx] = (0, react.useState)(FALLBACK_BOTTOM_PX);
|
|
12071
|
+
/** File-list pane width, adjustable by dragging the divider. */
|
|
12072
|
+
const [listWidth, setListWidth] = (0, react.useState)(240);
|
|
12073
|
+
const resizeDrag = (0, react.useRef)(null);
|
|
11880
12074
|
(0, react.useEffect)(() => {
|
|
11881
12075
|
onRefresh(current);
|
|
11882
12076
|
const timer = setInterval(() => {
|
|
@@ -11886,9 +12080,63 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
11886
12080
|
clearInterval(timer);
|
|
11887
12081
|
};
|
|
11888
12082
|
}, [current, onRefresh]);
|
|
12083
|
+
(0, react.useEffect)(() => {
|
|
12084
|
+
if (!open) return;
|
|
12085
|
+
const MEASURE_INTERVAL_MS = 400;
|
|
12086
|
+
const measure = () => {
|
|
12087
|
+
const scrollers = document.querySelectorAll(SCROLL_SELECTOR);
|
|
12088
|
+
for (const scroller of scrollers) {
|
|
12089
|
+
const seat = scroller.querySelector(SEAT_SELECTOR);
|
|
12090
|
+
if (seat === null) continue;
|
|
12091
|
+
const seatRect = seat.getBoundingClientRect();
|
|
12092
|
+
if (!(seatRect.bottom >= window.innerHeight - DOCKED_TOLERANCE_PX && seatRect.top > 0 && seatRect.top < window.innerHeight)) continue;
|
|
12093
|
+
const height = Number.parseFloat(scroller.style.getPropertyValue(COMPOSER_HEIGHT_VAR));
|
|
12094
|
+
const clearance = Number.isFinite(height) && height > 0 ? height : window.innerHeight - seatRect.top;
|
|
12095
|
+
setBottomPx(Math.round(clearance) + COMPOSER_GAP_PX);
|
|
12096
|
+
return;
|
|
12097
|
+
}
|
|
12098
|
+
setBottomPx(FALLBACK_BOTTOM_PX);
|
|
12099
|
+
};
|
|
12100
|
+
measure();
|
|
12101
|
+
const seats = [...document.querySelectorAll(SEAT_SELECTOR)];
|
|
12102
|
+
const observer = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(measure);
|
|
12103
|
+
for (const seat of seats) observer?.observe(seat);
|
|
12104
|
+
const timer = window.setInterval(measure, MEASURE_INTERVAL_MS);
|
|
12105
|
+
window.addEventListener("resize", measure);
|
|
12106
|
+
return () => {
|
|
12107
|
+
observer?.disconnect();
|
|
12108
|
+
window.clearInterval(timer);
|
|
12109
|
+
window.removeEventListener("resize", measure);
|
|
12110
|
+
};
|
|
12111
|
+
}, [open]);
|
|
12112
|
+
(0, react.useEffect)(() => {
|
|
12113
|
+
if (!open) return;
|
|
12114
|
+
const onPointerDown = (event) => {
|
|
12115
|
+
const target = event.target;
|
|
12116
|
+
if (target === null) return;
|
|
12117
|
+
const element = target instanceof Element ? target : target.parentElement;
|
|
12118
|
+
if (element !== null && (element.closest("[data-diff-approval-panel]") !== null || element.closest("[data-diff-approval-badge]") !== null || element.closest(KEEP_OPEN_SELECTOR) !== null)) return;
|
|
12119
|
+
setOpen(false);
|
|
12120
|
+
};
|
|
12121
|
+
document.addEventListener("pointerdown", onPointerDown, true);
|
|
12122
|
+
return () => {
|
|
12123
|
+
document.removeEventListener("pointerdown", onPointerDown, true);
|
|
12124
|
+
};
|
|
12125
|
+
}, [open]);
|
|
11889
12126
|
const files = snapshot.files;
|
|
11890
12127
|
const mine = files.filter((file) => file.sessionId === current);
|
|
11891
12128
|
const theirs = files.filter((file) => file.sessionId !== current);
|
|
12129
|
+
(0, react.useEffect)(() => {
|
|
12130
|
+
if (!open) return;
|
|
12131
|
+
if (selected !== "" && files.some((file) => file.id === selected)) return;
|
|
12132
|
+
const next = [...mine, ...theirs][0];
|
|
12133
|
+
if (next !== void 0 && next.id !== selected) setSelected(next.id);
|
|
12134
|
+
}, [
|
|
12135
|
+
open,
|
|
12136
|
+
current,
|
|
12137
|
+
files,
|
|
12138
|
+
selected
|
|
12139
|
+
]);
|
|
11892
12140
|
(0, react.useEffect)(() => {
|
|
11893
12141
|
if (open && openedCount > 0 && snapshot.read && snapshot.error === void 0 && files.length === 0) {
|
|
11894
12142
|
setOpenedCount(0);
|
|
@@ -11905,30 +12153,64 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
11905
12153
|
if (!open) setOpenedCount(files.length);
|
|
11906
12154
|
setOpen((value) => !value);
|
|
11907
12155
|
};
|
|
11908
|
-
const renderEntry = (entry) => (0, react_jsx_runtime.jsx)(
|
|
12156
|
+
const renderEntry = (entry) => (0, react_jsx_runtime.jsx)(PendingFileRow, {
|
|
11909
12157
|
file: entry,
|
|
11910
|
-
files,
|
|
11911
12158
|
selected: selected === entry.id,
|
|
11912
|
-
busy: snapshot.busy.has(entry.id),
|
|
11913
12159
|
t,
|
|
11914
|
-
onSelect: setSelected
|
|
11915
|
-
onKeep,
|
|
11916
|
-
onRevert
|
|
12160
|
+
onSelect: setSelected
|
|
11917
12161
|
}, entry.id);
|
|
12162
|
+
const selectedFile = files.find((file) => file.id === selected);
|
|
12163
|
+
/** Drag the list/detail divider; width follows the pointer within its bounds. */
|
|
12164
|
+
const startResize = (event) => {
|
|
12165
|
+
if (event.button !== 0) return;
|
|
12166
|
+
event.preventDefault();
|
|
12167
|
+
resizeDrag.current = {
|
|
12168
|
+
startX: event.clientX,
|
|
12169
|
+
startWidth: listWidth
|
|
12170
|
+
};
|
|
12171
|
+
document.body.style.userSelect = "none";
|
|
12172
|
+
document.body.style.cursor = "col-resize";
|
|
12173
|
+
const onMove = (move) => {
|
|
12174
|
+
const start = resizeDrag.current;
|
|
12175
|
+
if (start === null) return;
|
|
12176
|
+
const next = start.startWidth + (move.clientX - start.startX);
|
|
12177
|
+
setListWidth(Math.min(Math.max(next, MIN_LIST_WIDTH_PX), MAX_LIST_WIDTH_PX));
|
|
12178
|
+
};
|
|
12179
|
+
const onUp = () => {
|
|
12180
|
+
resizeDrag.current = null;
|
|
12181
|
+
document.body.style.userSelect = "";
|
|
12182
|
+
document.body.style.cursor = "";
|
|
12183
|
+
window.removeEventListener("mousemove", onMove);
|
|
12184
|
+
window.removeEventListener("mouseup", onUp);
|
|
12185
|
+
};
|
|
12186
|
+
window.addEventListener("mousemove", onMove);
|
|
12187
|
+
window.addEventListener("mouseup", onUp);
|
|
12188
|
+
};
|
|
11918
12189
|
return (0, react_jsx_runtime.jsxs)("div", {
|
|
11919
12190
|
className: wide ? PendingPanel_module_css_default.layer : `${PendingPanel_module_css_default.layer} ${PendingPanel_module_css_default.rail}`,
|
|
11920
12191
|
children: [open && (0, react_jsx_runtime.jsxs)("section", {
|
|
11921
12192
|
className: PendingPanel_module_css_default.panel,
|
|
12193
|
+
style: { bottom: bottomPx },
|
|
11922
12194
|
"data-diff-approval-panel": true,
|
|
11923
12195
|
"aria-label": t("panel.title"),
|
|
11924
|
-
children: [(0, react_jsx_runtime.
|
|
12196
|
+
children: [(0, react_jsx_runtime.jsxs)("header", {
|
|
11925
12197
|
className: PendingPanel_module_css_default.header,
|
|
11926
|
-
children: (0, react_jsx_runtime.jsx)("span", {
|
|
12198
|
+
children: [(0, react_jsx_runtime.jsx)("span", {
|
|
11927
12199
|
className: PendingPanel_module_css_default.title,
|
|
11928
12200
|
children: t("panel.title")
|
|
11929
|
-
})
|
|
11930
|
-
|
|
11931
|
-
|
|
12201
|
+
}), (0, react_jsx_runtime.jsx)("button", {
|
|
12202
|
+
type: "button",
|
|
12203
|
+
className: PendingPanel_module_css_default.close,
|
|
12204
|
+
"data-diff-approval-close": true,
|
|
12205
|
+
"aria-label": t("action.close"),
|
|
12206
|
+
title: t("action.close"),
|
|
12207
|
+
onClick: () => {
|
|
12208
|
+
setOpen(false);
|
|
12209
|
+
},
|
|
12210
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCloseOutline16, { size: 14 })
|
|
12211
|
+
})]
|
|
12212
|
+
}), snapshot.error !== void 0 || !snapshot.read || files.length === 0 ? (0, react_jsx_runtime.jsxs)("div", {
|
|
12213
|
+
className: PendingPanel_module_css_default.states,
|
|
11932
12214
|
children: [
|
|
11933
12215
|
snapshot.error !== void 0 && (0, react_jsx_runtime.jsx)("p", {
|
|
11934
12216
|
className: PendingPanel_module_css_default.readError,
|
|
@@ -11942,25 +12224,49 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
11942
12224
|
snapshot.read && snapshot.error === void 0 && files.length === 0 && (0, react_jsx_runtime.jsx)("p", {
|
|
11943
12225
|
className: PendingPanel_module_css_default.note,
|
|
11944
12226
|
children: t("panel.empty")
|
|
12227
|
+
})
|
|
12228
|
+
]
|
|
12229
|
+
}) : (0, react_jsx_runtime.jsxs)("div", {
|
|
12230
|
+
className: PendingPanel_module_css_default.split,
|
|
12231
|
+
children: [
|
|
12232
|
+
(0, react_jsx_runtime.jsxs)("nav", {
|
|
12233
|
+
className: PendingPanel_module_css_default.fileList,
|
|
12234
|
+
style: { width: listWidth },
|
|
12235
|
+
"data-diff-approval-file-list": true,
|
|
12236
|
+
children: [mine.length > 0 && (0, react_jsx_runtime.jsxs)("section", { children: [(0, react_jsx_runtime.jsx)("h3", {
|
|
12237
|
+
className: PendingPanel_module_css_default.group,
|
|
12238
|
+
children: t("panel.group.current")
|
|
12239
|
+
}), (0, react_jsx_runtime.jsx)("ul", {
|
|
12240
|
+
className: PendingPanel_module_css_default.rows,
|
|
12241
|
+
children: mine.map(renderEntry)
|
|
12242
|
+
})] }), theirs.length > 0 && (0, react_jsx_runtime.jsxs)("section", { children: [(0, react_jsx_runtime.jsx)("h3", {
|
|
12243
|
+
className: PendingPanel_module_css_default.group,
|
|
12244
|
+
children: t("panel.group.others")
|
|
12245
|
+
}), (0, react_jsx_runtime.jsx)("ul", {
|
|
12246
|
+
className: PendingPanel_module_css_default.rows,
|
|
12247
|
+
children: theirs.map(renderEntry)
|
|
12248
|
+
})] })]
|
|
11945
12249
|
}),
|
|
11946
|
-
|
|
11947
|
-
className: PendingPanel_module_css_default.
|
|
11948
|
-
|
|
12250
|
+
(0, react_jsx_runtime.jsx)("div", {
|
|
12251
|
+
className: PendingPanel_module_css_default.resizeHandle,
|
|
12252
|
+
"data-diff-resize": true,
|
|
12253
|
+
onMouseDown: startResize
|
|
11949
12254
|
}),
|
|
11950
|
-
|
|
11951
|
-
className: PendingPanel_module_css_default.
|
|
11952
|
-
children:
|
|
11953
|
-
|
|
11954
|
-
|
|
11955
|
-
|
|
11956
|
-
|
|
11957
|
-
|
|
11958
|
-
|
|
11959
|
-
|
|
11960
|
-
|
|
11961
|
-
|
|
11962
|
-
|
|
11963
|
-
|
|
12255
|
+
(0, react_jsx_runtime.jsx)("div", {
|
|
12256
|
+
className: PendingPanel_module_css_default.detail,
|
|
12257
|
+
children: selectedFile === void 0 ? (0, react_jsx_runtime.jsx)("p", {
|
|
12258
|
+
className: PendingPanel_module_css_default.detailEmpty,
|
|
12259
|
+
children: t("panel.selectHint")
|
|
12260
|
+
}) : (0, react_jsx_runtime.jsx)(PendingDiff, {
|
|
12261
|
+
file: selectedFile,
|
|
12262
|
+
files,
|
|
12263
|
+
busy: snapshot.busy.has(selectedFile.id),
|
|
12264
|
+
t,
|
|
12265
|
+
onKeep,
|
|
12266
|
+
onRevert,
|
|
12267
|
+
onOpen
|
|
12268
|
+
})
|
|
12269
|
+
})
|
|
11964
12270
|
]
|
|
11965
12271
|
})]
|
|
11966
12272
|
}), (0, react_jsx_runtime.jsx)("div", {
|
|
@@ -11969,7 +12275,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
11969
12275
|
type: "button",
|
|
11970
12276
|
className: PendingPanel_module_css_default.badge,
|
|
11971
12277
|
"data-diff-approval-badge": files.length,
|
|
11972
|
-
"data-active": open
|
|
12278
|
+
"data-active": open ? "" : void 0,
|
|
11973
12279
|
"aria-label": t("panel.aria"),
|
|
11974
12280
|
"aria-expanded": open,
|
|
11975
12281
|
onClick: toggleOpen,
|
|
@@ -12018,6 +12324,13 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12018
12324
|
sessionId,
|
|
12019
12325
|
id
|
|
12020
12326
|
}));
|
|
12327
|
+
},
|
|
12328
|
+
async open(sessionId, id, action) {
|
|
12329
|
+
return openOf(await rpc.call(DIFF_APPROVAL_CHANNEL, "open", {
|
|
12330
|
+
sessionId,
|
|
12331
|
+
id,
|
|
12332
|
+
action
|
|
12333
|
+
}));
|
|
12021
12334
|
}
|
|
12022
12335
|
};
|
|
12023
12336
|
}
|
|
@@ -12066,6 +12379,15 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12066
12379
|
if (outcome !== "kept" && outcome !== "reverted" && outcome !== "missing") throw new Error("the action returned a malformed outcome");
|
|
12067
12380
|
return { outcome };
|
|
12068
12381
|
}
|
|
12382
|
+
/** Narrow the open endpoint's value; a malformed wire value is an open failure. */
|
|
12383
|
+
function openOf(result) {
|
|
12384
|
+
if (!result.ok) throw new Error(`${result.error.code}: ${result.error.message}`);
|
|
12385
|
+
const value = result.value;
|
|
12386
|
+
if (typeof value !== "object" || value === null) throw new Error("the action returned a malformed value");
|
|
12387
|
+
const outcome = value.outcome;
|
|
12388
|
+
if (outcome !== "opened" && outcome !== "missing") throw new Error("the action returned a malformed outcome");
|
|
12389
|
+
return { outcome };
|
|
12390
|
+
}
|
|
12069
12391
|
//#endregion
|
|
12070
12392
|
//#region lib/types/client/store.js
|
|
12071
12393
|
/**
|
|
@@ -12158,6 +12480,16 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12158
12480
|
await port.revert(sessionId, id);
|
|
12159
12481
|
});
|
|
12160
12482
|
},
|
|
12483
|
+
async open(sessionId, id, action) {
|
|
12484
|
+
try {
|
|
12485
|
+
await port.open(sessionId, id, action);
|
|
12486
|
+
} catch (error) {
|
|
12487
|
+
publish({
|
|
12488
|
+
...snapshot,
|
|
12489
|
+
error: error instanceof Error ? error.message : String(error)
|
|
12490
|
+
});
|
|
12491
|
+
}
|
|
12492
|
+
},
|
|
12161
12493
|
reset() {
|
|
12162
12494
|
publish({
|
|
12163
12495
|
read: false,
|
|
@@ -12181,18 +12513,26 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12181
12513
|
"panel.group.others": "其他会话",
|
|
12182
12514
|
"panel.aria": "待处理改动",
|
|
12183
12515
|
"panel.stats": "+{added} -{removed}",
|
|
12184
|
-
"panel.selectHint": "
|
|
12516
|
+
"panel.selectHint": "点击每项查看整个文件的差异;选中文本后,用底部状态栏或 Ctrl+L 复制引用",
|
|
12185
12517
|
"panel.missing": "文件已不存在",
|
|
12186
12518
|
"panel.missingHint": "该文件已不存在,回退会恢复该文件。",
|
|
12187
12519
|
"panel.createHint": "回退会删除该新建的文件。",
|
|
12188
12520
|
"row.create": "新增文件",
|
|
12521
|
+
"row.added": "+{added}",
|
|
12522
|
+
"row.removed": "-{removed}",
|
|
12189
12523
|
"action.keep": "保留",
|
|
12190
12524
|
"action.revert": "回退",
|
|
12525
|
+
"action.openFile": "打开文件",
|
|
12526
|
+
"action.revealFile": "打开所在目录",
|
|
12191
12527
|
"action.busy": "处理中…",
|
|
12192
12528
|
"action.prevDiff": "上一处差异",
|
|
12193
12529
|
"action.nextDiff": "下一处差异",
|
|
12194
|
-
"action.
|
|
12530
|
+
"action.copyHint": "复制引用",
|
|
12195
12531
|
"action.copied": "已复制",
|
|
12532
|
+
"action.langAuto": "自动",
|
|
12533
|
+
"action.langAutoDetected": "自动:{lang}",
|
|
12534
|
+
"action.langSelect": "高亮语言",
|
|
12535
|
+
"action.close": "关闭",
|
|
12196
12536
|
"status.kept": "已保留",
|
|
12197
12537
|
"status.reverted": "已回退",
|
|
12198
12538
|
"status.missing": "该改动已不存在"
|
|
@@ -12207,18 +12547,26 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12207
12547
|
"panel.group.others": "Other sessions",
|
|
12208
12548
|
"panel.aria": "Pending changes",
|
|
12209
12549
|
"panel.stats": "+{added} -{removed}",
|
|
12210
|
-
"panel.selectHint": "Select an item to review its whole-file diff;
|
|
12550
|
+
"panel.selectHint": "Select an item to review its whole-file diff; select text and copy its reference from the status bar (Ctrl+L)",
|
|
12211
12551
|
"panel.missing": "File is gone",
|
|
12212
12552
|
"panel.missingHint": "This file no longer exists; reverting restores it.",
|
|
12213
12553
|
"panel.createHint": "Reverting removes this created file.",
|
|
12214
12554
|
"row.create": "New file",
|
|
12555
|
+
"row.added": "+{added}",
|
|
12556
|
+
"row.removed": "-{removed}",
|
|
12215
12557
|
"action.keep": "Keep",
|
|
12216
12558
|
"action.revert": "Revert",
|
|
12559
|
+
"action.openFile": "Open file",
|
|
12560
|
+
"action.revealFile": "Reveal in folder",
|
|
12217
12561
|
"action.busy": "Working…",
|
|
12218
12562
|
"action.prevDiff": "Previous diff",
|
|
12219
12563
|
"action.nextDiff": "Next diff",
|
|
12220
|
-
"action.
|
|
12564
|
+
"action.copyHint": "Copy reference",
|
|
12221
12565
|
"action.copied": "Copied",
|
|
12566
|
+
"action.langAuto": "Auto",
|
|
12567
|
+
"action.langAutoDetected": "Auto: {lang}",
|
|
12568
|
+
"action.langSelect": "Highlight language",
|
|
12569
|
+
"action.close": "Close",
|
|
12222
12570
|
"status.kept": "Kept",
|
|
12223
12571
|
"status.reverted": "Reverted",
|
|
12224
12572
|
"status.missing": "This change no longer exists"
|
|
@@ -12256,7 +12604,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12256
12604
|
store.refresh(sessionId);
|
|
12257
12605
|
},
|
|
12258
12606
|
onKeep: (sessionId, path) => store.keep(sessionId, path),
|
|
12259
|
-
onRevert: (sessionId, path) => store.revert(sessionId, path)
|
|
12607
|
+
onRevert: (sessionId, path) => store.revert(sessionId, path),
|
|
12608
|
+
onOpen: (sessionId, id, action) => store.open(sessionId, id, action)
|
|
12260
12609
|
})
|
|
12261
12610
|
}, PendingPanel));
|
|
12262
12611
|
}
|