dsh-diff-approval 0.12.0 → 0.13.1
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 +840 -270
- 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/client/whole-file-diff.d.ts +9 -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 {
|
|
@@ -651,13 +652,34 @@ window.__ModuleLoader__.load({
|
|
|
651
652
|
* @param newText - the file content after the pending change.
|
|
652
653
|
* @returns the complete row list with totals.
|
|
653
654
|
*/
|
|
655
|
+
/**
|
|
656
|
+
* Normalize content for equality: line endings → `\n`, and a single trailing
|
|
657
|
+
* newline is a terminator rather than a line. The result is the line bodies
|
|
658
|
+
* joined by `\n` with no trailing newline, so representation-only differences
|
|
659
|
+
* (EOL style, trailing-newline presence) compare equal.
|
|
660
|
+
* @param text - the content to normalize.
|
|
661
|
+
* @returns the normalized line bodies.
|
|
662
|
+
*/
|
|
663
|
+
function contentKey(text) {
|
|
664
|
+
const normalized = text.replace(/\r\n?/g, "\n");
|
|
665
|
+
return normalized.endsWith("\n") ? normalized.slice(0, -1) : normalized;
|
|
666
|
+
}
|
|
654
667
|
function computeWholeFileDiff(oldText, newText) {
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
668
|
+
const oldNorm = oldText.replace(/\r\n?/g, "\n");
|
|
669
|
+
const newNorm = newText.replace(/\r\n?/g, "\n");
|
|
670
|
+
if (contentKey(oldNorm) === contentKey(newNorm)) return {
|
|
671
|
+
rows: contentLines(oldNorm).map((text, index) => ({
|
|
672
|
+
kind: "context",
|
|
673
|
+
text,
|
|
674
|
+
oldLine: index + 1,
|
|
675
|
+
newLine: index + 1
|
|
676
|
+
})),
|
|
677
|
+
removed: 0,
|
|
678
|
+
added: 0
|
|
679
|
+
};
|
|
680
|
+
const oldLines = contentLines(oldNorm);
|
|
681
|
+
const newLines = contentLines(newNorm);
|
|
682
|
+
const patch = structuredPatch("", "", oldNorm, newNorm, void 0, void 0, { context: Math.max(1, oldLines.length, newLines.length) });
|
|
661
683
|
const rows = [];
|
|
662
684
|
let removed = 0;
|
|
663
685
|
let added = 0;
|
|
@@ -11693,6 +11715,15 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
11693
11715
|
//#endregion
|
|
11694
11716
|
//#region lib/types/client/reference.js
|
|
11695
11717
|
/**
|
|
11718
|
+
* Reference labels for the selection toolbar: a workspace-relative path (or
|
|
11719
|
+
* the absolute path when the file is outside the workspace) plus a 1-based
|
|
11720
|
+
* line range. Pure derivation so the display rule is unit-testable without
|
|
11721
|
+
* the panel.
|
|
11722
|
+
* @module dsh-diff-approval/client/reference
|
|
11723
|
+
*/
|
|
11724
|
+
/** The marker that replaces a reference's line number when its lines are gone. */
|
|
11725
|
+
const LINE_MISSING_LABEL = "LINE_MISSING";
|
|
11726
|
+
/**
|
|
11696
11727
|
* The path embedded in a copied reference: workspace-relative (forward
|
|
11697
11728
|
* slashes) when the file lives inside the current workspace, the absolute
|
|
11698
11729
|
* path otherwise. A bare file name is never enough — a reference must resolve
|
|
@@ -11720,15 +11751,66 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
11720
11751
|
return start === end ? String(start) : `${start}-${end}`;
|
|
11721
11752
|
}
|
|
11722
11753
|
/**
|
|
11723
|
-
* Build the clipboard text for a selected line range
|
|
11754
|
+
* Build the clipboard text for a selected line range, wrapped in parentheses so
|
|
11755
|
+
* the reference reads as one unambiguous token (and can be matched precisely).
|
|
11724
11756
|
* @param path - the selected file's path.
|
|
11725
11757
|
* @param workspacePath - the current workspace root, or `undefined`.
|
|
11726
11758
|
* @param start - first selected line number.
|
|
11727
11759
|
* @param end - last selected line number.
|
|
11728
|
-
* @returns the `path:range` reference text.
|
|
11760
|
+
* @returns the `(path:range)` reference text.
|
|
11729
11761
|
*/
|
|
11730
11762
|
function referenceOf(path, workspacePath, start, end) {
|
|
11731
|
-
return
|
|
11763
|
+
return `(${referencePathOf(path, workspacePath)}:${lineRangeLabel(start, end)})`;
|
|
11764
|
+
}
|
|
11765
|
+
/**
|
|
11766
|
+
* Map one referenced line range from `oldContent` coordinates to `newContent`
|
|
11767
|
+
* coordinates. Lines that survive (unchanged context) map to their new line
|
|
11768
|
+
* numbers, and the surviving lines' min/max span is returned. When every line
|
|
11769
|
+
* in the range was removed, returns `undefined` (the reference is expired).
|
|
11770
|
+
* @param oldContent - the file content the reference was made against.
|
|
11771
|
+
* @param newContent - the file content now.
|
|
11772
|
+
* @param start - first referenced line (1-based, inclusive).
|
|
11773
|
+
* @param end - last referenced line (1-based, inclusive).
|
|
11774
|
+
* @returns the surviving range, or `undefined` when nothing survives.
|
|
11775
|
+
*/
|
|
11776
|
+
function remapReferenceRange(oldContent, newContent, start, end) {
|
|
11777
|
+
const diff = computeWholeFileDiff(oldContent, newContent);
|
|
11778
|
+
const oldToNew = /* @__PURE__ */ new Map();
|
|
11779
|
+
for (const row of diff.rows) if (row.oldLine !== void 0 && row.newLine !== void 0) oldToNew.set(row.oldLine, row.newLine);
|
|
11780
|
+
let min = Infinity;
|
|
11781
|
+
let max = -Infinity;
|
|
11782
|
+
for (let line = start; line <= end; line++) {
|
|
11783
|
+
const next = oldToNew.get(line);
|
|
11784
|
+
if (next === void 0) continue;
|
|
11785
|
+
min = Math.min(min, next);
|
|
11786
|
+
max = Math.max(max, next);
|
|
11787
|
+
}
|
|
11788
|
+
if (min === Infinity) return void 0;
|
|
11789
|
+
return {
|
|
11790
|
+
start: min,
|
|
11791
|
+
end: max
|
|
11792
|
+
};
|
|
11793
|
+
}
|
|
11794
|
+
/**
|
|
11795
|
+
* Rewrite every `(referencePath:line)` / `(referencePath:start-end)` occurrence
|
|
11796
|
+
* in `text`, remapping each range from `oldContent` to `newContent`. A range
|
|
11797
|
+
* whose lines all survived becomes the new range; one whose lines were all
|
|
11798
|
+
* removed becomes `(referencePath:LINE_MISSING)`.
|
|
11799
|
+
* @param text - the free text (composer draft, queued message) to rewrite.
|
|
11800
|
+
* @param referencePath - the file's reference path (workspace-relative or absolute).
|
|
11801
|
+
* @param oldContent - the file content the references were made against.
|
|
11802
|
+
* @param newContent - the file content now.
|
|
11803
|
+
* @returns the rewritten text.
|
|
11804
|
+
*/
|
|
11805
|
+
function remapReferences(text, referencePath, oldContent, newContent) {
|
|
11806
|
+
const escaped = referencePath.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
11807
|
+
const regex = new RegExp(`\\(${escaped}:(\\d+)(?:-(\\d+))?\\)`, "g");
|
|
11808
|
+
return text.replace(regex, (_whole, startText, endText) => {
|
|
11809
|
+
const start = Number(startText);
|
|
11810
|
+
const mapped = remapReferenceRange(oldContent, newContent, start, endText === void 0 ? start : Number(endText));
|
|
11811
|
+
if (mapped === void 0) return `(${referencePath}:${LINE_MISSING_LABEL})`;
|
|
11812
|
+
return `(${referencePath}:${lineRangeLabel(mapped.start, mapped.end)})`;
|
|
11813
|
+
});
|
|
11732
11814
|
}
|
|
11733
11815
|
//#endregion
|
|
11734
11816
|
//#region lib/types/client/settings.js
|
|
@@ -11805,9 +11887,42 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
11805
11887
|
function setSplitMode(value) {
|
|
11806
11888
|
localStorage.setItem(SPLIT_MODE_KEY, value ? "1" : "0");
|
|
11807
11889
|
}
|
|
11890
|
+
const QUICK_SUMMON_KEY = "diff-approval:quick-summon-key";
|
|
11891
|
+
/**
|
|
11892
|
+
* The quick-summon chord. Stored as `Modifier+...+Key`; falls back to
|
|
11893
|
+
* {@link DEFAULT_QUICK_SUMMON}.
|
|
11894
|
+
* @returns the chord string.
|
|
11895
|
+
*/
|
|
11896
|
+
function quickSummonKey() {
|
|
11897
|
+
return localStorage.getItem(QUICK_SUMMON_KEY) ?? "Ctrl+D";
|
|
11898
|
+
}
|
|
11899
|
+
/** Persist the quick-summon chord. */
|
|
11900
|
+
function setQuickSummonKey(value) {
|
|
11901
|
+
localStorage.setItem(QUICK_SUMMON_KEY, value);
|
|
11902
|
+
}
|
|
11903
|
+
/**
|
|
11904
|
+
* Whether a keyboard event matches a chord string like `Ctrl+D`. Modifier
|
|
11905
|
+
* names are matched case-insensitively (`Ctrl`/`Control`, `Alt`/`Option`,
|
|
11906
|
+
* `Shift`, `Meta`/`Cmd`/`Command`/`Win`); the final part is the key. Exact
|
|
11907
|
+
* modifier set is required (extra modifiers do not match).
|
|
11908
|
+
* @param event - the keydown event.
|
|
11909
|
+
* @param shortcut - the chord string.
|
|
11910
|
+
* @returns whether the event matches.
|
|
11911
|
+
*/
|
|
11912
|
+
function matchesShortcut(event, shortcut) {
|
|
11913
|
+
const parts = shortcut.split("+").map((part) => part.trim().toLowerCase());
|
|
11914
|
+
const key = parts.pop();
|
|
11915
|
+
if (key === void 0 || key === "") return false;
|
|
11916
|
+
const mods = new Set(parts);
|
|
11917
|
+
const ctrl = mods.has("ctrl") || mods.has("control");
|
|
11918
|
+
const alt = mods.has("alt") || mods.has("option");
|
|
11919
|
+
const shift = mods.has("shift");
|
|
11920
|
+
const meta = mods.has("meta") || mods.has("cmd") || mods.has("command") || mods.has("win");
|
|
11921
|
+
return event.key.toLowerCase() === key && event.ctrlKey === ctrl && event.altKey === alt && event.shiftKey === shift && event.metaKey === meta;
|
|
11922
|
+
}
|
|
11808
11923
|
//#endregion
|
|
11809
11924
|
//#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)}";
|
|
11925
|
+
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
11926
|
const tagId = "dsh-diff-approval/PendingPanel.module.css";
|
|
11812
11927
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
11813
11928
|
const tag = document.createElement("style");
|
|
@@ -11817,111 +11932,115 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
11817
11932
|
document.head.appendChild(tag);
|
|
11818
11933
|
}
|
|
11819
11934
|
var PendingPanel_module_css_default = {
|
|
11820
|
-
"layer": "F1KBNa_layer",
|
|
11821
|
-
"rowHead": "F1KBNa_rowHead",
|
|
11822
|
-
"header": "F1KBNa_header",
|
|
11823
|
-
"searchCount": "F1KBNa_searchCount",
|
|
11824
|
-
"splitRdel": "F1KBNa_splitRdel",
|
|
11825
|
-
"blockActions": "F1KBNa_blockActions",
|
|
11826
|
-
"badge": "F1KBNa_badge",
|
|
11827
|
-
"fileList": "F1KBNa_fileList",
|
|
11828
|
-
"badgeLabel": "F1KBNa_badgeLabel",
|
|
11829
|
-
"rows": "F1KBNa_rows",
|
|
11830
|
-
"settingsRowTitle": "F1KBNa_settingsRowTitle",
|
|
11831
|
-
"rail": "F1KBNa_rail",
|
|
11832
|
-
"settingsPage": "F1KBNa_settingsPage",
|
|
11833
|
-
"add": "F1KBNa_add",
|
|
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",
|
|
11848
|
-
"blockFlash": "F1KBNa_blockFlash",
|
|
11849
|
-
"importButton": "F1KBNa_importButton",
|
|
11850
|
-
"del": "F1KBNa_del",
|
|
11851
|
-
"splitRoot": "F1KBNa_splitRoot",
|
|
11852
|
-
"states": "F1KBNa_states",
|
|
11853
|
-
"note": "F1KBNa_note",
|
|
11854
|
-
"panel": "F1KBNa_panel",
|
|
11855
11935
|
"title": "F1KBNa_title",
|
|
11856
|
-
"settingsSelector": "F1KBNa_settingsSelector",
|
|
11857
11936
|
"diffBodyWrap": "F1KBNa_diffBodyWrap",
|
|
11937
|
+
"settingsSelector": "F1KBNa_settingsSelector",
|
|
11938
|
+
"confirmBackdrop": "F1KBNa_confirmBackdrop",
|
|
11939
|
+
"noteCentered": "F1KBNa_noteCentered",
|
|
11940
|
+
"actionError": "F1KBNa_actionError",
|
|
11941
|
+
"rows": "F1KBNa_rows",
|
|
11942
|
+
"diffActions": "F1KBNa_diffActions",
|
|
11858
11943
|
"diffBody": "F1KBNa_diffBody",
|
|
11859
|
-
"
|
|
11860
|
-
"
|
|
11861
|
-
"delCount": "F1KBNa_delCount",
|
|
11862
|
-
"addCount": "F1KBNa_addCount",
|
|
11863
|
-
"diffStats": "F1KBNa_diffStats",
|
|
11864
|
-
"close": "F1KBNa_close",
|
|
11865
|
-
"kindHint": "F1KBNa_kindHint",
|
|
11866
|
-
"blockPosition": "F1KBNa_blockPosition",
|
|
11867
|
-
"searchInput": "F1KBNa_searchInput",
|
|
11944
|
+
"note": "F1KBNa_note",
|
|
11945
|
+
"diffFlash": "F1KBNa_diffFlash",
|
|
11868
11946
|
"overviewRuler": "F1KBNa_overviewRuler",
|
|
11869
|
-
"vSpacer": "F1KBNa_vSpacer",
|
|
11870
|
-
"context": "F1KBNa_context",
|
|
11871
|
-
"fullscreenBackdrop": "F1KBNa_fullscreenBackdrop",
|
|
11872
|
-
"gutter": "F1KBNa_gutter",
|
|
11873
11947
|
"iconAction": "F1KBNa_iconAction",
|
|
11874
|
-
"
|
|
11875
|
-
"
|
|
11876
|
-
"
|
|
11877
|
-
"splitRadd": "F1KBNa_splitRadd",
|
|
11878
|
-
"rowMeta": "F1KBNa_rowMeta",
|
|
11879
|
-
"diffHeader": "F1KBNa_diffHeader",
|
|
11880
|
-
"footerButtons": "F1KBNa_footerButtons",
|
|
11881
|
-
"headerActions": "F1KBNa_headerActions",
|
|
11948
|
+
"context": "F1KBNa_context",
|
|
11949
|
+
"panel": "F1KBNa_panel",
|
|
11950
|
+
"langSelect": "F1KBNa_langSelect",
|
|
11882
11951
|
"actionQuietDisabled": "F1KBNa_actionQuietDisabled",
|
|
11883
|
-
"
|
|
11884
|
-
"missing": "F1KBNa_missing",
|
|
11885
|
-
"markerDel": "F1KBNa_markerDel",
|
|
11952
|
+
"wrapActive": "F1KBNa_wrapActive",
|
|
11886
11953
|
"settingsRowDesc": "F1KBNa_settingsRowDesc",
|
|
11887
|
-
"
|
|
11888
|
-
"importNote": "F1KBNa_importNote",
|
|
11889
|
-
"listScroll": "F1KBNa_listScroll",
|
|
11890
|
-
"group": "F1KBNa_group",
|
|
11891
|
-
"divergedHint": "F1KBNa_divergedHint",
|
|
11892
|
-
"splitCol": "F1KBNa_splitCol",
|
|
11893
|
-
"resizeHandle": "F1KBNa_resizeHandle",
|
|
11954
|
+
"confirmActions": "F1KBNa_confirmActions",
|
|
11894
11955
|
"actionPrimary": "F1KBNa_actionPrimary",
|
|
11895
|
-
"
|
|
11896
|
-
"
|
|
11897
|
-
"
|
|
11898
|
-
"
|
|
11899
|
-
"
|
|
11900
|
-
"
|
|
11901
|
-
"hint": "F1KBNa_hint",
|
|
11902
|
-
"diff": "F1KBNa_diff",
|
|
11956
|
+
"rowFailed": "F1KBNa_rowFailed",
|
|
11957
|
+
"expand": "F1KBNa_expand",
|
|
11958
|
+
"blockPosition": "F1KBNa_blockPosition",
|
|
11959
|
+
"vSpacer": "F1KBNa_vSpacer",
|
|
11960
|
+
"rowPath": "F1KBNa_rowPath",
|
|
11961
|
+
"wrap": "F1KBNa_wrap",
|
|
11903
11962
|
"markerAdd": "F1KBNa_markerAdd",
|
|
11963
|
+
"splitHScroll": "F1KBNa_splitHScroll",
|
|
11964
|
+
"delCount": "F1KBNa_delCount",
|
|
11965
|
+
"subline": "F1KBNa_subline",
|
|
11966
|
+
"detail": "F1KBNa_detail",
|
|
11967
|
+
"footerButtons": "F1KBNa_footerButtons",
|
|
11968
|
+
"splitRoot": "F1KBNa_splitRoot",
|
|
11969
|
+
"splitCol": "F1KBNa_splitCol",
|
|
11970
|
+
"splitHScrollFill": "F1KBNa_splitHScrollFill",
|
|
11971
|
+
"splitLadd": "F1KBNa_splitLadd",
|
|
11904
11972
|
"code": "F1KBNa_code",
|
|
11973
|
+
"splitRadd": "F1KBNa_splitRadd",
|
|
11974
|
+
"settingsRowText": "F1KBNa_settingsRowText",
|
|
11975
|
+
"split": "F1KBNa_split",
|
|
11976
|
+
"action": "F1KBNa_action",
|
|
11977
|
+
"kindHint": "F1KBNa_kindHint",
|
|
11978
|
+
"layer": "F1KBNa_layer",
|
|
11979
|
+
"badgeCount": "F1KBNa_badgeCount",
|
|
11980
|
+
"diffHeader": "F1KBNa_diffHeader",
|
|
11981
|
+
"diffStats": "F1KBNa_diffStats",
|
|
11982
|
+
"addCount": "F1KBNa_addCount",
|
|
11983
|
+
"confirmText": "F1KBNa_confirmText",
|
|
11984
|
+
"settingsPage": "F1KBNa_settingsPage",
|
|
11985
|
+
"searchBar": "F1KBNa_searchBar",
|
|
11986
|
+
"del": "F1KBNa_del",
|
|
11987
|
+
"statusAction": "F1KBNa_statusAction",
|
|
11988
|
+
"splitHScrollRow": "F1KBNa_splitHScrollRow",
|
|
11989
|
+
"splitLdel": "F1KBNa_splitLdel",
|
|
11990
|
+
"flexSpacer": "F1KBNa_flexSpacer",
|
|
11991
|
+
"fileList": "F1KBNa_fileList",
|
|
11992
|
+
"notice": "F1KBNa_notice",
|
|
11993
|
+
"bulkActions": "F1KBNa_bulkActions",
|
|
11994
|
+
"missingHint": "F1KBNa_missingHint",
|
|
11995
|
+
"group": "F1KBNa_group",
|
|
11996
|
+
"markerDel": "F1KBNa_markerDel",
|
|
11997
|
+
"readError": "F1KBNa_readError",
|
|
11998
|
+
"diffPath": "F1KBNa_diffPath",
|
|
11999
|
+
"settingsSelectorChevron": "F1KBNa_settingsSelectorChevron",
|
|
12000
|
+
"overviewMarker": "F1KBNa_overviewMarker",
|
|
12001
|
+
"add": "F1KBNa_add",
|
|
12002
|
+
"statusBar": "F1KBNa_statusBar",
|
|
11905
12003
|
"emptyState": "F1KBNa_emptyState",
|
|
12004
|
+
"hint": "F1KBNa_hint",
|
|
11906
12005
|
"expandExpanded": "F1KBNa_expandExpanded",
|
|
12006
|
+
"close": "F1KBNa_close",
|
|
12007
|
+
"searchInput": "F1KBNa_searchInput",
|
|
12008
|
+
"lines": "F1KBNa_lines",
|
|
12009
|
+
"badgeLabel": "F1KBNa_badgeLabel",
|
|
12010
|
+
"noticeText": "F1KBNa_noticeText",
|
|
12011
|
+
"resizeHandle": "F1KBNa_resizeHandle",
|
|
12012
|
+
"blockActions": "F1KBNa_blockActions",
|
|
11907
12013
|
"langLabel": "F1KBNa_langLabel",
|
|
11908
|
-
"searchBar": "F1KBNa_searchBar",
|
|
11909
|
-
"badgeCount": "F1KBNa_badgeCount",
|
|
11910
|
-
"diffActions": "F1KBNa_diffActions",
|
|
11911
|
-
"splitDivider": "F1KBNa_splitDivider",
|
|
11912
|
-
"settingsRow": "F1KBNa_settingsRow",
|
|
11913
12014
|
"noticeButton": "F1KBNa_noticeButton",
|
|
11914
|
-
"
|
|
11915
|
-
"
|
|
11916
|
-
"
|
|
12015
|
+
"confirmCard": "F1KBNa_confirmCard",
|
|
12016
|
+
"headerActions": "F1KBNa_headerActions",
|
|
12017
|
+
"settingsRow": "F1KBNa_settingsRow",
|
|
12018
|
+
"importButton": "F1KBNa_importButton",
|
|
12019
|
+
"rowHead": "F1KBNa_rowHead",
|
|
12020
|
+
"searchCount": "F1KBNa_searchCount",
|
|
12021
|
+
"diff": "F1KBNa_diff",
|
|
12022
|
+
"row": "F1KBNa_row",
|
|
12023
|
+
"line": "F1KBNa_line",
|
|
12024
|
+
"gutter": "F1KBNa_gutter",
|
|
12025
|
+
"splitCols": "F1KBNa_splitCols",
|
|
12026
|
+
"importNote": "F1KBNa_importNote",
|
|
12027
|
+
"splitDivider": "F1KBNa_splitDivider",
|
|
12028
|
+
"listScroll": "F1KBNa_listScroll",
|
|
12029
|
+
"rail": "F1KBNa_rail",
|
|
12030
|
+
"missing": "F1KBNa_missing",
|
|
12031
|
+
"rowMeta": "F1KBNa_rowMeta",
|
|
11917
12032
|
"fileListFloat": "F1KBNa_fileListFloat",
|
|
11918
|
-
"
|
|
11919
|
-
"
|
|
11920
|
-
"
|
|
12033
|
+
"badge": "F1KBNa_badge",
|
|
12034
|
+
"divergedHint": "F1KBNa_divergedHint",
|
|
12035
|
+
"diffBodySplit": "F1KBNa_diffBodySplit",
|
|
12036
|
+
"fullscreenBackdrop": "F1KBNa_fullscreenBackdrop",
|
|
12037
|
+
"header": "F1KBNa_header",
|
|
11921
12038
|
"kindTag": "F1KBNa_kindTag",
|
|
11922
|
-
"
|
|
11923
|
-
"
|
|
11924
|
-
"
|
|
12039
|
+
"settingsRowTitle": "F1KBNa_settingsRowTitle",
|
|
12040
|
+
"blockFlash": "F1KBNa_blockFlash",
|
|
12041
|
+
"detailEmpty": "F1KBNa_detailEmpty",
|
|
12042
|
+
"states": "F1KBNa_states",
|
|
12043
|
+
"splitRdel": "F1KBNa_splitRdel"
|
|
11925
12044
|
};
|
|
11926
12045
|
//#endregion
|
|
11927
12046
|
//#region lib/types/client/PendingPanel.js
|
|
@@ -11960,6 +12079,10 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
11960
12079
|
/** Total width of the two line-number gutters, subtracted from the code width
|
|
11961
12080
|
* when measuring wrapped line heights. */
|
|
11962
12081
|
const WRAP_GUTTERS_PX = 88;
|
|
12082
|
+
/** The dsh shell's sidebar auto-collapse breakpoint (ui-layout columns.ts):
|
|
12083
|
+
* below it the sidebar auto-collapses, and the file list floats on the same
|
|
12084
|
+
* breakpoint so the two stay consistent. */
|
|
12085
|
+
const SIDEBAR_AUTO_COLLAPSE_PX = 1024;
|
|
11963
12086
|
/** A shared canvas for measuring wrapped line heights (CPU-only, no DOM reflow). */
|
|
11964
12087
|
let measureCanvas;
|
|
11965
12088
|
/**
|
|
@@ -12551,12 +12674,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12551
12674
|
const clamped = Math.max(0, Math.min(target, body.scrollHeight - body.clientHeight));
|
|
12552
12675
|
if (body.scrollTop !== clamped) body.scrollTop = clamped;
|
|
12553
12676
|
setScrollTop(clamped);
|
|
12554
|
-
}, [
|
|
12555
|
-
model,
|
|
12556
|
-
focus,
|
|
12557
|
-
flashKey,
|
|
12558
|
-
pairCount
|
|
12559
|
-
]);
|
|
12677
|
+
}, [focus, flashKey]);
|
|
12560
12678
|
const onScroll = () => {
|
|
12561
12679
|
setScrollTop(bodyRef.current?.scrollTop ?? 0);
|
|
12562
12680
|
};
|
|
@@ -12951,7 +13069,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12951
13069
|
title: failedMessage,
|
|
12952
13070
|
children: t("row.failed")
|
|
12953
13071
|
}),
|
|
12954
|
-
(0, react_jsx_runtime.jsxs)("span", {
|
|
13072
|
+
(stats.added !== 0 || stats.removed !== 0) && (0, react_jsx_runtime.jsxs)("span", {
|
|
12955
13073
|
className: PendingPanel_module_css_default.rowMeta,
|
|
12956
13074
|
children: [(0, react_jsx_runtime.jsx)("span", {
|
|
12957
13075
|
className: PendingPanel_module_css_default.addCount,
|
|
@@ -12967,7 +13085,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12967
13085
|
});
|
|
12968
13086
|
}
|
|
12969
13087
|
/** 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 }) {
|
|
13088
|
+
function PendingDiff({ file, busy, workspacePath, jumpSignal, undoFlash, failedMessage, onPasteReference, onToast, t, onKeep, onRevert, onBlockKeep, onBlockRevert, onOpen, floatMode, floatOpen, onToggleFileList }) {
|
|
12971
13089
|
const [langOverride, setLangOverride] = (0, react.useState)(void 0);
|
|
12972
13090
|
const [langMenuOpen, setLangMenuOpen] = (0, react.useState)(false);
|
|
12973
13091
|
const langMenuItems = (0, react.useMemo)(() => [{
|
|
@@ -13071,6 +13189,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13071
13189
|
const [flashKey, setFlashKey] = (0, react.useState)(0);
|
|
13072
13190
|
(0, react.useEffect)(() => {
|
|
13073
13191
|
setFocus(0);
|
|
13192
|
+
setScrollTick((tick) => tick + 1);
|
|
13074
13193
|
bodyRef.current?.focus();
|
|
13075
13194
|
setFlashKey((key) => key + 1);
|
|
13076
13195
|
setHoveredBlock(void 0);
|
|
@@ -13091,6 +13210,32 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13091
13210
|
const blockRanges = (0, react.useMemo)(() => {
|
|
13092
13211
|
return model.blocks.map((block) => blockRangesOf(model.diff.rows, block));
|
|
13093
13212
|
}, [model]);
|
|
13213
|
+
const coveredBlockIndices = (0, react.useMemo)(() => {
|
|
13214
|
+
if (selection === void 0 || splitView) return [];
|
|
13215
|
+
const covered = [];
|
|
13216
|
+
for (let index = 0; index < model.blocks.length; index++) {
|
|
13217
|
+
const block = model.blocks[index];
|
|
13218
|
+
if (selection.start <= block.start && block.end <= selection.end) covered.push(index);
|
|
13219
|
+
}
|
|
13220
|
+
return covered;
|
|
13221
|
+
}, [
|
|
13222
|
+
selection,
|
|
13223
|
+
splitView,
|
|
13224
|
+
model
|
|
13225
|
+
]);
|
|
13226
|
+
const selectionRange = (0, react.useMemo)(() => {
|
|
13227
|
+
if (coveredBlockIndices.length === 0) return void 0;
|
|
13228
|
+
const firstIndex = coveredBlockIndices[0];
|
|
13229
|
+
const lastIndex = coveredBlockIndices[coveredBlockIndices.length - 1];
|
|
13230
|
+
if (firstIndex === void 0 || lastIndex === void 0) return void 0;
|
|
13231
|
+
const first = model.blocks[firstIndex];
|
|
13232
|
+
const last = model.blocks[lastIndex];
|
|
13233
|
+
if (first === void 0 || last === void 0) return void 0;
|
|
13234
|
+
return blockRangesOf(model.diff.rows, {
|
|
13235
|
+
start: first.start,
|
|
13236
|
+
end: last.end
|
|
13237
|
+
});
|
|
13238
|
+
}, [coveredBlockIndices, model]);
|
|
13094
13239
|
const searchMatches = (0, react.useMemo)(() => {
|
|
13095
13240
|
if (searchQuery === "") return [];
|
|
13096
13241
|
const lower = searchQuery.toLowerCase();
|
|
@@ -13196,6 +13341,13 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13196
13341
|
const visibleRows = rows.slice(start, end);
|
|
13197
13342
|
const blockEnd = hoveredBlock === void 0 ? void 0 : model.blocks[hoveredBlock]?.end;
|
|
13198
13343
|
const blockActionsTop = blockEnd === void 0 ? 0 : Math.min(offsetOf(blockEnd + 1), Math.max(0, totalHeight - BLOCK_ACTIONS_FRAME_PX));
|
|
13344
|
+
const selectionBlockEnd = (() => {
|
|
13345
|
+
if (coveredBlockIndices.length === 0) return void 0;
|
|
13346
|
+
const lastIndex = coveredBlockIndices[coveredBlockIndices.length - 1];
|
|
13347
|
+
if (lastIndex === void 0) return void 0;
|
|
13348
|
+
return model.blocks[lastIndex]?.end;
|
|
13349
|
+
})();
|
|
13350
|
+
const selectionActionsTop = selectionBlockEnd === void 0 ? 0 : Math.min(offsetOf(selectionBlockEnd + 1), Math.max(0, totalHeight - BLOCK_ACTIONS_FRAME_PX));
|
|
13199
13351
|
const widestLine = (0, react.useMemo)(() => {
|
|
13200
13352
|
let widest = 0;
|
|
13201
13353
|
for (const row of model.diff.rows) if (row.text.length > widest) widest = row.text.length;
|
|
@@ -13239,10 +13391,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13239
13391
|
if (body.scrollTop !== clamped) body.scrollTop = clamped;
|
|
13240
13392
|
setScrollTop(clamped);
|
|
13241
13393
|
}, [
|
|
13242
|
-
model,
|
|
13243
13394
|
focus,
|
|
13244
13395
|
scrollTick,
|
|
13245
|
-
rowCount,
|
|
13246
13396
|
rowOffsets === null
|
|
13247
13397
|
]);
|
|
13248
13398
|
const jump = (direction) => {
|
|
@@ -13278,10 +13428,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13278
13428
|
setScrollTick((tick) => tick + 1);
|
|
13279
13429
|
setFlashKey((key) => key + 1);
|
|
13280
13430
|
};
|
|
13281
|
-
const
|
|
13282
|
-
if (busy || hoveredBlock === void 0) return;
|
|
13283
|
-
const operated = hoveredBlock;
|
|
13284
|
-
const range = blockRanges[operated];
|
|
13431
|
+
const runBlockAction = async (action, range, operated) => {
|
|
13285
13432
|
await (action === "keep" ? onBlockKeep(file.sessionId, file.id, range) : onBlockRevert(file.sessionId, file.id, range));
|
|
13286
13433
|
const count = model.blocks.length;
|
|
13287
13434
|
if (count === 0) return;
|
|
@@ -13291,6 +13438,18 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13291
13438
|
setScrollTick((tick) => tick + 1);
|
|
13292
13439
|
setFlashKey((key) => key + 1);
|
|
13293
13440
|
};
|
|
13441
|
+
const handleBlockAction = async (action) => {
|
|
13442
|
+
if (busy || hoveredBlock === void 0) return;
|
|
13443
|
+
const operated = hoveredBlock;
|
|
13444
|
+
const range = blockRanges[operated];
|
|
13445
|
+
await runBlockAction(action, range, operated);
|
|
13446
|
+
};
|
|
13447
|
+
const handleSelectionAction = async (action) => {
|
|
13448
|
+
if (busy || selectionRange === void 0) return;
|
|
13449
|
+
const firstCovered = coveredBlockIndices[0];
|
|
13450
|
+
if (firstCovered === void 0) return;
|
|
13451
|
+
await runBlockAction(action, selectionRange, firstCovered);
|
|
13452
|
+
};
|
|
13294
13453
|
(0, react.useEffect)(() => {
|
|
13295
13454
|
if (jumpSignal === 0) return;
|
|
13296
13455
|
jumpBlock(1);
|
|
@@ -13329,16 +13488,22 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13329
13488
|
})();
|
|
13330
13489
|
const copySelection = (0, react.useCallback)(async () => {
|
|
13331
13490
|
if (selectionReference === void 0) return;
|
|
13491
|
+
if (pasteOnCopyEnabled()) {
|
|
13492
|
+
onPasteReference(file.sessionId, selectionReference);
|
|
13493
|
+
return;
|
|
13494
|
+
}
|
|
13332
13495
|
if (!await (0, _deepseek_ai_dsh_client_ui_primitives.writeClipboard)(selectionReference)) return;
|
|
13333
13496
|
setCopied(true);
|
|
13334
|
-
|
|
13497
|
+
onToast(t("action.copied"));
|
|
13335
13498
|
window.setTimeout(() => {
|
|
13336
13499
|
setCopied(false);
|
|
13337
13500
|
}, 1500);
|
|
13338
13501
|
}, [
|
|
13339
13502
|
file.sessionId,
|
|
13340
13503
|
onPasteReference,
|
|
13341
|
-
|
|
13504
|
+
onToast,
|
|
13505
|
+
selectionReference,
|
|
13506
|
+
t
|
|
13342
13507
|
]);
|
|
13343
13508
|
(0, react.useEffect)(() => {
|
|
13344
13509
|
const onKeyDown = (event) => {
|
|
@@ -13458,7 +13623,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13458
13623
|
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconListPenOutline16, { size: 14 })
|
|
13459
13624
|
})
|
|
13460
13625
|
}),
|
|
13461
|
-
(0, react_jsx_runtime.jsx)("span", {
|
|
13626
|
+
(model.diff.added !== 0 || model.diff.removed !== 0) && (0, react_jsx_runtime.jsx)("span", {
|
|
13462
13627
|
className: PendingPanel_module_css_default.diffStats,
|
|
13463
13628
|
children: t("panel.stats", {
|
|
13464
13629
|
added: model.diff.added,
|
|
@@ -13600,7 +13765,30 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13600
13765
|
"aria-hidden": "true"
|
|
13601
13766
|
})
|
|
13602
13767
|
]
|
|
13603
|
-
}),
|
|
13768
|
+
}), selectionRange !== void 0 ? (0, react_jsx_runtime.jsxs)("div", {
|
|
13769
|
+
className: PendingPanel_module_css_default.blockActions,
|
|
13770
|
+
"data-diff-selection-actions": true,
|
|
13771
|
+
style: { top: selectionActionsTop },
|
|
13772
|
+
children: [(0, react_jsx_runtime.jsx)("button", {
|
|
13773
|
+
type: "button",
|
|
13774
|
+
className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.actionPrimary}`,
|
|
13775
|
+
"data-diff-selection-keep": true,
|
|
13776
|
+
disabled: busy,
|
|
13777
|
+
onClick: () => {
|
|
13778
|
+
handleSelectionAction("keep");
|
|
13779
|
+
},
|
|
13780
|
+
children: t("action.keep")
|
|
13781
|
+
}), (0, react_jsx_runtime.jsx)("button", {
|
|
13782
|
+
type: "button",
|
|
13783
|
+
className: PendingPanel_module_css_default.action,
|
|
13784
|
+
"data-diff-selection-revert": true,
|
|
13785
|
+
disabled: busy,
|
|
13786
|
+
onClick: () => {
|
|
13787
|
+
handleSelectionAction("revert");
|
|
13788
|
+
},
|
|
13789
|
+
children: t("action.revert")
|
|
13790
|
+
})]
|
|
13791
|
+
}) : hoveredBlock !== void 0 && model.blocks[hoveredBlock] !== void 0 ? (0, react_jsx_runtime.jsxs)("div", {
|
|
13604
13792
|
className: PendingPanel_module_css_default.blockActions,
|
|
13605
13793
|
"data-diff-block-actions": true,
|
|
13606
13794
|
style: { top: blockActionsTop },
|
|
@@ -13656,7 +13844,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13656
13844
|
children: t("action.revert")
|
|
13657
13845
|
})
|
|
13658
13846
|
]
|
|
13659
|
-
})]
|
|
13847
|
+
}) : null]
|
|
13660
13848
|
}),
|
|
13661
13849
|
focusedBlock !== void 0 && flashKey > 0 && (0, react_jsx_runtime.jsx)("div", {
|
|
13662
13850
|
className: PendingPanel_module_css_default.blockFlash,
|
|
@@ -13818,7 +14006,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13818
14006
|
});
|
|
13819
14007
|
}
|
|
13820
14008
|
/** 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 }) {
|
|
14009
|
+
function PendingPanel({ wide, useSessions, usePending, onRefresh, onKeep, onRevert, onBlockKeep, onBlockRevert, onOpen, onPasteReference, onUndo, onRedo, onImportVcs, onAckRedoCleared, onAckJustResolved, collapseSidebar, t }) {
|
|
13822
14010
|
const current = useSessions((state) => state.current);
|
|
13823
14011
|
const currentBlank = useSessions((state) => {
|
|
13824
14012
|
const id = state.current;
|
|
@@ -13846,8 +14034,12 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13846
14034
|
const [importToast, setImportToast] = (0, react.useState)(null);
|
|
13847
14035
|
/** A transient banner for a keep/revert failure. */
|
|
13848
14036
|
const [actionToast, setActionToast] = (0, react.useState)(null);
|
|
14037
|
+
/** A transient banner confirming a reference was copied to the clipboard. */
|
|
14038
|
+
const [copyToast, setCopyToast] = (0, react.useState)(null);
|
|
13849
14039
|
/** Whether the redo-cleared notice is showing (bottom-right, OK to dismiss). */
|
|
13850
14040
|
const [redoClearedNotice, setRedoClearedNotice] = (0, react.useState)(false);
|
|
14041
|
+
/** A file whose last block just resolved, pending a remove-or-keep choice. */
|
|
14042
|
+
const [confirmDismiss, setConfirmDismiss] = (0, react.useState)(null);
|
|
13851
14043
|
/** Bottom offset tracking the chat composer's top edge so the input stays visible. */
|
|
13852
14044
|
const [bottomPx, setBottomPx] = (0, react.useState)(FALLBACK_BOTTOM_PX);
|
|
13853
14045
|
/** Fullscreen expanded: the panel bottom pins to the window edge, ignoring the composer offset. */
|
|
@@ -13860,6 +14052,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13860
14052
|
/** The review panel's width, measured so the file list can collapse when it
|
|
13861
14053
|
* would take more than a third of it (browser zoom / window resize). */
|
|
13862
14054
|
const [panelWidth, setPanelWidth] = (0, react.useState)(0);
|
|
14055
|
+
const [viewportWidth, setViewportWidth] = (0, react.useState)(() => window.innerWidth);
|
|
13863
14056
|
const panelRef = (0, react.useRef)(null);
|
|
13864
14057
|
const splitRef = (0, react.useRef)(null);
|
|
13865
14058
|
/** The code scroll box's bounds within the split, so the floating card is
|
|
@@ -13887,10 +14080,19 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13887
14080
|
observer?.disconnect();
|
|
13888
14081
|
};
|
|
13889
14082
|
}, [open]);
|
|
13890
|
-
const floatMode =
|
|
14083
|
+
const floatMode = viewportWidth < SIDEBAR_AUTO_COLLAPSE_PX;
|
|
13891
14084
|
const toggleFileList = () => {
|
|
13892
14085
|
setFloatOpen((value) => !value);
|
|
13893
14086
|
};
|
|
14087
|
+
(0, react.useEffect)(() => {
|
|
14088
|
+
const onResize = () => {
|
|
14089
|
+
setViewportWidth(window.innerWidth);
|
|
14090
|
+
};
|
|
14091
|
+
window.addEventListener("resize", onResize);
|
|
14092
|
+
return () => {
|
|
14093
|
+
window.removeEventListener("resize", onResize);
|
|
14094
|
+
};
|
|
14095
|
+
}, []);
|
|
13894
14096
|
(0, react.useEffect)(() => {
|
|
13895
14097
|
if (!floatMode || !floatOpen) return;
|
|
13896
14098
|
const el = panelRef.current;
|
|
@@ -13992,6 +14194,11 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13992
14194
|
if (fresh.length > 0) setActionToast(fresh[0][1]);
|
|
13993
14195
|
failedRef.current = current;
|
|
13994
14196
|
}, [snapshot.failed]);
|
|
14197
|
+
(0, react.useEffect)(() => {
|
|
14198
|
+
if (snapshot.justResolved === void 0) return;
|
|
14199
|
+
setConfirmDismiss(snapshot.justResolved);
|
|
14200
|
+
onAckJustResolved();
|
|
14201
|
+
}, [snapshot.justResolved, onAckJustResolved]);
|
|
13995
14202
|
(0, react.useEffect)(() => {
|
|
13996
14203
|
if (!open) return;
|
|
13997
14204
|
if (selected !== "" && files.some((file) => file.id === selected)) return;
|
|
@@ -14022,6 +14229,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
14022
14229
|
}
|
|
14023
14230
|
};
|
|
14024
14231
|
const toggleOpen = () => {
|
|
14232
|
+
if (!open) collapseSidebar();
|
|
14025
14233
|
setOpen((value) => !value);
|
|
14026
14234
|
};
|
|
14027
14235
|
(0, react.useEffect)(() => {
|
|
@@ -14048,6 +14256,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
14048
14256
|
}
|
|
14049
14257
|
}, entry.id);
|
|
14050
14258
|
const selectedFile = files.find((file) => file.id === selected);
|
|
14259
|
+
/** The file whose removal is being confirmed, if any. */
|
|
14260
|
+
const confirmFile = confirmDismiss === null ? void 0 : files.find((file) => file.id === confirmDismiss);
|
|
14051
14261
|
const fileListBody = (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)("div", {
|
|
14052
14262
|
className: PendingPanel_module_css_default.listScroll,
|
|
14053
14263
|
children: files.length > 0 && (0, react_jsx_runtime.jsxs)("section", { children: [(0, react_jsx_runtime.jsx)("h3", {
|
|
@@ -14115,6 +14325,58 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
14115
14325
|
handleUndo,
|
|
14116
14326
|
handleRedo
|
|
14117
14327
|
]);
|
|
14328
|
+
(0, react.useEffect)(() => {
|
|
14329
|
+
if (!open || current === void 0) return;
|
|
14330
|
+
const onKeyDown = (event) => {
|
|
14331
|
+
if (!(event.ctrlKey || event.metaKey) || event.altKey) return;
|
|
14332
|
+
if (event.key.toLowerCase() !== "tab") return;
|
|
14333
|
+
const target = event.target;
|
|
14334
|
+
if (target instanceof Element && target.closest("input, textarea, [contenteditable=\"true\"]") !== null) return;
|
|
14335
|
+
if (files.length === 0) return;
|
|
14336
|
+
event.preventDefault();
|
|
14337
|
+
const index = files.findIndex((file) => file.id === selected);
|
|
14338
|
+
const direction = event.shiftKey ? -1 : 1;
|
|
14339
|
+
const next = files[(index + direction + files.length) % files.length];
|
|
14340
|
+
if (next !== void 0) setSelected(next.id);
|
|
14341
|
+
};
|
|
14342
|
+
window.addEventListener("keydown", onKeyDown, true);
|
|
14343
|
+
return () => {
|
|
14344
|
+
window.removeEventListener("keydown", onKeyDown, true);
|
|
14345
|
+
};
|
|
14346
|
+
}, [
|
|
14347
|
+
open,
|
|
14348
|
+
current,
|
|
14349
|
+
files,
|
|
14350
|
+
selected
|
|
14351
|
+
]);
|
|
14352
|
+
(0, react.useEffect)(() => {
|
|
14353
|
+
const onKeyDown = (event) => {
|
|
14354
|
+
if (!matchesShortcut(event, quickSummonKey())) return;
|
|
14355
|
+
const target = event.target;
|
|
14356
|
+
if (target instanceof Element && target.closest("input, textarea, [contenteditable=\"true\"]") !== null) return;
|
|
14357
|
+
event.preventDefault();
|
|
14358
|
+
if (!open) collapseSidebar();
|
|
14359
|
+
setOpen((value) => !value);
|
|
14360
|
+
};
|
|
14361
|
+
window.addEventListener("keydown", onKeyDown, true);
|
|
14362
|
+
return () => {
|
|
14363
|
+
window.removeEventListener("keydown", onKeyDown, true);
|
|
14364
|
+
};
|
|
14365
|
+
}, [open, collapseSidebar]);
|
|
14366
|
+
(0, react.useEffect)(() => {
|
|
14367
|
+
if (!open) return;
|
|
14368
|
+
const onKeyDown = (event) => {
|
|
14369
|
+
if (event.key !== "Escape") return;
|
|
14370
|
+
const target = event.target;
|
|
14371
|
+
if (target instanceof Element && target.closest("input, textarea, [contenteditable=\"true\"]") !== null) return;
|
|
14372
|
+
event.preventDefault();
|
|
14373
|
+
setOpen(false);
|
|
14374
|
+
};
|
|
14375
|
+
window.addEventListener("keydown", onKeyDown, true);
|
|
14376
|
+
return () => {
|
|
14377
|
+
window.removeEventListener("keydown", onKeyDown, true);
|
|
14378
|
+
};
|
|
14379
|
+
}, [open]);
|
|
14118
14380
|
/** Drag the list/detail divider; width follows the pointer within its bounds. */
|
|
14119
14381
|
const startResize = (event) => {
|
|
14120
14382
|
if (event.button !== 0) return;
|
|
@@ -14156,162 +14418,207 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
14156
14418
|
setActionToast(null);
|
|
14157
14419
|
}
|
|
14158
14420
|
}),
|
|
14159
|
-
|
|
14421
|
+
copyToast !== null && (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Toast, {
|
|
14422
|
+
text: copyToast,
|
|
14423
|
+
onDone: () => {
|
|
14424
|
+
setCopyToast(null);
|
|
14425
|
+
}
|
|
14426
|
+
}),
|
|
14427
|
+
open && (0, react_dom.createPortal)((0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [expanded && (0, react_jsx_runtime.jsx)("div", {
|
|
14160
14428
|
className: PendingPanel_module_css_default.fullscreenBackdrop,
|
|
14161
14429
|
"data-diff-fullscreen-backdrop": true
|
|
14162
|
-
}),
|
|
14163
|
-
open && (0, react_jsx_runtime.jsxs)("section", {
|
|
14430
|
+
}), (0, react_jsx_runtime.jsxs)("section", {
|
|
14164
14431
|
className: PendingPanel_module_css_default.panel,
|
|
14165
14432
|
ref: panelRef,
|
|
14166
14433
|
style: { bottom: expanded ? PANEL_INSET_PX : bottomPx },
|
|
14167
14434
|
"data-diff-approval-panel": true,
|
|
14168
14435
|
"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
|
-
|
|
14436
|
+
children: [
|
|
14437
|
+
(0, react_jsx_runtime.jsxs)("header", {
|
|
14438
|
+
className: PendingPanel_module_css_default.header,
|
|
14439
|
+
children: [(0, react_jsx_runtime.jsx)("span", {
|
|
14440
|
+
className: PendingPanel_module_css_default.title,
|
|
14441
|
+
children: t("panel.title")
|
|
14442
|
+
}), (0, react_jsx_runtime.jsxs)("div", {
|
|
14443
|
+
className: PendingPanel_module_css_default.headerActions,
|
|
14444
|
+
children: [
|
|
14445
|
+
(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
14446
|
+
label: t("action.settings"),
|
|
14447
|
+
side: "bottom",
|
|
14448
|
+
delayMs: 500,
|
|
14449
|
+
children: (0, react_jsx_runtime.jsx)("button", {
|
|
14450
|
+
type: "button",
|
|
14451
|
+
className: PendingPanel_module_css_default.expand,
|
|
14452
|
+
"data-diff-approval-settings": true,
|
|
14453
|
+
"aria-label": t("action.settings"),
|
|
14454
|
+
onClick: () => {
|
|
14455
|
+
setOpen(false);
|
|
14456
|
+
openSettingsSection(t("settings.tabLabel"));
|
|
14457
|
+
},
|
|
14458
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconSettingsOutline16, { size: 14 })
|
|
14459
|
+
})
|
|
14460
|
+
}),
|
|
14461
|
+
(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
14462
|
+
label: t(expanded ? "action.exitFullscreen" : "action.expand"),
|
|
14463
|
+
side: "bottom",
|
|
14464
|
+
delayMs: 500,
|
|
14465
|
+
children: (0, react_jsx_runtime.jsx)("button", {
|
|
14466
|
+
type: "button",
|
|
14467
|
+
className: expanded ? `${PendingPanel_module_css_default.expand} ${PendingPanel_module_css_default.expandExpanded}` : PendingPanel_module_css_default.expand,
|
|
14468
|
+
"data-diff-approval-expand": true,
|
|
14469
|
+
"aria-label": t(expanded ? "action.exitFullscreen" : "action.expand"),
|
|
14470
|
+
onClick: () => {
|
|
14471
|
+
if (!expanded) collapseSidebar();
|
|
14472
|
+
setExpanded((value) => !value);
|
|
14473
|
+
},
|
|
14474
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconFullscreenOutline16, { size: 14 })
|
|
14475
|
+
})
|
|
14476
|
+
}),
|
|
14477
|
+
(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
14478
|
+
label: t("action.close"),
|
|
14479
|
+
side: "bottom",
|
|
14480
|
+
delayMs: 500,
|
|
14481
|
+
children: (0, react_jsx_runtime.jsx)("button", {
|
|
14482
|
+
type: "button",
|
|
14483
|
+
className: PendingPanel_module_css_default.close,
|
|
14484
|
+
"data-diff-approval-close": true,
|
|
14485
|
+
"aria-label": t("action.close"),
|
|
14486
|
+
onClick: () => {
|
|
14487
|
+
setOpen(false);
|
|
14488
|
+
},
|
|
14489
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCloseOutline16, { size: 14 })
|
|
14490
|
+
})
|
|
14191
14491
|
})
|
|
14492
|
+
]
|
|
14493
|
+
})]
|
|
14494
|
+
}),
|
|
14495
|
+
snapshot.error !== void 0 || !snapshot.read || files.length === 0 ? (0, react_jsx_runtime.jsxs)("div", {
|
|
14496
|
+
className: PendingPanel_module_css_default.states,
|
|
14497
|
+
children: [
|
|
14498
|
+
snapshot.error !== void 0 && (0, react_jsx_runtime.jsx)("p", {
|
|
14499
|
+
className: PendingPanel_module_css_default.readError,
|
|
14500
|
+
role: "alert",
|
|
14501
|
+
children: t("panel.readFailed", { message: snapshot.error })
|
|
14192
14502
|
}),
|
|
14193
|
-
(0, react_jsx_runtime.jsx)(
|
|
14194
|
-
|
|
14195
|
-
|
|
14196
|
-
|
|
14197
|
-
|
|
14198
|
-
|
|
14199
|
-
|
|
14200
|
-
"
|
|
14201
|
-
|
|
14202
|
-
|
|
14203
|
-
|
|
14503
|
+
!snapshot.read && snapshot.error === void 0 && (0, react_jsx_runtime.jsx)("p", {
|
|
14504
|
+
className: PendingPanel_module_css_default.note,
|
|
14505
|
+
children: t("panel.loading")
|
|
14506
|
+
}),
|
|
14507
|
+
snapshot.read && snapshot.error === void 0 && files.length === 0 && (0, react_jsx_runtime.jsxs)("div", {
|
|
14508
|
+
className: PendingPanel_module_css_default.emptyState,
|
|
14509
|
+
children: [
|
|
14510
|
+
(0, react_jsx_runtime.jsx)("p", {
|
|
14511
|
+
className: `${PendingPanel_module_css_default.note} ${PendingPanel_module_css_default.noteCentered}`,
|
|
14512
|
+
children: t("panel.empty")
|
|
14513
|
+
}),
|
|
14514
|
+
(0, react_jsx_runtime.jsx)("button", {
|
|
14515
|
+
type: "button",
|
|
14516
|
+
className: PendingPanel_module_css_default.importButton,
|
|
14517
|
+
"data-diff-import-vcs": true,
|
|
14518
|
+
disabled: importBusy,
|
|
14519
|
+
onClick: () => {
|
|
14520
|
+
runImportVcs();
|
|
14521
|
+
},
|
|
14522
|
+
children: importBusy ? t("action.importVcsBusy") : t("action.importVcs")
|
|
14523
|
+
}),
|
|
14524
|
+
importNote !== void 0 && (0, react_jsx_runtime.jsx)("p", {
|
|
14525
|
+
className: PendingPanel_module_css_default.importNote,
|
|
14526
|
+
role: importFailed ? "alert" : void 0,
|
|
14527
|
+
children: importNote
|
|
14528
|
+
})
|
|
14529
|
+
]
|
|
14530
|
+
})
|
|
14531
|
+
]
|
|
14532
|
+
}) : (0, react_jsx_runtime.jsxs)("div", {
|
|
14533
|
+
className: PendingPanel_module_css_default.split,
|
|
14534
|
+
ref: splitRef,
|
|
14535
|
+
children: [
|
|
14536
|
+
!floatMode && (0, react_jsx_runtime.jsx)("nav", {
|
|
14537
|
+
className: PendingPanel_module_css_default.fileList,
|
|
14538
|
+
style: { width: listWidth },
|
|
14539
|
+
"data-diff-approval-file-list": true,
|
|
14540
|
+
children: fileListBody
|
|
14541
|
+
}),
|
|
14542
|
+
!floatMode && (0, react_jsx_runtime.jsx)("div", {
|
|
14543
|
+
className: PendingPanel_module_css_default.resizeHandle,
|
|
14544
|
+
"data-diff-resize": true,
|
|
14545
|
+
onMouseDown: startResize
|
|
14546
|
+
}),
|
|
14547
|
+
(0, react_jsx_runtime.jsx)("div", {
|
|
14548
|
+
className: PendingPanel_module_css_default.detail,
|
|
14549
|
+
children: selectedFile === void 0 ? (0, react_jsx_runtime.jsx)("p", {
|
|
14550
|
+
className: PendingPanel_module_css_default.detailEmpty,
|
|
14551
|
+
children: t("panel.selectHint")
|
|
14552
|
+
}) : (0, react_jsx_runtime.jsx)(PendingDiff, {
|
|
14553
|
+
file: selectedFile,
|
|
14554
|
+
busy: snapshot.busy.has(selectedFile.id),
|
|
14555
|
+
workspacePath: snapshot.workspacePath,
|
|
14556
|
+
jumpSignal,
|
|
14557
|
+
undoFlash,
|
|
14558
|
+
failedMessage: failed.get(selectedFile.id),
|
|
14559
|
+
onPasteReference,
|
|
14560
|
+
onToast: (text) => {
|
|
14561
|
+
setCopyToast(text);
|
|
14204
14562
|
},
|
|
14205
|
-
|
|
14563
|
+
t,
|
|
14564
|
+
onKeep,
|
|
14565
|
+
onRevert,
|
|
14566
|
+
onBlockKeep,
|
|
14567
|
+
onBlockRevert,
|
|
14568
|
+
onOpen,
|
|
14569
|
+
floatMode,
|
|
14570
|
+
floatOpen,
|
|
14571
|
+
onToggleFileList: toggleFileList
|
|
14206
14572
|
})
|
|
14207
14573
|
}),
|
|
14208
|
-
(0, react_jsx_runtime.jsx)(
|
|
14209
|
-
|
|
14210
|
-
|
|
14211
|
-
|
|
14212
|
-
|
|
14574
|
+
floatMode && floatOpen && files.length > 0 && floatBox !== null && (0, react_jsx_runtime.jsx)("div", {
|
|
14575
|
+
className: PendingPanel_module_css_default.fileListFloat,
|
|
14576
|
+
style: {
|
|
14577
|
+
left: floatBox.left + FLOAT_LIST_MARGIN_PX,
|
|
14578
|
+
top: floatBox.top + FLOAT_LIST_MARGIN_PX,
|
|
14579
|
+
width: Math.min(listWidth, Math.max(0, floatBox.width - 24)),
|
|
14580
|
+
height: Math.max(0, floatBox.height - 24)
|
|
14581
|
+
},
|
|
14582
|
+
"data-diff-floating-file-list": true,
|
|
14583
|
+
children: fileListBody
|
|
14584
|
+
})
|
|
14585
|
+
]
|
|
14586
|
+
}),
|
|
14587
|
+
confirmFile !== void 0 && (0, react_jsx_runtime.jsx)("div", {
|
|
14588
|
+
className: PendingPanel_module_css_default.confirmBackdrop,
|
|
14589
|
+
"data-diff-confirm": true,
|
|
14590
|
+
children: (0, react_jsx_runtime.jsxs)("div", {
|
|
14591
|
+
className: PendingPanel_module_css_default.confirmCard,
|
|
14592
|
+
role: "dialog",
|
|
14593
|
+
"aria-modal": "true",
|
|
14594
|
+
children: [(0, react_jsx_runtime.jsx)("p", {
|
|
14595
|
+
className: PendingPanel_module_css_default.confirmText,
|
|
14596
|
+
children: t("panel.resolvedAsk", { file: basenameOf(confirmFile.path) })
|
|
14597
|
+
}), (0, react_jsx_runtime.jsxs)("div", {
|
|
14598
|
+
className: PendingPanel_module_css_default.confirmActions,
|
|
14599
|
+
children: [(0, react_jsx_runtime.jsx)("button", {
|
|
14213
14600
|
type: "button",
|
|
14214
|
-
className: PendingPanel_module_css_default.
|
|
14215
|
-
"data-diff-
|
|
14216
|
-
"aria-label": t("action.close"),
|
|
14601
|
+
className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.actionPrimary}`,
|
|
14602
|
+
"data-diff-confirm-remove": true,
|
|
14217
14603
|
onClick: () => {
|
|
14218
|
-
|
|
14604
|
+
setConfirmDismiss(null);
|
|
14605
|
+
onKeep(confirmFile.sessionId, confirmFile.id);
|
|
14219
14606
|
},
|
|
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", {
|
|
14607
|
+
children: t("row.dismiss")
|
|
14608
|
+
}), (0, react_jsx_runtime.jsx)("button", {
|
|
14245
14609
|
type: "button",
|
|
14246
|
-
className: PendingPanel_module_css_default.
|
|
14247
|
-
"data-diff-
|
|
14248
|
-
disabled: importBusy,
|
|
14610
|
+
className: PendingPanel_module_css_default.action,
|
|
14611
|
+
"data-diff-confirm-keep": true,
|
|
14249
14612
|
onClick: () => {
|
|
14250
|
-
|
|
14613
|
+
setConfirmDismiss(null);
|
|
14251
14614
|
},
|
|
14252
|
-
children:
|
|
14253
|
-
})
|
|
14254
|
-
|
|
14255
|
-
className: PendingPanel_module_css_default.importNote,
|
|
14256
|
-
role: importFailed ? "alert" : void 0,
|
|
14257
|
-
children: importNote
|
|
14258
|
-
})
|
|
14259
|
-
]
|
|
14260
|
-
})
|
|
14261
|
-
]
|
|
14262
|
-
}) : (0, react_jsx_runtime.jsxs)("div", {
|
|
14263
|
-
className: PendingPanel_module_css_default.split,
|
|
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
|
|
14615
|
+
children: t("panel.keepInList")
|
|
14616
|
+
})]
|
|
14617
|
+
})]
|
|
14311
14618
|
})
|
|
14312
|
-
|
|
14313
|
-
|
|
14314
|
-
}),
|
|
14619
|
+
})
|
|
14620
|
+
]
|
|
14621
|
+
})] }), document.body),
|
|
14315
14622
|
(0, react_jsx_runtime.jsx)("div", {
|
|
14316
14623
|
className: PendingPanel_module_css_default.footerButtons,
|
|
14317
14624
|
children: (0, react_jsx_runtime.jsxs)("button", {
|
|
@@ -14474,6 +14781,69 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
14474
14781
|
})]
|
|
14475
14782
|
});
|
|
14476
14783
|
}
|
|
14784
|
+
/** Build the `Modifier+...+Key` chord label from a keydown event; a bare
|
|
14785
|
+
* modifier key alone returns undefined (wait for the full combo). */
|
|
14786
|
+
function chordLabel(event) {
|
|
14787
|
+
const key = event.key;
|
|
14788
|
+
if (key === "Control" || key === "Shift" || key === "Alt" || key === "Meta") return void 0;
|
|
14789
|
+
const parts = [];
|
|
14790
|
+
if (event.ctrlKey) parts.push("Ctrl");
|
|
14791
|
+
if (event.altKey) parts.push("Alt");
|
|
14792
|
+
if (event.shiftKey) parts.push("Shift");
|
|
14793
|
+
if (event.metaKey) parts.push("Meta");
|
|
14794
|
+
parts.push(key.length === 1 ? key.toUpperCase() : key);
|
|
14795
|
+
return parts.join("+");
|
|
14796
|
+
}
|
|
14797
|
+
/** A button that records the next key chord (modifiers + key) as the shortcut. */
|
|
14798
|
+
function ShortcutRecorder({ value, onChange, dataAttribute, placeholder }) {
|
|
14799
|
+
const [recording, setRecording] = (0, react.useState)(false);
|
|
14800
|
+
return (0, react_jsx_runtime.jsxs)("button", {
|
|
14801
|
+
type: "button",
|
|
14802
|
+
className: PendingPanel_module_css_default.settingsSelector,
|
|
14803
|
+
onClick: () => {
|
|
14804
|
+
setRecording(true);
|
|
14805
|
+
},
|
|
14806
|
+
onBlur: () => {
|
|
14807
|
+
setRecording(false);
|
|
14808
|
+
},
|
|
14809
|
+
onKeyDown: recording ? (event) => {
|
|
14810
|
+
event.preventDefault();
|
|
14811
|
+
event.stopPropagation();
|
|
14812
|
+
if (event.key === "Escape") {
|
|
14813
|
+
setRecording(false);
|
|
14814
|
+
return;
|
|
14815
|
+
}
|
|
14816
|
+
const chord = chordLabel(event);
|
|
14817
|
+
if (chord !== void 0) {
|
|
14818
|
+
onChange(chord);
|
|
14819
|
+
setRecording(false);
|
|
14820
|
+
}
|
|
14821
|
+
} : void 0,
|
|
14822
|
+
[dataAttribute]: true,
|
|
14823
|
+
children: [recording ? placeholder : value, (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { className: PendingPanel_module_css_default.settingsSelectorChevron })]
|
|
14824
|
+
});
|
|
14825
|
+
}
|
|
14826
|
+
/** One shortcut row: title + description, chord recorder right. */
|
|
14827
|
+
function ShortcutRow({ title, description, value, onChange, dataAttribute, placeholder }) {
|
|
14828
|
+
return (0, react_jsx_runtime.jsxs)("div", {
|
|
14829
|
+
className: PendingPanel_module_css_default.settingsRow,
|
|
14830
|
+
children: [(0, react_jsx_runtime.jsxs)("div", {
|
|
14831
|
+
className: PendingPanel_module_css_default.settingsRowText,
|
|
14832
|
+
children: [(0, react_jsx_runtime.jsx)("div", {
|
|
14833
|
+
className: PendingPanel_module_css_default.settingsRowTitle,
|
|
14834
|
+
children: title
|
|
14835
|
+
}), (0, react_jsx_runtime.jsx)("div", {
|
|
14836
|
+
className: PendingPanel_module_css_default.settingsRowDesc,
|
|
14837
|
+
children: description
|
|
14838
|
+
})]
|
|
14839
|
+
}), (0, react_jsx_runtime.jsx)(ShortcutRecorder, {
|
|
14840
|
+
value,
|
|
14841
|
+
onChange,
|
|
14842
|
+
dataAttribute,
|
|
14843
|
+
placeholder
|
|
14844
|
+
})]
|
|
14845
|
+
});
|
|
14846
|
+
}
|
|
14477
14847
|
/**
|
|
14478
14848
|
* The plugin's preferences: auto-paste a copied reference into the input,
|
|
14479
14849
|
* whether importing workspace VCS changes includes untracked files, and the
|
|
@@ -14490,6 +14860,11 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
14490
14860
|
const [tabOpen, setTabOpen] = (0, react.useState)(false);
|
|
14491
14861
|
const [split, setSplitState] = (0, react.useState)(splitMode);
|
|
14492
14862
|
const [splitOpen, setSplitOpen] = (0, react.useState)(false);
|
|
14863
|
+
const [summon, setSummonState] = (0, react.useState)(quickSummonKey);
|
|
14864
|
+
const setSummon = (value) => {
|
|
14865
|
+
setSummonState(value);
|
|
14866
|
+
setQuickSummonKey(value);
|
|
14867
|
+
};
|
|
14493
14868
|
const setPasteOnCopy = (value) => {
|
|
14494
14869
|
setPasteOnCopyState(value);
|
|
14495
14870
|
setPasteOnCopyEnabled(value);
|
|
@@ -14548,6 +14923,14 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
14548
14923
|
onSelect: setSplit,
|
|
14549
14924
|
dataAttribute: "data-diff-split-mode-select",
|
|
14550
14925
|
t
|
|
14926
|
+
}),
|
|
14927
|
+
(0, react_jsx_runtime.jsx)(ShortcutRow, {
|
|
14928
|
+
title: t("panel.quickSummon"),
|
|
14929
|
+
description: t("panel.quickSummonDesc"),
|
|
14930
|
+
value: summon,
|
|
14931
|
+
onChange: setSummon,
|
|
14932
|
+
dataAttribute: "data-diff-quick-summon-key",
|
|
14933
|
+
placeholder: t("panel.recordShortcut")
|
|
14551
14934
|
})
|
|
14552
14935
|
]
|
|
14553
14936
|
});
|
|
@@ -14671,9 +15054,14 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
14671
15054
|
const outcome = value.outcome;
|
|
14672
15055
|
if (outcome !== "kept" && outcome !== "reverted" && outcome !== "missing" && outcome !== "undone" && outcome !== "redone" && outcome !== "nothing") throw new Error("the action returned a malformed outcome");
|
|
14673
15056
|
const id = value.id;
|
|
14674
|
-
|
|
15057
|
+
const entryId = typeof id === "string" && id.length > 0 ? id : void 0;
|
|
15058
|
+
return value.resolved === true ? {
|
|
14675
15059
|
outcome,
|
|
14676
|
-
id:
|
|
15060
|
+
id: entryId,
|
|
15061
|
+
resolved: true
|
|
15062
|
+
} : {
|
|
15063
|
+
outcome,
|
|
15064
|
+
id: entryId
|
|
14677
15065
|
};
|
|
14678
15066
|
}
|
|
14679
15067
|
/** Narrow the vcs-import endpoint's value; a malformed wire value is a failure. */
|
|
@@ -14726,11 +15114,18 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
14726
15114
|
};
|
|
14727
15115
|
const listeners = /* @__PURE__ */ new Set();
|
|
14728
15116
|
let redoCleared = false;
|
|
15117
|
+
let justResolved;
|
|
14729
15118
|
const publish = (next) => {
|
|
14730
|
-
|
|
14731
|
-
|
|
15119
|
+
let result = next;
|
|
15120
|
+
if (redoCleared) result = {
|
|
15121
|
+
...result,
|
|
14732
15122
|
redoCleared: true
|
|
14733
|
-
}
|
|
15123
|
+
};
|
|
15124
|
+
if (justResolved !== void 0) result = {
|
|
15125
|
+
...result,
|
|
15126
|
+
justResolved
|
|
15127
|
+
};
|
|
15128
|
+
snapshot = result;
|
|
14734
15129
|
for (const listener of [...listeners]) listener();
|
|
14735
15130
|
};
|
|
14736
15131
|
const failedOf = (value) => value.failed ?? EMPTY_FAILED;
|
|
@@ -14839,8 +15234,9 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
14839
15234
|
...base,
|
|
14840
15235
|
busy: /* @__PURE__ */ new Set([...snapshot.busy, id])
|
|
14841
15236
|
});
|
|
15237
|
+
let value;
|
|
14842
15238
|
try {
|
|
14843
|
-
await port.blockKeep(sessionId, id, block);
|
|
15239
|
+
value = await port.blockKeep(sessionId, id, block);
|
|
14844
15240
|
} catch (error) {
|
|
14845
15241
|
markFailed(id, error instanceof Error ? error.message : String(error));
|
|
14846
15242
|
publish({
|
|
@@ -14850,6 +15246,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
14850
15246
|
return;
|
|
14851
15247
|
}
|
|
14852
15248
|
clearFailed(id);
|
|
15249
|
+
if (value.resolved === true) justResolved = id;
|
|
14853
15250
|
await this.refresh(sessionId);
|
|
14854
15251
|
},
|
|
14855
15252
|
async blockRevert(sessionId, id, block) {
|
|
@@ -14858,8 +15255,9 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
14858
15255
|
...base,
|
|
14859
15256
|
busy: /* @__PURE__ */ new Set([...snapshot.busy, id])
|
|
14860
15257
|
});
|
|
15258
|
+
let value;
|
|
14861
15259
|
try {
|
|
14862
|
-
await port.blockRevert(sessionId, id, block);
|
|
15260
|
+
value = await port.blockRevert(sessionId, id, block);
|
|
14863
15261
|
} catch (error) {
|
|
14864
15262
|
markFailed(id, error instanceof Error ? error.message : String(error));
|
|
14865
15263
|
publish({
|
|
@@ -14869,6 +15267,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
14869
15267
|
return;
|
|
14870
15268
|
}
|
|
14871
15269
|
clearFailed(id);
|
|
15270
|
+
if (value.resolved === true) justResolved = id;
|
|
14872
15271
|
await this.refresh(sessionId);
|
|
14873
15272
|
},
|
|
14874
15273
|
async undo(sessionId) {
|
|
@@ -14907,6 +15306,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
14907
15306
|
}
|
|
14908
15307
|
},
|
|
14909
15308
|
reset() {
|
|
15309
|
+
justResolved = void 0;
|
|
14910
15310
|
publish({
|
|
14911
15311
|
read: false,
|
|
14912
15312
|
files: [],
|
|
@@ -14917,6 +15317,128 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
14917
15317
|
redoCleared = false;
|
|
14918
15318
|
const { redoCleared: _omit, ...rest } = snapshot;
|
|
14919
15319
|
publish(rest);
|
|
15320
|
+
},
|
|
15321
|
+
clearJustResolved() {
|
|
15322
|
+
justResolved = void 0;
|
|
15323
|
+
const { justResolved: _omit, ...rest } = snapshot;
|
|
15324
|
+
publish(rest);
|
|
15325
|
+
}
|
|
15326
|
+
};
|
|
15327
|
+
}
|
|
15328
|
+
//#endregion
|
|
15329
|
+
//#region lib/types/client/remap-sync.js
|
|
15330
|
+
/**
|
|
15331
|
+
* Reference remapping sync: track each pending file's last-seen content and,
|
|
15332
|
+
* when it changes (an agent edit, a block revert, or an external adoption),
|
|
15333
|
+
* rewrite stale references in the current composer draft and the pending queue.
|
|
15334
|
+
* Pure orchestration over the pending store; the actual line remapping lives in
|
|
15335
|
+
* `reference.ts`.
|
|
15336
|
+
* @module dsh-diff-approval/client/remap-sync
|
|
15337
|
+
*/
|
|
15338
|
+
/**
|
|
15339
|
+
* Subscribe to the pending store and remap references as each file's content
|
|
15340
|
+
* changes. The first observation of a file only seeds the baseline; a later
|
|
15341
|
+
* `newText` change remaps (draft + queue) and advances the baseline. Files that
|
|
15342
|
+
* leave the list drop their baseline so a future re-appearance re-baselines.
|
|
15343
|
+
* @param opts - the sync inputs.
|
|
15344
|
+
* @returns an unsubscribe function plus a direct remap verb for whole-file reverts.
|
|
15345
|
+
*/
|
|
15346
|
+
function attachReferenceRemap(opts) {
|
|
15347
|
+
const { store, readDraft, writeDraft, readQueue, writeQueue } = opts;
|
|
15348
|
+
const lastContent = /* @__PURE__ */ new Map();
|
|
15349
|
+
const remap = (path, oldText, newText, workspacePath) => {
|
|
15350
|
+
const referencePath = referencePathOf(path, workspacePath);
|
|
15351
|
+
const draft = readDraft();
|
|
15352
|
+
if (draft !== void 0 && draft !== "") {
|
|
15353
|
+
const rewritten = remapReferences(draft, referencePath, oldText, newText);
|
|
15354
|
+
if (rewritten !== draft) writeDraft(rewritten);
|
|
15355
|
+
}
|
|
15356
|
+
for (const message of readQueue()) {
|
|
15357
|
+
let changed = false;
|
|
15358
|
+
const content = message.content.map((block) => {
|
|
15359
|
+
if (block.type !== "text" || block.text === void 0) return block;
|
|
15360
|
+
const rewritten = remapReferences(block.text, referencePath, oldText, newText);
|
|
15361
|
+
if (rewritten !== block.text) {
|
|
15362
|
+
changed = true;
|
|
15363
|
+
return {
|
|
15364
|
+
...block,
|
|
15365
|
+
text: rewritten
|
|
15366
|
+
};
|
|
15367
|
+
}
|
|
15368
|
+
return block;
|
|
15369
|
+
});
|
|
15370
|
+
if (changed) writeQueue(message.id, content);
|
|
15371
|
+
}
|
|
15372
|
+
};
|
|
15373
|
+
const observe = () => {
|
|
15374
|
+
const snapshot = store.getSnapshot();
|
|
15375
|
+
for (const file of snapshot.files) {
|
|
15376
|
+
const previous = lastContent.get(file.path);
|
|
15377
|
+
if (previous !== void 0 && contentKey(previous) !== contentKey(file.newText)) remap(file.path, previous, file.newText, snapshot.workspacePath);
|
|
15378
|
+
lastContent.set(file.path, file.newText);
|
|
15379
|
+
}
|
|
15380
|
+
for (const path of [...lastContent.keys()]) if (!snapshot.files.some((file) => file.path === path)) lastContent.delete(path);
|
|
15381
|
+
};
|
|
15382
|
+
const unsubscribe = store.subscribe(observe);
|
|
15383
|
+
observe();
|
|
15384
|
+
return {
|
|
15385
|
+
unsubscribe,
|
|
15386
|
+
remapFile: (path, oldText, newText) => {
|
|
15387
|
+
remap(path, oldText, newText, store.getSnapshot().workspacePath);
|
|
15388
|
+
}
|
|
15389
|
+
};
|
|
15390
|
+
}
|
|
15391
|
+
//#endregion
|
|
15392
|
+
//#region lib/types/client/conversation-access.js
|
|
15393
|
+
/**
|
|
15394
|
+
* Scope-addressed access to the session's composer draft and pending queue.
|
|
15395
|
+
* Extracted from the plugin entry so the wiring (not just the remap math) is
|
|
15396
|
+
* unit-testable against a faithful fake of the DSH conversation service.
|
|
15397
|
+
* @module dsh-diff-approval/client/conversation-access
|
|
15398
|
+
*/
|
|
15399
|
+
/**
|
|
15400
|
+
* Resolve the current session's scoped conversation face. The scoped context
|
|
15401
|
+
* (`sessions.scope(id)`) carries no `conversation` inject of its own, so reading
|
|
15402
|
+
* it as a property (`actx.conversation`) trips Cordis's inject check and throws
|
|
15403
|
+
* `cannot get property "conversation" without inject`. `actx.get('conversation')`
|
|
15404
|
+
* bypasses that check yet still returns the traceable bound to `actx`, so its
|
|
15405
|
+
* verbs (e.g. `updateQueue`) resolve the right session scope.
|
|
15406
|
+
*/
|
|
15407
|
+
function resolveConversation(ctx, sessionId) {
|
|
15408
|
+
if (sessionId === void 0) return void 0;
|
|
15409
|
+
const actx = ctx.get("sessions")?.scope(sessionId);
|
|
15410
|
+
if (actx === void 0) return void 0;
|
|
15411
|
+
const conversation = actx.get("conversation");
|
|
15412
|
+
if (conversation?.input === void 0) return void 0;
|
|
15413
|
+
return {
|
|
15414
|
+
actx,
|
|
15415
|
+
conversation
|
|
15416
|
+
};
|
|
15417
|
+
}
|
|
15418
|
+
/**
|
|
15419
|
+
* Build the per-call-resolved draft/queue accessor. `sessionId` is a function
|
|
15420
|
+
* so the accessor always addresses the *current* session, even though it is
|
|
15421
|
+
* handed to the remap sync once.
|
|
15422
|
+
*/
|
|
15423
|
+
function conversationAccess(ctx, sessionId) {
|
|
15424
|
+
return {
|
|
15425
|
+
writeDraft: (text) => {
|
|
15426
|
+
const scoped = resolveConversation(ctx, sessionId());
|
|
15427
|
+
if (scoped === void 0) return;
|
|
15428
|
+
scoped.conversation.input.for(scoped.actx).setDraft(text);
|
|
15429
|
+
},
|
|
15430
|
+
readQueue: () => {
|
|
15431
|
+
const scoped = resolveConversation(ctx, sessionId());
|
|
15432
|
+
if (scoped === void 0) return [];
|
|
15433
|
+
return scoped.conversation.input.for(scoped.actx).state.getSnapshot().queue.filter((item) => item.placement === "queued");
|
|
15434
|
+
},
|
|
15435
|
+
writeQueue: (itemId, content) => {
|
|
15436
|
+
const scoped = resolveConversation(ctx, sessionId());
|
|
15437
|
+
if (scoped === void 0) return;
|
|
15438
|
+
scoped.conversation.updateQueue(itemId, {
|
|
15439
|
+
kind: "edit",
|
|
15440
|
+
content
|
|
15441
|
+
});
|
|
14920
15442
|
}
|
|
14921
15443
|
};
|
|
14922
15444
|
}
|
|
@@ -14950,9 +15472,13 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
14950
15472
|
"panel.tabWidthDesc": "差异中制表符的缩进宽度,可选 2 / 4 / 8 个空格(默认 4),同时作用于行宽折行测量。",
|
|
14951
15473
|
"panel.splitMode": "双栏对比",
|
|
14952
15474
|
"panel.splitModeDesc": "开启后整文件差异用左「改前」|右「当前」双栏、逐行对齐的视图展示,默认关闭使用单栏(合并)视图。",
|
|
15475
|
+
"panel.quickSummon": "快速呼出",
|
|
15476
|
+
"panel.quickSummonDesc": "用键盘快捷键打开/关闭差异面板(默认 Ctrl+D)。点击右侧按钮后按下新的按键组合即可修改,Esc 取消。",
|
|
15477
|
+
"panel.recordShortcut": "按下快捷键…",
|
|
14953
15478
|
"settings.tabLabel": "改动审批",
|
|
14954
15479
|
"row.create": "新增文件",
|
|
14955
15480
|
"row.failed": "失败",
|
|
15481
|
+
"row.dismiss": "移除",
|
|
14956
15482
|
"row.added": "+{added}",
|
|
14957
15483
|
"row.removed": "-{removed}",
|
|
14958
15484
|
"action.keep": "保留",
|
|
@@ -14987,7 +15513,9 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
14987
15513
|
"action.close": "关闭",
|
|
14988
15514
|
"status.kept": "已保留",
|
|
14989
15515
|
"status.reverted": "已回退",
|
|
14990
|
-
"status.missing": "该改动已不存在"
|
|
15516
|
+
"status.missing": "该改动已不存在",
|
|
15517
|
+
"panel.resolvedAsk": "「{file}」的所有改动都已处理,是否从列表移除?",
|
|
15518
|
+
"panel.keepInList": "保留在列表"
|
|
14991
15519
|
};
|
|
14992
15520
|
/** English pending-edit review messages. */
|
|
14993
15521
|
const en = {
|
|
@@ -15015,9 +15543,13 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
15015
15543
|
"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
15544
|
"panel.splitMode": "Side-by-side view",
|
|
15017
15545
|
"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.",
|
|
15546
|
+
"panel.quickSummon": "Quick summon",
|
|
15547
|
+
"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.",
|
|
15548
|
+
"panel.recordShortcut": "Press keys…",
|
|
15018
15549
|
"settings.tabLabel": "Diff Approval",
|
|
15019
15550
|
"row.create": "New file",
|
|
15020
15551
|
"row.failed": "Failed",
|
|
15552
|
+
"row.dismiss": "Remove",
|
|
15021
15553
|
"row.added": "+{added}",
|
|
15022
15554
|
"row.removed": "-{removed}",
|
|
15023
15555
|
"action.keep": "Keep",
|
|
@@ -15052,17 +15584,21 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
15052
15584
|
"action.close": "Close",
|
|
15053
15585
|
"status.kept": "Kept",
|
|
15054
15586
|
"status.reverted": "Reverted",
|
|
15055
|
-
"status.missing": "This change no longer exists"
|
|
15587
|
+
"status.missing": "This change no longer exists",
|
|
15588
|
+
"panel.resolvedAsk": "All changes in \"{file}\" are resolved. Remove it from the list?",
|
|
15589
|
+
"panel.keepInList": "Keep in list"
|
|
15056
15590
|
};
|
|
15057
15591
|
//#endregion
|
|
15058
15592
|
//#region lib/types/client/index.js
|
|
15059
15593
|
/** Pending-edit review panel, browser half: footer action, pending list, and whole-file diff viewer. */
|
|
15060
|
-
/** Required services: locale, slots, the wire channel,
|
|
15594
|
+
/** Required services: locale, slots, the wire channel, the current session, and
|
|
15595
|
+
* the layout controller (this plugin collapses the sidebar before its modal opens). */
|
|
15061
15596
|
const inject = [
|
|
15062
15597
|
"slots",
|
|
15063
15598
|
"locale",
|
|
15064
15599
|
"connection",
|
|
15065
|
-
"sessions"
|
|
15600
|
+
"sessions",
|
|
15601
|
+
"layout"
|
|
15066
15602
|
];
|
|
15067
15603
|
/**
|
|
15068
15604
|
* The dsh web-react renderer gives `div[data-slot="sidebar.footer.action"]` an
|
|
@@ -15129,6 +15665,29 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
15129
15665
|
}), "ui-diff-approval: dictionaries");
|
|
15130
15666
|
const t = ctx.locale.bind(NS);
|
|
15131
15667
|
const store = createPendingDiffStore(createDiffApprovalPort(ctx.get("connection").rpc));
|
|
15668
|
+
let currentSessionId;
|
|
15669
|
+
let remapFile = () => {};
|
|
15670
|
+
const access = conversationAccess(ctx, () => currentSessionId);
|
|
15671
|
+
ctx.effect(() => {
|
|
15672
|
+
const attached = attachReferenceRemap({
|
|
15673
|
+
store,
|
|
15674
|
+
readDraft: () => document.querySelector("[data-composer-card] textarea")?.value,
|
|
15675
|
+
writeDraft: access.writeDraft,
|
|
15676
|
+
readQueue: access.readQueue,
|
|
15677
|
+
writeQueue: access.writeQueue
|
|
15678
|
+
});
|
|
15679
|
+
remapFile = attached.remapFile;
|
|
15680
|
+
return attached.unsubscribe;
|
|
15681
|
+
}, "diff-approval: reference remap");
|
|
15682
|
+
const collapseSidebar = () => {
|
|
15683
|
+
if (window.innerWidth >= 1024) return;
|
|
15684
|
+
const ctxLayout = ctx.layout;
|
|
15685
|
+
if (ctxLayout === void 0) return;
|
|
15686
|
+
if (document.querySelector("[data-sidebar-collapsed]") !== null) return;
|
|
15687
|
+
try {
|
|
15688
|
+
ctxLayout.toggleSidebar();
|
|
15689
|
+
} catch {}
|
|
15690
|
+
};
|
|
15132
15691
|
ctx.on("connection/reset", () => {
|
|
15133
15692
|
store.reset();
|
|
15134
15693
|
});
|
|
@@ -15139,10 +15698,19 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
15139
15698
|
inject: () => ({
|
|
15140
15699
|
hooks: { pending: store },
|
|
15141
15700
|
onRefresh: (sessionId) => {
|
|
15701
|
+
currentSessionId = sessionId;
|
|
15142
15702
|
store.refresh(sessionId);
|
|
15143
15703
|
},
|
|
15144
15704
|
onKeep: (sessionId, path) => store.keep(sessionId, path),
|
|
15145
|
-
onRevert: (sessionId, path) =>
|
|
15705
|
+
onRevert: (sessionId, path) => {
|
|
15706
|
+
const entry = store.getSnapshot().files.find((file) => file.id === path);
|
|
15707
|
+
const before = entry?.newText;
|
|
15708
|
+
const after = entry?.oldText;
|
|
15709
|
+
const filePath = entry?.path;
|
|
15710
|
+
return store.revert(sessionId, path).then(() => {
|
|
15711
|
+
if (filePath !== void 0 && before !== void 0 && after !== void 0) remapFile(filePath, before, after);
|
|
15712
|
+
});
|
|
15713
|
+
},
|
|
15146
15714
|
onBlockKeep: (sessionId, id, block) => store.blockKeep(sessionId, id, block),
|
|
15147
15715
|
onBlockRevert: (sessionId, id, block) => store.blockRevert(sessionId, id, block),
|
|
15148
15716
|
onOpen: (sessionId, id, action) => store.open(sessionId, id, action),
|
|
@@ -15150,6 +15718,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
15150
15718
|
onRedo: (sessionId) => store.redo(sessionId),
|
|
15151
15719
|
onImportVcs: (sessionId, includeUntracked) => store.importVcs(sessionId, includeUntracked),
|
|
15152
15720
|
onAckRedoCleared: () => store.clearRedoCleared(),
|
|
15721
|
+
onAckJustResolved: () => store.clearJustResolved(),
|
|
15153
15722
|
onPasteReference: (sessionId, reference) => {
|
|
15154
15723
|
const actx = ctx.get("sessions")?.scope(sessionId);
|
|
15155
15724
|
if (actx === void 0) return;
|
|
@@ -15159,7 +15728,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
15159
15728
|
const base = textarea?.value ?? "";
|
|
15160
15729
|
conversation.input.for(actx).setDraft(base === "" ? reference : `${base} ${reference}`);
|
|
15161
15730
|
textarea?.focus();
|
|
15162
|
-
}
|
|
15731
|
+
},
|
|
15732
|
+
collapseSidebar
|
|
15163
15733
|
})
|
|
15164
15734
|
}, PendingPanel));
|
|
15165
15735
|
ctx.slots.inject("settings.section", () => ctx.slots.register({
|