dsh-diff-approval 0.6.0 → 0.8.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 +18 -10
- package/README.zh.md +18 -10
- package/docs/images/pending-panel.png +0 -0
- package/docs/images/pending-panel.zh.png +0 -0
- package/lib/client.js +1017 -265
- package/lib/index.js +614 -13
- package/lib/types/client/PendingPanel.d.ts +11 -1
- package/lib/types/client/SettingsTab.d.ts +11 -0
- package/lib/types/client/locales.d.ts +40 -0
- package/lib/types/client/port.d.ts +7 -1
- package/lib/types/client/settings.d.ts +19 -0
- package/lib/types/client/slots.d.ts +11 -1
- package/lib/types/client/store.d.ts +7 -1
- package/lib/types/pending.d.ts +12 -0
- package/lib/types/types.d.ts +13 -2
- package/lib/types/vcs.d.ts +89 -0
- package/package.json +3 -1
package/lib/client.js
CHANGED
|
@@ -11620,8 +11620,39 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
11620
11620
|
return `${referencePathOf(path, workspacePath)}:${lineRangeLabel(start, end)}`;
|
|
11621
11621
|
}
|
|
11622
11622
|
//#endregion
|
|
11623
|
+
//#region lib/types/client/settings.js
|
|
11624
|
+
/** Client preferences for the review panel, persisted in localStorage. */
|
|
11625
|
+
const PASTE_ON_COPY_KEY = "diff-approval:paste-on-copy";
|
|
11626
|
+
const IMPORT_UNTRACKED_KEY = "diff-approval:import-untracked";
|
|
11627
|
+
/**
|
|
11628
|
+
* Whether copying a reference should also paste it into the chat input and
|
|
11629
|
+
* focus it. Defaults to on; only an explicit `'0'` disables it.
|
|
11630
|
+
* @returns whether auto-paste is enabled.
|
|
11631
|
+
*/
|
|
11632
|
+
function pasteOnCopyEnabled() {
|
|
11633
|
+
return localStorage.getItem(PASTE_ON_COPY_KEY) !== "0";
|
|
11634
|
+
}
|
|
11635
|
+
/** Persist the auto-paste preference. */
|
|
11636
|
+
function setPasteOnCopyEnabled(value) {
|
|
11637
|
+
localStorage.setItem(PASTE_ON_COPY_KEY, value ? "1" : "0");
|
|
11638
|
+
}
|
|
11639
|
+
/**
|
|
11640
|
+
* Whether importing workspace VCS changes includes new/untracked files (git
|
|
11641
|
+
* `??`, svn `?`, p4 unversioned). Defaults to off: collecting them scans the
|
|
11642
|
+
* whole workspace, which can be slow on large trees, so the preference is
|
|
11643
|
+
* opt-in. Only an explicit `'1'` enables it.
|
|
11644
|
+
* @returns whether untracked files are imported.
|
|
11645
|
+
*/
|
|
11646
|
+
function includeUntrackedEnabled() {
|
|
11647
|
+
return localStorage.getItem(IMPORT_UNTRACKED_KEY) === "1";
|
|
11648
|
+
}
|
|
11649
|
+
/** Persist the import-untracked preference. */
|
|
11650
|
+
function setIncludeUntrackedEnabled(value) {
|
|
11651
|
+
localStorage.setItem(IMPORT_UNTRACKED_KEY, value ? "1" : "0");
|
|
11652
|
+
}
|
|
11653
|
+
//#endregion
|
|
11623
11654
|
//#region \0dsh-css:/home/runner/work/dsh-diff-approval/dsh-diff-approval/src/client/PendingPanel.module.css.mjs
|
|
11624
|
-
const css = ".F1KBNa_layer{box-sizing:border-box;flex:none;align-items:center;width:calc(100% + 8px);height:42px;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:42px;color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border:none;border-radius:12px;align-items:center;gap:8px;padding:0 10px 0 8px;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;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_headerActions{align-items:center;gap:2px;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_actionPrimary{background:var(--dsw-alias-state-business-primary);border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-static-neutral-bluish-50)}.F1KBNa_actionPrimary:hover:not(:disabled){background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 85%, var(--dsw-static-neutral-bluish-1000))}.F1KBNa_actionPrimary:disabled{background:var(--dsw-alias-state-business-primary);color:var(--dsw-static-neutral-bluish-50);opacity:.55}.F1KBNa_iconAction{justify-content:center;align-items:center;min-height:25px;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_expand{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_expand:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_expandExpanded svg{transform:rotate(180deg)}.F1KBNa_diffBodyWrap{flex:1;min-height:0;display:flex;position:relative}.F1KBNa_diffBody{min-width:0;font:var(--dsw-font-markdown-code-block);cursor:text;flex:1;padding:0;position:relative;overflow:auto}.F1KBNa_diffBody::-webkit-scrollbar,.F1KBNa_diffBody::-webkit-scrollbar-track,.F1KBNa_diffBody::-webkit-scrollbar-thumb{cursor:default}.F1KBNa_blockActions{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-markdown-code-block);box-shadow:var(--dsw-shadow-lv1);z-index:2;border-radius:10px;align-items:center;gap:4px;padding:4px;display:flex;position:absolute;right:6px}.F1KBNa_overviewRuler{pointer-events:none;opacity:.5;width:4px;position:absolute;top:0;bottom:0;right:0}.F1KBNa_overviewMarker{border-radius:2px;width:100%;min-height:2px;position:absolute;right:0}.F1KBNa_markerDel{background-color:var(--dsw-alias-state-error-primary)}.F1KBNa_markerAdd{background-color:var(--dsw-alias-state-success-primary)}.F1KBNa_lines{border-spacing:0;width:max-content;min-width:100%;display:table}.F1KBNa_line{height:22px;line-height:22px;display:table-row}.F1KBNa_vSpacer{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;cursor:default;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}";
|
|
11655
|
+
const css = ".F1KBNa_layer{box-sizing:border-box;flex:none;align-items:center;width:calc(100% + 4px);height:42px;margin:4px -2px;display:flex;position:relative}.F1KBNa_footerButtons{align-items:center;width:100%;display:flex}.F1KBNa_badge{box-sizing:border-box;width:100%;height:42px;color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border:none;border-radius:12px;align-items:center;gap:8px;padding:0 10px 0 8px;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_badge:disabled{color:var(--dsw-alias-label-tertiary);cursor:default;background:0 0}.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;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_fullscreenBackdrop{z-index:29;background:var(--dsw-specific-sidebar-fill);position:fixed;inset:0}.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_headerActions{align-items:center;gap:2px;display:flex}.F1KBNa_settingsPage{padding:8px 12px}.F1KBNa_settingsRow{border-bottom:1px solid var(--dsw-alias-border-l2);align-items:center;gap:8px;padding:16px 0;display:flex}.F1KBNa_settingsRowText{flex-direction:column;flex:1;gap:4px;min-width:0;padding-right:48px;display:flex}.F1KBNa_settingsRowTitle{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:400;line-height:22px}.F1KBNa_settingsRowDesc{color:var(--dsw-alias-label-tertiary);font-size:12px;font-weight:400;line-height:18px}.F1KBNa_settingsSelector{background:var(--dsw-alias-bg-module-platform);height:36px;font:inherit;color:var(--dsw-alias-label-primary);cursor:pointer;border:none;border-radius:18px;align-items:center;gap:12px;padding:0 14px;font-size:14px;line-height:22px;display:inline-flex}.F1KBNa_settingsSelector:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_settingsSelectorChevron{flex:none}.F1KBNa_states{flex-direction:column;flex:1;min-height:0;padding:4px 12px 12px;display:flex;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-direction:column;flex:none;width:240px;min-height:0;padding:4px 8px 12px;display:flex}.F1KBNa_listScroll{flex:1;min-height:0;overflow-y:auto}.F1KBNa_bulkActions{flex:none;gap:6px;padding-top:8px;display:flex}.F1KBNa_bulkActions .F1KBNa_action{text-align:center;flex:1}.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_noteCentered{text-align:center;margin:auto}.F1KBNa_emptyState{flex-direction:column;align-items:center;gap:10px;margin:auto;display:flex}.F1KBNa_importButton{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border-radius:8px;padding:5px 14px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_importButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_importButton:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.F1KBNa_importNote{color:var(--dsw-alias-label-tertiary);text-align:center;margin: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_rowFailed{border:1px solid var(--dsw-alias-state-error-primary);color:var(--dsw-alias-state-error-primary);white-space:nowrap;border-radius:6px;flex:none;padding:1px 6px;font-size:11px;line-height:14px}.F1KBNa_actionError{border-bottom:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-state-error-primary);overflow-wrap:anywhere;margin:0;padding:6px 8px;font-size:12px;line-height:18px}.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_actionPrimary{background:var(--dsw-alias-state-business-primary);border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-static-neutral-bluish-50)}.F1KBNa_actionPrimary:hover:not(:disabled){background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 85%, var(--dsw-static-neutral-bluish-1000))}.F1KBNa_actionPrimary:disabled{background:var(--dsw-alias-state-business-primary);color:var(--dsw-static-neutral-bluish-50);opacity:.55}.F1KBNa_actionQuietDisabled:disabled{cursor:pointer;color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-border-l1);background:0 0}.F1KBNa_actionPrimary.F1KBNa_actionQuietDisabled:disabled{background:var(--dsw-alias-state-business-primary);border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-static-neutral-bluish-50);opacity:1}.F1KBNa_iconAction{justify-content:center;align-items:center;min-height:25px;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_expand{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_expand:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_expandExpanded svg{transform:rotate(180deg)}.F1KBNa_diffBodyWrap{flex:1;min-height:0;display:flex;position:relative}.F1KBNa_diffBody{min-width:0;font:var(--dsw-font-markdown-code-block);cursor:text;outline:none;flex:1;padding:0;position:relative;overflow:auto}.F1KBNa_diffBody::-webkit-scrollbar,.F1KBNa_diffBody::-webkit-scrollbar-track,.F1KBNa_diffBody::-webkit-scrollbar-thumb{cursor:default}.F1KBNa_blockActions{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-markdown-code-block);box-shadow:var(--dsw-shadow-lv1);z-index:2;border-radius:10px;align-items:center;gap:9px;padding:5px;display:flex;position:absolute;right:8px}.F1KBNa_blockPosition{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;white-space:nowrap;margin-top:1px;margin-left:7px;font-size:12px;line-height:16px}.F1KBNa_searchBar{z-index:3;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-markdown-code-block);box-shadow:var(--dsw-shadow-lv1);border-radius:10px;align-items:center;gap:4px;padding:4px;display:flex;position:absolute;top:8px;right:8px}.F1KBNa_searchInput{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);width:150px;color:var(--dsw-alias-label-primary);border-radius:6px;outline:none;padding:3px 8px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_searchInput:focus{border-color:var(--dsw-alias-state-business-primary)}.F1KBNa_searchCount{text-align:center;min-width:34px;color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;white-space:nowrap;font-size:12px;line-height:16px}.F1KBNa_diffBody [data-diff-search=hit]{background-image:linear-gradient(#facc1529,#facc1529)}.F1KBNa_diffBody [data-diff-search=current]{background-image:linear-gradient(#facc1552,#facc1552)}.F1KBNa_blockFlash{z-index:1;box-sizing:border-box;border:2px solid var(--dsw-alias-state-business-primary);pointer-events:none;border-radius:4px;animation:1s ease-out forwards F1KBNa_diffFlash;position:absolute;left:0;right:0}@keyframes F1KBNa_diffFlash{0%{opacity:1}to{opacity:0}}.F1KBNa_overviewRuler{pointer-events:none;opacity:.5;width:4px;position:absolute;top:0;bottom:0;right:0}.F1KBNa_overviewMarker{border-radius:2px;width:100%;min-height:2px;position:absolute;right:0}.F1KBNa_markerDel{background-color:var(--dsw-alias-state-error-primary)}.F1KBNa_markerAdd{background-color:var(--dsw-alias-state-success-primary)}.F1KBNa_lines{border-spacing:0;width:max-content;min-width:100%;display:table}.F1KBNa_line{height:22px;line-height:22px;display:table-row}.F1KBNa_vSpacer{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;cursor:default;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}";
|
|
11625
11656
|
const tagId = "dsh-diff-approval/PendingPanel.module.css";
|
|
11626
11657
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
11627
11658
|
const tag = document.createElement("style");
|
|
@@ -11631,69 +11662,92 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
11631
11662
|
document.head.appendChild(tag);
|
|
11632
11663
|
}
|
|
11633
11664
|
var PendingPanel_module_css_default = {
|
|
11634
|
-
"diffHeader": "F1KBNa_diffHeader",
|
|
11635
|
-
"missing": "F1KBNa_missing",
|
|
11636
|
-
"resizeHandle": "F1KBNa_resizeHandle",
|
|
11637
|
-
"diffBody": "F1KBNa_diffBody",
|
|
11638
|
-
"rowPath": "F1KBNa_rowPath",
|
|
11639
11665
|
"expandExpanded": "F1KBNa_expandExpanded",
|
|
11640
|
-
"
|
|
11641
|
-
"
|
|
11642
|
-
"
|
|
11666
|
+
"panel": "F1KBNa_panel",
|
|
11667
|
+
"fullscreenBackdrop": "F1KBNa_fullscreenBackdrop",
|
|
11668
|
+
"settingsPage": "F1KBNa_settingsPage",
|
|
11669
|
+
"hint": "F1KBNa_hint",
|
|
11670
|
+
"row": "F1KBNa_row",
|
|
11671
|
+
"title": "F1KBNa_title",
|
|
11672
|
+
"blockActions": "F1KBNa_blockActions",
|
|
11673
|
+
"langLabel": "F1KBNa_langLabel",
|
|
11643
11674
|
"detailEmpty": "F1KBNa_detailEmpty",
|
|
11644
|
-
"
|
|
11675
|
+
"del": "F1KBNa_del",
|
|
11676
|
+
"listScroll": "F1KBNa_listScroll",
|
|
11645
11677
|
"close": "F1KBNa_close",
|
|
11646
|
-
"
|
|
11647
|
-
"statusBar": "F1KBNa_statusBar",
|
|
11648
|
-
"diffStats": "F1KBNa_diffStats",
|
|
11649
|
-
"footerButtons": "F1KBNa_footerButtons",
|
|
11650
|
-
"title": "F1KBNa_title",
|
|
11651
|
-
"row": "F1KBNa_row",
|
|
11652
|
-
"delCount": "F1KBNa_delCount",
|
|
11653
|
-
"expand": "F1KBNa_expand",
|
|
11654
|
-
"layer": "F1KBNa_layer",
|
|
11678
|
+
"group": "F1KBNa_group",
|
|
11655
11679
|
"diffActions": "F1KBNa_diffActions",
|
|
11656
|
-
"
|
|
11657
|
-
"
|
|
11658
|
-
"
|
|
11659
|
-
"
|
|
11660
|
-
"
|
|
11680
|
+
"diffBodyWrap": "F1KBNa_diffBodyWrap",
|
|
11681
|
+
"states": "F1KBNa_states",
|
|
11682
|
+
"searchInput": "F1KBNa_searchInput",
|
|
11683
|
+
"settingsRowText": "F1KBNa_settingsRowText",
|
|
11684
|
+
"note": "F1KBNa_note",
|
|
11685
|
+
"addCount": "F1KBNa_addCount",
|
|
11686
|
+
"layer": "F1KBNa_layer",
|
|
11687
|
+
"diff": "F1KBNa_diff",
|
|
11661
11688
|
"add": "F1KBNa_add",
|
|
11662
|
-
"
|
|
11663
|
-
"
|
|
11689
|
+
"overviewMarker": "F1KBNa_overviewMarker",
|
|
11690
|
+
"settingsRowDesc": "F1KBNa_settingsRowDesc",
|
|
11691
|
+
"actionQuietDisabled": "F1KBNa_actionQuietDisabled",
|
|
11692
|
+
"searchCount": "F1KBNa_searchCount",
|
|
11664
11693
|
"badgeCount": "F1KBNa_badgeCount",
|
|
11665
|
-
"
|
|
11694
|
+
"context": "F1KBNa_context",
|
|
11695
|
+
"settingsSelectorChevron": "F1KBNa_settingsSelectorChevron",
|
|
11696
|
+
"kindHint": "F1KBNa_kindHint",
|
|
11697
|
+
"footerButtons": "F1KBNa_footerButtons",
|
|
11698
|
+
"diffHeader": "F1KBNa_diffHeader",
|
|
11699
|
+
"resizeHandle": "F1KBNa_resizeHandle",
|
|
11700
|
+
"statusBar": "F1KBNa_statusBar",
|
|
11701
|
+
"rowPath": "F1KBNa_rowPath",
|
|
11702
|
+
"settingsSelector": "F1KBNa_settingsSelector",
|
|
11703
|
+
"importButton": "F1KBNa_importButton",
|
|
11704
|
+
"markerAdd": "F1KBNa_markerAdd",
|
|
11705
|
+
"header": "F1KBNa_header",
|
|
11706
|
+
"settingsRowTitle": "F1KBNa_settingsRowTitle",
|
|
11707
|
+
"emptyState": "F1KBNa_emptyState",
|
|
11666
11708
|
"rail": "F1KBNa_rail",
|
|
11667
|
-
"
|
|
11668
|
-
"hint": "F1KBNa_hint",
|
|
11669
|
-
"code": "F1KBNa_code",
|
|
11670
|
-
"detail": "F1KBNa_detail",
|
|
11671
|
-
"readError": "F1KBNa_readError",
|
|
11709
|
+
"diffFlash": "F1KBNa_diffFlash",
|
|
11672
11710
|
"action": "F1KBNa_action",
|
|
11673
|
-
"
|
|
11711
|
+
"detail": "F1KBNa_detail",
|
|
11712
|
+
"rowMeta": "F1KBNa_rowMeta",
|
|
11713
|
+
"actionError": "F1KBNa_actionError",
|
|
11714
|
+
"diffStats": "F1KBNa_diffStats",
|
|
11715
|
+
"flexSpacer": "F1KBNa_flexSpacer",
|
|
11716
|
+
"diffBody": "F1KBNa_diffBody",
|
|
11674
11717
|
"statusAction": "F1KBNa_statusAction",
|
|
11675
|
-
"
|
|
11676
|
-
"
|
|
11677
|
-
"
|
|
11678
|
-
"
|
|
11679
|
-
"
|
|
11718
|
+
"readError": "F1KBNa_readError",
|
|
11719
|
+
"kindTag": "F1KBNa_kindTag",
|
|
11720
|
+
"delCount": "F1KBNa_delCount",
|
|
11721
|
+
"blockPosition": "F1KBNa_blockPosition",
|
|
11722
|
+
"overviewRuler": "F1KBNa_overviewRuler",
|
|
11723
|
+
"rowFailed": "F1KBNa_rowFailed",
|
|
11724
|
+
"headerActions": "F1KBNa_headerActions",
|
|
11725
|
+
"divergedHint": "F1KBNa_divergedHint",
|
|
11726
|
+
"code": "F1KBNa_code",
|
|
11727
|
+
"noteCentered": "F1KBNa_noteCentered",
|
|
11728
|
+
"expand": "F1KBNa_expand",
|
|
11680
11729
|
"vSpacer": "F1KBNa_vSpacer",
|
|
11681
|
-
"
|
|
11682
|
-
"
|
|
11683
|
-
"gutter": "F1KBNa_gutter",
|
|
11730
|
+
"importNote": "F1KBNa_importNote",
|
|
11731
|
+
"settingsRow": "F1KBNa_settingsRow",
|
|
11684
11732
|
"split": "F1KBNa_split",
|
|
11685
|
-
"
|
|
11686
|
-
"overviewRuler": "F1KBNa_overviewRuler",
|
|
11687
|
-
"rowMeta": "F1KBNa_rowMeta",
|
|
11688
|
-
"addCount": "F1KBNa_addCount",
|
|
11689
|
-
"diff": "F1KBNa_diff",
|
|
11690
|
-
"fileList": "F1KBNa_fileList",
|
|
11733
|
+
"missing": "F1KBNa_missing",
|
|
11691
11734
|
"actionPrimary": "F1KBNa_actionPrimary",
|
|
11692
|
-
"
|
|
11693
|
-
"
|
|
11694
|
-
"del": "F1KBNa_del",
|
|
11735
|
+
"blockFlash": "F1KBNa_blockFlash",
|
|
11736
|
+
"langSelect": "F1KBNa_langSelect",
|
|
11695
11737
|
"badge": "F1KBNa_badge",
|
|
11696
|
-
"
|
|
11738
|
+
"diffPath": "F1KBNa_diffPath",
|
|
11739
|
+
"iconAction": "F1KBNa_iconAction",
|
|
11740
|
+
"markerDel": "F1KBNa_markerDel",
|
|
11741
|
+
"bulkActions": "F1KBNa_bulkActions",
|
|
11742
|
+
"gutter": "F1KBNa_gutter",
|
|
11743
|
+
"rowHead": "F1KBNa_rowHead",
|
|
11744
|
+
"searchBar": "F1KBNa_searchBar",
|
|
11745
|
+
"fileList": "F1KBNa_fileList",
|
|
11746
|
+
"lines": "F1KBNa_lines",
|
|
11747
|
+
"rows": "F1KBNa_rows",
|
|
11748
|
+
"missingHint": "F1KBNa_missingHint",
|
|
11749
|
+
"line": "F1KBNa_line",
|
|
11750
|
+
"badgeLabel": "F1KBNa_badgeLabel"
|
|
11697
11751
|
};
|
|
11698
11752
|
//#endregion
|
|
11699
11753
|
//#region lib/types/client/PendingPanel.js
|
|
@@ -11727,25 +11781,55 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
11727
11781
|
const MAX_LIST_WIDTH_PX = 560;
|
|
11728
11782
|
/** Fixed diff-row height in px; the virtual window and jump math are built on it. */
|
|
11729
11783
|
const ROW_HEIGHT_PX = 22;
|
|
11784
|
+
/** The overview ruler's width in px (mirrors `.overviewRuler`). The flash is
|
|
11785
|
+
* kept off it even when the scroller has no vertical scrollbar. */
|
|
11786
|
+
const OVERVIEW_RULER_WIDTH_PX = 4;
|
|
11730
11787
|
/** Rows rendered beyond the visible window in each direction. */
|
|
11731
11788
|
const OVERSCAN_ROWS = 8;
|
|
11789
|
+
/** Height of the floating per-block Keep/Revert frame in px: 26px actions +
|
|
11790
|
+
* 5px frame padding on each side + 1px border on each side, plus a little
|
|
11791
|
+
* breathing room so the bottom padding never sits flush against it. */
|
|
11792
|
+
const BLOCK_ACTIONS_FRAME_PX = 40;
|
|
11793
|
+
/** How long a fully-processed list stays open before the panel folds, so the
|
|
11794
|
+
* last action (a Keep-all/Revert-all especially) can still be undone with
|
|
11795
|
+
* Ctrl+Z. An undo that restores an entry cancels the pending close. */
|
|
11796
|
+
const EMPTY_CLOSE_GRACE_MS = 3e3;
|
|
11732
11797
|
/** The trailing file-name segment of a path, used for row display. */
|
|
11733
11798
|
function basenameOf(path) {
|
|
11734
11799
|
const index = Math.max(path.lastIndexOf("/"), path.lastIndexOf("\\"));
|
|
11735
11800
|
return index < 0 ? path : path.slice(index + 1);
|
|
11736
11801
|
}
|
|
11802
|
+
/**
|
|
11803
|
+
* Open the DSH settings dialog and switch to this plugin's section. The
|
|
11804
|
+
* settings shell keeps its open state and the active section id as
|
|
11805
|
+
* component-local viewing state with no cross-plugin service, so the dialog
|
|
11806
|
+
* is opened by clicking the sidebar's settings trigger and then the nav cell
|
|
11807
|
+
* for this section. `element.click()` still fires React's delegated click
|
|
11808
|
+
* handlers, reaching the same state transitions a user gesture would.
|
|
11809
|
+
* @param sectionLabel - the nav label of this plugin's settings section.
|
|
11810
|
+
*/
|
|
11811
|
+
function openSettingsSection(sectionLabel) {
|
|
11812
|
+
const trigger = document.querySelector("button[aria-haspopup=\"dialog\"]");
|
|
11813
|
+
if (trigger === null) return;
|
|
11814
|
+
trigger.click();
|
|
11815
|
+
requestAnimationFrame(() => {
|
|
11816
|
+
Array.from(document.querySelectorAll("button")).find((button) => button.textContent?.trim() === sectionLabel)?.click();
|
|
11817
|
+
});
|
|
11818
|
+
}
|
|
11737
11819
|
/** The diff body's row class per line kind. */
|
|
11738
11820
|
const ROW_CLASS = {
|
|
11739
11821
|
context: PendingPanel_module_css_default.context,
|
|
11740
11822
|
del: PendingPanel_module_css_default.del,
|
|
11741
11823
|
add: PendingPanel_module_css_default.add
|
|
11742
11824
|
};
|
|
11825
|
+
/** Empty failure map reused as the snapshot's canonical absent value. */
|
|
11826
|
+
const EMPTY_FAILED_MAP = /* @__PURE__ */ new Map();
|
|
11743
11827
|
/**
|
|
11744
11828
|
* One rendered diff row, memoized so a poll or an unrelated state change
|
|
11745
11829
|
* does not re-render rows whose content, highlight, and focus are unchanged.
|
|
11746
11830
|
*/
|
|
11747
11831
|
const DiffRow = (0, react.memo)(function DiffRow(props) {
|
|
11748
|
-
const { index, row, runs, focused, onRowHover } = props;
|
|
11832
|
+
const { index, row, runs, focused, searchHit, searchCurrent, onRowHover } = props;
|
|
11749
11833
|
const lineNumber = row.kind === "del" ? row.oldLine : row.newLine;
|
|
11750
11834
|
const sideRuns = row.kind === "del" ? runs?.oldRuns : runs?.newRuns;
|
|
11751
11835
|
const lineRuns = lineNumber === void 0 ? void 0 : sideRuns?.[lineNumber - 1];
|
|
@@ -11758,6 +11842,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
11758
11842
|
"data-diff-line": row.kind,
|
|
11759
11843
|
"data-diff-row": index,
|
|
11760
11844
|
"data-diff-focused": focused ? "" : void 0,
|
|
11845
|
+
"data-diff-search": searchHit ? searchCurrent ? "current" : "hit" : void 0,
|
|
11761
11846
|
onMouseEnter: () => {
|
|
11762
11847
|
onRowHover(index);
|
|
11763
11848
|
},
|
|
@@ -11900,7 +11985,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
11900
11985
|
};
|
|
11901
11986
|
}
|
|
11902
11987
|
/** One row of the file list: the clickable head in the left pane. */
|
|
11903
|
-
function PendingFileRow({ file, selected, t, onSelect }) {
|
|
11988
|
+
function PendingFileRow({ file, selected, failedMessage, t, onSelect }) {
|
|
11904
11989
|
const stats = (0, react.useMemo)(() => computeWholeFileDiff(file.oldText, file.newText), [file.oldText, file.newText]);
|
|
11905
11990
|
return (0, react_jsx_runtime.jsx)("li", {
|
|
11906
11991
|
className: PendingPanel_module_css_default.row,
|
|
@@ -11929,6 +12014,11 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
11929
12014
|
title: t("panel.missingHint"),
|
|
11930
12015
|
children: t("panel.missing")
|
|
11931
12016
|
}),
|
|
12017
|
+
failedMessage !== void 0 && (0, react_jsx_runtime.jsx)("span", {
|
|
12018
|
+
className: PendingPanel_module_css_default.rowFailed,
|
|
12019
|
+
title: failedMessage,
|
|
12020
|
+
children: t("row.failed")
|
|
12021
|
+
}),
|
|
11932
12022
|
(0, react_jsx_runtime.jsxs)("span", {
|
|
11933
12023
|
className: PendingPanel_module_css_default.rowMeta,
|
|
11934
12024
|
children: [(0, react_jsx_runtime.jsx)("span", {
|
|
@@ -11945,7 +12035,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
11945
12035
|
});
|
|
11946
12036
|
}
|
|
11947
12037
|
/** The selected file's diff, actions, jump controls, and copy toolbar. */
|
|
11948
|
-
function PendingDiff({ file, busy, workspacePath, t, onKeep, onRevert, onBlockKeep, onBlockRevert, onOpen }) {
|
|
12038
|
+
function PendingDiff({ file, busy, workspacePath, jumpSignal, undoFlash, failedMessage, onPasteReference, t, onKeep, onRevert, onBlockKeep, onBlockRevert, onOpen }) {
|
|
11949
12039
|
const [langOverride, setLangOverride] = (0, react.useState)(void 0);
|
|
11950
12040
|
const [langMenuOpen, setLangMenuOpen] = (0, react.useState)(false);
|
|
11951
12041
|
const langMenuItems = (0, react.useMemo)(() => [{
|
|
@@ -12026,19 +12116,76 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12026
12116
|
const [hoveredBlock, setHoveredBlock] = (0, react.useState)(void 0);
|
|
12027
12117
|
const [selection, setSelection] = (0, react.useState)(void 0);
|
|
12028
12118
|
const [copied, setCopied] = (0, react.useState)(false);
|
|
12119
|
+
const [searchOpen, setSearchOpen] = (0, react.useState)(false);
|
|
12120
|
+
const [searchQuery, setSearchQuery] = (0, react.useState)("");
|
|
12121
|
+
const [searchIndex, setSearchIndex] = (0, react.useState)(0);
|
|
12122
|
+
const searchInputRef = (0, react.useRef)(null);
|
|
12123
|
+
const [flashKey, setFlashKey] = (0, react.useState)(0);
|
|
12029
12124
|
(0, react.useEffect)(() => {
|
|
12030
12125
|
setFocus(0);
|
|
12031
12126
|
setScrollTop(0);
|
|
12032
12127
|
if (bodyRef.current !== null) bodyRef.current.scrollTop = 0;
|
|
12128
|
+
bodyRef.current?.focus();
|
|
12129
|
+
setFlashKey((key) => key + 1);
|
|
12033
12130
|
setHoveredBlock(void 0);
|
|
12034
12131
|
setSelection(void 0);
|
|
12035
12132
|
setLangOverride(void 0);
|
|
12036
12133
|
setLangMenuOpen(false);
|
|
12037
12134
|
setCopied(false);
|
|
12135
|
+
setSearchOpen(false);
|
|
12136
|
+
setSearchQuery("");
|
|
12137
|
+
setSearchIndex(0);
|
|
12038
12138
|
}, [file.id]);
|
|
12139
|
+
(0, react.useEffect)(() => {
|
|
12140
|
+
if (undoFlash === 0) return;
|
|
12141
|
+
setFocus(0);
|
|
12142
|
+
setScrollTick((tick) => tick + 1);
|
|
12143
|
+
setFlashKey((key) => key + 1);
|
|
12144
|
+
}, [undoFlash]);
|
|
12039
12145
|
const blockRanges = (0, react.useMemo)(() => {
|
|
12040
12146
|
return model.blocks.map((block) => blockRangesOf(model.diff.rows, block));
|
|
12041
12147
|
}, [model]);
|
|
12148
|
+
const searchMatches = (0, react.useMemo)(() => {
|
|
12149
|
+
if (searchQuery === "") return [];
|
|
12150
|
+
const lower = searchQuery.toLowerCase();
|
|
12151
|
+
const matches = [];
|
|
12152
|
+
for (let index = 0; index < model.diff.rows.length; index++) if (model.diff.rows[index].text.toLowerCase().includes(lower)) matches.push(index);
|
|
12153
|
+
return matches;
|
|
12154
|
+
}, [model, searchQuery]);
|
|
12155
|
+
const searchHitSet = (0, react.useMemo)(() => new Set(searchMatches), [searchMatches]);
|
|
12156
|
+
const currentSearchRow = searchMatches.length === 0 ? void 0 : searchMatches[searchIndex % searchMatches.length];
|
|
12157
|
+
const goSearch = (direction) => {
|
|
12158
|
+
if (searchMatches.length === 0) return;
|
|
12159
|
+
setSearchIndex((current) => (current + direction + searchMatches.length) % searchMatches.length);
|
|
12160
|
+
};
|
|
12161
|
+
const toggleSearch = () => {
|
|
12162
|
+
if (searchOpen) {
|
|
12163
|
+
setSearchOpen(false);
|
|
12164
|
+
setSearchQuery("");
|
|
12165
|
+
setSearchIndex(0);
|
|
12166
|
+
} else setSearchOpen(true);
|
|
12167
|
+
};
|
|
12168
|
+
const closeSearch = () => {
|
|
12169
|
+
setSearchOpen(false);
|
|
12170
|
+
setSearchQuery("");
|
|
12171
|
+
setSearchIndex(0);
|
|
12172
|
+
};
|
|
12173
|
+
(0, react.useEffect)(() => {
|
|
12174
|
+
if (searchOpen) searchInputRef.current?.focus();
|
|
12175
|
+
}, [searchOpen]);
|
|
12176
|
+
(0, react.useEffect)(() => {
|
|
12177
|
+
setSearchIndex(0);
|
|
12178
|
+
}, [searchQuery, file.id]);
|
|
12179
|
+
(0, react.useLayoutEffect)(() => {
|
|
12180
|
+
const row = currentSearchRow;
|
|
12181
|
+
if (row === void 0) return;
|
|
12182
|
+
const body = bodyRef.current;
|
|
12183
|
+
if (body === null) return;
|
|
12184
|
+
const target = row * ROW_HEIGHT_PX + ROW_HEIGHT_PX / 2 - body.clientHeight / 2;
|
|
12185
|
+
const clamped = Math.max(0, Math.min(target, body.scrollHeight - body.clientHeight));
|
|
12186
|
+
if (body.scrollTop !== clamped) body.scrollTop = clamped;
|
|
12187
|
+
setScrollTop(clamped);
|
|
12188
|
+
}, [currentSearchRow, searchMatches]);
|
|
12042
12189
|
const blockIndexByRow = (0, react.useMemo)(() => {
|
|
12043
12190
|
const map = /* @__PURE__ */ new Map();
|
|
12044
12191
|
model.blocks.forEach((block, blockIndex) => {
|
|
@@ -12055,6 +12202,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12055
12202
|
const start = Math.max(0, Math.floor(scrollTop / ROW_HEIGHT_PX) - OVERSCAN_ROWS);
|
|
12056
12203
|
const end = Math.min(rowCount, Math.ceil((scrollTop + viewport) / ROW_HEIGHT_PX) + OVERSCAN_ROWS);
|
|
12057
12204
|
const visibleRows = rows.slice(start, end);
|
|
12205
|
+
const hoveredBlockEnd = hoveredBlock !== void 0 ? model.blocks[hoveredBlock]?.end : void 0;
|
|
12206
|
+
const blockActionsPadPx = hoveredBlockEnd === void 0 ? 0 : Math.max(0, (hoveredBlockEnd + 1) * ROW_HEIGHT_PX + BLOCK_ACTIONS_FRAME_PX - rowCount * ROW_HEIGHT_PX);
|
|
12058
12207
|
const widestLine = (0, react.useMemo)(() => {
|
|
12059
12208
|
let widest = 0;
|
|
12060
12209
|
for (const row of model.diff.rows) if (row.text.length > widest) widest = row.text.length;
|
|
@@ -12073,7 +12222,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12073
12222
|
observer?.disconnect();
|
|
12074
12223
|
};
|
|
12075
12224
|
}, [file.id]);
|
|
12076
|
-
(0, react.
|
|
12225
|
+
(0, react.useLayoutEffect)(() => {
|
|
12077
12226
|
if (rowCount === 0) return;
|
|
12078
12227
|
const block = model.blocks[focus];
|
|
12079
12228
|
if (block === void 0) return;
|
|
@@ -12102,7 +12251,12 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12102
12251
|
return 0;
|
|
12103
12252
|
});
|
|
12104
12253
|
setScrollTick((tick) => tick + 1);
|
|
12254
|
+
setFlashKey((key) => key + 1);
|
|
12105
12255
|
};
|
|
12256
|
+
(0, react.useEffect)(() => {
|
|
12257
|
+
if (jumpSignal === 0) return;
|
|
12258
|
+
jump(1);
|
|
12259
|
+
}, [jumpSignal]);
|
|
12106
12260
|
const onScroll = () => {
|
|
12107
12261
|
const body = bodyRef.current;
|
|
12108
12262
|
if (body === null) return;
|
|
@@ -12127,10 +12281,15 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12127
12281
|
if (selectionReference === void 0) return;
|
|
12128
12282
|
if (!await (0, _deepseek_ai_dsh_client_ui_primitives.writeClipboard)(selectionReference)) return;
|
|
12129
12283
|
setCopied(true);
|
|
12284
|
+
if (pasteOnCopyEnabled()) onPasteReference(file.sessionId, selectionReference);
|
|
12130
12285
|
window.setTimeout(() => {
|
|
12131
12286
|
setCopied(false);
|
|
12132
12287
|
}, 1500);
|
|
12133
|
-
}, [
|
|
12288
|
+
}, [
|
|
12289
|
+
file.sessionId,
|
|
12290
|
+
onPasteReference,
|
|
12291
|
+
selectionReference
|
|
12292
|
+
]);
|
|
12134
12293
|
(0, react.useEffect)(() => {
|
|
12135
12294
|
const onKeyDown = (event) => {
|
|
12136
12295
|
if (!(event.ctrlKey || event.metaKey) || event.altKey || event.shiftKey) return;
|
|
@@ -12139,13 +12298,50 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12139
12298
|
event.preventDefault();
|
|
12140
12299
|
copySelection();
|
|
12141
12300
|
};
|
|
12142
|
-
|
|
12301
|
+
window.addEventListener("keydown", onKeyDown, true);
|
|
12143
12302
|
return () => {
|
|
12144
|
-
|
|
12303
|
+
window.removeEventListener("keydown", onKeyDown, true);
|
|
12145
12304
|
};
|
|
12146
12305
|
}, [copySelection]);
|
|
12306
|
+
(0, react.useEffect)(() => {
|
|
12307
|
+
const onKeyDown = (event) => {
|
|
12308
|
+
if (!(event.ctrlKey || event.metaKey) || event.altKey || event.shiftKey) return;
|
|
12309
|
+
if (event.key.toLowerCase() !== "f") return;
|
|
12310
|
+
event.preventDefault();
|
|
12311
|
+
setSearchOpen(true);
|
|
12312
|
+
searchInputRef.current?.focus();
|
|
12313
|
+
searchInputRef.current?.select();
|
|
12314
|
+
};
|
|
12315
|
+
window.addEventListener("keydown", onKeyDown, true);
|
|
12316
|
+
return () => {
|
|
12317
|
+
window.removeEventListener("keydown", onKeyDown, true);
|
|
12318
|
+
};
|
|
12319
|
+
}, []);
|
|
12320
|
+
const jumpRef = (0, react.useRef)(jump);
|
|
12321
|
+
jumpRef.current = jump;
|
|
12322
|
+
(0, react.useEffect)(() => {
|
|
12323
|
+
const onKeyDown = (event) => {
|
|
12324
|
+
if (!(event.ctrlKey || event.metaKey) || event.altKey || event.shiftKey) return;
|
|
12325
|
+
const key = event.key.toLowerCase();
|
|
12326
|
+
if (key !== "arrowup" && key !== "arrowdown") return;
|
|
12327
|
+
const target = event.target;
|
|
12328
|
+
if (target instanceof Element && target.closest("input, textarea, [contenteditable=\"true\"]") !== null) return;
|
|
12329
|
+
event.preventDefault();
|
|
12330
|
+
jumpRef.current(key === "arrowup" ? -1 : 1);
|
|
12331
|
+
};
|
|
12332
|
+
window.addEventListener("keydown", onKeyDown, true);
|
|
12333
|
+
return () => {
|
|
12334
|
+
window.removeEventListener("keydown", onKeyDown, true);
|
|
12335
|
+
};
|
|
12336
|
+
}, []);
|
|
12147
12337
|
const focusedBlock = model.blocks.length > 0 ? model.blocks[focus] : void 0;
|
|
12148
12338
|
const inFocusedBlock = (index) => focusedBlock !== void 0 && index >= focusedBlock.start && index <= focusedBlock.end;
|
|
12339
|
+
const flashWidth = (() => {
|
|
12340
|
+
const scroller = bodyRef.current;
|
|
12341
|
+
if (scroller === null) return 0;
|
|
12342
|
+
const scrollbarWidth = scroller.offsetWidth - scroller.clientWidth;
|
|
12343
|
+
return Math.max(0, scroller.clientWidth - (scrollbarWidth > 0 ? 0 : OVERVIEW_RULER_WIDTH_PX));
|
|
12344
|
+
})();
|
|
12149
12345
|
return (0, react_jsx_runtime.jsxs)("div", {
|
|
12150
12346
|
className: PendingPanel_module_css_default.diff,
|
|
12151
12347
|
"data-diff-approval-diff": true,
|
|
@@ -12234,105 +12430,211 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12234
12430
|
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { size: 14 })
|
|
12235
12431
|
})
|
|
12236
12432
|
})] }),
|
|
12433
|
+
(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
12434
|
+
label: t("action.search"),
|
|
12435
|
+
side: "bottom",
|
|
12436
|
+
delayMs: 500,
|
|
12437
|
+
children: (0, react_jsx_runtime.jsx)("button", {
|
|
12438
|
+
type: "button",
|
|
12439
|
+
className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.iconAction}`,
|
|
12440
|
+
"data-diff-search-toggle": true,
|
|
12441
|
+
"aria-label": t("action.search"),
|
|
12442
|
+
onClick: toggleSearch,
|
|
12443
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconSearchOutline16, { size: 14 })
|
|
12444
|
+
})
|
|
12445
|
+
}),
|
|
12237
12446
|
(0, react_jsx_runtime.jsx)("span", { className: PendingPanel_module_css_default.flexSpacer }),
|
|
12238
12447
|
(0, react_jsx_runtime.jsx)("button", {
|
|
12239
12448
|
type: "button",
|
|
12240
|
-
className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.actionPrimary}`,
|
|
12449
|
+
className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.actionPrimary} ${PendingPanel_module_css_default.actionQuietDisabled}`,
|
|
12241
12450
|
"data-diff-keep": true,
|
|
12242
12451
|
disabled: busy,
|
|
12243
12452
|
onClick: () => {
|
|
12244
12453
|
onKeep(file.sessionId, file.id);
|
|
12245
12454
|
},
|
|
12246
|
-
children:
|
|
12455
|
+
children: t("action.keep")
|
|
12247
12456
|
}),
|
|
12248
12457
|
(0, react_jsx_runtime.jsx)("button", {
|
|
12249
12458
|
type: "button",
|
|
12250
|
-
className: PendingPanel_module_css_default.action
|
|
12459
|
+
className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.actionQuietDisabled}`,
|
|
12251
12460
|
"data-diff-revert": true,
|
|
12252
12461
|
disabled: busy,
|
|
12253
12462
|
onClick: () => {
|
|
12254
12463
|
onRevert(file.sessionId, file.id);
|
|
12255
12464
|
},
|
|
12256
|
-
children:
|
|
12465
|
+
children: t("action.revert")
|
|
12257
12466
|
})
|
|
12258
12467
|
]
|
|
12259
12468
|
}),
|
|
12469
|
+
failedMessage !== void 0 && (0, react_jsx_runtime.jsx)("p", {
|
|
12470
|
+
className: PendingPanel_module_css_default.actionError,
|
|
12471
|
+
"data-diff-action-error": true,
|
|
12472
|
+
children: failedMessage
|
|
12473
|
+
}),
|
|
12260
12474
|
file.missing && (0, react_jsx_runtime.jsx)("p", {
|
|
12261
12475
|
className: PendingPanel_module_css_default.missingHint,
|
|
12262
12476
|
children: t("panel.missingHint")
|
|
12263
12477
|
}),
|
|
12264
12478
|
(0, react_jsx_runtime.jsxs)("div", {
|
|
12265
12479
|
className: PendingPanel_module_css_default.diffBodyWrap,
|
|
12266
|
-
children: [
|
|
12267
|
-
|
|
12268
|
-
|
|
12269
|
-
|
|
12270
|
-
|
|
12271
|
-
|
|
12272
|
-
|
|
12273
|
-
|
|
12274
|
-
|
|
12275
|
-
|
|
12276
|
-
|
|
12480
|
+
children: [
|
|
12481
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
12482
|
+
className: PendingPanel_module_css_default.diffBody,
|
|
12483
|
+
ref: bodyRef,
|
|
12484
|
+
tabIndex: 0,
|
|
12485
|
+
onScroll,
|
|
12486
|
+
onMouseLeave: () => {
|
|
12487
|
+
setHoveredBlock(void 0);
|
|
12488
|
+
},
|
|
12489
|
+
"data-diff-body": true,
|
|
12490
|
+
children: [(0, react_jsx_runtime.jsxs)("div", {
|
|
12491
|
+
className: PendingPanel_module_css_default.lines,
|
|
12492
|
+
style: { minWidth: `max(100%, ${widestLine}ch)` },
|
|
12493
|
+
children: [
|
|
12494
|
+
start > 0 && (0, react_jsx_runtime.jsx)("div", {
|
|
12495
|
+
className: PendingPanel_module_css_default.vSpacer,
|
|
12496
|
+
style: { height: start * ROW_HEIGHT_PX },
|
|
12497
|
+
"aria-hidden": "true"
|
|
12498
|
+
}),
|
|
12499
|
+
visibleRows.map((row, offset) => {
|
|
12500
|
+
const index = start + offset;
|
|
12501
|
+
return (0, react_jsx_runtime.jsx)(DiffRow, {
|
|
12502
|
+
index,
|
|
12503
|
+
row,
|
|
12504
|
+
runs,
|
|
12505
|
+
focused: inFocusedBlock(index),
|
|
12506
|
+
searchHit: searchHitSet.has(index),
|
|
12507
|
+
searchCurrent: index === currentSearchRow,
|
|
12508
|
+
onRowHover
|
|
12509
|
+
}, index);
|
|
12510
|
+
}),
|
|
12511
|
+
end < rowCount && (0, react_jsx_runtime.jsx)("div", {
|
|
12512
|
+
className: PendingPanel_module_css_default.vSpacer,
|
|
12513
|
+
style: { height: (rowCount - end) * ROW_HEIGHT_PX },
|
|
12514
|
+
"aria-hidden": "true"
|
|
12515
|
+
}),
|
|
12516
|
+
blockActionsPadPx > 0 && (0, react_jsx_runtime.jsx)("div", {
|
|
12517
|
+
className: PendingPanel_module_css_default.vSpacer,
|
|
12518
|
+
style: { height: blockActionsPadPx },
|
|
12519
|
+
"aria-hidden": "true"
|
|
12520
|
+
})
|
|
12521
|
+
]
|
|
12522
|
+
}), hoveredBlock !== void 0 && model.blocks[hoveredBlock] !== void 0 && (0, react_jsx_runtime.jsxs)("div", {
|
|
12523
|
+
className: PendingPanel_module_css_default.blockActions,
|
|
12524
|
+
"data-diff-block-actions": true,
|
|
12525
|
+
style: { top: (model.blocks[hoveredBlock].end + 1) * ROW_HEIGHT_PX },
|
|
12526
|
+
children: [
|
|
12527
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
12528
|
+
className: PendingPanel_module_css_default.blockPosition,
|
|
12529
|
+
"data-diff-block-position": true,
|
|
12530
|
+
children: t("panel.blockPosition", {
|
|
12531
|
+
current: hoveredBlock + 1,
|
|
12532
|
+
total: model.blocks.length
|
|
12533
|
+
})
|
|
12534
|
+
}),
|
|
12535
|
+
(0, react_jsx_runtime.jsx)("button", {
|
|
12536
|
+
type: "button",
|
|
12537
|
+
className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.actionPrimary}`,
|
|
12538
|
+
"data-diff-block-keep": true,
|
|
12539
|
+
disabled: busy,
|
|
12540
|
+
onClick: () => {
|
|
12541
|
+
onBlockKeep(file.sessionId, file.id, blockRanges[hoveredBlock]);
|
|
12542
|
+
},
|
|
12543
|
+
children: t("action.keep")
|
|
12544
|
+
}),
|
|
12545
|
+
(0, react_jsx_runtime.jsx)("button", {
|
|
12546
|
+
type: "button",
|
|
12547
|
+
className: PendingPanel_module_css_default.action,
|
|
12548
|
+
"data-diff-block-revert": true,
|
|
12549
|
+
disabled: busy,
|
|
12550
|
+
onClick: () => {
|
|
12551
|
+
onBlockRevert(file.sessionId, file.id, blockRanges[hoveredBlock]);
|
|
12552
|
+
},
|
|
12553
|
+
children: t("action.revert")
|
|
12554
|
+
})
|
|
12555
|
+
]
|
|
12556
|
+
})]
|
|
12557
|
+
}),
|
|
12558
|
+
focusedBlock !== void 0 && flashKey > 0 && (0, react_jsx_runtime.jsx)("div", {
|
|
12559
|
+
className: PendingPanel_module_css_default.blockFlash,
|
|
12560
|
+
"data-diff-block-flash": true,
|
|
12561
|
+
style: {
|
|
12562
|
+
top: focusedBlock.start * ROW_HEIGHT_PX - scrollTop,
|
|
12563
|
+
height: Math.min((focusedBlock.end - focusedBlock.start + 1) * ROW_HEIGHT_PX, viewportHeight > 0 ? viewportHeight : Number.POSITIVE_INFINITY),
|
|
12564
|
+
width: flashWidth
|
|
12565
|
+
}
|
|
12566
|
+
}, flashKey),
|
|
12567
|
+
searchOpen && (0, react_jsx_runtime.jsxs)("div", {
|
|
12568
|
+
className: PendingPanel_module_css_default.searchBar,
|
|
12569
|
+
"data-diff-searchbar": true,
|
|
12277
12570
|
children: [
|
|
12278
|
-
|
|
12279
|
-
|
|
12280
|
-
|
|
12281
|
-
"
|
|
12571
|
+
(0, react_jsx_runtime.jsx)("input", {
|
|
12572
|
+
ref: searchInputRef,
|
|
12573
|
+
className: PendingPanel_module_css_default.searchInput,
|
|
12574
|
+
"data-diff-search-input": true,
|
|
12575
|
+
value: searchQuery,
|
|
12576
|
+
placeholder: t("panel.searchPlaceholder"),
|
|
12577
|
+
onChange: (event) => {
|
|
12578
|
+
setSearchQuery(event.target.value);
|
|
12579
|
+
},
|
|
12580
|
+
onKeyDown: (event) => {
|
|
12581
|
+
if (event.key === "Enter") {
|
|
12582
|
+
event.preventDefault();
|
|
12583
|
+
goSearch(event.shiftKey ? -1 : 1);
|
|
12584
|
+
} else if (event.key === "Escape") closeSearch();
|
|
12585
|
+
}
|
|
12586
|
+
}),
|
|
12587
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
12588
|
+
className: PendingPanel_module_css_default.searchCount,
|
|
12589
|
+
"data-diff-search-count": true,
|
|
12590
|
+
children: searchMatches.length === 0 ? "0/0" : `${searchIndex % searchMatches.length + 1}/${searchMatches.length}`
|
|
12591
|
+
}),
|
|
12592
|
+
(0, react_jsx_runtime.jsx)("button", {
|
|
12593
|
+
type: "button",
|
|
12594
|
+
className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.iconAction}`,
|
|
12595
|
+
"data-diff-search-prev": true,
|
|
12596
|
+
"aria-label": t("action.prevDiff"),
|
|
12597
|
+
disabled: searchMatches.length === 0,
|
|
12598
|
+
onClick: () => {
|
|
12599
|
+
goSearch(-1);
|
|
12600
|
+
},
|
|
12601
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronUpOutline14, { size: 14 })
|
|
12282
12602
|
}),
|
|
12283
|
-
|
|
12284
|
-
|
|
12285
|
-
|
|
12286
|
-
|
|
12287
|
-
|
|
12288
|
-
|
|
12289
|
-
|
|
12290
|
-
|
|
12291
|
-
},
|
|
12603
|
+
(0, react_jsx_runtime.jsx)("button", {
|
|
12604
|
+
type: "button",
|
|
12605
|
+
className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.iconAction}`,
|
|
12606
|
+
"data-diff-search-next": true,
|
|
12607
|
+
"aria-label": t("action.nextDiff"),
|
|
12608
|
+
disabled: searchMatches.length === 0,
|
|
12609
|
+
onClick: () => {
|
|
12610
|
+
goSearch(1);
|
|
12611
|
+
},
|
|
12612
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { size: 14 })
|
|
12292
12613
|
}),
|
|
12293
|
-
|
|
12294
|
-
|
|
12295
|
-
|
|
12296
|
-
"
|
|
12614
|
+
(0, react_jsx_runtime.jsx)("button", {
|
|
12615
|
+
type: "button",
|
|
12616
|
+
className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.iconAction}`,
|
|
12617
|
+
"data-diff-search-close": true,
|
|
12618
|
+
"aria-label": t("action.close"),
|
|
12619
|
+
onClick: closeSearch,
|
|
12620
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCloseOutline16, { size: 14 })
|
|
12297
12621
|
})
|
|
12298
12622
|
]
|
|
12299
|
-
}),
|
|
12300
|
-
|
|
12301
|
-
|
|
12302
|
-
|
|
12303
|
-
|
|
12304
|
-
|
|
12305
|
-
className: `${PendingPanel_module_css_default.
|
|
12306
|
-
"data-diff-
|
|
12307
|
-
|
|
12308
|
-
|
|
12309
|
-
|
|
12310
|
-
}
|
|
12311
|
-
|
|
12312
|
-
|
|
12313
|
-
|
|
12314
|
-
className: PendingPanel_module_css_default.action,
|
|
12315
|
-
"data-diff-block-revert": true,
|
|
12316
|
-
disabled: busy,
|
|
12317
|
-
onClick: () => {
|
|
12318
|
-
onBlockRevert(file.sessionId, file.id, blockRanges[hoveredBlock]);
|
|
12319
|
-
},
|
|
12320
|
-
children: t("action.revert")
|
|
12321
|
-
})]
|
|
12322
|
-
})]
|
|
12323
|
-
}), rulerMarkers.length > 0 && (0, react_jsx_runtime.jsx)("div", {
|
|
12324
|
-
className: PendingPanel_module_css_default.overviewRuler,
|
|
12325
|
-
"data-diff-approval-ruler": true,
|
|
12326
|
-
"aria-hidden": "true",
|
|
12327
|
-
children: rulerMarkers.map((marker, index) => (0, react_jsx_runtime.jsx)("div", {
|
|
12328
|
-
className: `${PendingPanel_module_css_default.overviewMarker} ${marker.kind === "del" ? PendingPanel_module_css_default.markerDel : PendingPanel_module_css_default.markerAdd}`,
|
|
12329
|
-
"data-diff-ruler-marker": marker.kind,
|
|
12330
|
-
style: {
|
|
12331
|
-
top: `${marker.top}%`,
|
|
12332
|
-
height: `${marker.height}%`
|
|
12333
|
-
}
|
|
12334
|
-
}, index))
|
|
12335
|
-
})]
|
|
12623
|
+
}),
|
|
12624
|
+
rulerMarkers.length > 0 && (0, react_jsx_runtime.jsx)("div", {
|
|
12625
|
+
className: PendingPanel_module_css_default.overviewRuler,
|
|
12626
|
+
"data-diff-approval-ruler": true,
|
|
12627
|
+
"aria-hidden": "true",
|
|
12628
|
+
children: rulerMarkers.map((marker, index) => (0, react_jsx_runtime.jsx)("div", {
|
|
12629
|
+
className: `${PendingPanel_module_css_default.overviewMarker} ${marker.kind === "del" ? PendingPanel_module_css_default.markerDel : PendingPanel_module_css_default.markerAdd}`,
|
|
12630
|
+
"data-diff-ruler-marker": marker.kind,
|
|
12631
|
+
style: {
|
|
12632
|
+
top: `${marker.top}%`,
|
|
12633
|
+
height: `${marker.height}%`
|
|
12634
|
+
}
|
|
12635
|
+
}, index))
|
|
12636
|
+
})
|
|
12637
|
+
]
|
|
12336
12638
|
}),
|
|
12337
12639
|
(0, react_jsx_runtime.jsxs)("div", {
|
|
12338
12640
|
className: PendingPanel_module_css_default.statusBar,
|
|
@@ -12395,11 +12697,34 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12395
12697
|
});
|
|
12396
12698
|
}
|
|
12397
12699
|
/** Render the pending-edit review panel and its unified footer action. */
|
|
12398
|
-
function PendingPanel({ wide, useSessions, usePending, onRefresh, onKeep, onRevert, onBlockKeep, onBlockRevert, onOpen, t }) {
|
|
12700
|
+
function PendingPanel({ wide, useSessions, usePending, onRefresh, onKeep, onRevert, onBlockKeep, onBlockRevert, onOpen, onPasteReference, onUndo, onRedo, onImportVcs, t }) {
|
|
12399
12701
|
const current = useSessions((state) => state.current);
|
|
12702
|
+
const currentBlank = useSessions((state) => {
|
|
12703
|
+
const id = state.current;
|
|
12704
|
+
return id === void 0 ? false : state.byId[id]?.blank ?? false;
|
|
12705
|
+
});
|
|
12706
|
+
const noSession = current === void 0 || currentBlank;
|
|
12400
12707
|
const snapshot = usePending((snapshot) => snapshot);
|
|
12401
12708
|
const [open, setOpen] = (0, react.useState)(false);
|
|
12402
12709
|
const [selected, setSelected] = (0, react.useState)("");
|
|
12710
|
+
/** Bumped when the already-open file is clicked again, to jump to the next
|
|
12711
|
+
* diff block in the open file's detail pane. */
|
|
12712
|
+
const [jumpSignal, setJumpSignal] = (0, react.useState)(0);
|
|
12713
|
+
/** Bumped when an undo/redo affected the already-open file, so its detail
|
|
12714
|
+
* pane re-selects the undone diff (flash). */
|
|
12715
|
+
const [undoFlash, setUndoFlash] = (0, react.useState)(0);
|
|
12716
|
+
/** Which bulk decision (keep-all / revert-all) is running; null when idle. */
|
|
12717
|
+
const [bulkBusy, setBulkBusy] = (0, react.useState)(null);
|
|
12718
|
+
/** True while a workspace-changes import is running. */
|
|
12719
|
+
const [importBusy, setImportBusy] = (0, react.useState)(false);
|
|
12720
|
+
/** Feedback under the empty note after an import (no VCS, or a failure). */
|
|
12721
|
+
const [importNote, setImportNote] = (0, react.useState)(void 0);
|
|
12722
|
+
/** Whether the last import note is a failure (drives the alert role). */
|
|
12723
|
+
const [importFailed, setImportFailed] = (0, react.useState)(false);
|
|
12724
|
+
/** A transient banner for an import that found nothing to bring in. */
|
|
12725
|
+
const [importToast, setImportToast] = (0, react.useState)(null);
|
|
12726
|
+
/** A transient banner for a keep/revert failure. */
|
|
12727
|
+
const [actionToast, setActionToast] = (0, react.useState)(null);
|
|
12403
12728
|
/** Pending count captured at open time; auto-close needs a list that emptied. */
|
|
12404
12729
|
const [openedCount, setOpenedCount] = (0, react.useState)(0);
|
|
12405
12730
|
/** Bottom offset tracking the chat composer's top edge so the input stays visible. */
|
|
@@ -12461,13 +12786,27 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12461
12786
|
document.removeEventListener("pointerdown", onPointerDown, true);
|
|
12462
12787
|
};
|
|
12463
12788
|
}, [open]);
|
|
12464
|
-
const files = snapshot.files;
|
|
12465
|
-
|
|
12466
|
-
const
|
|
12789
|
+
const files = snapshot.files.filter((file) => file.sessionId === current);
|
|
12790
|
+
/** Per-file keep/revert failures, surfaced inline on the row and detail. */
|
|
12791
|
+
const failed = snapshot.failed ?? EMPTY_FAILED_MAP;
|
|
12792
|
+
const failedInitialized = (0, react.useRef)(false);
|
|
12793
|
+
const failedRef = (0, react.useRef)(void 0);
|
|
12794
|
+
(0, react.useEffect)(() => {
|
|
12795
|
+
const current = snapshot.failed;
|
|
12796
|
+
if (!failedInitialized.current) {
|
|
12797
|
+
failedInitialized.current = true;
|
|
12798
|
+
failedRef.current = current;
|
|
12799
|
+
return;
|
|
12800
|
+
}
|
|
12801
|
+
const previous = failedRef.current;
|
|
12802
|
+
const fresh = [...(current ?? EMPTY_FAILED_MAP).entries()].filter(([id]) => previous === void 0 || !previous.has(id));
|
|
12803
|
+
if (fresh.length > 0) setActionToast(fresh[0][1]);
|
|
12804
|
+
failedRef.current = current;
|
|
12805
|
+
}, [snapshot.failed]);
|
|
12467
12806
|
(0, react.useEffect)(() => {
|
|
12468
12807
|
if (!open) return;
|
|
12469
12808
|
if (selected !== "" && files.some((file) => file.id === selected)) return;
|
|
12470
|
-
const next = [
|
|
12809
|
+
const next = files[0];
|
|
12471
12810
|
if (next !== void 0 && next.id !== selected) setSelected(next.id);
|
|
12472
12811
|
}, [
|
|
12473
12812
|
open,
|
|
@@ -12476,10 +12815,15 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12476
12815
|
selected
|
|
12477
12816
|
]);
|
|
12478
12817
|
(0, react.useEffect)(() => {
|
|
12479
|
-
if (open
|
|
12818
|
+
if (!open || openedCount === 0) return;
|
|
12819
|
+
if (!(snapshot.read && snapshot.error === void 0 && files.length === 0)) return;
|
|
12820
|
+
const timer = window.setTimeout(() => {
|
|
12480
12821
|
setOpenedCount(0);
|
|
12481
12822
|
setOpen(false);
|
|
12482
|
-
}
|
|
12823
|
+
}, EMPTY_CLOSE_GRACE_MS);
|
|
12824
|
+
return () => {
|
|
12825
|
+
window.clearTimeout(timer);
|
|
12826
|
+
};
|
|
12483
12827
|
}, [
|
|
12484
12828
|
open,
|
|
12485
12829
|
openedCount,
|
|
@@ -12487,17 +12831,88 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12487
12831
|
snapshot.error,
|
|
12488
12832
|
files.length
|
|
12489
12833
|
]);
|
|
12834
|
+
const runImportVcs = async () => {
|
|
12835
|
+
if (current === void 0 || importBusy) return;
|
|
12836
|
+
setImportBusy(true);
|
|
12837
|
+
setImportNote(void 0);
|
|
12838
|
+
setImportFailed(false);
|
|
12839
|
+
setImportToast(null);
|
|
12840
|
+
try {
|
|
12841
|
+
const value = await onImportVcs(current, includeUntrackedEnabled());
|
|
12842
|
+
await onRefresh(current);
|
|
12843
|
+
if (!value.detected) setImportNote(t("panel.importNoVcs"));
|
|
12844
|
+
else if (value.imported === 0) setImportToast(t("panel.importNone"));
|
|
12845
|
+
} catch (error) {
|
|
12846
|
+
setImportFailed(true);
|
|
12847
|
+
setImportNote(t("panel.importFailed", { message: error instanceof Error ? error.message : String(error) }));
|
|
12848
|
+
} finally {
|
|
12849
|
+
setImportBusy(false);
|
|
12850
|
+
}
|
|
12851
|
+
};
|
|
12490
12852
|
const toggleOpen = () => {
|
|
12491
12853
|
if (!open) setOpenedCount(files.length);
|
|
12492
12854
|
setOpen((value) => !value);
|
|
12493
12855
|
};
|
|
12856
|
+
(0, react.useEffect)(() => {
|
|
12857
|
+
if (noSession) setOpen(false);
|
|
12858
|
+
}, [noSession]);
|
|
12859
|
+
/** Run the same decision over every current-session file, sequentially. */
|
|
12860
|
+
const runBulk = async (kind) => {
|
|
12861
|
+
setBulkBusy(kind);
|
|
12862
|
+
try {
|
|
12863
|
+
for (const file of files) if (kind === "keep") await onKeep(file.sessionId, file.id);
|
|
12864
|
+
else await onRevert(file.sessionId, file.id);
|
|
12865
|
+
} finally {
|
|
12866
|
+
setBulkBusy(null);
|
|
12867
|
+
}
|
|
12868
|
+
};
|
|
12494
12869
|
const renderEntry = (entry) => (0, react_jsx_runtime.jsx)(PendingFileRow, {
|
|
12495
12870
|
file: entry,
|
|
12496
12871
|
selected: selected === entry.id,
|
|
12872
|
+
failedMessage: failed.get(entry.id),
|
|
12497
12873
|
t,
|
|
12498
|
-
onSelect:
|
|
12874
|
+
onSelect: (id) => {
|
|
12875
|
+
if (id === selected) setJumpSignal((signal) => signal + 1);
|
|
12876
|
+
else setSelected(id);
|
|
12877
|
+
}
|
|
12499
12878
|
}, entry.id);
|
|
12500
12879
|
const selectedFile = files.find((file) => file.id === selected);
|
|
12880
|
+
const handleUndo = async (sessionId) => {
|
|
12881
|
+
const id = await onUndo(sessionId);
|
|
12882
|
+
if (id === void 0) return;
|
|
12883
|
+
if (id === selected) setUndoFlash((signal) => signal + 1);
|
|
12884
|
+
else setSelected(id);
|
|
12885
|
+
};
|
|
12886
|
+
const handleRedo = async (sessionId) => {
|
|
12887
|
+
const id = await onRedo(sessionId);
|
|
12888
|
+
if (id === void 0) return;
|
|
12889
|
+
if (id === selected) setUndoFlash((signal) => signal + 1);
|
|
12890
|
+
else setSelected(id);
|
|
12891
|
+
};
|
|
12892
|
+
(0, react.useEffect)(() => {
|
|
12893
|
+
if (!open || current === void 0) return;
|
|
12894
|
+
const onKeyDown = (event) => {
|
|
12895
|
+
if (!(event.ctrlKey || event.metaKey) || event.altKey) return;
|
|
12896
|
+
const key = event.key.toLowerCase();
|
|
12897
|
+
if (key !== "z" && key !== "y") return;
|
|
12898
|
+
const target = event.target;
|
|
12899
|
+
if (target instanceof Element && target.closest("input, textarea, [contenteditable=\"true\"]") !== null) return;
|
|
12900
|
+
event.preventDefault();
|
|
12901
|
+
if (key === "z") {
|
|
12902
|
+
if (event.shiftKey) handleRedo(current);
|
|
12903
|
+
else handleUndo(current);
|
|
12904
|
+
} else handleRedo(current);
|
|
12905
|
+
};
|
|
12906
|
+
window.addEventListener("keydown", onKeyDown, true);
|
|
12907
|
+
return () => {
|
|
12908
|
+
window.removeEventListener("keydown", onKeyDown, true);
|
|
12909
|
+
};
|
|
12910
|
+
}, [
|
|
12911
|
+
open,
|
|
12912
|
+
current,
|
|
12913
|
+
handleUndo,
|
|
12914
|
+
handleRedo
|
|
12915
|
+
]);
|
|
12501
12916
|
/** Drag the list/detail divider; width follows the pointer within its bounds. */
|
|
12502
12917
|
const startResize = (event) => {
|
|
12503
12918
|
if (event.button !== 0) return;
|
|
@@ -12526,132 +12941,316 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12526
12941
|
};
|
|
12527
12942
|
return (0, react_jsx_runtime.jsxs)("div", {
|
|
12528
12943
|
className: wide ? PendingPanel_module_css_default.layer : `${PendingPanel_module_css_default.layer} ${PendingPanel_module_css_default.rail}`,
|
|
12529
|
-
children: [
|
|
12530
|
-
|
|
12531
|
-
|
|
12532
|
-
|
|
12533
|
-
|
|
12534
|
-
|
|
12535
|
-
|
|
12536
|
-
|
|
12537
|
-
|
|
12538
|
-
|
|
12539
|
-
|
|
12540
|
-
|
|
12541
|
-
|
|
12542
|
-
|
|
12543
|
-
|
|
12544
|
-
|
|
12545
|
-
|
|
12546
|
-
|
|
12547
|
-
|
|
12548
|
-
|
|
12549
|
-
|
|
12550
|
-
|
|
12551
|
-
|
|
12552
|
-
|
|
12553
|
-
|
|
12944
|
+
children: [
|
|
12945
|
+
importToast !== null && (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Toast, {
|
|
12946
|
+
text: importToast,
|
|
12947
|
+
onDone: () => {
|
|
12948
|
+
setImportToast(null);
|
|
12949
|
+
}
|
|
12950
|
+
}),
|
|
12951
|
+
actionToast !== null && (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Toast, {
|
|
12952
|
+
text: actionToast,
|
|
12953
|
+
onDone: () => {
|
|
12954
|
+
setActionToast(null);
|
|
12955
|
+
}
|
|
12956
|
+
}),
|
|
12957
|
+
open && expanded && (0, react_jsx_runtime.jsx)("div", {
|
|
12958
|
+
className: PendingPanel_module_css_default.fullscreenBackdrop,
|
|
12959
|
+
"data-diff-fullscreen-backdrop": true
|
|
12960
|
+
}),
|
|
12961
|
+
open && (0, react_jsx_runtime.jsxs)("section", {
|
|
12962
|
+
className: PendingPanel_module_css_default.panel,
|
|
12963
|
+
style: { bottom: expanded ? PANEL_INSET_PX : bottomPx },
|
|
12964
|
+
"data-diff-approval-panel": true,
|
|
12965
|
+
"aria-label": t("panel.title"),
|
|
12966
|
+
children: [(0, react_jsx_runtime.jsxs)("header", {
|
|
12967
|
+
className: PendingPanel_module_css_default.header,
|
|
12968
|
+
children: [(0, react_jsx_runtime.jsx)("span", {
|
|
12969
|
+
className: PendingPanel_module_css_default.title,
|
|
12970
|
+
children: t("panel.title")
|
|
12971
|
+
}), (0, react_jsx_runtime.jsxs)("div", {
|
|
12972
|
+
className: PendingPanel_module_css_default.headerActions,
|
|
12973
|
+
children: [
|
|
12974
|
+
(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
12975
|
+
label: t("action.settings"),
|
|
12976
|
+
side: "bottom",
|
|
12977
|
+
delayMs: 500,
|
|
12978
|
+
children: (0, react_jsx_runtime.jsx)("button", {
|
|
12979
|
+
type: "button",
|
|
12980
|
+
className: PendingPanel_module_css_default.expand,
|
|
12981
|
+
"data-diff-approval-settings": true,
|
|
12982
|
+
"aria-label": t("action.settings"),
|
|
12983
|
+
onClick: () => {
|
|
12984
|
+
setOpen(false);
|
|
12985
|
+
openSettingsSection(t("settings.tabLabel"));
|
|
12986
|
+
},
|
|
12987
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconSettingsOutline16, { size: 14 })
|
|
12988
|
+
})
|
|
12989
|
+
}),
|
|
12990
|
+
(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
12991
|
+
label: t(expanded ? "action.exitFullscreen" : "action.expand"),
|
|
12992
|
+
side: "bottom",
|
|
12993
|
+
delayMs: 500,
|
|
12994
|
+
children: (0, react_jsx_runtime.jsx)("button", {
|
|
12995
|
+
type: "button",
|
|
12996
|
+
className: expanded ? `${PendingPanel_module_css_default.expand} ${PendingPanel_module_css_default.expandExpanded}` : PendingPanel_module_css_default.expand,
|
|
12997
|
+
"data-diff-approval-expand": true,
|
|
12998
|
+
"aria-label": t(expanded ? "action.exitFullscreen" : "action.expand"),
|
|
12999
|
+
onClick: () => {
|
|
13000
|
+
setExpanded((value) => !value);
|
|
13001
|
+
},
|
|
13002
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconFullscreenOutline16, { size: 14 })
|
|
13003
|
+
})
|
|
13004
|
+
}),
|
|
13005
|
+
(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
13006
|
+
label: t("action.close"),
|
|
13007
|
+
side: "bottom",
|
|
13008
|
+
delayMs: 500,
|
|
13009
|
+
children: (0, react_jsx_runtime.jsx)("button", {
|
|
13010
|
+
type: "button",
|
|
13011
|
+
className: PendingPanel_module_css_default.close,
|
|
13012
|
+
"data-diff-approval-close": true,
|
|
13013
|
+
"aria-label": t("action.close"),
|
|
13014
|
+
onClick: () => {
|
|
13015
|
+
setOpen(false);
|
|
13016
|
+
},
|
|
13017
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCloseOutline16, { size: 14 })
|
|
13018
|
+
})
|
|
13019
|
+
})
|
|
13020
|
+
]
|
|
13021
|
+
})]
|
|
13022
|
+
}), snapshot.error !== void 0 || !snapshot.read || files.length === 0 ? (0, react_jsx_runtime.jsxs)("div", {
|
|
13023
|
+
className: PendingPanel_module_css_default.states,
|
|
13024
|
+
children: [
|
|
13025
|
+
snapshot.error !== void 0 && (0, react_jsx_runtime.jsx)("p", {
|
|
13026
|
+
className: PendingPanel_module_css_default.readError,
|
|
13027
|
+
role: "alert",
|
|
13028
|
+
children: t("panel.readFailed", { message: snapshot.error })
|
|
13029
|
+
}),
|
|
13030
|
+
!snapshot.read && snapshot.error === void 0 && (0, react_jsx_runtime.jsx)("p", {
|
|
13031
|
+
className: PendingPanel_module_css_default.note,
|
|
13032
|
+
children: t("panel.loading")
|
|
13033
|
+
}),
|
|
13034
|
+
snapshot.read && snapshot.error === void 0 && files.length === 0 && (0, react_jsx_runtime.jsxs)("div", {
|
|
13035
|
+
className: PendingPanel_module_css_default.emptyState,
|
|
13036
|
+
children: [
|
|
13037
|
+
(0, react_jsx_runtime.jsx)("p", {
|
|
13038
|
+
className: `${PendingPanel_module_css_default.note} ${PendingPanel_module_css_default.noteCentered}`,
|
|
13039
|
+
children: t("panel.empty")
|
|
13040
|
+
}),
|
|
13041
|
+
(0, react_jsx_runtime.jsx)("button", {
|
|
13042
|
+
type: "button",
|
|
13043
|
+
className: PendingPanel_module_css_default.importButton,
|
|
13044
|
+
"data-diff-import-vcs": true,
|
|
13045
|
+
disabled: importBusy,
|
|
13046
|
+
onClick: () => {
|
|
13047
|
+
runImportVcs();
|
|
13048
|
+
},
|
|
13049
|
+
children: importBusy ? t("action.importVcsBusy") : t("action.importVcs")
|
|
13050
|
+
}),
|
|
13051
|
+
importNote !== void 0 && (0, react_jsx_runtime.jsx)("p", {
|
|
13052
|
+
className: PendingPanel_module_css_default.importNote,
|
|
13053
|
+
role: importFailed ? "alert" : void 0,
|
|
13054
|
+
children: importNote
|
|
13055
|
+
})
|
|
13056
|
+
]
|
|
12554
13057
|
})
|
|
12555
|
-
|
|
12556
|
-
|
|
12557
|
-
|
|
12558
|
-
|
|
12559
|
-
|
|
12560
|
-
|
|
12561
|
-
|
|
12562
|
-
"data-diff-approval-
|
|
12563
|
-
|
|
12564
|
-
|
|
12565
|
-
|
|
12566
|
-
|
|
12567
|
-
|
|
13058
|
+
]
|
|
13059
|
+
}) : (0, react_jsx_runtime.jsxs)("div", {
|
|
13060
|
+
className: PendingPanel_module_css_default.split,
|
|
13061
|
+
children: [
|
|
13062
|
+
(0, react_jsx_runtime.jsxs)("nav", {
|
|
13063
|
+
className: PendingPanel_module_css_default.fileList,
|
|
13064
|
+
style: { width: listWidth },
|
|
13065
|
+
"data-diff-approval-file-list": true,
|
|
13066
|
+
children: [(0, react_jsx_runtime.jsx)("div", {
|
|
13067
|
+
className: PendingPanel_module_css_default.listScroll,
|
|
13068
|
+
children: files.length > 0 && (0, react_jsx_runtime.jsxs)("section", { children: [(0, react_jsx_runtime.jsx)("h3", {
|
|
13069
|
+
className: PendingPanel_module_css_default.group,
|
|
13070
|
+
children: t("panel.group.current")
|
|
13071
|
+
}), (0, react_jsx_runtime.jsx)("ul", {
|
|
13072
|
+
className: PendingPanel_module_css_default.rows,
|
|
13073
|
+
children: files.map(renderEntry)
|
|
13074
|
+
})] })
|
|
13075
|
+
}), files.length > 0 && (0, react_jsx_runtime.jsxs)("div", {
|
|
13076
|
+
className: PendingPanel_module_css_default.bulkActions,
|
|
13077
|
+
children: [(0, react_jsx_runtime.jsx)("button", {
|
|
13078
|
+
type: "button",
|
|
13079
|
+
className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.actionPrimary}`,
|
|
13080
|
+
"data-diff-keep-all": true,
|
|
13081
|
+
disabled: bulkBusy !== null,
|
|
13082
|
+
onClick: () => {
|
|
13083
|
+
runBulk("keep");
|
|
13084
|
+
},
|
|
13085
|
+
children: bulkBusy === "keep" ? t("action.busy") : t("action.keepAll")
|
|
13086
|
+
}), (0, react_jsx_runtime.jsx)("button", {
|
|
13087
|
+
type: "button",
|
|
13088
|
+
className: PendingPanel_module_css_default.action,
|
|
13089
|
+
"data-diff-revert-all": true,
|
|
13090
|
+
disabled: bulkBusy !== null,
|
|
13091
|
+
onClick: () => {
|
|
13092
|
+
runBulk("revert");
|
|
13093
|
+
},
|
|
13094
|
+
children: bulkBusy === "revert" ? t("action.busy") : t("action.revertAll")
|
|
13095
|
+
})]
|
|
13096
|
+
})]
|
|
13097
|
+
}),
|
|
13098
|
+
(0, react_jsx_runtime.jsx)("div", {
|
|
13099
|
+
className: PendingPanel_module_css_default.resizeHandle,
|
|
13100
|
+
"data-diff-resize": true,
|
|
13101
|
+
onMouseDown: startResize
|
|
13102
|
+
}),
|
|
13103
|
+
(0, react_jsx_runtime.jsx)("div", {
|
|
13104
|
+
className: PendingPanel_module_css_default.detail,
|
|
13105
|
+
children: selectedFile === void 0 ? (0, react_jsx_runtime.jsx)("p", {
|
|
13106
|
+
className: PendingPanel_module_css_default.detailEmpty,
|
|
13107
|
+
children: t("panel.selectHint")
|
|
13108
|
+
}) : (0, react_jsx_runtime.jsx)(PendingDiff, {
|
|
13109
|
+
file: selectedFile,
|
|
13110
|
+
busy: snapshot.busy.has(selectedFile.id),
|
|
13111
|
+
workspacePath: snapshot.workspacePath,
|
|
13112
|
+
jumpSignal,
|
|
13113
|
+
undoFlash,
|
|
13114
|
+
failedMessage: failed.get(selectedFile.id),
|
|
13115
|
+
onPasteReference,
|
|
13116
|
+
t,
|
|
13117
|
+
onKeep,
|
|
13118
|
+
onRevert,
|
|
13119
|
+
onBlockKeep,
|
|
13120
|
+
onBlockRevert,
|
|
13121
|
+
onOpen
|
|
13122
|
+
})
|
|
12568
13123
|
})
|
|
12569
|
-
|
|
13124
|
+
]
|
|
12570
13125
|
})]
|
|
12571
|
-
}),
|
|
12572
|
-
|
|
12573
|
-
|
|
12574
|
-
|
|
12575
|
-
|
|
12576
|
-
|
|
12577
|
-
|
|
12578
|
-
|
|
12579
|
-
|
|
12580
|
-
|
|
12581
|
-
|
|
12582
|
-
|
|
12583
|
-
|
|
12584
|
-
|
|
12585
|
-
|
|
12586
|
-
|
|
12587
|
-
|
|
12588
|
-
|
|
12589
|
-
|
|
12590
|
-
|
|
12591
|
-
|
|
12592
|
-
className: PendingPanel_module_css_default.fileList,
|
|
12593
|
-
style: { width: listWidth },
|
|
12594
|
-
"data-diff-approval-file-list": true,
|
|
12595
|
-
children: [mine.length > 0 && (0, react_jsx_runtime.jsxs)("section", { children: [(0, react_jsx_runtime.jsx)("h3", {
|
|
12596
|
-
className: PendingPanel_module_css_default.group,
|
|
12597
|
-
children: t("panel.group.current")
|
|
12598
|
-
}), (0, react_jsx_runtime.jsx)("ul", {
|
|
12599
|
-
className: PendingPanel_module_css_default.rows,
|
|
12600
|
-
children: mine.map(renderEntry)
|
|
12601
|
-
})] }), theirs.length > 0 && (0, react_jsx_runtime.jsxs)("section", { children: [(0, react_jsx_runtime.jsx)("h3", {
|
|
12602
|
-
className: PendingPanel_module_css_default.group,
|
|
12603
|
-
children: t("panel.group.others")
|
|
12604
|
-
}), (0, react_jsx_runtime.jsx)("ul", {
|
|
12605
|
-
className: PendingPanel_module_css_default.rows,
|
|
12606
|
-
children: theirs.map(renderEntry)
|
|
12607
|
-
})] })]
|
|
12608
|
-
}),
|
|
12609
|
-
(0, react_jsx_runtime.jsx)("div", {
|
|
12610
|
-
className: PendingPanel_module_css_default.resizeHandle,
|
|
12611
|
-
"data-diff-resize": true,
|
|
12612
|
-
onMouseDown: startResize
|
|
12613
|
-
}),
|
|
12614
|
-
(0, react_jsx_runtime.jsx)("div", {
|
|
12615
|
-
className: PendingPanel_module_css_default.detail,
|
|
12616
|
-
children: selectedFile === void 0 ? (0, react_jsx_runtime.jsx)("p", {
|
|
12617
|
-
className: PendingPanel_module_css_default.detailEmpty,
|
|
12618
|
-
children: t("panel.selectHint")
|
|
12619
|
-
}) : (0, react_jsx_runtime.jsx)(PendingDiff, {
|
|
12620
|
-
file: selectedFile,
|
|
12621
|
-
busy: snapshot.busy.has(selectedFile.id),
|
|
12622
|
-
workspacePath: snapshot.workspacePath,
|
|
12623
|
-
t,
|
|
12624
|
-
onKeep,
|
|
12625
|
-
onRevert,
|
|
12626
|
-
onBlockKeep,
|
|
12627
|
-
onBlockRevert,
|
|
12628
|
-
onOpen
|
|
13126
|
+
}),
|
|
13127
|
+
(0, react_jsx_runtime.jsx)("div", {
|
|
13128
|
+
className: PendingPanel_module_css_default.footerButtons,
|
|
13129
|
+
children: (0, react_jsx_runtime.jsxs)("button", {
|
|
13130
|
+
type: "button",
|
|
13131
|
+
className: noSession ? `${PendingPanel_module_css_default.badge} ${PendingPanel_module_css_default.badgeDisabled}` : PendingPanel_module_css_default.badge,
|
|
13132
|
+
"data-diff-approval-badge": files.length,
|
|
13133
|
+
"data-active": open ? "" : void 0,
|
|
13134
|
+
"aria-label": t("panel.aria"),
|
|
13135
|
+
"aria-expanded": open,
|
|
13136
|
+
disabled: noSession,
|
|
13137
|
+
onClick: toggleOpen,
|
|
13138
|
+
children: [
|
|
13139
|
+
(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconListPenOutline16, { size: wide ? 16 : 18 }),
|
|
13140
|
+
wide && (0, react_jsx_runtime.jsx)("span", {
|
|
13141
|
+
className: PendingPanel_module_css_default.badgeLabel,
|
|
13142
|
+
children: t("panel.aria")
|
|
13143
|
+
}),
|
|
13144
|
+
(wide || files.length > 0) && (0, react_jsx_runtime.jsx)("span", {
|
|
13145
|
+
className: PendingPanel_module_css_default.badgeCount,
|
|
13146
|
+
children: files.length
|
|
12629
13147
|
})
|
|
12630
|
-
|
|
12631
|
-
|
|
12632
|
-
})]
|
|
12633
|
-
}), (0, react_jsx_runtime.jsx)("div", {
|
|
12634
|
-
className: PendingPanel_module_css_default.footerButtons,
|
|
12635
|
-
children: (0, react_jsx_runtime.jsxs)("button", {
|
|
12636
|
-
type: "button",
|
|
12637
|
-
className: PendingPanel_module_css_default.badge,
|
|
12638
|
-
"data-diff-approval-badge": files.length,
|
|
12639
|
-
"data-active": open ? "" : void 0,
|
|
12640
|
-
"aria-label": t("panel.aria"),
|
|
12641
|
-
"aria-expanded": open,
|
|
12642
|
-
onClick: toggleOpen,
|
|
12643
|
-
children: [
|
|
12644
|
-
(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconListPenOutline16, { size: wide ? 16 : 18 }),
|
|
12645
|
-
wide && (0, react_jsx_runtime.jsx)("span", {
|
|
12646
|
-
className: PendingPanel_module_css_default.badgeLabel,
|
|
12647
|
-
children: t("panel.aria")
|
|
12648
|
-
}),
|
|
12649
|
-
(wide || files.length > 0) && (0, react_jsx_runtime.jsx)("span", {
|
|
12650
|
-
className: PendingPanel_module_css_default.badgeCount,
|
|
12651
|
-
children: files.length
|
|
12652
|
-
})
|
|
12653
|
-
]
|
|
13148
|
+
]
|
|
13149
|
+
})
|
|
12654
13150
|
})
|
|
13151
|
+
]
|
|
13152
|
+
});
|
|
13153
|
+
}
|
|
13154
|
+
//#endregion
|
|
13155
|
+
//#region lib/types/client/SettingsTab.js
|
|
13156
|
+
/** DSH Settings top-level section for this plugin's preferences. */
|
|
13157
|
+
/** A pill picker offering the two boolean states 打开 / 关闭. */
|
|
13158
|
+
function OnOffPicker({ value, open, onOpenChange, onSelect, dataAttribute, t }) {
|
|
13159
|
+
return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Menu, {
|
|
13160
|
+
open,
|
|
13161
|
+
onClose: () => {
|
|
13162
|
+
onOpenChange(false);
|
|
13163
|
+
},
|
|
13164
|
+
items: [{
|
|
13165
|
+
id: "on",
|
|
13166
|
+
label: t("action.toggleOn")
|
|
13167
|
+
}, {
|
|
13168
|
+
id: "off",
|
|
13169
|
+
label: t("action.toggleOff")
|
|
13170
|
+
}],
|
|
13171
|
+
selectedId: value ? "on" : "off",
|
|
13172
|
+
onSelect: (id) => {
|
|
13173
|
+
onOpenChange(false);
|
|
13174
|
+
onSelect(id === "on");
|
|
13175
|
+
},
|
|
13176
|
+
align: "end",
|
|
13177
|
+
portal: true,
|
|
13178
|
+
anchor: (0, react_jsx_runtime.jsxs)("button", {
|
|
13179
|
+
type: "button",
|
|
13180
|
+
className: PendingPanel_module_css_default.settingsSelector,
|
|
13181
|
+
"aria-haspopup": "menu",
|
|
13182
|
+
"aria-expanded": open,
|
|
13183
|
+
onClick: () => {
|
|
13184
|
+
onOpenChange(!open);
|
|
13185
|
+
},
|
|
13186
|
+
[dataAttribute]: true,
|
|
13187
|
+
children: [value ? t("action.toggleOn") : t("action.toggleOff"), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { className: PendingPanel_module_css_default.settingsSelectorChevron })]
|
|
13188
|
+
})
|
|
13189
|
+
});
|
|
13190
|
+
}
|
|
13191
|
+
/** One Agent-preset-style preference row: title + description, pill picker right. */
|
|
13192
|
+
function PreferenceRow({ title, description, value, open, onOpenChange, onSelect, dataAttribute, t }) {
|
|
13193
|
+
return (0, react_jsx_runtime.jsxs)("div", {
|
|
13194
|
+
className: PendingPanel_module_css_default.settingsRow,
|
|
13195
|
+
children: [(0, react_jsx_runtime.jsxs)("div", {
|
|
13196
|
+
className: PendingPanel_module_css_default.settingsRowText,
|
|
13197
|
+
children: [(0, react_jsx_runtime.jsx)("div", {
|
|
13198
|
+
className: PendingPanel_module_css_default.settingsRowTitle,
|
|
13199
|
+
children: title
|
|
13200
|
+
}), (0, react_jsx_runtime.jsx)("div", {
|
|
13201
|
+
className: PendingPanel_module_css_default.settingsRowDesc,
|
|
13202
|
+
children: description
|
|
13203
|
+
})]
|
|
13204
|
+
}), (0, react_jsx_runtime.jsx)(OnOffPicker, {
|
|
13205
|
+
value,
|
|
13206
|
+
open,
|
|
13207
|
+
onOpenChange,
|
|
13208
|
+
onSelect,
|
|
13209
|
+
dataAttribute,
|
|
13210
|
+
t
|
|
13211
|
+
})]
|
|
13212
|
+
});
|
|
13213
|
+
}
|
|
13214
|
+
/**
|
|
13215
|
+
* The plugin's preferences: auto-paste a copied reference into the input, and
|
|
13216
|
+
* whether importing workspace VCS changes includes untracked files. Each row
|
|
13217
|
+
* mirrors the harness's Agent-preset row (title + description on the left, a
|
|
13218
|
+
* pill picker on the right) with the two boolean states 打开 / 关闭.
|
|
13219
|
+
*/
|
|
13220
|
+
function DiffApprovalSettingsTab({ t }) {
|
|
13221
|
+
const [pasteOnCopy, setPasteOnCopyState] = (0, react.useState)(pasteOnCopyEnabled);
|
|
13222
|
+
const [pasteOnCopyOpen, setPasteOnCopyOpen] = (0, react.useState)(false);
|
|
13223
|
+
const [includeUntracked, setIncludeUntrackedState] = (0, react.useState)(includeUntrackedEnabled);
|
|
13224
|
+
const [includeUntrackedOpen, setIncludeUntrackedOpen] = (0, react.useState)(false);
|
|
13225
|
+
const setPasteOnCopy = (value) => {
|
|
13226
|
+
setPasteOnCopyState(value);
|
|
13227
|
+
setPasteOnCopyEnabled(value);
|
|
13228
|
+
};
|
|
13229
|
+
const setIncludeUntracked = (value) => {
|
|
13230
|
+
setIncludeUntrackedState(value);
|
|
13231
|
+
setIncludeUntrackedEnabled(value);
|
|
13232
|
+
};
|
|
13233
|
+
return (0, react_jsx_runtime.jsxs)("div", {
|
|
13234
|
+
className: PendingPanel_module_css_default.settingsPage,
|
|
13235
|
+
"data-diff-settings": true,
|
|
13236
|
+
children: [(0, react_jsx_runtime.jsx)(PreferenceRow, {
|
|
13237
|
+
title: t("panel.pasteOnCopy"),
|
|
13238
|
+
description: t("panel.pasteOnCopyDesc"),
|
|
13239
|
+
value: pasteOnCopy,
|
|
13240
|
+
open: pasteOnCopyOpen,
|
|
13241
|
+
onOpenChange: setPasteOnCopyOpen,
|
|
13242
|
+
onSelect: setPasteOnCopy,
|
|
13243
|
+
dataAttribute: "data-diff-paste-on-copy-select",
|
|
13244
|
+
t
|
|
13245
|
+
}), (0, react_jsx_runtime.jsx)(PreferenceRow, {
|
|
13246
|
+
title: t("panel.importUntracked"),
|
|
13247
|
+
description: t("panel.importUntrackedDesc"),
|
|
13248
|
+
value: includeUntracked,
|
|
13249
|
+
open: includeUntrackedOpen,
|
|
13250
|
+
onOpenChange: setIncludeUntrackedOpen,
|
|
13251
|
+
onSelect: setIncludeUntracked,
|
|
13252
|
+
dataAttribute: "data-diff-import-untracked-select",
|
|
13253
|
+
t
|
|
12655
13254
|
})]
|
|
12656
13255
|
});
|
|
12657
13256
|
}
|
|
@@ -12700,6 +13299,18 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12700
13299
|
block
|
|
12701
13300
|
}));
|
|
12702
13301
|
},
|
|
13302
|
+
async undo(sessionId) {
|
|
13303
|
+
return actionOf(await rpc.call(DIFF_APPROVAL_CHANNEL, "undo", { sessionId }));
|
|
13304
|
+
},
|
|
13305
|
+
async redo(sessionId) {
|
|
13306
|
+
return actionOf(await rpc.call(DIFF_APPROVAL_CHANNEL, "redo", { sessionId }));
|
|
13307
|
+
},
|
|
13308
|
+
async importVcs(sessionId, includeUntracked) {
|
|
13309
|
+
return importValueOf(await rpc.call(DIFF_APPROVAL_CHANNEL, "vcs-import", {
|
|
13310
|
+
sessionId,
|
|
13311
|
+
includeUntracked
|
|
13312
|
+
}));
|
|
13313
|
+
},
|
|
12703
13314
|
async open(sessionId, id, action) {
|
|
12704
13315
|
return openOf(await rpc.call(DIFF_APPROVAL_CHANNEL, "open", {
|
|
12705
13316
|
sessionId,
|
|
@@ -12756,8 +13367,25 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12756
13367
|
const value = result.value;
|
|
12757
13368
|
if (typeof value !== "object" || value === null) throw new Error("the action returned a malformed value");
|
|
12758
13369
|
const outcome = value.outcome;
|
|
12759
|
-
if (outcome !== "kept" && outcome !== "reverted" && outcome !== "missing") throw new Error("the action returned a malformed outcome");
|
|
12760
|
-
|
|
13370
|
+
if (outcome !== "kept" && outcome !== "reverted" && outcome !== "missing" && outcome !== "undone" && outcome !== "redone" && outcome !== "nothing") throw new Error("the action returned a malformed outcome");
|
|
13371
|
+
const id = value.id;
|
|
13372
|
+
return {
|
|
13373
|
+
outcome,
|
|
13374
|
+
id: typeof id === "string" && id.length > 0 ? id : void 0
|
|
13375
|
+
};
|
|
13376
|
+
}
|
|
13377
|
+
/** Narrow the vcs-import endpoint's value; a malformed wire value is a failure. */
|
|
13378
|
+
function importValueOf(result) {
|
|
13379
|
+
if (!result.ok) throw new Error(`${result.error.code}: ${result.error.message}`);
|
|
13380
|
+
const value = result.value;
|
|
13381
|
+
if (typeof value !== "object" || value === null) throw new Error("the import returned a malformed value");
|
|
13382
|
+
const imported = value.imported;
|
|
13383
|
+
const detected = value.detected;
|
|
13384
|
+
if (typeof imported !== "number" || typeof detected !== "boolean") throw new Error("the import returned a malformed value");
|
|
13385
|
+
return {
|
|
13386
|
+
imported,
|
|
13387
|
+
detected
|
|
13388
|
+
};
|
|
12761
13389
|
}
|
|
12762
13390
|
/** Narrow the open endpoint's value; a malformed wire value is an open failure. */
|
|
12763
13391
|
function openOf(result) {
|
|
@@ -12779,6 +13407,10 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12779
13407
|
*/
|
|
12780
13408
|
/** An empty busy set reused as the snapshot's canonical absent value. */
|
|
12781
13409
|
const EMPTY_BUSY = /* @__PURE__ */ new Set();
|
|
13410
|
+
/** An empty failure map reused as the snapshot's canonical absent value. */
|
|
13411
|
+
const EMPTY_FAILED = /* @__PURE__ */ new Map();
|
|
13412
|
+
/** How long a failed keep/revert hint stays visible before it auto-clears. */
|
|
13413
|
+
const FAILED_HINT_MS = 5e3;
|
|
12782
13414
|
/**
|
|
12783
13415
|
* Create the store over the review-channel port.
|
|
12784
13416
|
* @param port - the typed channel port.
|
|
@@ -12795,22 +13427,51 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12795
13427
|
snapshot = next;
|
|
12796
13428
|
for (const listener of [...listeners]) listener();
|
|
12797
13429
|
};
|
|
13430
|
+
const failedOf = (value) => value.failed ?? EMPTY_FAILED;
|
|
13431
|
+
/** Record one entry's failed keep/revert with its message; auto-clears after a few seconds. */
|
|
13432
|
+
const markFailed = (id, message) => {
|
|
13433
|
+
publish({
|
|
13434
|
+
...snapshot,
|
|
13435
|
+
failed: new Map([...failedOf(snapshot), [id, message]])
|
|
13436
|
+
});
|
|
13437
|
+
window.setTimeout(() => {
|
|
13438
|
+
if (failedOf(snapshot).get(id) !== message) return;
|
|
13439
|
+
const next = new Map(failedOf(snapshot));
|
|
13440
|
+
next.delete(id);
|
|
13441
|
+
publish({
|
|
13442
|
+
...snapshot,
|
|
13443
|
+
failed: next
|
|
13444
|
+
});
|
|
13445
|
+
}, FAILED_HINT_MS);
|
|
13446
|
+
};
|
|
13447
|
+
/** Drop one entry's failure marker after a successful retry. */
|
|
13448
|
+
const clearFailed = (id) => {
|
|
13449
|
+
if (!failedOf(snapshot).has(id)) return;
|
|
13450
|
+
const next = new Map(failedOf(snapshot));
|
|
13451
|
+
next.delete(id);
|
|
13452
|
+
publish({
|
|
13453
|
+
...snapshot,
|
|
13454
|
+
failed: next
|
|
13455
|
+
});
|
|
13456
|
+
};
|
|
12798
13457
|
const withBusy = async (id, action) => {
|
|
12799
13458
|
const { error: _cleared, ...base } = snapshot;
|
|
12800
13459
|
publish({
|
|
12801
13460
|
...base,
|
|
13461
|
+
failed: failedOf(snapshot),
|
|
12802
13462
|
busy: /* @__PURE__ */ new Set([...snapshot.busy, id])
|
|
12803
13463
|
});
|
|
12804
13464
|
try {
|
|
12805
13465
|
await action();
|
|
12806
13466
|
} catch (error) {
|
|
13467
|
+
markFailed(id, error instanceof Error ? error.message : String(error));
|
|
12807
13468
|
publish({
|
|
12808
13469
|
...snapshot,
|
|
12809
|
-
error: error instanceof Error ? error.message : String(error),
|
|
12810
13470
|
busy: new Set([...snapshot.busy].filter((busy) => busy !== id))
|
|
12811
13471
|
});
|
|
12812
13472
|
return;
|
|
12813
13473
|
}
|
|
13474
|
+
clearFailed(id);
|
|
12814
13475
|
publish({
|
|
12815
13476
|
...snapshot,
|
|
12816
13477
|
files: snapshot.files.filter((file) => file.id !== id),
|
|
@@ -12830,7 +13491,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12830
13491
|
publish({
|
|
12831
13492
|
read: true,
|
|
12832
13493
|
files: [],
|
|
12833
|
-
busy: EMPTY_BUSY
|
|
13494
|
+
busy: EMPTY_BUSY,
|
|
13495
|
+
failed: failedOf(snapshot)
|
|
12834
13496
|
});
|
|
12835
13497
|
return;
|
|
12836
13498
|
}
|
|
@@ -12840,7 +13502,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12840
13502
|
read: true,
|
|
12841
13503
|
files,
|
|
12842
13504
|
workspacePath,
|
|
12843
|
-
busy: EMPTY_BUSY
|
|
13505
|
+
busy: EMPTY_BUSY,
|
|
13506
|
+
failed: failedOf(snapshot)
|
|
12844
13507
|
});
|
|
12845
13508
|
} catch (error) {
|
|
12846
13509
|
publish({
|
|
@@ -12848,7 +13511,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12848
13511
|
files: snapshot.files,
|
|
12849
13512
|
workspacePath: snapshot.workspacePath,
|
|
12850
13513
|
error: error instanceof Error ? error.message : String(error),
|
|
12851
|
-
busy: snapshot.busy
|
|
13514
|
+
busy: snapshot.busy,
|
|
13515
|
+
failed: failedOf(snapshot)
|
|
12852
13516
|
});
|
|
12853
13517
|
}
|
|
12854
13518
|
},
|
|
@@ -12871,13 +13535,14 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12871
13535
|
try {
|
|
12872
13536
|
await port.blockKeep(sessionId, id, block);
|
|
12873
13537
|
} catch (error) {
|
|
13538
|
+
markFailed(id, error instanceof Error ? error.message : String(error));
|
|
12874
13539
|
publish({
|
|
12875
13540
|
...snapshot,
|
|
12876
|
-
error: error instanceof Error ? error.message : String(error),
|
|
12877
13541
|
busy: new Set([...snapshot.busy].filter((busy) => busy !== id))
|
|
12878
13542
|
});
|
|
12879
13543
|
return;
|
|
12880
13544
|
}
|
|
13545
|
+
clearFailed(id);
|
|
12881
13546
|
await this.refresh(sessionId);
|
|
12882
13547
|
},
|
|
12883
13548
|
async blockRevert(sessionId, id, block) {
|
|
@@ -12889,14 +13554,40 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12889
13554
|
try {
|
|
12890
13555
|
await port.blockRevert(sessionId, id, block);
|
|
12891
13556
|
} catch (error) {
|
|
13557
|
+
markFailed(id, error instanceof Error ? error.message : String(error));
|
|
12892
13558
|
publish({
|
|
12893
13559
|
...snapshot,
|
|
12894
|
-
error: error instanceof Error ? error.message : String(error),
|
|
12895
13560
|
busy: new Set([...snapshot.busy].filter((busy) => busy !== id))
|
|
12896
13561
|
});
|
|
12897
13562
|
return;
|
|
12898
13563
|
}
|
|
13564
|
+
clearFailed(id);
|
|
13565
|
+
await this.refresh(sessionId);
|
|
13566
|
+
},
|
|
13567
|
+
async undo(sessionId) {
|
|
13568
|
+
try {
|
|
13569
|
+
const value = await port.undo(sessionId);
|
|
13570
|
+
await this.refresh(sessionId);
|
|
13571
|
+
const id = value.id;
|
|
13572
|
+
return id !== void 0 && snapshot.files.some((file) => file.id === id) ? id : void 0;
|
|
13573
|
+
} catch {
|
|
13574
|
+
return;
|
|
13575
|
+
}
|
|
13576
|
+
},
|
|
13577
|
+
async redo(sessionId) {
|
|
13578
|
+
try {
|
|
13579
|
+
const value = await port.redo(sessionId);
|
|
13580
|
+
await this.refresh(sessionId);
|
|
13581
|
+
const id = value.id;
|
|
13582
|
+
return id !== void 0 && snapshot.files.some((file) => file.id === id) ? id : void 0;
|
|
13583
|
+
} catch {
|
|
13584
|
+
return;
|
|
13585
|
+
}
|
|
13586
|
+
},
|
|
13587
|
+
async importVcs(sessionId, includeUntracked) {
|
|
13588
|
+
const value = await port.importVcs(sessionId, includeUntracked);
|
|
12899
13589
|
await this.refresh(sessionId);
|
|
13590
|
+
return value;
|
|
12900
13591
|
},
|
|
12901
13592
|
async open(sessionId, id, action) {
|
|
12902
13593
|
try {
|
|
@@ -12931,15 +13622,25 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12931
13622
|
"panel.group.others": "其他会话",
|
|
12932
13623
|
"panel.aria": "待处理改动",
|
|
12933
13624
|
"panel.stats": "+{added} -{removed}",
|
|
13625
|
+
"panel.blockPosition": "第 {current}/{total} 块",
|
|
12934
13626
|
"panel.selectHint": "点击每项查看整个文件的差异;选中文本后,用底部状态栏或 Ctrl+L 复制引用",
|
|
13627
|
+
"panel.searchPlaceholder": "搜索",
|
|
12935
13628
|
"panel.missing": "文件已不存在",
|
|
12936
13629
|
"panel.missingHint": "该文件已不存在,回退会恢复该文件。",
|
|
12937
13630
|
"panel.createHint": "回退会删除该新建的文件。",
|
|
13631
|
+
"panel.pasteOnCopy": "复制引用后自动粘贴到消息输入框",
|
|
13632
|
+
"panel.pasteOnCopyDesc": "开启后,复制的引用会自动填入消息输入框,输入框会获得焦点。",
|
|
13633
|
+
"panel.importUntracked": "导入未跟踪的文件改动",
|
|
13634
|
+
"panel.importUntrackedDesc": "开启后,导入工作区改动会包含未跟踪/未版本化的新增文件(Git 未跟踪、SVN 未版本化、Perforce 未版本化)。收集改动需要扫描整个工作区,文件数量大时可能较慢。",
|
|
13635
|
+
"settings.tabLabel": "改动审批",
|
|
12938
13636
|
"row.create": "新增文件",
|
|
13637
|
+
"row.failed": "失败",
|
|
12939
13638
|
"row.added": "+{added}",
|
|
12940
13639
|
"row.removed": "-{removed}",
|
|
12941
13640
|
"action.keep": "保留",
|
|
12942
13641
|
"action.revert": "回退",
|
|
13642
|
+
"action.keepAll": "全部保留",
|
|
13643
|
+
"action.revertAll": "全部回退",
|
|
12943
13644
|
"action.openFile": "打开文件",
|
|
12944
13645
|
"action.revealFile": "打开所在目录",
|
|
12945
13646
|
"action.busy": "处理中…",
|
|
@@ -12950,6 +13651,16 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12950
13651
|
"action.langAuto": "自动",
|
|
12951
13652
|
"action.langAutoDetected": "自动:{lang}",
|
|
12952
13653
|
"action.langSelect": "高亮语言",
|
|
13654
|
+
"action.toggleOn": "打开",
|
|
13655
|
+
"action.toggleOff": "关闭",
|
|
13656
|
+
"action.importVcs": "导入工作区改动",
|
|
13657
|
+
"action.importVcsBusy": "导入中…",
|
|
13658
|
+
"panel.importNone": "没有可导入的改动",
|
|
13659
|
+
"panel.importDone": "已导入 {count} 个改动",
|
|
13660
|
+
"panel.importNoVcs": "未检测到版本控制(Git / SVN / Perforce)",
|
|
13661
|
+
"panel.importFailed": "导入失败:{message}",
|
|
13662
|
+
"action.search": "搜索 (Ctrl+F)",
|
|
13663
|
+
"action.settings": "设置",
|
|
12953
13664
|
"action.expand": "展开全屏",
|
|
12954
13665
|
"action.exitFullscreen": "退出全屏",
|
|
12955
13666
|
"action.close": "关闭",
|
|
@@ -12967,15 +13678,25 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12967
13678
|
"panel.group.others": "Other sessions",
|
|
12968
13679
|
"panel.aria": "Pending changes",
|
|
12969
13680
|
"panel.stats": "+{added} -{removed}",
|
|
13681
|
+
"panel.blockPosition": "{current}/{total}",
|
|
12970
13682
|
"panel.selectHint": "Select an item to review its whole-file diff; select text and copy its reference from the status bar (Ctrl+L)",
|
|
13683
|
+
"panel.searchPlaceholder": "Search",
|
|
12971
13684
|
"panel.missing": "File is gone",
|
|
12972
13685
|
"panel.missingHint": "This file no longer exists; reverting restores it.",
|
|
12973
13686
|
"panel.createHint": "Reverting removes this created file.",
|
|
13687
|
+
"panel.pasteOnCopy": "Paste the copied reference into the composer",
|
|
13688
|
+
"panel.pasteOnCopyDesc": "When enabled, a copied reference is pasted into the composer, which then receives focus.",
|
|
13689
|
+
"panel.importUntracked": "Import changes to untracked files",
|
|
13690
|
+
"panel.importUntrackedDesc": "When enabled, importing workspace changes includes new/untracked files (Git-untracked, SVN-unversioned, Perforce-unversioned). Collecting changes scans the whole workspace, which can be slow on large trees.",
|
|
13691
|
+
"settings.tabLabel": "Diff Approval",
|
|
12974
13692
|
"row.create": "New file",
|
|
13693
|
+
"row.failed": "Failed",
|
|
12975
13694
|
"row.added": "+{added}",
|
|
12976
13695
|
"row.removed": "-{removed}",
|
|
12977
13696
|
"action.keep": "Keep",
|
|
12978
13697
|
"action.revert": "Revert",
|
|
13698
|
+
"action.keepAll": "Keep all",
|
|
13699
|
+
"action.revertAll": "Revert all",
|
|
12979
13700
|
"action.openFile": "Open file",
|
|
12980
13701
|
"action.revealFile": "Reveal in folder",
|
|
12981
13702
|
"action.busy": "Working…",
|
|
@@ -12986,6 +13707,16 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12986
13707
|
"action.langAuto": "Auto",
|
|
12987
13708
|
"action.langAutoDetected": "Auto: {lang}",
|
|
12988
13709
|
"action.langSelect": "Highlight language",
|
|
13710
|
+
"action.toggleOn": "On",
|
|
13711
|
+
"action.toggleOff": "Off",
|
|
13712
|
+
"action.importVcs": "Import workspace changes",
|
|
13713
|
+
"action.importVcsBusy": "Importing…",
|
|
13714
|
+
"panel.importNone": "No changes to import",
|
|
13715
|
+
"panel.importDone": "Imported {count} changes",
|
|
13716
|
+
"panel.importNoVcs": "No version control detected (Git / SVN / Perforce)",
|
|
13717
|
+
"panel.importFailed": "Import failed: {message}",
|
|
13718
|
+
"action.search": "Search (Ctrl+F)",
|
|
13719
|
+
"action.settings": "Settings",
|
|
12989
13720
|
"action.expand": "Expand fullscreen",
|
|
12990
13721
|
"action.exitFullscreen": "Exit fullscreen",
|
|
12991
13722
|
"action.close": "Close",
|
|
@@ -13012,6 +13743,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13012
13743
|
zh,
|
|
13013
13744
|
en
|
|
13014
13745
|
}), "ui-diff-approval: dictionaries");
|
|
13746
|
+
const t = ctx.locale.bind(NS);
|
|
13015
13747
|
const store = createPendingDiffStore(createDiffApprovalPort(ctx.get("connection").rpc));
|
|
13016
13748
|
ctx.on("connection/reset", () => {
|
|
13017
13749
|
store.reset();
|
|
@@ -13029,9 +13761,29 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13029
13761
|
onRevert: (sessionId, path) => store.revert(sessionId, path),
|
|
13030
13762
|
onBlockKeep: (sessionId, id, block) => store.blockKeep(sessionId, id, block),
|
|
13031
13763
|
onBlockRevert: (sessionId, id, block) => store.blockRevert(sessionId, id, block),
|
|
13032
|
-
onOpen: (sessionId, id, action) => store.open(sessionId, id, action)
|
|
13764
|
+
onOpen: (sessionId, id, action) => store.open(sessionId, id, action),
|
|
13765
|
+
onUndo: (sessionId) => store.undo(sessionId),
|
|
13766
|
+
onRedo: (sessionId) => store.redo(sessionId),
|
|
13767
|
+
onImportVcs: (sessionId, includeUntracked) => store.importVcs(sessionId, includeUntracked),
|
|
13768
|
+
onPasteReference: (sessionId, reference) => {
|
|
13769
|
+
const actx = ctx.get("sessions")?.scope(sessionId);
|
|
13770
|
+
if (actx === void 0) return;
|
|
13771
|
+
const conversation = actx.get("conversation");
|
|
13772
|
+
if (conversation?.input === void 0) return;
|
|
13773
|
+
const textarea = document.querySelector("[data-composer-card] textarea");
|
|
13774
|
+
const base = textarea?.value ?? "";
|
|
13775
|
+
conversation.input.for(actx).setDraft(base === "" ? reference : `${base} ${reference}`);
|
|
13776
|
+
textarea?.focus();
|
|
13777
|
+
}
|
|
13033
13778
|
})
|
|
13034
13779
|
}, PendingPanel));
|
|
13780
|
+
ctx.slots.inject("settings.section", () => ctx.slots.register({
|
|
13781
|
+
name: "settings.section",
|
|
13782
|
+
id: "diff-approval",
|
|
13783
|
+
order: 100,
|
|
13784
|
+
label: () => t("settings.tabLabel"),
|
|
13785
|
+
locale: NS
|
|
13786
|
+
}, DiffApprovalSettingsTab));
|
|
13035
13787
|
}
|
|
13036
13788
|
//#endregion
|
|
13037
13789
|
exports.DIFF_APPROVAL_CHANNEL = DIFF_APPROVAL_CHANNEL;
|