dsh-diff-approval 0.12.0 → 0.13.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 +9 -3
- package/README.zh.md +9 -3
- package/lib/client.js +822 -260
- package/lib/index.js +24 -30
- package/lib/types/client/PendingPanel.d.ts +5 -1
- package/lib/types/client/conversation-access.d.ts +67 -0
- package/lib/types/client/index.d.ts +2 -1
- package/lib/types/client/locales.d.ts +12 -0
- package/lib/types/client/reference.d.ts +32 -2
- package/lib/types/client/remap-sync.d.ts +44 -0
- package/lib/types/client/settings.d.ts +20 -0
- package/lib/types/client/slots.d.ts +8 -0
- package/lib/types/client/store.d.ts +2 -0
- package/lib/types/types.d.ts +3 -0
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -18,6 +18,7 @@ window.__ModuleLoader__.load({
|
|
|
18
18
|
//#endregion
|
|
19
19
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
20
20
|
let react = require("react");
|
|
21
|
+
let react_dom = require("react-dom");
|
|
21
22
|
let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
22
23
|
//#region node_modules/.pnpm/diff@9.0.0/node_modules/diff/libesm/diff/base.js
|
|
23
24
|
var Diff = class {
|
|
@@ -654,6 +655,16 @@ window.__ModuleLoader__.load({
|
|
|
654
655
|
function computeWholeFileDiff(oldText, newText) {
|
|
655
656
|
oldText = oldText.replace(/\r\n?/g, "\n");
|
|
656
657
|
newText = newText.replace(/\r\n?/g, "\n");
|
|
658
|
+
if (oldText === newText) return {
|
|
659
|
+
rows: contentLines(oldText).map((text, index) => ({
|
|
660
|
+
kind: "context",
|
|
661
|
+
text,
|
|
662
|
+
oldLine: index + 1,
|
|
663
|
+
newLine: index + 1
|
|
664
|
+
})),
|
|
665
|
+
removed: 0,
|
|
666
|
+
added: 0
|
|
667
|
+
};
|
|
657
668
|
const oldLines = contentLines(oldText);
|
|
658
669
|
const newLines = contentLines(newText);
|
|
659
670
|
const context = Math.max(1, oldLines.length, newLines.length);
|
|
@@ -11693,6 +11704,15 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
11693
11704
|
//#endregion
|
|
11694
11705
|
//#region lib/types/client/reference.js
|
|
11695
11706
|
/**
|
|
11707
|
+
* Reference labels for the selection toolbar: a workspace-relative path (or
|
|
11708
|
+
* the absolute path when the file is outside the workspace) plus a 1-based
|
|
11709
|
+
* line range. Pure derivation so the display rule is unit-testable without
|
|
11710
|
+
* the panel.
|
|
11711
|
+
* @module dsh-diff-approval/client/reference
|
|
11712
|
+
*/
|
|
11713
|
+
/** The marker that replaces a reference's line number when its lines are gone. */
|
|
11714
|
+
const LINE_MISSING_LABEL = "LINE_MISSING";
|
|
11715
|
+
/**
|
|
11696
11716
|
* The path embedded in a copied reference: workspace-relative (forward
|
|
11697
11717
|
* slashes) when the file lives inside the current workspace, the absolute
|
|
11698
11718
|
* path otherwise. A bare file name is never enough — a reference must resolve
|
|
@@ -11720,15 +11740,66 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
11720
11740
|
return start === end ? String(start) : `${start}-${end}`;
|
|
11721
11741
|
}
|
|
11722
11742
|
/**
|
|
11723
|
-
* Build the clipboard text for a selected line range
|
|
11743
|
+
* Build the clipboard text for a selected line range, wrapped in parentheses so
|
|
11744
|
+
* the reference reads as one unambiguous token (and can be matched precisely).
|
|
11724
11745
|
* @param path - the selected file's path.
|
|
11725
11746
|
* @param workspacePath - the current workspace root, or `undefined`.
|
|
11726
11747
|
* @param start - first selected line number.
|
|
11727
11748
|
* @param end - last selected line number.
|
|
11728
|
-
* @returns the `path:range` reference text.
|
|
11749
|
+
* @returns the `(path:range)` reference text.
|
|
11729
11750
|
*/
|
|
11730
11751
|
function referenceOf(path, workspacePath, start, end) {
|
|
11731
|
-
return
|
|
11752
|
+
return `(${referencePathOf(path, workspacePath)}:${lineRangeLabel(start, end)})`;
|
|
11753
|
+
}
|
|
11754
|
+
/**
|
|
11755
|
+
* Map one referenced line range from `oldContent` coordinates to `newContent`
|
|
11756
|
+
* coordinates. Lines that survive (unchanged context) map to their new line
|
|
11757
|
+
* numbers, and the surviving lines' min/max span is returned. When every line
|
|
11758
|
+
* in the range was removed, returns `undefined` (the reference is expired).
|
|
11759
|
+
* @param oldContent - the file content the reference was made against.
|
|
11760
|
+
* @param newContent - the file content now.
|
|
11761
|
+
* @param start - first referenced line (1-based, inclusive).
|
|
11762
|
+
* @param end - last referenced line (1-based, inclusive).
|
|
11763
|
+
* @returns the surviving range, or `undefined` when nothing survives.
|
|
11764
|
+
*/
|
|
11765
|
+
function remapReferenceRange(oldContent, newContent, start, end) {
|
|
11766
|
+
const diff = computeWholeFileDiff(oldContent, newContent);
|
|
11767
|
+
const oldToNew = /* @__PURE__ */ new Map();
|
|
11768
|
+
for (const row of diff.rows) if (row.oldLine !== void 0 && row.newLine !== void 0) oldToNew.set(row.oldLine, row.newLine);
|
|
11769
|
+
let min = Infinity;
|
|
11770
|
+
let max = -Infinity;
|
|
11771
|
+
for (let line = start; line <= end; line++) {
|
|
11772
|
+
const next = oldToNew.get(line);
|
|
11773
|
+
if (next === void 0) continue;
|
|
11774
|
+
min = Math.min(min, next);
|
|
11775
|
+
max = Math.max(max, next);
|
|
11776
|
+
}
|
|
11777
|
+
if (min === Infinity) return void 0;
|
|
11778
|
+
return {
|
|
11779
|
+
start: min,
|
|
11780
|
+
end: max
|
|
11781
|
+
};
|
|
11782
|
+
}
|
|
11783
|
+
/**
|
|
11784
|
+
* Rewrite every `(referencePath:line)` / `(referencePath:start-end)` occurrence
|
|
11785
|
+
* in `text`, remapping each range from `oldContent` to `newContent`. A range
|
|
11786
|
+
* whose lines all survived becomes the new range; one whose lines were all
|
|
11787
|
+
* removed becomes `(referencePath:LINE_MISSING)`.
|
|
11788
|
+
* @param text - the free text (composer draft, queued message) to rewrite.
|
|
11789
|
+
* @param referencePath - the file's reference path (workspace-relative or absolute).
|
|
11790
|
+
* @param oldContent - the file content the references were made against.
|
|
11791
|
+
* @param newContent - the file content now.
|
|
11792
|
+
* @returns the rewritten text.
|
|
11793
|
+
*/
|
|
11794
|
+
function remapReferences(text, referencePath, oldContent, newContent) {
|
|
11795
|
+
const escaped = referencePath.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
11796
|
+
const regex = new RegExp(`\\(${escaped}:(\\d+)(?:-(\\d+))?\\)`, "g");
|
|
11797
|
+
return text.replace(regex, (_whole, startText, endText) => {
|
|
11798
|
+
const start = Number(startText);
|
|
11799
|
+
const mapped = remapReferenceRange(oldContent, newContent, start, endText === void 0 ? start : Number(endText));
|
|
11800
|
+
if (mapped === void 0) return `(${referencePath}:${LINE_MISSING_LABEL})`;
|
|
11801
|
+
return `(${referencePath}:${lineRangeLabel(mapped.start, mapped.end)})`;
|
|
11802
|
+
});
|
|
11732
11803
|
}
|
|
11733
11804
|
//#endregion
|
|
11734
11805
|
//#region lib/types/client/settings.js
|
|
@@ -11805,9 +11876,42 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
11805
11876
|
function setSplitMode(value) {
|
|
11806
11877
|
localStorage.setItem(SPLIT_MODE_KEY, value ? "1" : "0");
|
|
11807
11878
|
}
|
|
11879
|
+
const QUICK_SUMMON_KEY = "diff-approval:quick-summon-key";
|
|
11880
|
+
/**
|
|
11881
|
+
* The quick-summon chord. Stored as `Modifier+...+Key`; falls back to
|
|
11882
|
+
* {@link DEFAULT_QUICK_SUMMON}.
|
|
11883
|
+
* @returns the chord string.
|
|
11884
|
+
*/
|
|
11885
|
+
function quickSummonKey() {
|
|
11886
|
+
return localStorage.getItem(QUICK_SUMMON_KEY) ?? "Ctrl+D";
|
|
11887
|
+
}
|
|
11888
|
+
/** Persist the quick-summon chord. */
|
|
11889
|
+
function setQuickSummonKey(value) {
|
|
11890
|
+
localStorage.setItem(QUICK_SUMMON_KEY, value);
|
|
11891
|
+
}
|
|
11892
|
+
/**
|
|
11893
|
+
* Whether a keyboard event matches a chord string like `Ctrl+D`. Modifier
|
|
11894
|
+
* names are matched case-insensitively (`Ctrl`/`Control`, `Alt`/`Option`,
|
|
11895
|
+
* `Shift`, `Meta`/`Cmd`/`Command`/`Win`); the final part is the key. Exact
|
|
11896
|
+
* modifier set is required (extra modifiers do not match).
|
|
11897
|
+
* @param event - the keydown event.
|
|
11898
|
+
* @param shortcut - the chord string.
|
|
11899
|
+
* @returns whether the event matches.
|
|
11900
|
+
*/
|
|
11901
|
+
function matchesShortcut(event, shortcut) {
|
|
11902
|
+
const parts = shortcut.split("+").map((part) => part.trim().toLowerCase());
|
|
11903
|
+
const key = parts.pop();
|
|
11904
|
+
if (key === void 0 || key === "") return false;
|
|
11905
|
+
const mods = new Set(parts);
|
|
11906
|
+
const ctrl = mods.has("ctrl") || mods.has("control");
|
|
11907
|
+
const alt = mods.has("alt") || mods.has("option");
|
|
11908
|
+
const shift = mods.has("shift");
|
|
11909
|
+
const meta = mods.has("meta") || mods.has("cmd") || mods.has("command") || mods.has("win");
|
|
11910
|
+
return event.key.toLowerCase() === key && event.ctrlKey === ctrl && event.altKey === alt && event.shiftKey === shift && event.metaKey === meta;
|
|
11911
|
+
}
|
|
11808
11912
|
//#endregion
|
|
11809
11913
|
//#region \0dsh-css:/home/runner/work/dsh-diff-approval/dsh-diff-approval/src/client/PendingPanel.module.css.mjs
|
|
11810
|
-
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;position:relative}.F1KBNa_fileListFloat{z-index:40;box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);box-shadow:var(--dsw-shadow-lv2);border-radius:12px;flex-direction:column;padding:6px 8px 10px;display:flex;position:absolute;overflow:hidden}.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;gap:8px;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}.F1KBNa_notice{z-index:60;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);max-width:360px;box-shadow:var(--dsw-shadow-lv3);border-radius:10px;align-items:flex-start;gap:12px;padding:12px 14px;display:flex;position:fixed;bottom:24px;right:24px}.F1KBNa_noticeText{font:var(--dsw-font-caption);color:var(--dsw-alias-label-primary);flex:1;margin:0;line-height:1.45}.F1KBNa_noticeButton{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);font:var(--dsw-font-caption);cursor:pointer;border-radius:6px;flex:none;padding:4px 10px}.F1KBNa_noticeButton:hover{background:var(--dsw-alias-interactive-bg-hover-solid)}.F1KBNa_wrap .F1KBNa_line{height:auto;min-height:22px}.F1KBNa_subline{white-space:pre;height:22px;line-height:22px;display:block;overflow:hidden}.F1KBNa_wrapActive{background:var(--dsw-alias-state-business-primary);border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-static-neutral-bluish-50)}.F1KBNa_wrapActive:hover{background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 85%, var(--dsw-static-neutral-bluish-1000))}.F1KBNa_splitRoot{flex-direction:column;flex:1;min-height:0;display:flex;position:relative}.F1KBNa_diffBodySplit{flex:1;min-height:0;overflow-x:hidden}.F1KBNa_splitCols{width:100%;min-width:0;display:flex}.F1KBNa_splitCol{box-sizing:border-box;flex:1 1 0;min-width:0;overflow:hidden}.F1KBNa_splitDivider{background:var(--dsw-alias-border-l2);flex:0 0 1px}.F1KBNa_splitCol .F1KBNa_gutter,.F1KBNa_splitCol .F1KBNa_code{vertical-align:top}.F1KBNa_splitHScrollRow{border-top:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);flex:none;width:100%;min-width:0;display:flex}.F1KBNa_splitHScroll{flex:1 1 0;min-width:0;height:15px;overflow:auto hidden}.F1KBNa_splitHScroll::-webkit-scrollbar{height:15px}.F1KBNa_splitHScroll::-webkit-scrollbar-track{cursor:default}.F1KBNa_splitHScroll::-webkit-scrollbar-thumb{cursor:default}.F1KBNa_splitHScrollFill{height:1px}.F1KBNa_splitLdel{background-color:color-mix(in srgb, var(--dsw-alias-state-error-primary) 12%, transparent)}.F1KBNa_splitLadd{background-color:color-mix(in srgb, var(--dsw-alias-state-success-primary) 10%, transparent)}.F1KBNa_splitRdel{background-color:color-mix(in srgb, var(--dsw-alias-state-error-primary) 12%, transparent)}.F1KBNa_splitRadd{background-color:color-mix(in srgb, var(--dsw-alias-state-success-primary) 10%, transparent)}";
|
|
11914
|
+
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;position:relative}.F1KBNa_fileListFloat{z-index:40;box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);box-shadow:var(--dsw-shadow-lv2);border-radius:12px;flex-direction:column;padding:6px 8px 10px;display:flex;position:absolute;overflow:hidden}.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_confirmBackdrop{z-index:5;background:color-mix(in srgb, var(--dsw-alias-bg-base) 55%, transparent);justify-content:center;align-items:center;padding:24px;display:flex;position:absolute;inset:0}.F1KBNa_confirmCard{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);max-width:340px;box-shadow:var(--dsw-shadow-lv3);border-radius:12px;flex-direction:column;gap:12px;padding:16px;display:flex}.F1KBNa_confirmText{font:var(--dsw-font-caption);color:var(--dsw-alias-label-primary);overflow-wrap:anywhere;margin:0;line-height:1.5}.F1KBNa_confirmActions{justify-content:flex-end;gap:8px;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);-webkit-text-size-adjust:100%;text-size-adjust:100%;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;gap:8px;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}.F1KBNa_notice{z-index:60;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);max-width:360px;box-shadow:var(--dsw-shadow-lv3);border-radius:10px;align-items:flex-start;gap:12px;padding:12px 14px;display:flex;position:fixed;bottom:24px;right:24px}.F1KBNa_noticeText{font:var(--dsw-font-caption);color:var(--dsw-alias-label-primary);flex:1;margin:0;line-height:1.45}.F1KBNa_noticeButton{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);font:var(--dsw-font-caption);cursor:pointer;border-radius:6px;flex:none;padding:4px 10px}.F1KBNa_noticeButton:hover{background:var(--dsw-alias-interactive-bg-hover-solid)}.F1KBNa_wrap .F1KBNa_line{height:auto;min-height:22px}.F1KBNa_subline{white-space:pre;height:22px;line-height:22px;display:block;overflow:hidden}.F1KBNa_wrapActive{background:var(--dsw-alias-state-business-primary);border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-static-neutral-bluish-50)}.F1KBNa_wrapActive:hover{background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 85%, var(--dsw-static-neutral-bluish-1000))}.F1KBNa_splitRoot{flex-direction:column;flex:1;min-height:0;display:flex;position:relative}.F1KBNa_diffBodySplit{flex:1;min-height:0;overflow-x:hidden}.F1KBNa_splitCols{width:100%;min-width:0;display:flex}.F1KBNa_splitCol{box-sizing:border-box;flex:1 1 0;min-width:0;overflow:hidden}.F1KBNa_splitDivider{background:var(--dsw-alias-border-l2);flex:0 0 1px}.F1KBNa_splitCol .F1KBNa_gutter,.F1KBNa_splitCol .F1KBNa_code{vertical-align:top}.F1KBNa_splitHScrollRow{border-top:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);flex:none;width:100%;min-width:0;display:flex}.F1KBNa_splitHScroll{flex:1 1 0;min-width:0;height:15px;overflow:auto hidden}.F1KBNa_splitHScroll::-webkit-scrollbar{height:15px}.F1KBNa_splitHScroll::-webkit-scrollbar-track{cursor:default}.F1KBNa_splitHScroll::-webkit-scrollbar-thumb{cursor:default}.F1KBNa_splitHScrollFill{height:1px}.F1KBNa_splitLdel{background-color:color-mix(in srgb, var(--dsw-alias-state-error-primary) 12%, transparent)}.F1KBNa_splitLadd{background-color:color-mix(in srgb, var(--dsw-alias-state-success-primary) 10%, transparent)}.F1KBNa_splitRdel{background-color:color-mix(in srgb, var(--dsw-alias-state-error-primary) 12%, transparent)}.F1KBNa_splitRadd{background-color:color-mix(in srgb, var(--dsw-alias-state-success-primary) 10%, transparent)}";
|
|
11811
11915
|
const tagId = "dsh-diff-approval/PendingPanel.module.css";
|
|
11812
11916
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
11813
11917
|
const tag = document.createElement("style");
|
|
@@ -11817,111 +11921,115 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
11817
11921
|
document.head.appendChild(tag);
|
|
11818
11922
|
}
|
|
11819
11923
|
var PendingPanel_module_css_default = {
|
|
11820
|
-
"
|
|
11821
|
-
"
|
|
11822
|
-
"
|
|
11823
|
-
"
|
|
11924
|
+
"kindHint": "F1KBNa_kindHint",
|
|
11925
|
+
"searchBar": "F1KBNa_searchBar",
|
|
11926
|
+
"diffPath": "F1KBNa_diffPath",
|
|
11927
|
+
"flexSpacer": "F1KBNa_flexSpacer",
|
|
11824
11928
|
"splitRdel": "F1KBNa_splitRdel",
|
|
11825
|
-
"blockActions": "F1KBNa_blockActions",
|
|
11826
|
-
"badge": "F1KBNa_badge",
|
|
11827
|
-
"fileList": "F1KBNa_fileList",
|
|
11828
|
-
"badgeLabel": "F1KBNa_badgeLabel",
|
|
11829
|
-
"rows": "F1KBNa_rows",
|
|
11830
11929
|
"settingsRowTitle": "F1KBNa_settingsRowTitle",
|
|
11831
|
-
"
|
|
11832
|
-
"
|
|
11833
|
-
"
|
|
11834
|
-
"splitCols": "F1KBNa_splitCols",
|
|
11835
|
-
"splitHScrollRow": "F1KBNa_splitHScrollRow",
|
|
11836
|
-
"splitHScroll": "F1KBNa_splitHScroll",
|
|
11837
|
-
"diffPath": "F1KBNa_diffPath",
|
|
11838
|
-
"settingsRowText": "F1KBNa_settingsRowText",
|
|
11839
|
-
"detailEmpty": "F1KBNa_detailEmpty",
|
|
11840
|
-
"action": "F1KBNa_action",
|
|
11841
|
-
"notice": "F1KBNa_notice",
|
|
11842
|
-
"splitHScrollFill": "F1KBNa_splitHScrollFill",
|
|
11843
|
-
"splitLdel": "F1KBNa_splitLdel",
|
|
11844
|
-
"diffBodySplit": "F1KBNa_diffBodySplit",
|
|
11845
|
-
"wrap": "F1KBNa_wrap",
|
|
11846
|
-
"row": "F1KBNa_row",
|
|
11847
|
-
"expand": "F1KBNa_expand",
|
|
11930
|
+
"settingsSelectorChevron": "F1KBNa_settingsSelectorChevron",
|
|
11931
|
+
"group": "F1KBNa_group",
|
|
11932
|
+
"iconAction": "F1KBNa_iconAction",
|
|
11848
11933
|
"blockFlash": "F1KBNa_blockFlash",
|
|
11849
|
-
"
|
|
11850
|
-
"
|
|
11851
|
-
"
|
|
11934
|
+
"overviewRuler": "F1KBNa_overviewRuler",
|
|
11935
|
+
"row": "F1KBNa_row",
|
|
11936
|
+
"close": "F1KBNa_close",
|
|
11937
|
+
"settingsRowDesc": "F1KBNa_settingsRowDesc",
|
|
11852
11938
|
"states": "F1KBNa_states",
|
|
11853
|
-
"
|
|
11854
|
-
"
|
|
11855
|
-
"
|
|
11856
|
-
"
|
|
11939
|
+
"code": "F1KBNa_code",
|
|
11940
|
+
"kindTag": "F1KBNa_kindTag",
|
|
11941
|
+
"badgeCount": "F1KBNa_badgeCount",
|
|
11942
|
+
"badge": "F1KBNa_badge",
|
|
11943
|
+
"emptyState": "F1KBNa_emptyState",
|
|
11944
|
+
"rowPath": "F1KBNa_rowPath",
|
|
11945
|
+
"notice": "F1KBNa_notice",
|
|
11857
11946
|
"diffBodyWrap": "F1KBNa_diffBodyWrap",
|
|
11858
|
-
"
|
|
11947
|
+
"missingHint": "F1KBNa_missingHint",
|
|
11948
|
+
"resizeHandle": "F1KBNa_resizeHandle",
|
|
11949
|
+
"splitRoot": "F1KBNa_splitRoot",
|
|
11950
|
+
"expandExpanded": "F1KBNa_expandExpanded",
|
|
11951
|
+
"splitLadd": "F1KBNa_splitLadd",
|
|
11952
|
+
"settingsPage": "F1KBNa_settingsPage",
|
|
11953
|
+
"fullscreenBackdrop": "F1KBNa_fullscreenBackdrop",
|
|
11954
|
+
"layer": "F1KBNa_layer",
|
|
11955
|
+
"settingsSelector": "F1KBNa_settingsSelector",
|
|
11859
11956
|
"readError": "F1KBNa_readError",
|
|
11860
|
-
"
|
|
11861
|
-
"delCount": "F1KBNa_delCount",
|
|
11957
|
+
"importButton": "F1KBNa_importButton",
|
|
11862
11958
|
"addCount": "F1KBNa_addCount",
|
|
11863
|
-
"diffStats": "F1KBNa_diffStats",
|
|
11864
|
-
"close": "F1KBNa_close",
|
|
11865
|
-
"kindHint": "F1KBNa_kindHint",
|
|
11866
|
-
"blockPosition": "F1KBNa_blockPosition",
|
|
11867
|
-
"searchInput": "F1KBNa_searchInput",
|
|
11868
|
-
"overviewRuler": "F1KBNa_overviewRuler",
|
|
11869
|
-
"vSpacer": "F1KBNa_vSpacer",
|
|
11870
11959
|
"context": "F1KBNa_context",
|
|
11871
|
-
"
|
|
11960
|
+
"header": "F1KBNa_header",
|
|
11872
11961
|
"gutter": "F1KBNa_gutter",
|
|
11873
|
-
"
|
|
11874
|
-
"
|
|
11962
|
+
"confirmActions": "F1KBNa_confirmActions",
|
|
11963
|
+
"searchInput": "F1KBNa_searchInput",
|
|
11964
|
+
"importNote": "F1KBNa_importNote",
|
|
11875
11965
|
"noticeText": "F1KBNa_noticeText",
|
|
11876
|
-
"
|
|
11877
|
-
"
|
|
11966
|
+
"wrap": "F1KBNa_wrap",
|
|
11967
|
+
"splitHScrollRow": "F1KBNa_splitHScrollRow",
|
|
11968
|
+
"blockActions": "F1KBNa_blockActions",
|
|
11969
|
+
"splitHScroll": "F1KBNa_splitHScroll",
|
|
11970
|
+
"splitHScrollFill": "F1KBNa_splitHScrollFill",
|
|
11971
|
+
"fileListFloat": "F1KBNa_fileListFloat",
|
|
11972
|
+
"noteCentered": "F1KBNa_noteCentered",
|
|
11973
|
+
"diffActions": "F1KBNa_diffActions",
|
|
11974
|
+
"searchCount": "F1KBNa_searchCount",
|
|
11975
|
+
"add": "F1KBNa_add",
|
|
11976
|
+
"diffStats": "F1KBNa_diffStats",
|
|
11977
|
+
"langLabel": "F1KBNa_langLabel",
|
|
11978
|
+
"detailEmpty": "F1KBNa_detailEmpty",
|
|
11979
|
+
"actionPrimary": "F1KBNa_actionPrimary",
|
|
11980
|
+
"diffBody": "F1KBNa_diffBody",
|
|
11878
11981
|
"rowMeta": "F1KBNa_rowMeta",
|
|
11879
11982
|
"diffHeader": "F1KBNa_diffHeader",
|
|
11880
|
-
"
|
|
11983
|
+
"blockPosition": "F1KBNa_blockPosition",
|
|
11984
|
+
"subline": "F1KBNa_subline",
|
|
11985
|
+
"splitCol": "F1KBNa_splitCol",
|
|
11986
|
+
"missing": "F1KBNa_missing",
|
|
11987
|
+
"splitDivider": "F1KBNa_splitDivider",
|
|
11988
|
+
"rowFailed": "F1KBNa_rowFailed",
|
|
11989
|
+
"listScroll": "F1KBNa_listScroll",
|
|
11990
|
+
"actionError": "F1KBNa_actionError",
|
|
11881
11991
|
"headerActions": "F1KBNa_headerActions",
|
|
11992
|
+
"confirmCard": "F1KBNa_confirmCard",
|
|
11882
11993
|
"actionQuietDisabled": "F1KBNa_actionQuietDisabled",
|
|
11883
|
-
"detail": "F1KBNa_detail",
|
|
11884
|
-
"missing": "F1KBNa_missing",
|
|
11885
11994
|
"markerDel": "F1KBNa_markerDel",
|
|
11886
|
-
"
|
|
11887
|
-
"langSelect": "F1KBNa_langSelect",
|
|
11888
|
-
"importNote": "F1KBNa_importNote",
|
|
11889
|
-
"listScroll": "F1KBNa_listScroll",
|
|
11890
|
-
"group": "F1KBNa_group",
|
|
11995
|
+
"bulkActions": "F1KBNa_bulkActions",
|
|
11891
11996
|
"divergedHint": "F1KBNa_divergedHint",
|
|
11892
|
-
"splitCol": "F1KBNa_splitCol",
|
|
11893
|
-
"resizeHandle": "F1KBNa_resizeHandle",
|
|
11894
|
-
"actionPrimary": "F1KBNa_actionPrimary",
|
|
11895
|
-
"diffFlash": "F1KBNa_diffFlash",
|
|
11896
|
-
"subline": "F1KBNa_subline",
|
|
11897
|
-
"statusAction": "F1KBNa_statusAction",
|
|
11898
|
-
"noteCentered": "F1KBNa_noteCentered",
|
|
11899
|
-
"actionError": "F1KBNa_actionError",
|
|
11900
11997
|
"lines": "F1KBNa_lines",
|
|
11901
|
-
"
|
|
11902
|
-
"
|
|
11998
|
+
"badgeLabel": "F1KBNa_badgeLabel",
|
|
11999
|
+
"detail": "F1KBNa_detail",
|
|
12000
|
+
"splitRadd": "F1KBNa_splitRadd",
|
|
12001
|
+
"footerButtons": "F1KBNa_footerButtons",
|
|
12002
|
+
"expand": "F1KBNa_expand",
|
|
12003
|
+
"overviewMarker": "F1KBNa_overviewMarker",
|
|
11903
12004
|
"markerAdd": "F1KBNa_markerAdd",
|
|
11904
|
-
"
|
|
11905
|
-
"
|
|
11906
|
-
"
|
|
11907
|
-
"
|
|
11908
|
-
"
|
|
11909
|
-
"
|
|
11910
|
-
"
|
|
11911
|
-
"
|
|
12005
|
+
"hint": "F1KBNa_hint",
|
|
12006
|
+
"line": "F1KBNa_line",
|
|
12007
|
+
"wrapActive": "F1KBNa_wrapActive",
|
|
12008
|
+
"diffBodySplit": "F1KBNa_diffBodySplit",
|
|
12009
|
+
"delCount": "F1KBNa_delCount",
|
|
12010
|
+
"confirmText": "F1KBNa_confirmText",
|
|
12011
|
+
"note": "F1KBNa_note",
|
|
12012
|
+
"rows": "F1KBNa_rows",
|
|
11912
12013
|
"settingsRow": "F1KBNa_settingsRow",
|
|
11913
|
-
"
|
|
11914
|
-
"
|
|
11915
|
-
"
|
|
11916
|
-
"
|
|
11917
|
-
"
|
|
11918
|
-
"
|
|
11919
|
-
"
|
|
11920
|
-
"
|
|
11921
|
-
"
|
|
11922
|
-
"
|
|
12014
|
+
"diffFlash": "F1KBNa_diffFlash",
|
|
12015
|
+
"del": "F1KBNa_del",
|
|
12016
|
+
"title": "F1KBNa_title",
|
|
12017
|
+
"statusAction": "F1KBNa_statusAction",
|
|
12018
|
+
"panel": "F1KBNa_panel",
|
|
12019
|
+
"fileList": "F1KBNa_fileList",
|
|
12020
|
+
"splitCols": "F1KBNa_splitCols",
|
|
12021
|
+
"settingsRowText": "F1KBNa_settingsRowText",
|
|
12022
|
+
"diff": "F1KBNa_diff",
|
|
12023
|
+
"confirmBackdrop": "F1KBNa_confirmBackdrop",
|
|
12024
|
+
"statusBar": "F1KBNa_statusBar",
|
|
12025
|
+
"splitLdel": "F1KBNa_splitLdel",
|
|
11923
12026
|
"split": "F1KBNa_split",
|
|
11924
|
-
"
|
|
12027
|
+
"langSelect": "F1KBNa_langSelect",
|
|
12028
|
+
"rail": "F1KBNa_rail",
|
|
12029
|
+
"rowHead": "F1KBNa_rowHead",
|
|
12030
|
+
"action": "F1KBNa_action",
|
|
12031
|
+
"vSpacer": "F1KBNa_vSpacer",
|
|
12032
|
+
"noticeButton": "F1KBNa_noticeButton"
|
|
11925
12033
|
};
|
|
11926
12034
|
//#endregion
|
|
11927
12035
|
//#region lib/types/client/PendingPanel.js
|
|
@@ -11960,6 +12068,10 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
11960
12068
|
/** Total width of the two line-number gutters, subtracted from the code width
|
|
11961
12069
|
* when measuring wrapped line heights. */
|
|
11962
12070
|
const WRAP_GUTTERS_PX = 88;
|
|
12071
|
+
/** The dsh shell's sidebar auto-collapse breakpoint (ui-layout columns.ts):
|
|
12072
|
+
* below it the sidebar auto-collapses, and the file list floats on the same
|
|
12073
|
+
* breakpoint so the two stay consistent. */
|
|
12074
|
+
const SIDEBAR_AUTO_COLLAPSE_PX = 1024;
|
|
11963
12075
|
/** A shared canvas for measuring wrapped line heights (CPU-only, no DOM reflow). */
|
|
11964
12076
|
let measureCanvas;
|
|
11965
12077
|
/**
|
|
@@ -12551,12 +12663,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12551
12663
|
const clamped = Math.max(0, Math.min(target, body.scrollHeight - body.clientHeight));
|
|
12552
12664
|
if (body.scrollTop !== clamped) body.scrollTop = clamped;
|
|
12553
12665
|
setScrollTop(clamped);
|
|
12554
|
-
}, [
|
|
12555
|
-
model,
|
|
12556
|
-
focus,
|
|
12557
|
-
flashKey,
|
|
12558
|
-
pairCount
|
|
12559
|
-
]);
|
|
12666
|
+
}, [focus, flashKey]);
|
|
12560
12667
|
const onScroll = () => {
|
|
12561
12668
|
setScrollTop(bodyRef.current?.scrollTop ?? 0);
|
|
12562
12669
|
};
|
|
@@ -12951,7 +13058,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12951
13058
|
title: failedMessage,
|
|
12952
13059
|
children: t("row.failed")
|
|
12953
13060
|
}),
|
|
12954
|
-
(0, react_jsx_runtime.jsxs)("span", {
|
|
13061
|
+
(stats.added !== 0 || stats.removed !== 0) && (0, react_jsx_runtime.jsxs)("span", {
|
|
12955
13062
|
className: PendingPanel_module_css_default.rowMeta,
|
|
12956
13063
|
children: [(0, react_jsx_runtime.jsx)("span", {
|
|
12957
13064
|
className: PendingPanel_module_css_default.addCount,
|
|
@@ -12967,7 +13074,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12967
13074
|
});
|
|
12968
13075
|
}
|
|
12969
13076
|
/** The selected file's diff, actions, jump controls, and copy toolbar. */
|
|
12970
|
-
function PendingDiff({ file, busy, workspacePath, jumpSignal, undoFlash, failedMessage, onPasteReference, t, onKeep, onRevert, onBlockKeep, onBlockRevert, onOpen, floatMode, floatOpen, onToggleFileList }) {
|
|
13077
|
+
function PendingDiff({ file, busy, workspacePath, jumpSignal, undoFlash, failedMessage, onPasteReference, onToast, t, onKeep, onRevert, onBlockKeep, onBlockRevert, onOpen, floatMode, floatOpen, onToggleFileList }) {
|
|
12971
13078
|
const [langOverride, setLangOverride] = (0, react.useState)(void 0);
|
|
12972
13079
|
const [langMenuOpen, setLangMenuOpen] = (0, react.useState)(false);
|
|
12973
13080
|
const langMenuItems = (0, react.useMemo)(() => [{
|
|
@@ -13071,6 +13178,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13071
13178
|
const [flashKey, setFlashKey] = (0, react.useState)(0);
|
|
13072
13179
|
(0, react.useEffect)(() => {
|
|
13073
13180
|
setFocus(0);
|
|
13181
|
+
setScrollTick((tick) => tick + 1);
|
|
13074
13182
|
bodyRef.current?.focus();
|
|
13075
13183
|
setFlashKey((key) => key + 1);
|
|
13076
13184
|
setHoveredBlock(void 0);
|
|
@@ -13091,6 +13199,32 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13091
13199
|
const blockRanges = (0, react.useMemo)(() => {
|
|
13092
13200
|
return model.blocks.map((block) => blockRangesOf(model.diff.rows, block));
|
|
13093
13201
|
}, [model]);
|
|
13202
|
+
const coveredBlockIndices = (0, react.useMemo)(() => {
|
|
13203
|
+
if (selection === void 0 || splitView) return [];
|
|
13204
|
+
const covered = [];
|
|
13205
|
+
for (let index = 0; index < model.blocks.length; index++) {
|
|
13206
|
+
const block = model.blocks[index];
|
|
13207
|
+
if (selection.start <= block.start && block.end <= selection.end) covered.push(index);
|
|
13208
|
+
}
|
|
13209
|
+
return covered;
|
|
13210
|
+
}, [
|
|
13211
|
+
selection,
|
|
13212
|
+
splitView,
|
|
13213
|
+
model
|
|
13214
|
+
]);
|
|
13215
|
+
const selectionRange = (0, react.useMemo)(() => {
|
|
13216
|
+
if (coveredBlockIndices.length === 0) return void 0;
|
|
13217
|
+
const firstIndex = coveredBlockIndices[0];
|
|
13218
|
+
const lastIndex = coveredBlockIndices[coveredBlockIndices.length - 1];
|
|
13219
|
+
if (firstIndex === void 0 || lastIndex === void 0) return void 0;
|
|
13220
|
+
const first = model.blocks[firstIndex];
|
|
13221
|
+
const last = model.blocks[lastIndex];
|
|
13222
|
+
if (first === void 0 || last === void 0) return void 0;
|
|
13223
|
+
return blockRangesOf(model.diff.rows, {
|
|
13224
|
+
start: first.start,
|
|
13225
|
+
end: last.end
|
|
13226
|
+
});
|
|
13227
|
+
}, [coveredBlockIndices, model]);
|
|
13094
13228
|
const searchMatches = (0, react.useMemo)(() => {
|
|
13095
13229
|
if (searchQuery === "") return [];
|
|
13096
13230
|
const lower = searchQuery.toLowerCase();
|
|
@@ -13196,6 +13330,13 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13196
13330
|
const visibleRows = rows.slice(start, end);
|
|
13197
13331
|
const blockEnd = hoveredBlock === void 0 ? void 0 : model.blocks[hoveredBlock]?.end;
|
|
13198
13332
|
const blockActionsTop = blockEnd === void 0 ? 0 : Math.min(offsetOf(blockEnd + 1), Math.max(0, totalHeight - BLOCK_ACTIONS_FRAME_PX));
|
|
13333
|
+
const selectionBlockEnd = (() => {
|
|
13334
|
+
if (coveredBlockIndices.length === 0) return void 0;
|
|
13335
|
+
const lastIndex = coveredBlockIndices[coveredBlockIndices.length - 1];
|
|
13336
|
+
if (lastIndex === void 0) return void 0;
|
|
13337
|
+
return model.blocks[lastIndex]?.end;
|
|
13338
|
+
})();
|
|
13339
|
+
const selectionActionsTop = selectionBlockEnd === void 0 ? 0 : Math.min(offsetOf(selectionBlockEnd + 1), Math.max(0, totalHeight - BLOCK_ACTIONS_FRAME_PX));
|
|
13199
13340
|
const widestLine = (0, react.useMemo)(() => {
|
|
13200
13341
|
let widest = 0;
|
|
13201
13342
|
for (const row of model.diff.rows) if (row.text.length > widest) widest = row.text.length;
|
|
@@ -13239,10 +13380,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13239
13380
|
if (body.scrollTop !== clamped) body.scrollTop = clamped;
|
|
13240
13381
|
setScrollTop(clamped);
|
|
13241
13382
|
}, [
|
|
13242
|
-
model,
|
|
13243
13383
|
focus,
|
|
13244
13384
|
scrollTick,
|
|
13245
|
-
rowCount,
|
|
13246
13385
|
rowOffsets === null
|
|
13247
13386
|
]);
|
|
13248
13387
|
const jump = (direction) => {
|
|
@@ -13278,10 +13417,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13278
13417
|
setScrollTick((tick) => tick + 1);
|
|
13279
13418
|
setFlashKey((key) => key + 1);
|
|
13280
13419
|
};
|
|
13281
|
-
const
|
|
13282
|
-
if (busy || hoveredBlock === void 0) return;
|
|
13283
|
-
const operated = hoveredBlock;
|
|
13284
|
-
const range = blockRanges[operated];
|
|
13420
|
+
const runBlockAction = async (action, range, operated) => {
|
|
13285
13421
|
await (action === "keep" ? onBlockKeep(file.sessionId, file.id, range) : onBlockRevert(file.sessionId, file.id, range));
|
|
13286
13422
|
const count = model.blocks.length;
|
|
13287
13423
|
if (count === 0) return;
|
|
@@ -13291,6 +13427,18 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13291
13427
|
setScrollTick((tick) => tick + 1);
|
|
13292
13428
|
setFlashKey((key) => key + 1);
|
|
13293
13429
|
};
|
|
13430
|
+
const handleBlockAction = async (action) => {
|
|
13431
|
+
if (busy || hoveredBlock === void 0) return;
|
|
13432
|
+
const operated = hoveredBlock;
|
|
13433
|
+
const range = blockRanges[operated];
|
|
13434
|
+
await runBlockAction(action, range, operated);
|
|
13435
|
+
};
|
|
13436
|
+
const handleSelectionAction = async (action) => {
|
|
13437
|
+
if (busy || selectionRange === void 0) return;
|
|
13438
|
+
const firstCovered = coveredBlockIndices[0];
|
|
13439
|
+
if (firstCovered === void 0) return;
|
|
13440
|
+
await runBlockAction(action, selectionRange, firstCovered);
|
|
13441
|
+
};
|
|
13294
13442
|
(0, react.useEffect)(() => {
|
|
13295
13443
|
if (jumpSignal === 0) return;
|
|
13296
13444
|
jumpBlock(1);
|
|
@@ -13329,16 +13477,22 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13329
13477
|
})();
|
|
13330
13478
|
const copySelection = (0, react.useCallback)(async () => {
|
|
13331
13479
|
if (selectionReference === void 0) return;
|
|
13480
|
+
if (pasteOnCopyEnabled()) {
|
|
13481
|
+
onPasteReference(file.sessionId, selectionReference);
|
|
13482
|
+
return;
|
|
13483
|
+
}
|
|
13332
13484
|
if (!await (0, _deepseek_ai_dsh_client_ui_primitives.writeClipboard)(selectionReference)) return;
|
|
13333
13485
|
setCopied(true);
|
|
13334
|
-
|
|
13486
|
+
onToast(t("action.copied"));
|
|
13335
13487
|
window.setTimeout(() => {
|
|
13336
13488
|
setCopied(false);
|
|
13337
13489
|
}, 1500);
|
|
13338
13490
|
}, [
|
|
13339
13491
|
file.sessionId,
|
|
13340
13492
|
onPasteReference,
|
|
13341
|
-
|
|
13493
|
+
onToast,
|
|
13494
|
+
selectionReference,
|
|
13495
|
+
t
|
|
13342
13496
|
]);
|
|
13343
13497
|
(0, react.useEffect)(() => {
|
|
13344
13498
|
const onKeyDown = (event) => {
|
|
@@ -13458,7 +13612,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13458
13612
|
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconListPenOutline16, { size: 14 })
|
|
13459
13613
|
})
|
|
13460
13614
|
}),
|
|
13461
|
-
(0, react_jsx_runtime.jsx)("span", {
|
|
13615
|
+
(model.diff.added !== 0 || model.diff.removed !== 0) && (0, react_jsx_runtime.jsx)("span", {
|
|
13462
13616
|
className: PendingPanel_module_css_default.diffStats,
|
|
13463
13617
|
children: t("panel.stats", {
|
|
13464
13618
|
added: model.diff.added,
|
|
@@ -13600,7 +13754,30 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13600
13754
|
"aria-hidden": "true"
|
|
13601
13755
|
})
|
|
13602
13756
|
]
|
|
13603
|
-
}),
|
|
13757
|
+
}), selectionRange !== void 0 ? (0, react_jsx_runtime.jsxs)("div", {
|
|
13758
|
+
className: PendingPanel_module_css_default.blockActions,
|
|
13759
|
+
"data-diff-selection-actions": true,
|
|
13760
|
+
style: { top: selectionActionsTop },
|
|
13761
|
+
children: [(0, react_jsx_runtime.jsx)("button", {
|
|
13762
|
+
type: "button",
|
|
13763
|
+
className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.actionPrimary}`,
|
|
13764
|
+
"data-diff-selection-keep": true,
|
|
13765
|
+
disabled: busy,
|
|
13766
|
+
onClick: () => {
|
|
13767
|
+
handleSelectionAction("keep");
|
|
13768
|
+
},
|
|
13769
|
+
children: t("action.keep")
|
|
13770
|
+
}), (0, react_jsx_runtime.jsx)("button", {
|
|
13771
|
+
type: "button",
|
|
13772
|
+
className: PendingPanel_module_css_default.action,
|
|
13773
|
+
"data-diff-selection-revert": true,
|
|
13774
|
+
disabled: busy,
|
|
13775
|
+
onClick: () => {
|
|
13776
|
+
handleSelectionAction("revert");
|
|
13777
|
+
},
|
|
13778
|
+
children: t("action.revert")
|
|
13779
|
+
})]
|
|
13780
|
+
}) : hoveredBlock !== void 0 && model.blocks[hoveredBlock] !== void 0 ? (0, react_jsx_runtime.jsxs)("div", {
|
|
13604
13781
|
className: PendingPanel_module_css_default.blockActions,
|
|
13605
13782
|
"data-diff-block-actions": true,
|
|
13606
13783
|
style: { top: blockActionsTop },
|
|
@@ -13656,7 +13833,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13656
13833
|
children: t("action.revert")
|
|
13657
13834
|
})
|
|
13658
13835
|
]
|
|
13659
|
-
})]
|
|
13836
|
+
}) : null]
|
|
13660
13837
|
}),
|
|
13661
13838
|
focusedBlock !== void 0 && flashKey > 0 && (0, react_jsx_runtime.jsx)("div", {
|
|
13662
13839
|
className: PendingPanel_module_css_default.blockFlash,
|
|
@@ -13818,7 +13995,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13818
13995
|
});
|
|
13819
13996
|
}
|
|
13820
13997
|
/** Render the pending-edit review panel and its unified footer action. */
|
|
13821
|
-
function PendingPanel({ wide, useSessions, usePending, onRefresh, onKeep, onRevert, onBlockKeep, onBlockRevert, onOpen, onPasteReference, onUndo, onRedo, onImportVcs, onAckRedoCleared, t }) {
|
|
13998
|
+
function PendingPanel({ wide, useSessions, usePending, onRefresh, onKeep, onRevert, onBlockKeep, onBlockRevert, onOpen, onPasteReference, onUndo, onRedo, onImportVcs, onAckRedoCleared, onAckJustResolved, collapseSidebar, t }) {
|
|
13822
13999
|
const current = useSessions((state) => state.current);
|
|
13823
14000
|
const currentBlank = useSessions((state) => {
|
|
13824
14001
|
const id = state.current;
|
|
@@ -13846,8 +14023,12 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13846
14023
|
const [importToast, setImportToast] = (0, react.useState)(null);
|
|
13847
14024
|
/** A transient banner for a keep/revert failure. */
|
|
13848
14025
|
const [actionToast, setActionToast] = (0, react.useState)(null);
|
|
14026
|
+
/** A transient banner confirming a reference was copied to the clipboard. */
|
|
14027
|
+
const [copyToast, setCopyToast] = (0, react.useState)(null);
|
|
13849
14028
|
/** Whether the redo-cleared notice is showing (bottom-right, OK to dismiss). */
|
|
13850
14029
|
const [redoClearedNotice, setRedoClearedNotice] = (0, react.useState)(false);
|
|
14030
|
+
/** A file whose last block just resolved, pending a remove-or-keep choice. */
|
|
14031
|
+
const [confirmDismiss, setConfirmDismiss] = (0, react.useState)(null);
|
|
13851
14032
|
/** Bottom offset tracking the chat composer's top edge so the input stays visible. */
|
|
13852
14033
|
const [bottomPx, setBottomPx] = (0, react.useState)(FALLBACK_BOTTOM_PX);
|
|
13853
14034
|
/** Fullscreen expanded: the panel bottom pins to the window edge, ignoring the composer offset. */
|
|
@@ -13860,6 +14041,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13860
14041
|
/** The review panel's width, measured so the file list can collapse when it
|
|
13861
14042
|
* would take more than a third of it (browser zoom / window resize). */
|
|
13862
14043
|
const [panelWidth, setPanelWidth] = (0, react.useState)(0);
|
|
14044
|
+
const [viewportWidth, setViewportWidth] = (0, react.useState)(() => window.innerWidth);
|
|
13863
14045
|
const panelRef = (0, react.useRef)(null);
|
|
13864
14046
|
const splitRef = (0, react.useRef)(null);
|
|
13865
14047
|
/** The code scroll box's bounds within the split, so the floating card is
|
|
@@ -13887,10 +14069,19 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13887
14069
|
observer?.disconnect();
|
|
13888
14070
|
};
|
|
13889
14071
|
}, [open]);
|
|
13890
|
-
const floatMode =
|
|
14072
|
+
const floatMode = viewportWidth < SIDEBAR_AUTO_COLLAPSE_PX;
|
|
13891
14073
|
const toggleFileList = () => {
|
|
13892
14074
|
setFloatOpen((value) => !value);
|
|
13893
14075
|
};
|
|
14076
|
+
(0, react.useEffect)(() => {
|
|
14077
|
+
const onResize = () => {
|
|
14078
|
+
setViewportWidth(window.innerWidth);
|
|
14079
|
+
};
|
|
14080
|
+
window.addEventListener("resize", onResize);
|
|
14081
|
+
return () => {
|
|
14082
|
+
window.removeEventListener("resize", onResize);
|
|
14083
|
+
};
|
|
14084
|
+
}, []);
|
|
13894
14085
|
(0, react.useEffect)(() => {
|
|
13895
14086
|
if (!floatMode || !floatOpen) return;
|
|
13896
14087
|
const el = panelRef.current;
|
|
@@ -13992,6 +14183,11 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13992
14183
|
if (fresh.length > 0) setActionToast(fresh[0][1]);
|
|
13993
14184
|
failedRef.current = current;
|
|
13994
14185
|
}, [snapshot.failed]);
|
|
14186
|
+
(0, react.useEffect)(() => {
|
|
14187
|
+
if (snapshot.justResolved === void 0) return;
|
|
14188
|
+
setConfirmDismiss(snapshot.justResolved);
|
|
14189
|
+
onAckJustResolved();
|
|
14190
|
+
}, [snapshot.justResolved, onAckJustResolved]);
|
|
13995
14191
|
(0, react.useEffect)(() => {
|
|
13996
14192
|
if (!open) return;
|
|
13997
14193
|
if (selected !== "" && files.some((file) => file.id === selected)) return;
|
|
@@ -14022,6 +14218,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
14022
14218
|
}
|
|
14023
14219
|
};
|
|
14024
14220
|
const toggleOpen = () => {
|
|
14221
|
+
if (!open) collapseSidebar();
|
|
14025
14222
|
setOpen((value) => !value);
|
|
14026
14223
|
};
|
|
14027
14224
|
(0, react.useEffect)(() => {
|
|
@@ -14048,6 +14245,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
14048
14245
|
}
|
|
14049
14246
|
}, entry.id);
|
|
14050
14247
|
const selectedFile = files.find((file) => file.id === selected);
|
|
14248
|
+
/** The file whose removal is being confirmed, if any. */
|
|
14249
|
+
const confirmFile = confirmDismiss === null ? void 0 : files.find((file) => file.id === confirmDismiss);
|
|
14051
14250
|
const fileListBody = (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)("div", {
|
|
14052
14251
|
className: PendingPanel_module_css_default.listScroll,
|
|
14053
14252
|
children: files.length > 0 && (0, react_jsx_runtime.jsxs)("section", { children: [(0, react_jsx_runtime.jsx)("h3", {
|
|
@@ -14115,6 +14314,58 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
14115
14314
|
handleUndo,
|
|
14116
14315
|
handleRedo
|
|
14117
14316
|
]);
|
|
14317
|
+
(0, react.useEffect)(() => {
|
|
14318
|
+
if (!open || current === void 0) return;
|
|
14319
|
+
const onKeyDown = (event) => {
|
|
14320
|
+
if (!(event.ctrlKey || event.metaKey) || event.altKey) return;
|
|
14321
|
+
if (event.key.toLowerCase() !== "tab") return;
|
|
14322
|
+
const target = event.target;
|
|
14323
|
+
if (target instanceof Element && target.closest("input, textarea, [contenteditable=\"true\"]") !== null) return;
|
|
14324
|
+
if (files.length === 0) return;
|
|
14325
|
+
event.preventDefault();
|
|
14326
|
+
const index = files.findIndex((file) => file.id === selected);
|
|
14327
|
+
const direction = event.shiftKey ? -1 : 1;
|
|
14328
|
+
const next = files[(index + direction + files.length) % files.length];
|
|
14329
|
+
if (next !== void 0) setSelected(next.id);
|
|
14330
|
+
};
|
|
14331
|
+
window.addEventListener("keydown", onKeyDown, true);
|
|
14332
|
+
return () => {
|
|
14333
|
+
window.removeEventListener("keydown", onKeyDown, true);
|
|
14334
|
+
};
|
|
14335
|
+
}, [
|
|
14336
|
+
open,
|
|
14337
|
+
current,
|
|
14338
|
+
files,
|
|
14339
|
+
selected
|
|
14340
|
+
]);
|
|
14341
|
+
(0, react.useEffect)(() => {
|
|
14342
|
+
const onKeyDown = (event) => {
|
|
14343
|
+
if (!matchesShortcut(event, quickSummonKey())) return;
|
|
14344
|
+
const target = event.target;
|
|
14345
|
+
if (target instanceof Element && target.closest("input, textarea, [contenteditable=\"true\"]") !== null) return;
|
|
14346
|
+
event.preventDefault();
|
|
14347
|
+
if (!open) collapseSidebar();
|
|
14348
|
+
setOpen((value) => !value);
|
|
14349
|
+
};
|
|
14350
|
+
window.addEventListener("keydown", onKeyDown, true);
|
|
14351
|
+
return () => {
|
|
14352
|
+
window.removeEventListener("keydown", onKeyDown, true);
|
|
14353
|
+
};
|
|
14354
|
+
}, [open, collapseSidebar]);
|
|
14355
|
+
(0, react.useEffect)(() => {
|
|
14356
|
+
if (!open) return;
|
|
14357
|
+
const onKeyDown = (event) => {
|
|
14358
|
+
if (event.key !== "Escape") return;
|
|
14359
|
+
const target = event.target;
|
|
14360
|
+
if (target instanceof Element && target.closest("input, textarea, [contenteditable=\"true\"]") !== null) return;
|
|
14361
|
+
event.preventDefault();
|
|
14362
|
+
setOpen(false);
|
|
14363
|
+
};
|
|
14364
|
+
window.addEventListener("keydown", onKeyDown, true);
|
|
14365
|
+
return () => {
|
|
14366
|
+
window.removeEventListener("keydown", onKeyDown, true);
|
|
14367
|
+
};
|
|
14368
|
+
}, [open]);
|
|
14118
14369
|
/** Drag the list/detail divider; width follows the pointer within its bounds. */
|
|
14119
14370
|
const startResize = (event) => {
|
|
14120
14371
|
if (event.button !== 0) return;
|
|
@@ -14156,162 +14407,207 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
14156
14407
|
setActionToast(null);
|
|
14157
14408
|
}
|
|
14158
14409
|
}),
|
|
14159
|
-
|
|
14410
|
+
copyToast !== null && (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Toast, {
|
|
14411
|
+
text: copyToast,
|
|
14412
|
+
onDone: () => {
|
|
14413
|
+
setCopyToast(null);
|
|
14414
|
+
}
|
|
14415
|
+
}),
|
|
14416
|
+
open && (0, react_dom.createPortal)((0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [expanded && (0, react_jsx_runtime.jsx)("div", {
|
|
14160
14417
|
className: PendingPanel_module_css_default.fullscreenBackdrop,
|
|
14161
14418
|
"data-diff-fullscreen-backdrop": true
|
|
14162
|
-
}),
|
|
14163
|
-
open && (0, react_jsx_runtime.jsxs)("section", {
|
|
14419
|
+
}), (0, react_jsx_runtime.jsxs)("section", {
|
|
14164
14420
|
className: PendingPanel_module_css_default.panel,
|
|
14165
14421
|
ref: panelRef,
|
|
14166
14422
|
style: { bottom: expanded ? PANEL_INSET_PX : bottomPx },
|
|
14167
14423
|
"data-diff-approval-panel": true,
|
|
14168
14424
|
"aria-label": t("panel.title"),
|
|
14169
|
-
children: [
|
|
14170
|
-
|
|
14171
|
-
|
|
14172
|
-
|
|
14173
|
-
|
|
14174
|
-
|
|
14175
|
-
|
|
14176
|
-
|
|
14177
|
-
|
|
14178
|
-
|
|
14179
|
-
|
|
14180
|
-
|
|
14181
|
-
|
|
14182
|
-
|
|
14183
|
-
|
|
14184
|
-
|
|
14185
|
-
|
|
14186
|
-
|
|
14187
|
-
|
|
14188
|
-
|
|
14189
|
-
|
|
14190
|
-
|
|
14425
|
+
children: [
|
|
14426
|
+
(0, react_jsx_runtime.jsxs)("header", {
|
|
14427
|
+
className: PendingPanel_module_css_default.header,
|
|
14428
|
+
children: [(0, react_jsx_runtime.jsx)("span", {
|
|
14429
|
+
className: PendingPanel_module_css_default.title,
|
|
14430
|
+
children: t("panel.title")
|
|
14431
|
+
}), (0, react_jsx_runtime.jsxs)("div", {
|
|
14432
|
+
className: PendingPanel_module_css_default.headerActions,
|
|
14433
|
+
children: [
|
|
14434
|
+
(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
14435
|
+
label: t("action.settings"),
|
|
14436
|
+
side: "bottom",
|
|
14437
|
+
delayMs: 500,
|
|
14438
|
+
children: (0, react_jsx_runtime.jsx)("button", {
|
|
14439
|
+
type: "button",
|
|
14440
|
+
className: PendingPanel_module_css_default.expand,
|
|
14441
|
+
"data-diff-approval-settings": true,
|
|
14442
|
+
"aria-label": t("action.settings"),
|
|
14443
|
+
onClick: () => {
|
|
14444
|
+
setOpen(false);
|
|
14445
|
+
openSettingsSection(t("settings.tabLabel"));
|
|
14446
|
+
},
|
|
14447
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconSettingsOutline16, { size: 14 })
|
|
14448
|
+
})
|
|
14449
|
+
}),
|
|
14450
|
+
(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
14451
|
+
label: t(expanded ? "action.exitFullscreen" : "action.expand"),
|
|
14452
|
+
side: "bottom",
|
|
14453
|
+
delayMs: 500,
|
|
14454
|
+
children: (0, react_jsx_runtime.jsx)("button", {
|
|
14455
|
+
type: "button",
|
|
14456
|
+
className: expanded ? `${PendingPanel_module_css_default.expand} ${PendingPanel_module_css_default.expandExpanded}` : PendingPanel_module_css_default.expand,
|
|
14457
|
+
"data-diff-approval-expand": true,
|
|
14458
|
+
"aria-label": t(expanded ? "action.exitFullscreen" : "action.expand"),
|
|
14459
|
+
onClick: () => {
|
|
14460
|
+
if (!expanded) collapseSidebar();
|
|
14461
|
+
setExpanded((value) => !value);
|
|
14462
|
+
},
|
|
14463
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconFullscreenOutline16, { size: 14 })
|
|
14464
|
+
})
|
|
14465
|
+
}),
|
|
14466
|
+
(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
14467
|
+
label: t("action.close"),
|
|
14468
|
+
side: "bottom",
|
|
14469
|
+
delayMs: 500,
|
|
14470
|
+
children: (0, react_jsx_runtime.jsx)("button", {
|
|
14471
|
+
type: "button",
|
|
14472
|
+
className: PendingPanel_module_css_default.close,
|
|
14473
|
+
"data-diff-approval-close": true,
|
|
14474
|
+
"aria-label": t("action.close"),
|
|
14475
|
+
onClick: () => {
|
|
14476
|
+
setOpen(false);
|
|
14477
|
+
},
|
|
14478
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCloseOutline16, { size: 14 })
|
|
14479
|
+
})
|
|
14191
14480
|
})
|
|
14481
|
+
]
|
|
14482
|
+
})]
|
|
14483
|
+
}),
|
|
14484
|
+
snapshot.error !== void 0 || !snapshot.read || files.length === 0 ? (0, react_jsx_runtime.jsxs)("div", {
|
|
14485
|
+
className: PendingPanel_module_css_default.states,
|
|
14486
|
+
children: [
|
|
14487
|
+
snapshot.error !== void 0 && (0, react_jsx_runtime.jsx)("p", {
|
|
14488
|
+
className: PendingPanel_module_css_default.readError,
|
|
14489
|
+
role: "alert",
|
|
14490
|
+
children: t("panel.readFailed", { message: snapshot.error })
|
|
14192
14491
|
}),
|
|
14193
|
-
(0, react_jsx_runtime.jsx)(
|
|
14194
|
-
|
|
14195
|
-
|
|
14196
|
-
|
|
14197
|
-
|
|
14198
|
-
|
|
14199
|
-
|
|
14200
|
-
"
|
|
14201
|
-
|
|
14202
|
-
|
|
14203
|
-
|
|
14492
|
+
!snapshot.read && snapshot.error === void 0 && (0, react_jsx_runtime.jsx)("p", {
|
|
14493
|
+
className: PendingPanel_module_css_default.note,
|
|
14494
|
+
children: t("panel.loading")
|
|
14495
|
+
}),
|
|
14496
|
+
snapshot.read && snapshot.error === void 0 && files.length === 0 && (0, react_jsx_runtime.jsxs)("div", {
|
|
14497
|
+
className: PendingPanel_module_css_default.emptyState,
|
|
14498
|
+
children: [
|
|
14499
|
+
(0, react_jsx_runtime.jsx)("p", {
|
|
14500
|
+
className: `${PendingPanel_module_css_default.note} ${PendingPanel_module_css_default.noteCentered}`,
|
|
14501
|
+
children: t("panel.empty")
|
|
14502
|
+
}),
|
|
14503
|
+
(0, react_jsx_runtime.jsx)("button", {
|
|
14504
|
+
type: "button",
|
|
14505
|
+
className: PendingPanel_module_css_default.importButton,
|
|
14506
|
+
"data-diff-import-vcs": true,
|
|
14507
|
+
disabled: importBusy,
|
|
14508
|
+
onClick: () => {
|
|
14509
|
+
runImportVcs();
|
|
14510
|
+
},
|
|
14511
|
+
children: importBusy ? t("action.importVcsBusy") : t("action.importVcs")
|
|
14512
|
+
}),
|
|
14513
|
+
importNote !== void 0 && (0, react_jsx_runtime.jsx)("p", {
|
|
14514
|
+
className: PendingPanel_module_css_default.importNote,
|
|
14515
|
+
role: importFailed ? "alert" : void 0,
|
|
14516
|
+
children: importNote
|
|
14517
|
+
})
|
|
14518
|
+
]
|
|
14519
|
+
})
|
|
14520
|
+
]
|
|
14521
|
+
}) : (0, react_jsx_runtime.jsxs)("div", {
|
|
14522
|
+
className: PendingPanel_module_css_default.split,
|
|
14523
|
+
ref: splitRef,
|
|
14524
|
+
children: [
|
|
14525
|
+
!floatMode && (0, react_jsx_runtime.jsx)("nav", {
|
|
14526
|
+
className: PendingPanel_module_css_default.fileList,
|
|
14527
|
+
style: { width: listWidth },
|
|
14528
|
+
"data-diff-approval-file-list": true,
|
|
14529
|
+
children: fileListBody
|
|
14530
|
+
}),
|
|
14531
|
+
!floatMode && (0, react_jsx_runtime.jsx)("div", {
|
|
14532
|
+
className: PendingPanel_module_css_default.resizeHandle,
|
|
14533
|
+
"data-diff-resize": true,
|
|
14534
|
+
onMouseDown: startResize
|
|
14535
|
+
}),
|
|
14536
|
+
(0, react_jsx_runtime.jsx)("div", {
|
|
14537
|
+
className: PendingPanel_module_css_default.detail,
|
|
14538
|
+
children: selectedFile === void 0 ? (0, react_jsx_runtime.jsx)("p", {
|
|
14539
|
+
className: PendingPanel_module_css_default.detailEmpty,
|
|
14540
|
+
children: t("panel.selectHint")
|
|
14541
|
+
}) : (0, react_jsx_runtime.jsx)(PendingDiff, {
|
|
14542
|
+
file: selectedFile,
|
|
14543
|
+
busy: snapshot.busy.has(selectedFile.id),
|
|
14544
|
+
workspacePath: snapshot.workspacePath,
|
|
14545
|
+
jumpSignal,
|
|
14546
|
+
undoFlash,
|
|
14547
|
+
failedMessage: failed.get(selectedFile.id),
|
|
14548
|
+
onPasteReference,
|
|
14549
|
+
onToast: (text) => {
|
|
14550
|
+
setCopyToast(text);
|
|
14204
14551
|
},
|
|
14205
|
-
|
|
14552
|
+
t,
|
|
14553
|
+
onKeep,
|
|
14554
|
+
onRevert,
|
|
14555
|
+
onBlockKeep,
|
|
14556
|
+
onBlockRevert,
|
|
14557
|
+
onOpen,
|
|
14558
|
+
floatMode,
|
|
14559
|
+
floatOpen,
|
|
14560
|
+
onToggleFileList: toggleFileList
|
|
14206
14561
|
})
|
|
14207
14562
|
}),
|
|
14208
|
-
(0, react_jsx_runtime.jsx)(
|
|
14209
|
-
|
|
14210
|
-
|
|
14211
|
-
|
|
14212
|
-
|
|
14563
|
+
floatMode && floatOpen && files.length > 0 && floatBox !== null && (0, react_jsx_runtime.jsx)("div", {
|
|
14564
|
+
className: PendingPanel_module_css_default.fileListFloat,
|
|
14565
|
+
style: {
|
|
14566
|
+
left: floatBox.left + FLOAT_LIST_MARGIN_PX,
|
|
14567
|
+
top: floatBox.top + FLOAT_LIST_MARGIN_PX,
|
|
14568
|
+
width: Math.min(listWidth, Math.max(0, floatBox.width - 24)),
|
|
14569
|
+
height: Math.max(0, floatBox.height - 24)
|
|
14570
|
+
},
|
|
14571
|
+
"data-diff-floating-file-list": true,
|
|
14572
|
+
children: fileListBody
|
|
14573
|
+
})
|
|
14574
|
+
]
|
|
14575
|
+
}),
|
|
14576
|
+
confirmFile !== void 0 && (0, react_jsx_runtime.jsx)("div", {
|
|
14577
|
+
className: PendingPanel_module_css_default.confirmBackdrop,
|
|
14578
|
+
"data-diff-confirm": true,
|
|
14579
|
+
children: (0, react_jsx_runtime.jsxs)("div", {
|
|
14580
|
+
className: PendingPanel_module_css_default.confirmCard,
|
|
14581
|
+
role: "dialog",
|
|
14582
|
+
"aria-modal": "true",
|
|
14583
|
+
children: [(0, react_jsx_runtime.jsx)("p", {
|
|
14584
|
+
className: PendingPanel_module_css_default.confirmText,
|
|
14585
|
+
children: t("panel.resolvedAsk", { file: basenameOf(confirmFile.path) })
|
|
14586
|
+
}), (0, react_jsx_runtime.jsxs)("div", {
|
|
14587
|
+
className: PendingPanel_module_css_default.confirmActions,
|
|
14588
|
+
children: [(0, react_jsx_runtime.jsx)("button", {
|
|
14213
14589
|
type: "button",
|
|
14214
|
-
className: PendingPanel_module_css_default.
|
|
14215
|
-
"data-diff-
|
|
14216
|
-
"aria-label": t("action.close"),
|
|
14590
|
+
className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.actionPrimary}`,
|
|
14591
|
+
"data-diff-confirm-remove": true,
|
|
14217
14592
|
onClick: () => {
|
|
14218
|
-
|
|
14593
|
+
setConfirmDismiss(null);
|
|
14594
|
+
onKeep(confirmFile.sessionId, confirmFile.id);
|
|
14219
14595
|
},
|
|
14220
|
-
children: (
|
|
14221
|
-
})
|
|
14222
|
-
})
|
|
14223
|
-
]
|
|
14224
|
-
})]
|
|
14225
|
-
}), snapshot.error !== void 0 || !snapshot.read || files.length === 0 ? (0, react_jsx_runtime.jsxs)("div", {
|
|
14226
|
-
className: PendingPanel_module_css_default.states,
|
|
14227
|
-
children: [
|
|
14228
|
-
snapshot.error !== void 0 && (0, react_jsx_runtime.jsx)("p", {
|
|
14229
|
-
className: PendingPanel_module_css_default.readError,
|
|
14230
|
-
role: "alert",
|
|
14231
|
-
children: t("panel.readFailed", { message: snapshot.error })
|
|
14232
|
-
}),
|
|
14233
|
-
!snapshot.read && snapshot.error === void 0 && (0, react_jsx_runtime.jsx)("p", {
|
|
14234
|
-
className: PendingPanel_module_css_default.note,
|
|
14235
|
-
children: t("panel.loading")
|
|
14236
|
-
}),
|
|
14237
|
-
snapshot.read && snapshot.error === void 0 && files.length === 0 && (0, react_jsx_runtime.jsxs)("div", {
|
|
14238
|
-
className: PendingPanel_module_css_default.emptyState,
|
|
14239
|
-
children: [
|
|
14240
|
-
(0, react_jsx_runtime.jsx)("p", {
|
|
14241
|
-
className: `${PendingPanel_module_css_default.note} ${PendingPanel_module_css_default.noteCentered}`,
|
|
14242
|
-
children: t("panel.empty")
|
|
14243
|
-
}),
|
|
14244
|
-
(0, react_jsx_runtime.jsx)("button", {
|
|
14596
|
+
children: t("row.dismiss")
|
|
14597
|
+
}), (0, react_jsx_runtime.jsx)("button", {
|
|
14245
14598
|
type: "button",
|
|
14246
|
-
className: PendingPanel_module_css_default.
|
|
14247
|
-
"data-diff-
|
|
14248
|
-
disabled: importBusy,
|
|
14599
|
+
className: PendingPanel_module_css_default.action,
|
|
14600
|
+
"data-diff-confirm-keep": true,
|
|
14249
14601
|
onClick: () => {
|
|
14250
|
-
|
|
14602
|
+
setConfirmDismiss(null);
|
|
14251
14603
|
},
|
|
14252
|
-
children:
|
|
14253
|
-
})
|
|
14254
|
-
|
|
14255
|
-
className: PendingPanel_module_css_default.importNote,
|
|
14256
|
-
role: importFailed ? "alert" : void 0,
|
|
14257
|
-
children: importNote
|
|
14258
|
-
})
|
|
14259
|
-
]
|
|
14604
|
+
children: t("panel.keepInList")
|
|
14605
|
+
})]
|
|
14606
|
+
})]
|
|
14260
14607
|
})
|
|
14261
|
-
|
|
14262
|
-
|
|
14263
|
-
|
|
14264
|
-
ref: splitRef,
|
|
14265
|
-
children: [
|
|
14266
|
-
!floatMode && (0, react_jsx_runtime.jsx)("nav", {
|
|
14267
|
-
className: PendingPanel_module_css_default.fileList,
|
|
14268
|
-
style: { width: listWidth },
|
|
14269
|
-
"data-diff-approval-file-list": true,
|
|
14270
|
-
children: fileListBody
|
|
14271
|
-
}),
|
|
14272
|
-
!floatMode && (0, react_jsx_runtime.jsx)("div", {
|
|
14273
|
-
className: PendingPanel_module_css_default.resizeHandle,
|
|
14274
|
-
"data-diff-resize": true,
|
|
14275
|
-
onMouseDown: startResize
|
|
14276
|
-
}),
|
|
14277
|
-
(0, react_jsx_runtime.jsx)("div", {
|
|
14278
|
-
className: PendingPanel_module_css_default.detail,
|
|
14279
|
-
children: selectedFile === void 0 ? (0, react_jsx_runtime.jsx)("p", {
|
|
14280
|
-
className: PendingPanel_module_css_default.detailEmpty,
|
|
14281
|
-
children: t("panel.selectHint")
|
|
14282
|
-
}) : (0, react_jsx_runtime.jsx)(PendingDiff, {
|
|
14283
|
-
file: selectedFile,
|
|
14284
|
-
busy: snapshot.busy.has(selectedFile.id),
|
|
14285
|
-
workspacePath: snapshot.workspacePath,
|
|
14286
|
-
jumpSignal,
|
|
14287
|
-
undoFlash,
|
|
14288
|
-
failedMessage: failed.get(selectedFile.id),
|
|
14289
|
-
onPasteReference,
|
|
14290
|
-
t,
|
|
14291
|
-
onKeep,
|
|
14292
|
-
onRevert,
|
|
14293
|
-
onBlockKeep,
|
|
14294
|
-
onBlockRevert,
|
|
14295
|
-
onOpen,
|
|
14296
|
-
floatMode,
|
|
14297
|
-
floatOpen,
|
|
14298
|
-
onToggleFileList: toggleFileList
|
|
14299
|
-
})
|
|
14300
|
-
}),
|
|
14301
|
-
floatMode && floatOpen && files.length > 0 && floatBox !== null && (0, react_jsx_runtime.jsx)("div", {
|
|
14302
|
-
className: PendingPanel_module_css_default.fileListFloat,
|
|
14303
|
-
style: {
|
|
14304
|
-
left: floatBox.left + FLOAT_LIST_MARGIN_PX,
|
|
14305
|
-
top: floatBox.top + FLOAT_LIST_MARGIN_PX,
|
|
14306
|
-
width: Math.min(listWidth, Math.max(0, floatBox.width - 24)),
|
|
14307
|
-
height: Math.max(0, floatBox.height - 24)
|
|
14308
|
-
},
|
|
14309
|
-
"data-diff-floating-file-list": true,
|
|
14310
|
-
children: fileListBody
|
|
14311
|
-
})
|
|
14312
|
-
]
|
|
14313
|
-
})]
|
|
14314
|
-
}),
|
|
14608
|
+
})
|
|
14609
|
+
]
|
|
14610
|
+
})] }), document.body),
|
|
14315
14611
|
(0, react_jsx_runtime.jsx)("div", {
|
|
14316
14612
|
className: PendingPanel_module_css_default.footerButtons,
|
|
14317
14613
|
children: (0, react_jsx_runtime.jsxs)("button", {
|
|
@@ -14474,6 +14770,69 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
14474
14770
|
})]
|
|
14475
14771
|
});
|
|
14476
14772
|
}
|
|
14773
|
+
/** Build the `Modifier+...+Key` chord label from a keydown event; a bare
|
|
14774
|
+
* modifier key alone returns undefined (wait for the full combo). */
|
|
14775
|
+
function chordLabel(event) {
|
|
14776
|
+
const key = event.key;
|
|
14777
|
+
if (key === "Control" || key === "Shift" || key === "Alt" || key === "Meta") return void 0;
|
|
14778
|
+
const parts = [];
|
|
14779
|
+
if (event.ctrlKey) parts.push("Ctrl");
|
|
14780
|
+
if (event.altKey) parts.push("Alt");
|
|
14781
|
+
if (event.shiftKey) parts.push("Shift");
|
|
14782
|
+
if (event.metaKey) parts.push("Meta");
|
|
14783
|
+
parts.push(key.length === 1 ? key.toUpperCase() : key);
|
|
14784
|
+
return parts.join("+");
|
|
14785
|
+
}
|
|
14786
|
+
/** A button that records the next key chord (modifiers + key) as the shortcut. */
|
|
14787
|
+
function ShortcutRecorder({ value, onChange, dataAttribute, placeholder }) {
|
|
14788
|
+
const [recording, setRecording] = (0, react.useState)(false);
|
|
14789
|
+
return (0, react_jsx_runtime.jsxs)("button", {
|
|
14790
|
+
type: "button",
|
|
14791
|
+
className: PendingPanel_module_css_default.settingsSelector,
|
|
14792
|
+
onClick: () => {
|
|
14793
|
+
setRecording(true);
|
|
14794
|
+
},
|
|
14795
|
+
onBlur: () => {
|
|
14796
|
+
setRecording(false);
|
|
14797
|
+
},
|
|
14798
|
+
onKeyDown: recording ? (event) => {
|
|
14799
|
+
event.preventDefault();
|
|
14800
|
+
event.stopPropagation();
|
|
14801
|
+
if (event.key === "Escape") {
|
|
14802
|
+
setRecording(false);
|
|
14803
|
+
return;
|
|
14804
|
+
}
|
|
14805
|
+
const chord = chordLabel(event);
|
|
14806
|
+
if (chord !== void 0) {
|
|
14807
|
+
onChange(chord);
|
|
14808
|
+
setRecording(false);
|
|
14809
|
+
}
|
|
14810
|
+
} : void 0,
|
|
14811
|
+
[dataAttribute]: true,
|
|
14812
|
+
children: [recording ? placeholder : value, (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { className: PendingPanel_module_css_default.settingsSelectorChevron })]
|
|
14813
|
+
});
|
|
14814
|
+
}
|
|
14815
|
+
/** One shortcut row: title + description, chord recorder right. */
|
|
14816
|
+
function ShortcutRow({ title, description, value, onChange, dataAttribute, placeholder }) {
|
|
14817
|
+
return (0, react_jsx_runtime.jsxs)("div", {
|
|
14818
|
+
className: PendingPanel_module_css_default.settingsRow,
|
|
14819
|
+
children: [(0, react_jsx_runtime.jsxs)("div", {
|
|
14820
|
+
className: PendingPanel_module_css_default.settingsRowText,
|
|
14821
|
+
children: [(0, react_jsx_runtime.jsx)("div", {
|
|
14822
|
+
className: PendingPanel_module_css_default.settingsRowTitle,
|
|
14823
|
+
children: title
|
|
14824
|
+
}), (0, react_jsx_runtime.jsx)("div", {
|
|
14825
|
+
className: PendingPanel_module_css_default.settingsRowDesc,
|
|
14826
|
+
children: description
|
|
14827
|
+
})]
|
|
14828
|
+
}), (0, react_jsx_runtime.jsx)(ShortcutRecorder, {
|
|
14829
|
+
value,
|
|
14830
|
+
onChange,
|
|
14831
|
+
dataAttribute,
|
|
14832
|
+
placeholder
|
|
14833
|
+
})]
|
|
14834
|
+
});
|
|
14835
|
+
}
|
|
14477
14836
|
/**
|
|
14478
14837
|
* The plugin's preferences: auto-paste a copied reference into the input,
|
|
14479
14838
|
* whether importing workspace VCS changes includes untracked files, and the
|
|
@@ -14490,6 +14849,11 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
14490
14849
|
const [tabOpen, setTabOpen] = (0, react.useState)(false);
|
|
14491
14850
|
const [split, setSplitState] = (0, react.useState)(splitMode);
|
|
14492
14851
|
const [splitOpen, setSplitOpen] = (0, react.useState)(false);
|
|
14852
|
+
const [summon, setSummonState] = (0, react.useState)(quickSummonKey);
|
|
14853
|
+
const setSummon = (value) => {
|
|
14854
|
+
setSummonState(value);
|
|
14855
|
+
setQuickSummonKey(value);
|
|
14856
|
+
};
|
|
14493
14857
|
const setPasteOnCopy = (value) => {
|
|
14494
14858
|
setPasteOnCopyState(value);
|
|
14495
14859
|
setPasteOnCopyEnabled(value);
|
|
@@ -14548,6 +14912,14 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
14548
14912
|
onSelect: setSplit,
|
|
14549
14913
|
dataAttribute: "data-diff-split-mode-select",
|
|
14550
14914
|
t
|
|
14915
|
+
}),
|
|
14916
|
+
(0, react_jsx_runtime.jsx)(ShortcutRow, {
|
|
14917
|
+
title: t("panel.quickSummon"),
|
|
14918
|
+
description: t("panel.quickSummonDesc"),
|
|
14919
|
+
value: summon,
|
|
14920
|
+
onChange: setSummon,
|
|
14921
|
+
dataAttribute: "data-diff-quick-summon-key",
|
|
14922
|
+
placeholder: t("panel.recordShortcut")
|
|
14551
14923
|
})
|
|
14552
14924
|
]
|
|
14553
14925
|
});
|
|
@@ -14671,9 +15043,14 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
14671
15043
|
const outcome = value.outcome;
|
|
14672
15044
|
if (outcome !== "kept" && outcome !== "reverted" && outcome !== "missing" && outcome !== "undone" && outcome !== "redone" && outcome !== "nothing") throw new Error("the action returned a malformed outcome");
|
|
14673
15045
|
const id = value.id;
|
|
14674
|
-
|
|
15046
|
+
const entryId = typeof id === "string" && id.length > 0 ? id : void 0;
|
|
15047
|
+
return value.resolved === true ? {
|
|
15048
|
+
outcome,
|
|
15049
|
+
id: entryId,
|
|
15050
|
+
resolved: true
|
|
15051
|
+
} : {
|
|
14675
15052
|
outcome,
|
|
14676
|
-
id:
|
|
15053
|
+
id: entryId
|
|
14677
15054
|
};
|
|
14678
15055
|
}
|
|
14679
15056
|
/** Narrow the vcs-import endpoint's value; a malformed wire value is a failure. */
|
|
@@ -14726,11 +15103,18 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
14726
15103
|
};
|
|
14727
15104
|
const listeners = /* @__PURE__ */ new Set();
|
|
14728
15105
|
let redoCleared = false;
|
|
15106
|
+
let justResolved;
|
|
14729
15107
|
const publish = (next) => {
|
|
14730
|
-
|
|
14731
|
-
|
|
15108
|
+
let result = next;
|
|
15109
|
+
if (redoCleared) result = {
|
|
15110
|
+
...result,
|
|
14732
15111
|
redoCleared: true
|
|
14733
|
-
}
|
|
15112
|
+
};
|
|
15113
|
+
if (justResolved !== void 0) result = {
|
|
15114
|
+
...result,
|
|
15115
|
+
justResolved
|
|
15116
|
+
};
|
|
15117
|
+
snapshot = result;
|
|
14734
15118
|
for (const listener of [...listeners]) listener();
|
|
14735
15119
|
};
|
|
14736
15120
|
const failedOf = (value) => value.failed ?? EMPTY_FAILED;
|
|
@@ -14839,8 +15223,9 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
14839
15223
|
...base,
|
|
14840
15224
|
busy: /* @__PURE__ */ new Set([...snapshot.busy, id])
|
|
14841
15225
|
});
|
|
15226
|
+
let value;
|
|
14842
15227
|
try {
|
|
14843
|
-
await port.blockKeep(sessionId, id, block);
|
|
15228
|
+
value = await port.blockKeep(sessionId, id, block);
|
|
14844
15229
|
} catch (error) {
|
|
14845
15230
|
markFailed(id, error instanceof Error ? error.message : String(error));
|
|
14846
15231
|
publish({
|
|
@@ -14850,6 +15235,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
14850
15235
|
return;
|
|
14851
15236
|
}
|
|
14852
15237
|
clearFailed(id);
|
|
15238
|
+
if (value.resolved === true) justResolved = id;
|
|
14853
15239
|
await this.refresh(sessionId);
|
|
14854
15240
|
},
|
|
14855
15241
|
async blockRevert(sessionId, id, block) {
|
|
@@ -14858,8 +15244,9 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
14858
15244
|
...base,
|
|
14859
15245
|
busy: /* @__PURE__ */ new Set([...snapshot.busy, id])
|
|
14860
15246
|
});
|
|
15247
|
+
let value;
|
|
14861
15248
|
try {
|
|
14862
|
-
await port.blockRevert(sessionId, id, block);
|
|
15249
|
+
value = await port.blockRevert(sessionId, id, block);
|
|
14863
15250
|
} catch (error) {
|
|
14864
15251
|
markFailed(id, error instanceof Error ? error.message : String(error));
|
|
14865
15252
|
publish({
|
|
@@ -14869,6 +15256,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
14869
15256
|
return;
|
|
14870
15257
|
}
|
|
14871
15258
|
clearFailed(id);
|
|
15259
|
+
if (value.resolved === true) justResolved = id;
|
|
14872
15260
|
await this.refresh(sessionId);
|
|
14873
15261
|
},
|
|
14874
15262
|
async undo(sessionId) {
|
|
@@ -14907,6 +15295,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
14907
15295
|
}
|
|
14908
15296
|
},
|
|
14909
15297
|
reset() {
|
|
15298
|
+
justResolved = void 0;
|
|
14910
15299
|
publish({
|
|
14911
15300
|
read: false,
|
|
14912
15301
|
files: [],
|
|
@@ -14917,6 +15306,131 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
14917
15306
|
redoCleared = false;
|
|
14918
15307
|
const { redoCleared: _omit, ...rest } = snapshot;
|
|
14919
15308
|
publish(rest);
|
|
15309
|
+
},
|
|
15310
|
+
clearJustResolved() {
|
|
15311
|
+
justResolved = void 0;
|
|
15312
|
+
const { justResolved: _omit, ...rest } = snapshot;
|
|
15313
|
+
publish(rest);
|
|
15314
|
+
}
|
|
15315
|
+
};
|
|
15316
|
+
}
|
|
15317
|
+
//#endregion
|
|
15318
|
+
//#region lib/types/client/remap-sync.js
|
|
15319
|
+
/**
|
|
15320
|
+
* Reference remapping sync: track each pending file's last-seen content and,
|
|
15321
|
+
* when it changes (an agent edit, a block revert, or an external adoption),
|
|
15322
|
+
* rewrite stale references in the current composer draft and the pending queue.
|
|
15323
|
+
* Pure orchestration over the pending store; the actual line remapping lives in
|
|
15324
|
+
* `reference.ts`.
|
|
15325
|
+
* @module dsh-diff-approval/client/remap-sync
|
|
15326
|
+
*/
|
|
15327
|
+
/**
|
|
15328
|
+
* Subscribe to the pending store and remap references as each file's content
|
|
15329
|
+
* changes. The first observation of a file only seeds the baseline; a later
|
|
15330
|
+
* `newText` change remaps (draft + queue) and advances the baseline. Files that
|
|
15331
|
+
* leave the list drop their baseline so a future re-appearance re-baselines.
|
|
15332
|
+
* @param opts - the sync inputs.
|
|
15333
|
+
* @returns an unsubscribe function plus a direct remap verb for whole-file reverts.
|
|
15334
|
+
*/
|
|
15335
|
+
function attachReferenceRemap(opts) {
|
|
15336
|
+
const { store, readDraft, writeDraft, readQueue, writeQueue } = opts;
|
|
15337
|
+
const lastContent = /* @__PURE__ */ new Map();
|
|
15338
|
+
const remap = (path, oldText, newText, workspacePath) => {
|
|
15339
|
+
const referencePath = referencePathOf(path, workspacePath);
|
|
15340
|
+
const draft = readDraft();
|
|
15341
|
+
if (draft !== void 0 && draft !== "") {
|
|
15342
|
+
const rewritten = remapReferences(draft, referencePath, oldText, newText);
|
|
15343
|
+
if (rewritten !== draft) writeDraft(rewritten);
|
|
15344
|
+
}
|
|
15345
|
+
for (const message of readQueue()) {
|
|
15346
|
+
let changed = false;
|
|
15347
|
+
const content = message.content.map((block) => {
|
|
15348
|
+
if (block.type !== "text" || block.text === void 0) return block;
|
|
15349
|
+
const rewritten = remapReferences(block.text, referencePath, oldText, newText);
|
|
15350
|
+
if (rewritten !== block.text) {
|
|
15351
|
+
changed = true;
|
|
15352
|
+
return {
|
|
15353
|
+
...block,
|
|
15354
|
+
text: rewritten
|
|
15355
|
+
};
|
|
15356
|
+
}
|
|
15357
|
+
return block;
|
|
15358
|
+
});
|
|
15359
|
+
if (changed) writeQueue(message.id, content);
|
|
15360
|
+
}
|
|
15361
|
+
};
|
|
15362
|
+
const observe = () => {
|
|
15363
|
+
const snapshot = store.getSnapshot();
|
|
15364
|
+
for (const file of snapshot.files) {
|
|
15365
|
+
const previous = lastContent.get(file.path);
|
|
15366
|
+
if (previous === void 0) lastContent.set(file.path, file.newText);
|
|
15367
|
+
else if (previous !== file.newText) {
|
|
15368
|
+
remap(file.path, previous, file.newText, snapshot.workspacePath);
|
|
15369
|
+
lastContent.set(file.path, file.newText);
|
|
15370
|
+
}
|
|
15371
|
+
}
|
|
15372
|
+
for (const path of [...lastContent.keys()]) if (!snapshot.files.some((file) => file.path === path)) lastContent.delete(path);
|
|
15373
|
+
};
|
|
15374
|
+
const unsubscribe = store.subscribe(observe);
|
|
15375
|
+
observe();
|
|
15376
|
+
return {
|
|
15377
|
+
unsubscribe,
|
|
15378
|
+
remapFile: (path, oldText, newText) => {
|
|
15379
|
+
remap(path, oldText, newText, store.getSnapshot().workspacePath);
|
|
15380
|
+
}
|
|
15381
|
+
};
|
|
15382
|
+
}
|
|
15383
|
+
//#endregion
|
|
15384
|
+
//#region lib/types/client/conversation-access.js
|
|
15385
|
+
/**
|
|
15386
|
+
* Scope-addressed access to the session's composer draft and pending queue.
|
|
15387
|
+
* Extracted from the plugin entry so the wiring (not just the remap math) is
|
|
15388
|
+
* unit-testable against a faithful fake of the DSH conversation service.
|
|
15389
|
+
* @module dsh-diff-approval/client/conversation-access
|
|
15390
|
+
*/
|
|
15391
|
+
/**
|
|
15392
|
+
* Resolve the current session's scoped conversation face. The scoped context
|
|
15393
|
+
* (`sessions.scope(id)`) carries no `conversation` inject of its own, so reading
|
|
15394
|
+
* it as a property (`actx.conversation`) trips Cordis's inject check and throws
|
|
15395
|
+
* `cannot get property "conversation" without inject`. `actx.get('conversation')`
|
|
15396
|
+
* bypasses that check yet still returns the traceable bound to `actx`, so its
|
|
15397
|
+
* verbs (e.g. `updateQueue`) resolve the right session scope.
|
|
15398
|
+
*/
|
|
15399
|
+
function resolveConversation(ctx, sessionId) {
|
|
15400
|
+
if (sessionId === void 0) return void 0;
|
|
15401
|
+
const actx = ctx.get("sessions")?.scope(sessionId);
|
|
15402
|
+
if (actx === void 0) return void 0;
|
|
15403
|
+
const conversation = actx.get("conversation");
|
|
15404
|
+
if (conversation?.input === void 0) return void 0;
|
|
15405
|
+
return {
|
|
15406
|
+
actx,
|
|
15407
|
+
conversation
|
|
15408
|
+
};
|
|
15409
|
+
}
|
|
15410
|
+
/**
|
|
15411
|
+
* Build the per-call-resolved draft/queue accessor. `sessionId` is a function
|
|
15412
|
+
* so the accessor always addresses the *current* session, even though it is
|
|
15413
|
+
* handed to the remap sync once.
|
|
15414
|
+
*/
|
|
15415
|
+
function conversationAccess(ctx, sessionId) {
|
|
15416
|
+
return {
|
|
15417
|
+
writeDraft: (text) => {
|
|
15418
|
+
const scoped = resolveConversation(ctx, sessionId());
|
|
15419
|
+
if (scoped === void 0) return;
|
|
15420
|
+
scoped.conversation.input.for(scoped.actx).setDraft(text);
|
|
15421
|
+
},
|
|
15422
|
+
readQueue: () => {
|
|
15423
|
+
const scoped = resolveConversation(ctx, sessionId());
|
|
15424
|
+
if (scoped === void 0) return [];
|
|
15425
|
+
return scoped.conversation.input.for(scoped.actx).state.getSnapshot().queue.filter((item) => item.placement === "queued");
|
|
15426
|
+
},
|
|
15427
|
+
writeQueue: (itemId, content) => {
|
|
15428
|
+
const scoped = resolveConversation(ctx, sessionId());
|
|
15429
|
+
if (scoped === void 0) return;
|
|
15430
|
+
scoped.conversation.updateQueue(itemId, {
|
|
15431
|
+
kind: "edit",
|
|
15432
|
+
content
|
|
15433
|
+
});
|
|
14920
15434
|
}
|
|
14921
15435
|
};
|
|
14922
15436
|
}
|
|
@@ -14950,9 +15464,13 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
14950
15464
|
"panel.tabWidthDesc": "差异中制表符的缩进宽度,可选 2 / 4 / 8 个空格(默认 4),同时作用于行宽折行测量。",
|
|
14951
15465
|
"panel.splitMode": "双栏对比",
|
|
14952
15466
|
"panel.splitModeDesc": "开启后整文件差异用左「改前」|右「当前」双栏、逐行对齐的视图展示,默认关闭使用单栏(合并)视图。",
|
|
15467
|
+
"panel.quickSummon": "快速呼出",
|
|
15468
|
+
"panel.quickSummonDesc": "用键盘快捷键打开/关闭差异面板(默认 Ctrl+D)。点击右侧按钮后按下新的按键组合即可修改,Esc 取消。",
|
|
15469
|
+
"panel.recordShortcut": "按下快捷键…",
|
|
14953
15470
|
"settings.tabLabel": "改动审批",
|
|
14954
15471
|
"row.create": "新增文件",
|
|
14955
15472
|
"row.failed": "失败",
|
|
15473
|
+
"row.dismiss": "移除",
|
|
14956
15474
|
"row.added": "+{added}",
|
|
14957
15475
|
"row.removed": "-{removed}",
|
|
14958
15476
|
"action.keep": "保留",
|
|
@@ -14987,7 +15505,9 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
14987
15505
|
"action.close": "关闭",
|
|
14988
15506
|
"status.kept": "已保留",
|
|
14989
15507
|
"status.reverted": "已回退",
|
|
14990
|
-
"status.missing": "该改动已不存在"
|
|
15508
|
+
"status.missing": "该改动已不存在",
|
|
15509
|
+
"panel.resolvedAsk": "「{file}」的所有改动都已处理,是否从列表移除?",
|
|
15510
|
+
"panel.keepInList": "保留在列表"
|
|
14991
15511
|
};
|
|
14992
15512
|
/** English pending-edit review messages. */
|
|
14993
15513
|
const en = {
|
|
@@ -15015,9 +15535,13 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
15015
15535
|
"panel.tabWidthDesc": "The indent width of a tab character in the differences, as 2 / 4 / 8 spaces (default 4). Also drives the wrapped-line measurement.",
|
|
15016
15536
|
"panel.splitMode": "Side-by-side view",
|
|
15017
15537
|
"panel.splitModeDesc": "When on, the whole-file differences render as a side-by-side (left \"before\" | right \"current\") line-aligned view. Off (default) uses the single-column unified view.",
|
|
15538
|
+
"panel.quickSummon": "Quick summon",
|
|
15539
|
+
"panel.quickSummonDesc": "Open or close the diff panel with a keyboard shortcut (default Ctrl+D). Click the button and press a new chord to change it; Esc cancels.",
|
|
15540
|
+
"panel.recordShortcut": "Press keys…",
|
|
15018
15541
|
"settings.tabLabel": "Diff Approval",
|
|
15019
15542
|
"row.create": "New file",
|
|
15020
15543
|
"row.failed": "Failed",
|
|
15544
|
+
"row.dismiss": "Remove",
|
|
15021
15545
|
"row.added": "+{added}",
|
|
15022
15546
|
"row.removed": "-{removed}",
|
|
15023
15547
|
"action.keep": "Keep",
|
|
@@ -15052,17 +15576,21 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
15052
15576
|
"action.close": "Close",
|
|
15053
15577
|
"status.kept": "Kept",
|
|
15054
15578
|
"status.reverted": "Reverted",
|
|
15055
|
-
"status.missing": "This change no longer exists"
|
|
15579
|
+
"status.missing": "This change no longer exists",
|
|
15580
|
+
"panel.resolvedAsk": "All changes in \"{file}\" are resolved. Remove it from the list?",
|
|
15581
|
+
"panel.keepInList": "Keep in list"
|
|
15056
15582
|
};
|
|
15057
15583
|
//#endregion
|
|
15058
15584
|
//#region lib/types/client/index.js
|
|
15059
15585
|
/** Pending-edit review panel, browser half: footer action, pending list, and whole-file diff viewer. */
|
|
15060
|
-
/** Required services: locale, slots, the wire channel,
|
|
15586
|
+
/** Required services: locale, slots, the wire channel, the current session, and
|
|
15587
|
+
* the layout controller (this plugin collapses the sidebar before its modal opens). */
|
|
15061
15588
|
const inject = [
|
|
15062
15589
|
"slots",
|
|
15063
15590
|
"locale",
|
|
15064
15591
|
"connection",
|
|
15065
|
-
"sessions"
|
|
15592
|
+
"sessions",
|
|
15593
|
+
"layout"
|
|
15066
15594
|
];
|
|
15067
15595
|
/**
|
|
15068
15596
|
* The dsh web-react renderer gives `div[data-slot="sidebar.footer.action"]` an
|
|
@@ -15129,6 +15657,29 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
15129
15657
|
}), "ui-diff-approval: dictionaries");
|
|
15130
15658
|
const t = ctx.locale.bind(NS);
|
|
15131
15659
|
const store = createPendingDiffStore(createDiffApprovalPort(ctx.get("connection").rpc));
|
|
15660
|
+
let currentSessionId;
|
|
15661
|
+
let remapFile = () => {};
|
|
15662
|
+
const access = conversationAccess(ctx, () => currentSessionId);
|
|
15663
|
+
ctx.effect(() => {
|
|
15664
|
+
const attached = attachReferenceRemap({
|
|
15665
|
+
store,
|
|
15666
|
+
readDraft: () => document.querySelector("[data-composer-card] textarea")?.value,
|
|
15667
|
+
writeDraft: access.writeDraft,
|
|
15668
|
+
readQueue: access.readQueue,
|
|
15669
|
+
writeQueue: access.writeQueue
|
|
15670
|
+
});
|
|
15671
|
+
remapFile = attached.remapFile;
|
|
15672
|
+
return attached.unsubscribe;
|
|
15673
|
+
}, "diff-approval: reference remap");
|
|
15674
|
+
const collapseSidebar = () => {
|
|
15675
|
+
if (window.innerWidth >= 1024) return;
|
|
15676
|
+
const ctxLayout = ctx.layout;
|
|
15677
|
+
if (ctxLayout === void 0) return;
|
|
15678
|
+
if (document.querySelector("[data-sidebar-collapsed]") !== null) return;
|
|
15679
|
+
try {
|
|
15680
|
+
ctxLayout.toggleSidebar();
|
|
15681
|
+
} catch {}
|
|
15682
|
+
};
|
|
15132
15683
|
ctx.on("connection/reset", () => {
|
|
15133
15684
|
store.reset();
|
|
15134
15685
|
});
|
|
@@ -15139,10 +15690,19 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
15139
15690
|
inject: () => ({
|
|
15140
15691
|
hooks: { pending: store },
|
|
15141
15692
|
onRefresh: (sessionId) => {
|
|
15693
|
+
currentSessionId = sessionId;
|
|
15142
15694
|
store.refresh(sessionId);
|
|
15143
15695
|
},
|
|
15144
15696
|
onKeep: (sessionId, path) => store.keep(sessionId, path),
|
|
15145
|
-
onRevert: (sessionId, path) =>
|
|
15697
|
+
onRevert: (sessionId, path) => {
|
|
15698
|
+
const entry = store.getSnapshot().files.find((file) => file.id === path);
|
|
15699
|
+
const before = entry?.newText;
|
|
15700
|
+
const after = entry?.oldText;
|
|
15701
|
+
const filePath = entry?.path;
|
|
15702
|
+
return store.revert(sessionId, path).then(() => {
|
|
15703
|
+
if (filePath !== void 0 && before !== void 0 && after !== void 0) remapFile(filePath, before, after);
|
|
15704
|
+
});
|
|
15705
|
+
},
|
|
15146
15706
|
onBlockKeep: (sessionId, id, block) => store.blockKeep(sessionId, id, block),
|
|
15147
15707
|
onBlockRevert: (sessionId, id, block) => store.blockRevert(sessionId, id, block),
|
|
15148
15708
|
onOpen: (sessionId, id, action) => store.open(sessionId, id, action),
|
|
@@ -15150,6 +15710,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
15150
15710
|
onRedo: (sessionId) => store.redo(sessionId),
|
|
15151
15711
|
onImportVcs: (sessionId, includeUntracked) => store.importVcs(sessionId, includeUntracked),
|
|
15152
15712
|
onAckRedoCleared: () => store.clearRedoCleared(),
|
|
15713
|
+
onAckJustResolved: () => store.clearJustResolved(),
|
|
15153
15714
|
onPasteReference: (sessionId, reference) => {
|
|
15154
15715
|
const actx = ctx.get("sessions")?.scope(sessionId);
|
|
15155
15716
|
if (actx === void 0) return;
|
|
@@ -15159,7 +15720,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
15159
15720
|
const base = textarea?.value ?? "";
|
|
15160
15721
|
conversation.input.for(actx).setDraft(base === "" ? reference : `${base} ${reference}`);
|
|
15161
15722
|
textarea?.focus();
|
|
15162
|
-
}
|
|
15723
|
+
},
|
|
15724
|
+
collapseSidebar
|
|
15163
15725
|
})
|
|
15164
15726
|
}, PendingPanel));
|
|
15165
15727
|
ctx.slots.inject("settings.section", () => ctx.slots.register({
|