dsh-diff-approval 0.26.0 → 0.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/client.js +2048 -617
- package/lib/index.js +25 -5
- package/lib/types/client/PendingPanel.d.ts +31 -0
- package/lib/types/client/discussion.d.ts +23 -2
- package/lib/types/client/dock.d.ts +10 -0
- package/lib/types/client/locales.d.ts +18 -2
- package/lib/types/client/panel-memory.d.ts +38 -0
- package/lib/types/client/slots.d.ts +6 -0
- package/lib/types/types.d.ts +6 -0
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -21,7 +21,7 @@ window.__ModuleLoader__.load({
|
|
|
21
21
|
let react_dom = require("react-dom");
|
|
22
22
|
let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
23
23
|
//#region \0dsh-css:/home/runner/work/dsh-diff-approval/dsh-diff-approval/src/client/PendingPanel.module.css.mjs
|
|
24
|
-
const css = ".F1KBNa_panelFailure{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);color:var(--dsw-alias-label-primary);border-radius:8px;align-items:center;gap:8px;padding:8px 10px;font-size:12px;line-height:16px;display:flex}.F1KBNa_panelFailureText{min-width:0}.F1KBNa_panelFailureRetry{border:1px solid var(--dsw-alias-border-l2);color:inherit;font:inherit;cursor:pointer;background:0 0;border-radius:6px;flex:none;margin-left:auto;padding:2px 8px}.F1KBNa_panelFailureRetry:hover{background:var(--dsw-alias-interactive-bg-hover)}.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_headerEntry{box-sizing:border-box;width:28px;height:28px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:28px;flex:none;justify-content:center;align-items:center;padding:6px;display:inline-flex;position:relative}.F1KBNa_headerEntry:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_headerEntry[data-active]{background:var(--dsw-alias-interactive-bg-hover-solid);color:var(--dsw-alias-label-primary)}.F1KBNa_headerEntry:disabled{color:var(--dsw-alias-label-tertiary);cursor:default;background:0 0}.F1KBNa_headerEntryCount{box-sizing:border-box;background:var(--dsw-alias-button-primary-fill);min-width:14px;height:14px;color:var(--dsw-alias-label-primary-foreground);text-align:center;font-variant-numeric:tabular-nums;pointer-events:none;border-radius:7px;padding:0 3px;font-size:10px;line-height:14px;position:absolute;top:-1px;right:-1px}.F1KBNa_headerEntry svg{display:block}.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_coverBackdrop{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);-webkit-user-select:none;user-select:none;border-radius:12px;flex-direction:column;display:flex;position:fixed;inset:8px 8px 128px;overflow:hidden}.F1KBNa_panel .F1KBNa_code,.F1KBNa_panel .F1KBNa_mdPreviewBody,.F1KBNa_panel .F1KBNa_discussionUser,.F1KBNa_panel .F1KBNa_discussionAnswer,.F1KBNa_panel .F1KBNa_quoteText,.F1KBNa_panel .F1KBNa_diffPath,.F1KBNa_panel .F1KBNa_rowPath,.F1KBNa_panel input,.F1KBNa_panel textarea,.F1KBNa_panel [contenteditable]{-webkit-user-select:text;user-select:text}.F1KBNa_panelDocked{width:100%;max-width:none;height:100%;box-shadow:none;border:none;border-radius:0;position:static;inset:auto}.F1KBNa_dockHost{flex-direction:column;min-height:0;display:flex;position:absolute;inset:0}.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_settingsGroup{border-bottom:1px solid var(--dsw-alias-border-l2)}.F1KBNa_settingsGroupHeader{width:100%;color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;text-align:left;background:0 0;border:none;align-items:center;gap:8px;padding:16px 0;display:flex}.F1KBNa_settingsGroupText{text-align:left;flex-direction:column;flex:1;gap:2px;min-width:0;display:flex}.F1KBNa_settingsGroupTitle{font-size:14px;font-weight:400;line-height:22px}.F1KBNa_settingsGroupDesc{color:var(--dsw-alias-label-tertiary);font-size:12px;font-weight:400;line-height:18px}.F1KBNa_settingsGroupChevron{margin-left:auto;transition:transform .15s}.F1KBNa_settingsGroup[data-open] .F1KBNa_settingsGroupChevron{transform:rotate(180deg)}.F1KBNa_settingsGroup[data-open] .F1KBNa_settingsGroupHeader{border-bottom:1px solid var(--dsw-alias-border-l2)}.F1KBNa_settingsGroupBody{flex-direction:column;display:flex}.F1KBNa_settingsGroupBody .F1KBNa_settingsRow{padding-left:16px}.F1KBNa_settingsGroupBody .F1KBNa_settingsRow:last-child,.F1KBNa_settingsPage>.F1KBNa_settingsRow:last-child{border-bottom:none}.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);min-width:72px;height:36px;font:inherit;color:var(--dsw-alias-label-primary);cursor:pointer;border:none;border-radius:18px;justify-content:center;align-items:center;padding:0 14px;font-size:14px;line-height:22px;display:inline-flex}.F1KBNa_settingsSelector:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_settingsSelector[data-recording]{box-shadow:inset 0 0 0 1px var(--dsw-alias-state-business-primary);color:var(--dsw-alias-label-secondary)}.F1KBNa_settingsReset{width:28px;height:28px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:28px;justify-content:center;align-items:center;margin-left:6px;padding:0;display:inline-flex}.F1KBNa_settingsReset:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_settingsReset:disabled{opacity:.4;cursor:default}.F1KBNa_colorPicker{position:relative}.F1KBNa_colorPickerTrigger{background:var(--dsw-alias-bg-module-platform);width:120px;height:36px;font:inherit;color:var(--dsw-alias-label-primary);cursor:pointer;border:none;border-radius:18px;align-items:center;gap:8px;padding:0 8px;font-size:12px;line-height:18px;display:inline-flex}.F1KBNa_colorPickerTrigger:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_colorSwatch{border:1px solid var(--dsw-alias-border-l2);border-radius:50%;flex:none;width:24px;height:24px}.F1KBNa_colorValue{text-overflow:ellipsis;white-space:nowrap;font-variant-numeric:tabular-nums;flex:1;min-width:0;overflow:hidden}.F1KBNa_colorPickerChevron{flex:none}.F1KBNa_colorBackdrop{z-index:40;position:fixed;inset:0}.F1KBNa_colorPickerPopover{z-index:41;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);box-shadow:var(--dsw-shadow-lv2);border-radius:10px;padding:10px;position:absolute;top:calc(100% + 6px);right:0}.F1KBNa_colorPickerPanel{flex-direction:column;gap:8px;display:flex}.F1KBNa_colorPickerInputRow{align-items:center;gap:8px;display:flex}.F1KBNa_colorPickerPreview{border:1px solid var(--dsw-alias-border-l2);border-radius:6px;flex:none;width:22px;height:22px}.F1KBNa_colorPickerInput{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-module-platform);min-width:0;height:30px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;flex:1;padding:0 8px;font-size:12px;line-height:28px}.F1KBNa_colorPickerInput:focus{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:-1px}.F1KBNa_colorSv{border:1px solid var(--dsw-alias-border-l1);cursor:crosshair;touch-action:none;border-radius:8px;height:140px;position:relative}.F1KBNa_colorSvCursor{pointer-events:none;border:2px solid #fff;border-radius:50%;width:14px;height:14px;position:absolute;transform:translate(-50%,-50%);box-shadow:0 0 0 1px #00000080}.F1KBNa_colorHue{border:1px solid var(--dsw-alias-border-l1);cursor:pointer;touch-action:none;border-radius:7px;height:14px;position:relative}.F1KBNa_colorHueCursor{pointer-events:none;border:2px solid #fff;border-radius:50%;width:16px;height:16px;position:absolute;top:50%;transform:translate(-50%,-50%);box-shadow:0 0 0 1px #00000080}.F1KBNa_diffPreview{z-index:2;border:1px solid var(--dsw-alias-border-l1);font:var(--dsw-font-markdown-code-block);background:var(--dsw-alias-markdown-code-block);border-radius:8px;margin:16px 0 8px;padding:8px;position:sticky;top:0;overflow:hidden}.F1KBNa_diffPreviewTitle{color:var(--dsw-alias-label-tertiary);margin-bottom:6px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_diffPreviewScroll{height:132px;overflow-y:auto}.F1KBNa_mdPreviewWrap{isolation:isolate;flex:1;min-width:0;min-height:0;display:flex;position:relative;overflow:hidden}.F1KBNa_mdPreviewBody{overscroll-behavior:none;min-width:0;min-height:0;color:var(--dsw-alias-label-primary);flex:1;padding:12px 16px;position:relative;overflow:auto}.F1KBNa_mdPreviewContent{width:100%;min-width:0;margin:0 auto}.F1KBNa_mdPreviewSingle{display:block}.F1KBNa_mdPreviewDouble{display:flex}.F1KBNa_mdPreviewBody .mdBlock{border-radius:4px;margin-bottom:12px;padding:2px 6px}.F1KBNa_mdPreviewBody .mdAdd{background-color:color-mix(in srgb, var(--dsh-diff-add-color,var(--dsw-alias-state-success-primary)) 10%, transparent)}.F1KBNa_mdPreviewBody .mdDel{background-color:color-mix(in srgb, var(--dsh-diff-del-color,var(--dsw-alias-state-error-primary)) 12%, transparent)}.F1KBNa_mdPreviewBody .mdWordDel{background-color:color-mix(in srgb, var(--dsh-diff-del-color,var(--dsw-alias-state-error-primary)) 34%, transparent);border-radius:2px;padding:0 1px}.F1KBNa_mdPreviewBody .mdWordAdd{background-color:color-mix(in srgb, var(--dsh-diff-add-color,var(--dsw-alias-state-success-primary)) 34%, transparent);border-radius:2px;padding:0 1px}.F1KBNa_mdPreviewBody .mdDouble{flex-direction:column;width:100%;min-width:0;display:flex}.F1KBNa_mdPreviewBody .mdDoubleRow{align-items:flex-start;width:100%;min-width:0;display:flex}.F1KBNa_mdPreviewBody .mdDoubleCol{flex:1;min-width:0}.F1KBNa_mdPreviewBody .mdDoubleRule{background:var(--dsw-alias-border-l2);flex:none;align-self:stretch;width:1px;margin:0 12px}.F1KBNa_mdPreviewFallback{font-family:var(--dsw-font-markdown-code-block);color:var(--dsw-alias-label-tertiary);padding:12px 16px;font-size:12px;line-height:18px}.F1KBNa_mdPreviewBody{word-break:break-word;font-size:13px;line-height:20px}.F1KBNa_mdPreviewBody>:first-child{margin-top:0}.F1KBNa_mdPreviewBody>:last-child{margin-bottom:0}.F1KBNa_mdPreviewBody h1,.F1KBNa_mdPreviewBody h2,.F1KBNa_mdPreviewBody h3,.F1KBNa_mdPreviewBody h4,.F1KBNa_mdPreviewBody h5,.F1KBNa_mdPreviewBody h6{margin:16px 0 8px;font-weight:600;line-height:1.3}.F1KBNa_mdPreviewBody h1{font-size:22px}.F1KBNa_mdPreviewBody h2{font-size:19px}.F1KBNa_mdPreviewBody h3{font-size:16px}.F1KBNa_mdPreviewBody h4{font-size:15px}.F1KBNa_mdPreviewBody h5{font-size:14px}.F1KBNa_mdPreviewBody h6{font-size:13px}.F1KBNa_mdPreviewBody p{margin:8px 0}.F1KBNa_mdPreviewBody ul,.F1KBNa_mdPreviewBody ol{margin:8px 0;padding-left:22px}.F1KBNa_mdPreviewBody li{margin:2px 0}.F1KBNa_mdPreviewBody a{color:var(--dsw-alias-state-business-primary);text-decoration:none}.F1KBNa_mdPreviewBody a:hover{text-decoration:underline}.F1KBNa_mdPreviewBody code{font-family:var(--dsw-font-markdown-code-block);background:#9e9e9e40;border-radius:4px;padding:1px 5px;font-size:12.5px}.F1KBNa_mdPreviewBody pre{overscroll-behavior-x:none;border:1px solid var(--dsw-alias-border-l1);font-family:var(--dsw-font-markdown-code-block);background:#9e9e9e40;border-radius:8px;margin:8px 0;padding:10px 12px;font-size:12.5px;line-height:18px;overflow:auto}.F1KBNa_mdPreviewBody pre code{background:0 0;padding:0}.F1KBNa_mdPreviewBody blockquote{border-left:3px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);margin:8px 0;padding:0 12px}.F1KBNa_mdPreviewBody hr{background:var(--dsw-alias-border-l1);border:none;height:1px;margin:16px 0}.F1KBNa_mdPreviewBody table{border-collapse:collapse;margin:8px 0}.F1KBNa_mdPreviewBody th,.F1KBNa_mdPreviewBody td{border:1px solid var(--dsw-alias-border-l1);padding:4px 10px}.F1KBNa_mdPreviewBody img{max-width:100%}.F1KBNa_mdPreviewBody .mdImageFallback{border:1px dashed var(--dsw-alias-border-l2);background:color-mix(in srgb, var(--dsw-alias-markdown-code-block) 45%, transparent);width:100%;min-height:120px;color:var(--dsw-alias-label-secondary);font-family:var(--dsw-font-markdown-code-block);text-align:center;white-space:pre-wrap;word-break:break-all;border-radius:4px;justify-content:center;align-items:center;margin:0 auto;padding:8px 12px;font-size:12px;line-height:16px;display:flex}.F1KBNa_toggle{border:1px solid var(--dsw-alias-border-l2);cursor:pointer;background:0 0;border-radius:18px;flex:none;width:60px;height:36px;padding:0;position:relative}.F1KBNa_toggle:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_toggle:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px}.F1KBNa_toggleOn{border-color:var(--dsw-alias-state-business-primary);background:var(--dsw-alias-state-business-primary)}.F1KBNa_toggleOn:hover{background:var(--dsw-alias-state-business-primary)}.F1KBNa_toggleThumb{background:var(--dsw-alias-label-primary);border-radius:50%;width:28px;height:28px;transition:left .12s;position:absolute;top:3px;left:3px}.F1KBNa_toggleOn .F1KBNa_toggleThumb{background:#fff;left:27px}.F1KBNa_stepper{align-items:center;gap:6px;display:inline-flex}.F1KBNa_stepperButton{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-module-platform);width:32px;height:32px;color:var(--dsw-alias-label-primary);cursor:pointer;border-radius:8px;padding:0;position:relative}.F1KBNa_stepperButton:before,.F1KBNa_stepperButton:after{content:\"\";background:currentColor;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)}.F1KBNa_stepperButton:before{width:10px;height:1px}.F1KBNa_stepperButton:after{width:1px;height:10px;display:none}.F1KBNa_stepperButtonUp:after{display:block}.F1KBNa_stepperButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_stepperButton:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.F1KBNa_stepperValue{text-align:center;min-width:2ch;color:var(--dsw-alias-label-primary);font-variant-numeric:tabular-nums;font-size:14px;line-height:22px}.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_fileListKnob{z-index:39;box-sizing:border-box;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);width:28px;height:28px;color:var(--dsw-alias-label-primary);cursor:pointer;box-shadow:var(--dsw-elevation-prominent);border-radius:8px;justify-content:center;align-items:center;padding:0;display:inline-flex;position:absolute}.F1KBNa_fileListKnob[data-open]{box-shadow:none;opacity:0}.F1KBNa_fileListKnob:not([data-open]){animation:.32s ease-in-out .5s both F1KBNa_fileListKnobIn}@keyframes F1KBNa_fileListKnobIn{0%{opacity:0}to{opacity:1}}.F1KBNa_fileListKnob:hover,.F1KBNa_fileListKnob:focus-visible{background-color:var(--dsw-alias-bg-base);background-image:linear-gradient(var(--dsw-alias-interactive-bg-hover), var(--dsw-alias-interactive-bg-hover))}.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:none;transform-origin:0 0;border-radius:12px;flex-direction:column;padding:6px 0 10px 8px;display:flex;position:absolute;overflow:hidden}.F1KBNa_fileListFloatClosing{pointer-events:none;animation:.14s ease-in forwards F1KBNa_fileListShrink}@keyframes F1KBNa_fileListShrink{0%{opacity:1;transform:scale(1)}to{opacity:0;transform:scale(.96)}}.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:scroll}.F1KBNa_bulkActions{flex:none;gap:6px;padding:8px 8px 0 0;display:flex}.F1KBNa_bulkActions .F1KBNa_action{text-align:center;flex:auto}.F1KBNa_addPath{justify-content:center;align-items:center;gap:4px;display:inline-flex}.F1KBNa_resizeHandle{cursor:col-resize;touch-action:none;background:0 0;flex:none;width:5px;margin:0 -2px}.F1KBNa_resizeHandle:hover{background:var(--dsw-alias-border-l2)}.F1KBNa_floatResizeHandle{z-index:41;cursor:col-resize;-webkit-user-select:none;user-select:none;touch-action:none;background:0 0;border-radius:4px;position:absolute}.F1KBNa_floatResizeHandle:hover{background-color:var(--dsw-alias-bg-base);background-image:linear-gradient(var(--dsw-alias-border-l2), 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:55;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{flex:none;justify-content:flex-end;align-items:center;gap:8px;display:flex}.F1KBNa_pickerCard{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);width:420px;max-width:100%;height:70%;max-height:100%;box-shadow:var(--dsw-shadow-lv3);border-radius:12px;flex-direction:column;gap:8px;padding:14px 16px 16px;display:flex;position:relative;overflow:hidden}.F1KBNa_pickerTitle{color:var(--dsw-alias-label-primary);flex:none;font-size:13px;font-weight:500;line-height:20px}.F1KBNa_pickerClose{width:22px;height:22px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;border-radius:6px;justify-content:center;align-items:center;padding:0;display:inline-flex;position:absolute;top:10px;right:10px}.F1KBNa_pickerClose:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_pickerForm{flex:none;gap:8px;display:flex}.F1KBNa_pickerInput{border:1px solid var(--dsw-alias-border-l1);min-width:0;color:var(--dsw-alias-label-primary);background:0 0;border-radius:8px;flex:auto;padding:3px 8px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_pickerInput:focus{border-color:var(--dsw-alias-state-business-primary);outline:none}.F1KBNa_tree{border:1px solid var(--dsw-alias-border-l1);border-radius:8px;flex:auto;min-height:0;padding:4px 2px 4px 4px;overflow:auto scroll}.F1KBNa_treeRow{border-radius:6px;align-items:center;gap:2px;padding-right:4px;display:flex}.F1KBNa_treeRow:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_treeRow[data-selected]{background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 18%, transparent)}.F1KBNa_treeCaret{width:16px;height:16px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;border-radius:4px;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}.F1KBNa_treeCaret:hover{color:var(--dsw-alias-label-primary)}.F1KBNa_treeName{min-width:0;color:var(--dsw-alias-label-primary);text-align:left;cursor:pointer;background:0 0;border:0;border-radius:6px;flex:auto;align-items:center;gap:6px;padding:2px 4px;font-family:inherit;font-size:12px;line-height:18px;display:flex}.F1KBNa_treeName:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.F1KBNa_treeNote{color:var(--dsw-alias-label-tertiary);margin:2px 0;font-size:12px;line-height:18px}.F1KBNa_pickerIcon{width:16px;height:16px;color:var(--dsw-alias-label-tertiary);flex:none;justify-content:center;align-items:center;display:inline-flex}.F1KBNa_pickerName{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.F1KBNa_pickerNote{color:var(--dsw-alias-label-tertiary);flex:none;margin:0;font-size:12px;line-height:18px}.F1KBNa_pickerCheck{color:var(--dsw-alias-label-secondary);cursor:pointer;align-items:center;gap:6px;margin-right:auto;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_groupHead{align-items:center;gap:4px;margin:8px 0 4px;padding-right:8px;display:flex}.F1KBNa_action.F1KBNa_addButton{box-sizing:border-box;border-radius:6px;flex:none;justify-content:center;align-items:center;width:20px;height:20px;min-height:0;padding:0;display:inline-flex}.F1KBNa_groupHead>.F1KBNa_group{margin:0}.F1KBNa_listHead{flex:none;align-items:center;gap:4px;margin:8px 1px 2px;padding-right:8px;display:flex}.F1KBNa_action.F1KBNa_addButton.F1KBNa_listFold{width:26px;height:26px}.F1KBNa_listTitle{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;font-weight:500;line-height:16px}.F1KBNa_listTabs{background:var(--dsw-alias-interactive-bg-hover);border-radius:8px;flex:auto;gap:2px;min-width:0;padding:2px;display:flex}.F1KBNa_listTab{color:var(--dsw-alias-label-secondary);font:inherit;cursor:pointer;background:0 0;border:none;border-radius:6px;flex:1;padding:3px 8px;font-size:12px;line-height:16px}.F1KBNa_listTab[aria-selected=true]{background:var(--dsw-alias-bg-base);color:var(--dsw-alias-label-primary)}.F1KBNa_commentRow{box-sizing:border-box;width:100%;color:inherit;text-align:left;cursor:pointer;background:0 0;border:none;border-radius:10px;padding:6px 8px;display:block}.F1KBNa_commentRow:hover{background:var(--dsw-alias-interactive-bg-hover-solid)}.F1KBNa_commentHead{align-items:baseline;gap:6px;min-width:0;display:flex}.F1KBNa_commentLabel{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--dsw-alias-label-secondary);font:var(--dsw-font-markdown-code-block);font-size:11px;line-height:16px;overflow:hidden}.F1KBNa_commentLost{color:var(--dsw-alias-label-tertiary);flex:none;font-size:11px;line-height:16px}.F1KBNa_commentTitle{text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-primary);font-size:12px;line-height:18px;display:block;overflow:hidden}.F1KBNa_listEmpty{color:var(--dsw-alias-label-tertiary);margin:8px 12px;font-size:12px;line-height:18px}.F1KBNa_emptyActions{flex-wrap:wrap;justify-content:center;gap:8px;display:flex}.F1KBNa_rows{margin:0;padding:0;list-style:none}.F1KBNa_row{border:1px solid #0000;border-radius:10px;margin:2px 0}.F1KBNa_rowMenuAnchor{display:none}.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:center;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;margin-left:4px;font-size:12px;line-height:18px;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(--dsh-diff-add-color,var(--dsw-alias-state-success-primary)) 60%, var(--dsw-alias-label-primary))}.F1KBNa_delCount{color:color-mix(in srgb, var(--dsh-diff-del-color,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_panelDocked .F1KBNa_diffHeader{background:var(--dsw-alias-bg-base)}.F1KBNa_diffPath{appearance:none;min-width:0;font:inherit;text-overflow:ellipsis;color:var(--dsw-alias-label-primary);background:0 0;border:0;flex:1;margin-left:4px;padding:0;font-size:12px;line-height:18px;position:relative;top:1px}.F1KBNa_diffPath:focus{outline:none}.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_divider{background:var(--dsw-alias-border-l1);align-self:stretch;width:1px;margin:2px 0}.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_actionChord{color:var(--dsw-alias-label-tertiary);margin-left:6px;font-size:11px}.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{isolation:isolate;flex:1;min-height:0;display:flex;position:relative;overflow:hidden}.F1KBNa_diffBody{overscroll-behavior:none;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_blockActionsDivider{background:var(--dsw-alias-border-l2);flex:none;align-self:stretch;width:1px;margin:2px 0}.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_searchToggle{border:1px solid var(--dsw-alias-border-l1);min-height:25px;color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border-radius:8px;justify-content:center;align-items:center;padding:4px 6px;display:inline-flex}.F1KBNa_searchToggle:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_searchToggleOn{border-color:var(--dsw-alias-state-business-primary);background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-state-business-primary)}.F1KBNa_searchMatch{color:inherit;background-color:#facc1542;border-radius:2px}.F1KBNa_searchMatchCurrent{color:inherit;background-color:#facc1599;border-radius:2px}.F1KBNa_blockFlash{z-index:3;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_diffFlashFade;position:absolute;left:0;right:0}.F1KBNa_blockFlashShake{animation:.7s ease-out forwards F1KBNa_diffFlashShake}.F1KBNa_discussionRow{background:var(--dsw-alias-bg-base);display:table-row}.F1KBNa_discussionCell{display:table-cell}.F1KBNa_discussionPin{z-index:2;width:0;height:0;position:sticky;left:0}.F1KBNa_discussion{z-index:2;box-sizing:border-box;border-left:3px solid var(--dsw-alias-state-business-primary);box-shadow:inset 0 1px 0 0 color-mix(in srgb, var(--dsw-alias-label-secondary) 55%, transparent), inset 0 -1px 0 0 color-mix(in srgb, var(--dsw-alias-label-secondary) 55%, transparent), inset -1px 0 0 0 color-mix(in srgb, var(--dsw-alias-label-secondary) 55%, transparent);cursor:default;background:0 0;flex-direction:column;display:flex;position:absolute;top:0;left:0;overflow:hidden}.F1KBNa_discussionHead{font:var(--dsw-font-markdown-code-block)}.F1KBNa_discussionBody,.F1KBNa_threadFontProbe{font:var(--dsw-font-markdown-base);font-size:calc(var(--dsh-content-font-size,14px) - 2px)}.F1KBNa_threadFontProbe{visibility:hidden;pointer-events:none;width:0;height:0;position:absolute;overflow:hidden}.F1KBNa_discussionBody{flex-direction:column;flex:auto;min-height:0;padding:0 12px;display:flex;overflow:hidden}.F1KBNa_discussion[data-lost]{border-left-color:var(--dsw-alias-label-secondary);background:repeating-linear-gradient(135deg, var(--dsw-alias-interactive-bg-hover) 0 4px, transparent 4px 8px);background-origin:border-box}.F1KBNa_discussion[data-lost] .F1KBNa_discussionSend,.F1KBNa_discussion[data-lost] .F1KBNa_discussionSend:hover:not(:disabled),.F1KBNa_discussion[data-lost] .F1KBNa_discussionSend:disabled{background:var(--dsw-alias-label-secondary);border-color:var(--dsw-alias-label-secondary);color:var(--dsw-alias-label-primary-foreground)}.F1KBNa_discussion[data-lost] .F1KBNa_discussionUser{background:color-mix(in srgb, var(--dsw-alias-label-secondary) 30%, transparent)}.F1KBNa_discussionAnswer{color:var(--dsw-alias-label-primary);white-space:pre-wrap;overflow-wrap:anywhere;cursor:text;margin:0;padding:0;font-family:inherit;line-height:22px}.F1KBNa_discussionUser{box-sizing:border-box;background:var(--dsw-specific-bubble,var(--dsw-alias-bg-layer-2,var(--dsw-alias-interactive-bg-hover)));width:fit-content;max-width:82%;color:var(--dsw-alias-label-primary);white-space:pre-wrap;overflow-wrap:anywhere;cursor:text;border-radius:8px 0 8px 8px;margin:6.6px 0 6.6px auto;padding:4.4px 11px;font-family:inherit;line-height:22px}.F1KBNa_discussionCode{box-sizing:border-box;font:var(--dsw-font-markdown-code);font-family:var(--ds-font-family-code);background:color-mix(in srgb, var(--dsw-alias-markdown-inline-code,var(--dsw-alias-interactive-bg-hover-solid)) 90%, var(--dsw-alias-label-secondary));border:.5px solid var(--dsw-alias-border-l1);border-radius:6px;align-items:center;padding:0 5px;font-size:.875em;line-height:16px;display:inline-flex}.F1KBNa_discussionBody strong{font-weight:700}.F1KBNa_discussionNote{color:var(--dsw-alias-label-secondary);white-space:pre-wrap;overflow-wrap:anywhere;margin:0;padding:0;font-family:inherit;line-height:22px}.F1KBNa_discussionNote[data-diff-discussion-hidden]{color:var(--dsw-alias-label-tertiary)}.F1KBNa_discussionDots{margin-left:1px}.F1KBNa_discussionDots>span{animation:1.2s ease-in-out infinite F1KBNa_discussionDot}.F1KBNa_discussionDots>span:nth-child(2){animation-delay:.15s}.F1KBNa_discussionDots>span:nth-child(3){animation-delay:.3s}@keyframes F1KBNa_discussionDot{0%,60%,to{opacity:.25}30%{opacity:1}}.F1KBNa_quoteLines{table-layout:fixed;border-spacing:0;width:calc(100% + 27px);min-width:0;color:var(--dsw-alias-label-primary);font:var(--dsw-font-markdown-code-block);line-height:var(--dsh-diff-line-height,22px);background:color-mix(in srgb, var(--dsw-alias-interactive-bg-hover) 55%, transparent);margin:0 -12px 0 -15px;display:table}.F1KBNa_quoteAdd{background-color:color-mix(in srgb, var(--dsh-diff-add-color,var(--dsw-alias-state-success-primary)) 12%, transparent)}.F1KBNa_quoteDel{background-color:color-mix(in srgb, var(--dsh-diff-del-color,var(--dsw-alias-state-error-primary)) 13%, transparent)}.F1KBNa_quoteLine{font-size:calc(1em * var(--dsh-diff-font-scale,1));height:var(--dsh-diff-line-height,22px);display:table-row}.F1KBNa_quoteCode{display:table-cell}.F1KBNa_quoteText{white-space:pre-wrap;overflow-wrap:anywhere;cursor:text;display:block}.F1KBNa_quoteNoWrap .F1KBNa_quoteText{white-space:pre;overflow-wrap:normal;overflow:hidden}.F1KBNa_quoteNoWrap .F1KBNa_quoteText:after{content:\"\";width:calc(var(--dsh-diff-quote-width,0px) + 100%);display:inline-block}.F1KBNa_discussionHead{box-sizing:border-box;flex:none;align-items:center;gap:8px;height:22px;padding:0 12px;font-size:12px;line-height:16px;display:flex}.F1KBNa_discussionCompose{box-sizing:border-box;flex:none;align-items:flex-end;gap:8px;height:44px;margin:auto -6px 0;padding:0 0 6.6px;display:flex}.F1KBNa_discussionInput{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);min-width:0;height:26px;color:var(--dsw-alias-label-primary);cursor:text;border-radius:6px;flex:auto;padding:3px 8px;font-family:inherit;line-height:18px}.F1KBNa_discussionToggle{width:18px;height:18px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:4px;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}.F1KBNa_discussionToggle:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_discussionRangeWrap{font:var(--dsw-font-markdown-code-block);flex:none}.F1KBNa_discussionRange{color:var(--dsw-alias-label-tertiary);font-family:inherit}.F1KBNa_discussionInput:focus{border-color:var(--dsw-alias-state-business-primary);outline:none}.F1KBNa_discussionInput::placeholder{font-family:inherit;font-size:inherit;color:var(--dsw-alias-label-tertiary)}.F1KBNa_discussionSend{box-sizing:border-box;white-space:nowrap;flex:none;justify-content:center;align-items:center;gap:6px;height:26px;padding-left:9px;padding-right:9px;display:inline-flex}.F1KBNa_rowDiscussed{--diff-row-wash:color-mix(in srgb, var(--dsw-alias-label-secondary) 14%, transparent);background-image:linear-gradient(var(--diff-row-wash), var(--diff-row-wash))}@keyframes F1KBNa_diffFlashFade{0%{opacity:1}to{opacity:0}}@keyframes F1KBNa_diffFlashShake{0%{opacity:1;transform:translateY(0)}10%{transform:translateY(1px)}20%{transform:translateY(-1px)}30%{transform:translateY(1px)}40%{transform:translateY(-1px)}50%{transform:translateY(1px)}60%{transform:translateY(-1px)}70%{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(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%;font-size:calc(1em * var(--dsh-diff-font-scale,1));display:table}.F1KBNa_line{height:var(--dsh-diff-line-height,22px);line-height:var(--dsh-diff-line-height,22px);-webkit-user-select:none;user-select:none;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;-webkit-user-select:none;user-select:none;cursor:default;padding-right:10px;display:table-cell}.F1KBNa_line>.F1KBNa_gutter{z-index:1;background-color:var(--dsw-alias-markdown-code-block);background-image:linear-gradient(var(--diff-row-tint,transparent), var(--diff-row-tint,transparent)), linear-gradient(var(--diff-row-wash,transparent), var(--diff-row-wash,transparent));position:sticky;left:0}.F1KBNa_line>.F1KBNa_gutter+.F1KBNa_gutter{left:44px}.F1KBNa_code{white-space:pre;-webkit-user-select:text;user-select:text;display:table-cell}.F1KBNa_context{color:var(--dsw-alias-label-primary)}.F1KBNa_del{--diff-row-tint:color-mix(in srgb, var(--dsh-diff-del-color,var(--dsw-alias-state-error-primary)) 20%, transparent);background-color:var(--diff-row-tint)}.F1KBNa_add{--diff-row-tint:color-mix(in srgb, var(--dsh-diff-add-color,var(--dsw-alias-state-success-primary)) 18%, transparent);background-color:var(--diff-row-tint)}.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_presentationSelect{cursor:pointer;height:28px;color:var(--dsw-alias-label-tertiary);background:0 0;border:none;border-radius:28px;justify-content:center;align-items:center;gap:2px;padding:0 6px;display:inline-flex}.F1KBNa_presentationSelect:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_chip{justify-content:flex-end;align-items:center;gap:5px;min-width:0;padding-right:14px;display:inline-flex}.F1KBNa_chipLabel{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.F1KBNa_coverHost{align-items:center;display:inline-flex;position:relative}.F1KBNa_coverCard{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);box-shadow:var(--dsw-shadow-lv2);border-radius:12px;align-items:center;gap:4px;padding:6px;display:flex}.F1KBNa_coverPopover{z-index:50;position:absolute;top:calc(100% + 6px);right:0}.F1KBNa_coverNotice{z-index:80;pointer-events:none;animation:1.25s ease-out forwards F1KBNa_coverNoticeFade;position:fixed;top:50%;left:50%;transform:translate(-50%,-50%)}.F1KBNa_coverNoticeCard{gap:4px;padding:6px 8px}@keyframes F1KBNa_coverNoticeFade{0%,78%{opacity:1}to{opacity:0}}.F1KBNa_coverNoticeGlyph{width:44px;height:44px;color:var(--dsw-alias-label-tertiary);border-radius:10px;justify-content:center;align-items:center;display:inline-flex}.F1KBNa_coverNoticeGlyph[data-on]{color:var(--dsw-alias-label-primary)}.F1KBNa_coverNoticeGlyph[data-changed]{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_coverNoticeText{clip-path:inset(50%);white-space:nowrap;width:1px;height:1px;position:absolute;overflow:hidden}.F1KBNa_coverButton{width:32px;height:32px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:8px;justify-content:center;align-items:center;padding:0;display:inline-flex}.F1KBNa_coverButton:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_coverButton[data-on]{color:var(--dsw-alias-label-primary)}.F1KBNa_presentationHost{align-items:center;display:inline-flex}.F1KBNa_chipPresentation{min-width:36px;height:20px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:20px;flex:none;justify-content:center;align-items:center;gap:2px;padding:0 6px;display:inline-flex}.F1KBNa_chipPresentation:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_mirrored{transform:scaleX(-1)}.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:var(--dsh-diff-line-height,22px)}.F1KBNa_subline{height:var(--dsh-diff-line-height,22px);line-height:var(--dsh-diff-line-height,22px);white-space:pre;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{isolation:isolate;flex-direction:column;flex:1;min-height:0;display:flex;position:relative;overflow:hidden}.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{overscroll-behavior-x:none;min-width:0;height:var(--dsh-scrollbar-width,8px);flex:1 1 0;overflow:auto hidden}.F1KBNa_splitHScroll::-webkit-scrollbar{height:var(--dsh-scrollbar-width,8px)}.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(--dsh-diff-del-color,var(--dsw-alias-state-error-primary)) 20%, transparent)}.F1KBNa_splitLadd{background-color:color-mix(in srgb, var(--dsh-diff-add-color,var(--dsw-alias-state-success-primary)) 18%, transparent)}.F1KBNa_splitRdel{background-color:color-mix(in srgb, var(--dsh-diff-del-color,var(--dsw-alias-state-error-primary)) 20%, transparent)}.F1KBNa_splitRadd{background-color:color-mix(in srgb, var(--dsh-diff-add-color,var(--dsw-alias-state-success-primary)) 18%, transparent)}.F1KBNa_intraDel{background-color:color-mix(in srgb, var(--dsh-diff-del-color,var(--dsw-alias-state-error-primary)) 34%, transparent);text-decoration:line-through}.F1KBNa_intraAdd{background-color:color-mix(in srgb, var(--dsh-diff-add-color,var(--dsw-alias-state-success-primary)) 32%, transparent)}";
|
|
24
|
+
const css = ".F1KBNa_panelFailure{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);color:var(--dsw-alias-label-primary);border-radius:8px;align-items:center;gap:8px;padding:8px 10px;font-size:12px;line-height:16px;display:flex}.F1KBNa_panelFailureText{min-width:0}.F1KBNa_panelFailureRetry{border:1px solid var(--dsw-alias-border-l2);color:inherit;font:inherit;cursor:pointer;background:0 0;border-radius:6px;flex:none;margin-left:auto;padding:2px 8px}.F1KBNa_panelFailureRetry:hover{background:var(--dsw-alias-interactive-bg-hover)}.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_headerEntry{box-sizing:border-box;width:28px;height:28px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:28px;flex:none;justify-content:center;align-items:center;padding:6px;display:inline-flex;position:relative}.F1KBNa_headerEntry:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_headerEntry[data-active]{background:var(--dsw-alias-interactive-bg-hover-solid);color:var(--dsw-alias-label-primary)}.F1KBNa_headerEntry:disabled{color:var(--dsw-alias-label-tertiary);cursor:default;background:0 0}.F1KBNa_headerEntryCount{box-sizing:border-box;background:var(--dsw-alias-button-primary-fill);min-width:14px;height:14px;color:var(--dsw-alias-label-primary-foreground);text-align:center;font-variant-numeric:tabular-nums;pointer-events:none;border-radius:7px;padding:0 3px;font-size:10px;line-height:14px;position:absolute;top:-1px;right:-1px}.F1KBNa_headerEntry svg{display:block}.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_coverBackdrop{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);-webkit-user-select:none;user-select:none;border-radius:12px;flex-direction:column;display:flex;position:fixed;inset:8px 8px 128px;overflow:hidden}.F1KBNa_panel .F1KBNa_code,.F1KBNa_panel .F1KBNa_mdPreviewBody,.F1KBNa_panel .F1KBNa_discussionUser,.F1KBNa_panel .F1KBNa_discussionAnswer,.F1KBNa_panel .F1KBNa_quoteText,.F1KBNa_panel .F1KBNa_diffPath,.F1KBNa_panel .F1KBNa_rowPath,.F1KBNa_panel input,.F1KBNa_panel textarea,.F1KBNa_panel [contenteditable]{-webkit-user-select:text;user-select:text}.F1KBNa_panelDocked{width:100%;max-width:none;height:100%;box-shadow:none;border:none;border-radius:0;position:static;inset:auto}.F1KBNa_dockHost{flex-direction:column;min-height:0;display:flex;position:absolute;inset:0}.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_settingsGroup{border-bottom:1px solid var(--dsw-alias-border-l2)}.F1KBNa_settingsGroupHeader{width:100%;color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;text-align:left;background:0 0;border:none;align-items:center;gap:8px;padding:16px 0;display:flex}.F1KBNa_settingsGroupText{text-align:left;flex-direction:column;flex:1;gap:2px;min-width:0;display:flex}.F1KBNa_settingsGroupTitle{font-size:14px;font-weight:400;line-height:22px}.F1KBNa_settingsGroupDesc{color:var(--dsw-alias-label-tertiary);font-size:12px;font-weight:400;line-height:18px}.F1KBNa_settingsGroupChevron{margin-left:auto;transition:transform .15s}.F1KBNa_settingsGroup[data-open] .F1KBNa_settingsGroupChevron{transform:rotate(180deg)}.F1KBNa_settingsGroup[data-open] .F1KBNa_settingsGroupHeader{border-bottom:1px solid var(--dsw-alias-border-l2)}.F1KBNa_settingsGroupBody{flex-direction:column;display:flex}.F1KBNa_settingsGroupBody .F1KBNa_settingsRow{padding-left:16px}.F1KBNa_settingsGroupBody .F1KBNa_settingsRow:last-child,.F1KBNa_settingsPage>.F1KBNa_settingsRow:last-child{border-bottom:none}.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);min-width:72px;height:36px;font:inherit;color:var(--dsw-alias-label-primary);cursor:pointer;border:none;border-radius:18px;justify-content:center;align-items:center;padding:0 14px;font-size:14px;line-height:22px;display:inline-flex}.F1KBNa_settingsSelector:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_settingsSelector[data-recording]{box-shadow:inset 0 0 0 1px var(--dsw-alias-state-business-primary);color:var(--dsw-alias-label-secondary)}.F1KBNa_settingsReset{width:28px;height:28px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:28px;justify-content:center;align-items:center;margin-left:6px;padding:0;display:inline-flex}.F1KBNa_settingsReset:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_settingsReset:disabled{opacity:.4;cursor:default}.F1KBNa_colorPicker{position:relative}.F1KBNa_colorPickerTrigger{background:var(--dsw-alias-bg-module-platform);width:120px;height:36px;font:inherit;color:var(--dsw-alias-label-primary);cursor:pointer;border:none;border-radius:18px;align-items:center;gap:8px;padding:0 8px;font-size:12px;line-height:18px;display:inline-flex}.F1KBNa_colorPickerTrigger:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_colorSwatch{border:1px solid var(--dsw-alias-border-l2);border-radius:50%;flex:none;width:24px;height:24px}.F1KBNa_colorValue{text-overflow:ellipsis;white-space:nowrap;font-variant-numeric:tabular-nums;flex:1;min-width:0;overflow:hidden}.F1KBNa_colorPickerChevron{flex:none}.F1KBNa_colorBackdrop{z-index:40;position:fixed;inset:0}.F1KBNa_colorPickerPopover{z-index:41;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);box-shadow:var(--dsw-shadow-lv2);border-radius:10px;padding:10px;position:absolute;top:calc(100% + 6px);right:0}.F1KBNa_colorPickerPanel{flex-direction:column;gap:8px;display:flex}.F1KBNa_colorPickerInputRow{align-items:center;gap:8px;display:flex}.F1KBNa_colorPickerPreview{border:1px solid var(--dsw-alias-border-l2);border-radius:6px;flex:none;width:22px;height:22px}.F1KBNa_colorPickerInput{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-module-platform);min-width:0;height:30px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;flex:1;padding:0 8px;font-size:12px;line-height:28px}.F1KBNa_colorPickerInput:focus{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:-1px}.F1KBNa_colorSv{border:1px solid var(--dsw-alias-border-l1);cursor:crosshair;touch-action:none;border-radius:8px;height:140px;position:relative}.F1KBNa_colorSvCursor{pointer-events:none;border:2px solid #fff;border-radius:50%;width:14px;height:14px;position:absolute;transform:translate(-50%,-50%);box-shadow:0 0 0 1px #00000080}.F1KBNa_colorHue{border:1px solid var(--dsw-alias-border-l1);cursor:pointer;touch-action:none;border-radius:7px;height:14px;position:relative}.F1KBNa_colorHueCursor{pointer-events:none;border:2px solid #fff;border-radius:50%;width:16px;height:16px;position:absolute;top:50%;transform:translate(-50%,-50%);box-shadow:0 0 0 1px #00000080}.F1KBNa_diffPreview{z-index:2;border:1px solid var(--dsw-alias-border-l1);font:var(--dsw-font-markdown-code-block);background:var(--dsw-alias-markdown-code-block);border-radius:8px;margin:16px 0 8px;padding:8px;position:sticky;top:0;overflow:hidden}.F1KBNa_diffPreviewTitle{color:var(--dsw-alias-label-tertiary);margin-bottom:6px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_diffPreviewScroll{height:132px;overflow-y:auto}.F1KBNa_mdPreviewWrap{isolation:isolate;flex:1;min-width:0;min-height:0;display:flex;position:relative;overflow:hidden}.F1KBNa_mdPreviewBody{overscroll-behavior:none;min-width:0;min-height:0;color:var(--dsw-alias-label-primary);flex:1;padding:12px 16px;position:relative;overflow:auto}.F1KBNa_mdPreviewContent{width:100%;min-width:0;margin:0 auto}.F1KBNa_mdPreviewSingle{display:block}.F1KBNa_mdPreviewDouble{display:flex}.F1KBNa_mdPreviewBody .mdBlock{border-radius:4px;margin-bottom:12px;padding:2px 6px}.F1KBNa_mdPreviewBody .mdAdd{background-color:color-mix(in srgb, var(--dsh-diff-add-color,var(--dsw-alias-state-success-primary)) 10%, transparent)}.F1KBNa_mdPreviewBody .mdDel{background-color:color-mix(in srgb, var(--dsh-diff-del-color,var(--dsw-alias-state-error-primary)) 12%, transparent)}.F1KBNa_mdPreviewBody .mdWordDel{background-color:color-mix(in srgb, var(--dsh-diff-del-color,var(--dsw-alias-state-error-primary)) 34%, transparent);border-radius:2px;padding:0 1px}.F1KBNa_mdPreviewBody .mdWordAdd{background-color:color-mix(in srgb, var(--dsh-diff-add-color,var(--dsw-alias-state-success-primary)) 34%, transparent);border-radius:2px;padding:0 1px}.F1KBNa_mdPreviewBody .mdDouble{flex-direction:column;width:100%;min-width:0;display:flex}.F1KBNa_mdPreviewBody .mdDoubleRow{align-items:flex-start;width:100%;min-width:0;display:flex}.F1KBNa_mdPreviewBody .mdDoubleCol{flex:1;min-width:0}.F1KBNa_mdPreviewBody .mdDoubleRule{background:var(--dsw-alias-border-l2);flex:none;align-self:stretch;width:1px;margin:0 12px}.F1KBNa_mdPreviewFallback{font-family:var(--dsw-font-markdown-code-block);color:var(--dsw-alias-label-tertiary);padding:12px 16px;font-size:12px;line-height:18px}.F1KBNa_mdPreviewBody{word-break:break-word;font-size:13px;line-height:20px}.F1KBNa_mdPreviewBody>:first-child{margin-top:0}.F1KBNa_mdPreviewBody>:last-child{margin-bottom:0}.F1KBNa_mdPreviewBody h1,.F1KBNa_mdPreviewBody h2,.F1KBNa_mdPreviewBody h3,.F1KBNa_mdPreviewBody h4,.F1KBNa_mdPreviewBody h5,.F1KBNa_mdPreviewBody h6{margin:16px 0 8px;font-weight:600;line-height:1.3}.F1KBNa_mdPreviewBody h1{font-size:22px}.F1KBNa_mdPreviewBody h2{font-size:19px}.F1KBNa_mdPreviewBody h3{font-size:16px}.F1KBNa_mdPreviewBody h4{font-size:15px}.F1KBNa_mdPreviewBody h5{font-size:14px}.F1KBNa_mdPreviewBody h6{font-size:13px}.F1KBNa_mdPreviewBody p{margin:8px 0}.F1KBNa_mdPreviewBody ul,.F1KBNa_mdPreviewBody ol{margin:8px 0;padding-left:22px}.F1KBNa_mdPreviewBody li{margin:2px 0}.F1KBNa_mdPreviewBody a{color:var(--dsw-alias-state-business-primary);text-decoration:none}.F1KBNa_mdPreviewBody a:hover{text-decoration:underline}.F1KBNa_mdPreviewBody code{font-family:var(--dsw-font-markdown-code-block);background:#9e9e9e40;border-radius:4px;padding:1px 5px;font-size:12.5px}.F1KBNa_mdPreviewBody pre{overscroll-behavior-x:none;border:1px solid var(--dsw-alias-border-l1);font-family:var(--dsw-font-markdown-code-block);background:#9e9e9e40;border-radius:8px;margin:8px 0;padding:10px 12px;font-size:12.5px;line-height:18px;overflow:auto}.F1KBNa_mdPreviewBody pre code{background:0 0;padding:0}.F1KBNa_mdPreviewBody blockquote{border-left:3px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);margin:8px 0;padding:0 12px}.F1KBNa_mdPreviewBody hr{background:var(--dsw-alias-border-l1);border:none;height:1px;margin:16px 0}.F1KBNa_mdPreviewBody table{border-collapse:collapse;margin:8px 0}.F1KBNa_mdPreviewBody th,.F1KBNa_mdPreviewBody td{border:1px solid var(--dsw-alias-border-l1);padding:4px 10px}.F1KBNa_mdPreviewBody img{max-width:100%}.F1KBNa_mdPreviewBody .mdImageFallback{border:1px dashed var(--dsw-alias-border-l2);background:color-mix(in srgb, var(--dsw-alias-markdown-code-block) 45%, transparent);width:100%;min-height:120px;color:var(--dsw-alias-label-secondary);font-family:var(--dsw-font-markdown-code-block);text-align:center;white-space:pre-wrap;word-break:break-all;border-radius:4px;justify-content:center;align-items:center;margin:0 auto;padding:8px 12px;font-size:12px;line-height:16px;display:flex}.F1KBNa_toggle{border:1px solid var(--dsw-alias-border-l2);cursor:pointer;background:0 0;border-radius:18px;flex:none;width:60px;height:36px;padding:0;position:relative}.F1KBNa_toggle:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_toggle:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px}.F1KBNa_toggleOn{border-color:var(--dsw-alias-state-business-primary);background:var(--dsw-alias-state-business-primary)}.F1KBNa_toggleOn:hover{background:var(--dsw-alias-state-business-primary)}.F1KBNa_toggleThumb{background:var(--dsw-alias-label-primary);border-radius:50%;width:28px;height:28px;transition:left .12s;position:absolute;top:3px;left:3px}.F1KBNa_toggleOn .F1KBNa_toggleThumb{background:#fff;left:27px}.F1KBNa_stepper{align-items:center;gap:6px;display:inline-flex}.F1KBNa_stepperButton{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-module-platform);width:32px;height:32px;color:var(--dsw-alias-label-primary);cursor:pointer;border-radius:8px;padding:0;position:relative}.F1KBNa_stepperButton:before,.F1KBNa_stepperButton:after{content:\"\";background:currentColor;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)}.F1KBNa_stepperButton:before{width:10px;height:1px}.F1KBNa_stepperButton:after{width:1px;height:10px;display:none}.F1KBNa_stepperButtonUp:after{display:block}.F1KBNa_stepperButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_stepperButton:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.F1KBNa_stepperValue{text-align:center;min-width:2ch;color:var(--dsw-alias-label-primary);font-variant-numeric:tabular-nums;font-size:14px;line-height:22px}.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_fileListKnob{z-index:39;box-sizing:border-box;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);width:28px;height:28px;color:var(--dsw-alias-label-primary);cursor:pointer;box-shadow:var(--dsw-elevation-prominent);border-radius:8px;justify-content:center;align-items:center;padding:0;display:inline-flex;position:absolute}.F1KBNa_fileListKnob[data-open]{box-shadow:none;opacity:0}.F1KBNa_fileListKnob:not([data-open]){animation:.32s ease-in-out .5s both F1KBNa_fileListKnobIn}@keyframes F1KBNa_fileListKnobIn{0%{opacity:0}to{opacity:1}}.F1KBNa_fileListKnob:hover,.F1KBNa_fileListKnob:focus-visible{background-color:var(--dsw-alias-bg-base);background-image:linear-gradient(var(--dsw-alias-interactive-bg-hover), var(--dsw-alias-interactive-bg-hover))}.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:none;transform-origin:0 0;border-radius:12px;flex-direction:column;padding:6px 0 10px 8px;display:flex;position:absolute;overflow:hidden}.F1KBNa_fileListFloatClosing{pointer-events:none;animation:.14s ease-in forwards F1KBNa_fileListShrink}@keyframes F1KBNa_fileListShrink{0%{opacity:1;transform:scale(1)}to{opacity:0;transform:scale(.96)}}.F1KBNa_fileList{box-sizing:border-box;border-right:1px solid var(--dsw-alias-border-l2);flex-direction:column;flex:none;width:260px;min-height:0;padding:4px 8px 12px;display:flex}.F1KBNa_listScroll{flex:1;min-height:0;overflow-y:scroll}.F1KBNa_bulkActions{flex:none;gap:6px;padding:8px 8px 0 0;display:flex}.F1KBNa_bulkActions .F1KBNa_action{text-align:center;flex:auto}.F1KBNa_addPath{justify-content:center;align-items:center;gap:4px;display:inline-flex}.F1KBNa_resizeHandle{cursor:col-resize;touch-action:none;background:0 0;flex:none;width:5px;margin:0 -2px}.F1KBNa_resizeHandle:hover{background:var(--dsw-alias-border-l2)}.F1KBNa_floatResizeHandle{z-index:41;cursor:col-resize;-webkit-user-select:none;user-select:none;touch-action:none;background:0 0;border-radius:4px;position:absolute}.F1KBNa_floatResizeHandle:hover{background-color:var(--dsw-alias-bg-base);background-image:linear-gradient(var(--dsw-alias-border-l2), 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:55;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{flex:none;justify-content:flex-end;align-items:center;gap:8px;display:flex}.F1KBNa_pickerCard{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);width:420px;max-width:100%;height:70%;max-height:100%;box-shadow:var(--dsw-shadow-lv3);border-radius:12px;flex-direction:column;gap:8px;padding:14px 16px 16px;display:flex;position:relative;overflow:hidden}.F1KBNa_pickerTitle{color:var(--dsw-alias-label-primary);flex:none;font-size:13px;font-weight:500;line-height:20px}.F1KBNa_pickerClose{width:22px;height:22px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;border-radius:6px;justify-content:center;align-items:center;padding:0;display:inline-flex;position:absolute;top:10px;right:10px}.F1KBNa_pickerClose:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_pickerForm{flex:none;gap:8px;display:flex}.F1KBNa_pickerInput{border:1px solid var(--dsw-alias-border-l1);min-width:0;color:var(--dsw-alias-label-primary);background:0 0;border-radius:8px;flex:auto;padding:3px 8px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_pickerInput:focus{border-color:var(--dsw-alias-state-business-primary);outline:none}.F1KBNa_tree{border:1px solid var(--dsw-alias-border-l1);border-radius:8px;flex:auto;min-height:0;padding:4px 2px 4px 4px;overflow:auto scroll}.F1KBNa_treeRow{border-radius:6px;align-items:center;gap:2px;padding-right:4px;display:flex}.F1KBNa_treeRow:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_treeRow[data-selected]{background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 18%, transparent)}.F1KBNa_treeCaret{width:16px;height:16px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;border-radius:4px;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}.F1KBNa_treeCaret:hover{color:var(--dsw-alias-label-primary)}.F1KBNa_treeName{min-width:0;color:var(--dsw-alias-label-primary);text-align:left;cursor:pointer;background:0 0;border:0;border-radius:6px;flex:auto;align-items:center;gap:6px;padding:2px 4px;font-family:inherit;font-size:12px;line-height:18px;display:flex}.F1KBNa_treeName:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.F1KBNa_treeNote{color:var(--dsw-alias-label-tertiary);margin:2px 0;font-size:12px;line-height:18px}.F1KBNa_pickerIcon{width:16px;height:16px;color:var(--dsw-alias-label-tertiary);flex:none;justify-content:center;align-items:center;display:inline-flex}.F1KBNa_pickerName{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.F1KBNa_pickerNote{color:var(--dsw-alias-label-tertiary);flex:none;margin:0;font-size:12px;line-height:18px}.F1KBNa_pickerCheck{color:var(--dsw-alias-label-secondary);cursor:pointer;align-items:center;gap:6px;margin-right:auto;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_groupHead{align-items:center;gap:4px;margin:8px 0 4px;padding-right:8px;display:flex}.F1KBNa_action.F1KBNa_addButton{box-sizing:border-box;border-radius:6px;flex:none;justify-content:center;align-items:center;width:20px;height:20px;min-height:0;padding:0;display:inline-flex}.F1KBNa_groupHead>.F1KBNa_group{margin:0}.F1KBNa_listHead{flex:none;align-items:center;gap:4px;margin:8px 1px 2px;padding-right:8px;display:flex}.F1KBNa_action.F1KBNa_addButton.F1KBNa_listFold{width:26px;height:26px}.F1KBNa_listTitle{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;font-weight:500;line-height:16px}.F1KBNa_listTabs{background:var(--dsw-alias-interactive-bg-hover);border-radius:8px;flex:auto;gap:2px;min-width:0;padding:2px;display:flex}.F1KBNa_listTab{color:var(--dsw-alias-label-secondary);font:inherit;cursor:pointer;background:0 0;border:none;border-radius:6px;flex:1;justify-content:center;align-items:center;gap:6px;padding:3px 8px;font-size:12px;line-height:16px;display:inline-flex}.F1KBNa_tabCount{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums}.F1KBNa_listTab[aria-selected=true]{background:var(--dsw-alias-bg-base);color:var(--dsw-alias-label-primary)}.F1KBNa_commentGroup{margin:0 0 6px}.F1KBNa_commentGroup:last-child{margin-bottom:0}.F1KBNa_commentGroupName{color:var(--dsw-alias-label-tertiary);margin:0;padding:4px 8px 2px;font-size:11px;font-weight:500;line-height:16px}.F1KBNa_commentRow{box-sizing:border-box;width:100%;color:inherit;text-align:left;cursor:pointer;background:0 0;border:none;border-radius:10px;padding:6px 8px;display:block}.F1KBNa_commentRow:hover{background:var(--dsw-alias-interactive-bg-hover-solid)}.F1KBNa_commentHead{align-items:baseline;gap:6px;min-width:0;display:flex}.F1KBNa_commentLabel{white-space:nowrap;text-align:right;color:var(--dsw-alias-label-secondary);font:var(--dsw-font-markdown-code-block);font-variant-numeric:tabular-nums;flex:none;font-size:11px;font-weight:700;line-height:16px}.F1KBNa_commentLost{color:var(--dsw-alias-label-tertiary);flex:none;font-size:11px;line-height:16px}.F1KBNa_commentTitle{text-overflow:ellipsis;white-space:nowrap;text-align:left;min-width:0;color:var(--dsw-alias-label-primary);flex:1;font-size:12px;line-height:18px;overflow:hidden}.F1KBNa_commentTitleEmpty{color:var(--dsw-alias-label-tertiary)}.F1KBNa_listEmpty{color:var(--dsw-alias-label-tertiary);margin:8px 12px;font-size:12px;line-height:18px}.F1KBNa_emptyActions{flex-wrap:wrap;justify-content:center;gap:8px;display:flex}.F1KBNa_rows{margin:0;padding:0;list-style:none}.F1KBNa_row{border:1px solid #0000;border-radius:10px;margin:2px 0}.F1KBNa_rowMenuAnchor{display:none}.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:center;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;margin-left:4px;font-size:12px;line-height:18px;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(--dsh-diff-add-color,var(--dsw-alias-state-success-primary)) 60%, var(--dsw-alias-label-primary))}.F1KBNa_delCount{color:color-mix(in srgb, var(--dsh-diff-del-color,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_panelDocked .F1KBNa_diffHeader{background:var(--dsw-alias-bg-base)}.F1KBNa_diffPath{appearance:none;min-width:0;font:inherit;text-overflow:ellipsis;color:var(--dsw-alias-label-primary);background:0 0;border:0;flex:1;margin-left:4px;padding:0;font-size:12px;line-height:18px;position:relative;top:1px}.F1KBNa_diffPath:focus{outline:none}.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_gotoHost{display:inline-flex}.F1KBNa_gotoLayer{z-index:30;place-items:center;display:grid;position:absolute;inset:0}.F1KBNa_gotoLayerRight{left:50%;right:var(--dsh-scrollbar-width,8px);bottom:calc(var(--dsh-scrollbar-width,8px) + 1px)}.F1KBNa_gotoBackdrop{z-index:29;position:fixed;inset:0}.F1KBNa_gotoBox{z-index:1;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:relative}.F1KBNa_gotoInput{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);width:9em;color:var(--dsw-alias-label-primary);border-radius:6px;outline:none;flex:none;padding:3px 8px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_gotoInput:focus{border-color:var(--dsw-alias-state-business-primary)}.F1KBNa_gotoAction{white-space:nowrap;flex:none}.F1KBNa_divider{background:var(--dsw-alias-border-l1);align-self:stretch;width:1px;margin:2px 0}.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_actionChord{color:var(--dsw-alias-label-tertiary);margin-left:6px;font-size:11px}.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{isolation:isolate;flex:1;min-height:0;display:flex;position:relative;overflow:hidden}.F1KBNa_diffBody{overscroll-behavior:none;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_blockActionsDivider{background:var(--dsw-alias-border-l2);flex:none;align-self:stretch;width:1px;margin:2px 0}.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_searchToggle{border:1px solid var(--dsw-alias-border-l1);min-height:25px;color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border-radius:8px;justify-content:center;align-items:center;padding:4px 6px;display:inline-flex}.F1KBNa_searchToggle:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_searchToggleOn{border-color:var(--dsw-alias-state-business-primary);background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-state-business-primary)}.F1KBNa_searchMatch{color:inherit;background-color:#facc1542;border-radius:2px}.F1KBNa_searchMatchCurrent{color:inherit;background-color:#facc1599;border-radius:2px}.F1KBNa_blockFlash{z-index:3;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_diffFlashFade;position:absolute;left:0;right:0}.F1KBNa_blockFlashShake{animation:.7s ease-out forwards F1KBNa_diffFlashShake}.F1KBNa_discussionRow{background:var(--dsw-alias-bg-base);display:table-row}.F1KBNa_discussionCell{display:table-cell}.F1KBNa_discussionPin{z-index:2;width:0;height:0;position:sticky;left:0}.F1KBNa_discussion{z-index:2;box-sizing:border-box;border-left:3px solid var(--dsw-alias-state-business-primary);box-shadow:inset 0 1px 0 0 color-mix(in srgb, var(--dsw-alias-label-secondary) 55%, transparent), inset 0 -1px 0 0 color-mix(in srgb, var(--dsw-alias-label-secondary) 55%, transparent), inset -1px 0 0 0 color-mix(in srgb, var(--dsw-alias-label-secondary) 55%, transparent);cursor:default;background:0 0;flex-direction:column;display:flex;position:absolute;top:0;left:0;overflow:hidden}.F1KBNa_discussionHead{font:var(--dsw-font-markdown-code-block)}.F1KBNa_discussionBody,.F1KBNa_threadFontProbe{font:var(--dsw-font-markdown-base);font-size:calc(var(--dsh-content-font-size,14px) - 2px)}.F1KBNa_threadFontProbe{visibility:hidden;pointer-events:none;width:0;height:0;position:absolute;overflow:hidden}.F1KBNa_discussionBody{flex-direction:column;flex:auto;min-height:0;padding:0 12px;display:flex;overflow:hidden}.F1KBNa_discussion[data-lost]{border-left-color:var(--dsw-alias-label-secondary);background:repeating-linear-gradient(135deg, var(--dsw-alias-interactive-bg-hover) 0 4px, transparent 4px 8px);background-origin:border-box}.F1KBNa_discussion[data-lost] .F1KBNa_discussionSend,.F1KBNa_discussion[data-lost] .F1KBNa_discussionSend:hover:not(:disabled),.F1KBNa_discussion[data-lost] .F1KBNa_discussionSend:disabled{background:var(--dsw-alias-label-secondary);border-color:var(--dsw-alias-label-secondary);color:var(--dsw-alias-label-primary-foreground)}.F1KBNa_discussion[data-lost] .F1KBNa_discussionUser{background:color-mix(in srgb, var(--dsw-alias-label-secondary) 30%, transparent)}.F1KBNa_discussionAnswer{color:var(--dsw-alias-label-primary);white-space:pre-wrap;overflow-wrap:anywhere;cursor:text;margin:0;padding:0;font-family:inherit;line-height:22px}.F1KBNa_discussionUser{box-sizing:border-box;background:var(--dsw-specific-bubble,var(--dsw-alias-bg-layer-2,var(--dsw-alias-interactive-bg-hover)));width:fit-content;max-width:82%;color:var(--dsw-alias-label-primary);white-space:pre-wrap;overflow-wrap:anywhere;cursor:text;border-radius:8px 0 8px 8px;margin:6.6px 0 6.6px auto;padding:4.4px 11px;font-family:inherit;line-height:22px}.F1KBNa_discussionCode{box-sizing:border-box;font:var(--dsw-font-markdown-code);font-family:var(--ds-font-family-code);background:color-mix(in srgb, var(--dsw-alias-markdown-inline-code,var(--dsw-alias-interactive-bg-hover-solid)) 90%, var(--dsw-alias-label-secondary));border:.5px solid var(--dsw-alias-border-l1);border-radius:6px;align-items:center;padding:0 5px;font-size:.875em;line-height:16px;display:inline-flex}.F1KBNa_discussionBody strong{font-weight:700}.F1KBNa_discussionNote{color:var(--dsw-alias-label-secondary);white-space:pre-wrap;overflow-wrap:anywhere;margin:0;padding:0;font-family:inherit;line-height:22px}.F1KBNa_discussionNote[data-diff-discussion-hidden]{color:var(--dsw-alias-label-tertiary)}.F1KBNa_discussionDots{margin-left:1px}.F1KBNa_discussionDots>span{animation:1.2s ease-in-out infinite F1KBNa_discussionDot}.F1KBNa_discussionDots>span:nth-child(2){animation-delay:.15s}.F1KBNa_discussionDots>span:nth-child(3){animation-delay:.3s}@keyframes F1KBNa_discussionDot{0%,60%,to{opacity:.25}30%{opacity:1}}.F1KBNa_quoteLines{table-layout:fixed;border-spacing:0;width:calc(100% + 27px);min-width:0;color:var(--dsw-alias-label-primary);font:var(--dsw-font-markdown-code-block);line-height:var(--dsh-diff-line-height,22px);background:color-mix(in srgb, var(--dsw-alias-interactive-bg-hover) 55%, transparent);margin:0 -12px 0 -15px;display:table}.F1KBNa_quoteAdd{background-color:color-mix(in srgb, var(--dsh-diff-add-color,var(--dsw-alias-state-success-primary)) 12%, transparent)}.F1KBNa_quoteDel{background-color:color-mix(in srgb, var(--dsh-diff-del-color,var(--dsw-alias-state-error-primary)) 13%, transparent)}.F1KBNa_quoteLine{font-size:calc(1em * var(--dsh-diff-font-scale,1));height:var(--dsh-diff-line-height,22px);display:table-row}.F1KBNa_quoteCode{display:table-cell}.F1KBNa_quoteText{white-space:pre-wrap;overflow-wrap:anywhere;cursor:text;display:block}.F1KBNa_quoteNoWrap .F1KBNa_quoteText{white-space:pre;overflow-wrap:normal;overflow:hidden}.F1KBNa_quoteNoWrap .F1KBNa_quoteText:after{content:\"\";width:calc(var(--dsh-diff-quote-width,0px) + 100%);display:inline-block}.F1KBNa_quoteSplit{align-self:stretch;align-items:flex-start;margin:0 -12px;display:flex}.F1KBNa_quoteSplitSide{flex:1 1 0;min-width:0}.F1KBNa_quoteSplitSide+.F1KBNa_quoteSplitSide{border-left:1px solid var(--dsw-alias-border-l2)}.F1KBNa_quoteSplitTable{table-layout:fixed;border-spacing:0;width:100%;display:table}.F1KBNa_quoteNoWrap .F1KBNa_quoteSplit [data-diff-quote-side=left] .F1KBNa_quoteText:after{content:\"\";width:calc(var(--dsh-quote-width-left,0px) + 100%);display:inline-block}.F1KBNa_quoteNoWrap .F1KBNa_quoteSplit [data-diff-quote-side=right] .F1KBNa_quoteText:after{content:\"\";width:calc(var(--dsh-quote-width-right,0px) + 100%);display:inline-block}.F1KBNa_discussionHead{box-sizing:border-box;flex:none;align-items:center;gap:8px;height:22px;padding:0 12px;font-size:12px;line-height:16px;display:flex}.F1KBNa_discussionCompose{box-sizing:border-box;flex:none;align-items:flex-end;gap:8px;height:44px;margin:0 -6px;padding:0 0 6.6px;display:flex}.F1KBNa_discussionSlack{flex:1 1 0;min-height:0;max-height:22px}.F1KBNa_discussionInput{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);min-width:0;height:26px;color:var(--dsw-alias-label-primary);cursor:text;border-radius:6px;flex:auto;padding:3px 8px;font-family:inherit;line-height:18px}.F1KBNa_discussionToggle{width:18px;height:18px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:4px;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}.F1KBNa_discussionToggle:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_discussionRangeWrap{font:var(--dsw-font-markdown-code-block);flex:none}.F1KBNa_discussionRange{color:var(--dsw-alias-label-tertiary);font-family:inherit}.F1KBNa_discussionInput:focus{border-color:var(--dsw-alias-state-business-primary);outline:none}.F1KBNa_discussionInput::placeholder{font-family:inherit;font-size:inherit;color:var(--dsw-alias-label-tertiary)}.F1KBNa_discussionSend{box-sizing:border-box;white-space:nowrap;flex:none;justify-content:center;align-items:center;gap:6px;height:26px;padding-left:9px;padding-right:9px;display:inline-flex}.F1KBNa_rowDiscussed{--diff-row-wash:color-mix(in srgb, var(--dsw-alias-label-secondary) 14%, transparent);background-image:linear-gradient(var(--diff-row-wash), var(--diff-row-wash))}@keyframes F1KBNa_diffFlashFade{0%{opacity:1}to{opacity:0}}@keyframes F1KBNa_diffFlashShake{0%{opacity:1;transform:translateY(0)}10%{transform:translateY(1px)}20%{transform:translateY(-1px)}30%{transform:translateY(1px)}40%{transform:translateY(-1px)}50%{transform:translateY(1px)}60%{transform:translateY(-1px)}70%{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(0)}}.F1KBNa_overviewRuler{pointer-events:none;opacity:.5;width:4px;position:absolute;top:0;bottom:0;right:0}.F1KBNa_overviewRulerSplit{width:var(--dsh-scrollbar-width,8px);bottom:calc(var(--dsh-scrollbar-width,8px) + 1px)}.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_markerSplitDel{width:50%;left:0;right:auto}.F1KBNa_markerSplitAdd{width:50%;left:auto;right:0}.F1KBNa_lines{border-spacing:0;width:max-content;min-width:100%;font-size:calc(1em * var(--dsh-diff-font-scale,1));display:table}.F1KBNa_line{height:var(--dsh-diff-line-height,22px);line-height:var(--dsh-diff-line-height,22px);-webkit-user-select:none;user-select:none;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;-webkit-user-select:none;user-select:none;cursor:default;padding-right:10px;display:table-cell}.F1KBNa_line>.F1KBNa_gutter{z-index:1;background-color:var(--dsw-alias-markdown-code-block);background-image:linear-gradient(var(--diff-row-tint,transparent), var(--diff-row-tint,transparent)), linear-gradient(var(--diff-row-wash,transparent), var(--diff-row-wash,transparent));position:sticky;left:0}.F1KBNa_line>.F1KBNa_gutter+.F1KBNa_gutter{left:44px}.F1KBNa_code{white-space:pre;-webkit-user-select:text;user-select:text;display:table-cell}.F1KBNa_context{color:var(--dsw-alias-label-primary)}.F1KBNa_del{--diff-row-tint:color-mix(in srgb, var(--dsh-diff-del-color,var(--dsw-alias-state-error-primary)) 20%, transparent);background-color:var(--diff-row-tint)}.F1KBNa_add{--diff-row-tint:color-mix(in srgb, var(--dsh-diff-add-color,var(--dsw-alias-state-success-primary)) 18%, transparent);background-color:var(--diff-row-tint)}.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_presentationSelect{cursor:pointer;height:28px;color:var(--dsw-alias-label-tertiary);background:0 0;border:none;border-radius:28px;justify-content:center;align-items:center;gap:2px;padding:0 6px;display:inline-flex}.F1KBNa_presentationSelect:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_chip{justify-content:flex-end;align-items:center;gap:5px;min-width:0;padding-right:14px;display:inline-flex}.F1KBNa_chipLabel{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.F1KBNa_coverHost{align-items:center;display:inline-flex;position:relative}.F1KBNa_coverCard{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);box-shadow:var(--dsw-shadow-lv2);border-radius:12px;align-items:center;gap:4px;padding:6px;display:flex}.F1KBNa_coverPopover{z-index:50;position:absolute;top:calc(100% + 6px);right:0}.F1KBNa_coverNotice{z-index:80;pointer-events:none;animation:1.25s ease-out forwards F1KBNa_coverNoticeFade;position:fixed;top:50%;left:50%;transform:translate(-50%,-50%)}.F1KBNa_coverNoticeCard{gap:4px;padding:6px 8px}@keyframes F1KBNa_coverNoticeFade{0%,78%{opacity:1}to{opacity:0}}.F1KBNa_coverNoticeGlyph{width:44px;height:44px;color:var(--dsw-alias-label-tertiary);border-radius:10px;justify-content:center;align-items:center;display:inline-flex}.F1KBNa_coverNoticeGlyph[data-on]{color:var(--dsw-alias-label-primary)}.F1KBNa_coverNoticeGlyph[data-changed]{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_coverNoticeText{clip-path:inset(50%);white-space:nowrap;width:1px;height:1px;position:absolute;overflow:hidden}.F1KBNa_coverButton{width:32px;height:32px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:8px;justify-content:center;align-items:center;padding:0;display:inline-flex}.F1KBNa_coverButton:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_coverButton[data-on]{color:var(--dsw-alias-label-primary)}.F1KBNa_presentationHost{align-items:center;display:inline-flex}.F1KBNa_chipPresentation{min-width:36px;height:20px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:20px;flex:none;justify-content:center;align-items:center;gap:2px;padding:0 6px;display:inline-flex}.F1KBNa_chipPresentation:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_mirrored{transform:scaleX(-1)}.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:var(--dsh-diff-line-height,22px)}.F1KBNa_subline{height:var(--dsh-diff-line-height,22px);line-height:var(--dsh-diff-line-height,22px);white-space:pre;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{isolation:isolate;flex-direction:column;flex:1;min-height:0;display:flex;position:relative;overflow:hidden}.F1KBNa_diffBodySplit{flex:1;min-height:0;overflow-x:hidden}.F1KBNa_splitCols{width:100%;min-width:0;min-height:100%;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_splitDiscussions{z-index:3;pointer-events:none;width:100%;height:0;position:absolute;top:0;left:0}.F1KBNa_splitDiscussion{box-sizing:border-box;pointer-events:auto;background:var(--dsw-alias-bg-base);position:absolute;left:0}.F1KBNa_splitSealed,.F1KBNa_splitSealed *{-webkit-user-select:none!important;user-select:none!important}.F1KBNa_splitSealedLeft [data-diff-split-side=left],.F1KBNa_splitSealedLeft [data-diff-split-side=left] *,.F1KBNa_splitSealedRight [data-diff-split-side=right],.F1KBNa_splitSealedRight [data-diff-split-side=right] *{-webkit-user-select:text!important;user-select:text!important}.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{overscroll-behavior-x:none;min-width:0;height:var(--dsh-scrollbar-width,8px);flex:1 1 0;overflow:auto hidden}.F1KBNa_splitHScroll::-webkit-scrollbar{height:var(--dsh-scrollbar-width,8px)}.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(--dsh-diff-del-color,var(--dsw-alias-state-error-primary)) 20%, transparent)}.F1KBNa_splitLadd{background-color:color-mix(in srgb, var(--dsh-diff-add-color,var(--dsw-alias-state-success-primary)) 18%, transparent)}.F1KBNa_splitRdel{background-color:color-mix(in srgb, var(--dsh-diff-del-color,var(--dsw-alias-state-error-primary)) 20%, transparent)}.F1KBNa_splitRadd{background-color:color-mix(in srgb, var(--dsh-diff-add-color,var(--dsw-alias-state-success-primary)) 18%, transparent)}.F1KBNa_intraDel{background-color:color-mix(in srgb, var(--dsh-diff-del-color,var(--dsw-alias-state-error-primary)) 34%, transparent);text-decoration:line-through}.F1KBNa_intraAdd{background-color:color-mix(in srgb, var(--dsh-diff-add-color,var(--dsw-alias-state-success-primary)) 32%, transparent)}";
|
|
25
25
|
const tagId = "dsh-diff-approval/PendingPanel.module.css";
|
|
26
26
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
27
27
|
const tag = document.createElement("style");
|
|
@@ -31,248 +31,271 @@ window.__ModuleLoader__.load({
|
|
|
31
31
|
document.head.appendChild(tag);
|
|
32
32
|
}
|
|
33
33
|
var PendingPanel_module_css_default = {
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"discussionDots": "F1KBNa_discussionDots",
|
|
39
|
-
"searchInput": "F1KBNa_searchInput",
|
|
40
|
-
"gutter": "F1KBNa_gutter",
|
|
41
|
-
"overviewRuler": "F1KBNa_overviewRuler",
|
|
42
|
-
"diffFlashFade": "F1KBNa_diffFlashFade",
|
|
43
|
-
"stepper": "F1KBNa_stepper",
|
|
44
|
-
"delCount": "F1KBNa_delCount",
|
|
45
|
-
"blockFlashShake": "F1KBNa_blockFlashShake",
|
|
46
|
-
"rowHead": "F1KBNa_rowHead",
|
|
47
|
-
"stepperValue": "F1KBNa_stepperValue",
|
|
48
|
-
"discussionRow": "F1KBNa_discussionRow",
|
|
49
|
-
"confirmText": "F1KBNa_confirmText",
|
|
50
|
-
"statusBar": "F1KBNa_statusBar",
|
|
51
|
-
"chip": "F1KBNa_chip",
|
|
52
|
-
"subline": "F1KBNa_subline",
|
|
53
|
-
"threadFontProbe": "F1KBNa_threadFontProbe",
|
|
54
|
-
"discussionDot": "F1KBNa_discussionDot",
|
|
55
|
-
"split": "F1KBNa_split",
|
|
56
|
-
"settingsGroupText": "F1KBNa_settingsGroupText",
|
|
57
|
-
"coverButton": "F1KBNa_coverButton",
|
|
34
|
+
"splitRdel": "F1KBNa_splitRdel",
|
|
35
|
+
"pickerTitle": "F1KBNa_pickerTitle",
|
|
36
|
+
"searchBar": "F1KBNa_searchBar",
|
|
37
|
+
"readError": "F1KBNa_readError",
|
|
58
38
|
"quoteNoWrap": "F1KBNa_quoteNoWrap",
|
|
39
|
+
"colorSv": "F1KBNa_colorSv",
|
|
59
40
|
"listTabs": "F1KBNa_listTabs",
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
-
"
|
|
63
|
-
"
|
|
64
|
-
"
|
|
65
|
-
"importButton": "F1KBNa_importButton",
|
|
66
|
-
"splitRoot": "F1KBNa_splitRoot",
|
|
67
|
-
"layer": "F1KBNa_layer",
|
|
68
|
-
"settingsRow": "F1KBNa_settingsRow",
|
|
69
|
-
"colorPicker": "F1KBNa_colorPicker",
|
|
70
|
-
"rowMenuAnchor": "F1KBNa_rowMenuAnchor",
|
|
71
|
-
"pickerCheck": "F1KBNa_pickerCheck",
|
|
72
|
-
"chipLabel": "F1KBNa_chipLabel",
|
|
73
|
-
"listScroll": "F1KBNa_listScroll",
|
|
74
|
-
"discussionHead": "F1KBNa_discussionHead",
|
|
41
|
+
"blockFlash": "F1KBNa_blockFlash",
|
|
42
|
+
"discussionToggle": "F1KBNa_discussionToggle",
|
|
43
|
+
"gotoHost": "F1KBNa_gotoHost",
|
|
44
|
+
"footerButtons": "F1KBNa_footerButtons",
|
|
45
|
+
"splitHScroll": "F1KBNa_splitHScroll",
|
|
75
46
|
"colorPickerChevron": "F1KBNa_colorPickerChevron",
|
|
76
|
-
"
|
|
77
|
-
"
|
|
78
|
-
"
|
|
79
|
-
"
|
|
80
|
-
"
|
|
81
|
-
"
|
|
82
|
-
"
|
|
83
|
-
"
|
|
84
|
-
"
|
|
85
|
-
"
|
|
86
|
-
"
|
|
87
|
-
"
|
|
47
|
+
"row": "F1KBNa_row",
|
|
48
|
+
"blockPosition": "F1KBNa_blockPosition",
|
|
49
|
+
"actionChord": "F1KBNa_actionChord",
|
|
50
|
+
"badge": "F1KBNa_badge",
|
|
51
|
+
"hint": "F1KBNa_hint",
|
|
52
|
+
"coverNoticeText": "F1KBNa_coverNoticeText",
|
|
53
|
+
"split": "F1KBNa_split",
|
|
54
|
+
"treeNote": "F1KBNa_treeNote",
|
|
55
|
+
"missingHint": "F1KBNa_missingHint",
|
|
56
|
+
"fileListFloatClosing": "F1KBNa_fileListFloatClosing",
|
|
57
|
+
"listTab": "F1KBNa_listTab",
|
|
58
|
+
"stepperButton": "F1KBNa_stepperButton",
|
|
59
|
+
"resizeHandle": "F1KBNa_resizeHandle",
|
|
60
|
+
"quoteSplitTable": "F1KBNa_quoteSplitTable",
|
|
61
|
+
"pickerCheck": "F1KBNa_pickerCheck",
|
|
62
|
+
"rowDiscussed": "F1KBNa_rowDiscussed",
|
|
63
|
+
"panelFailure": "F1KBNa_panelFailure",
|
|
64
|
+
"confirmBackdrop": "F1KBNa_confirmBackdrop",
|
|
65
|
+
"commentLabel": "F1KBNa_commentLabel",
|
|
66
|
+
"overviewRuler": "F1KBNa_overviewRuler",
|
|
67
|
+
"colorHueCursor": "F1KBNa_colorHueCursor",
|
|
68
|
+
"del": "F1KBNa_del",
|
|
69
|
+
"discussionInput": "F1KBNa_discussionInput",
|
|
70
|
+
"splitCols": "F1KBNa_splitCols",
|
|
71
|
+
"stepper": "F1KBNa_stepper",
|
|
72
|
+
"mdPreviewSingle": "F1KBNa_mdPreviewSingle",
|
|
73
|
+
"pickerIcon": "F1KBNa_pickerIcon",
|
|
74
|
+
"quoteText": "F1KBNa_quoteText",
|
|
75
|
+
"headerActions": "F1KBNa_headerActions",
|
|
76
|
+
"pickerCard": "F1KBNa_pickerCard",
|
|
77
|
+
"markerSplitAdd": "F1KBNa_markerSplitAdd",
|
|
78
|
+
"settingsGroupBody": "F1KBNa_settingsGroupBody",
|
|
88
79
|
"kindHint": "F1KBNa_kindHint",
|
|
89
|
-
"toggleThumb": "F1KBNa_toggleThumb",
|
|
90
|
-
"discussionPin": "F1KBNa_discussionPin",
|
|
91
80
|
"commentHead": "F1KBNa_commentHead",
|
|
92
|
-
"
|
|
93
|
-
"
|
|
94
|
-
"
|
|
95
|
-
"
|
|
96
|
-
"coverNoticeFade": "F1KBNa_coverNoticeFade",
|
|
97
|
-
"pickerClose": "F1KBNa_pickerClose",
|
|
98
|
-
"colorSwatch": "F1KBNa_colorSwatch",
|
|
99
|
-
"colorHueCursor": "F1KBNa_colorHueCursor",
|
|
100
|
-
"coverNoticeText": "F1KBNa_coverNoticeText",
|
|
101
|
-
"close": "F1KBNa_close",
|
|
102
|
-
"lines": "F1KBNa_lines",
|
|
103
|
-
"discussionSend": "F1KBNa_discussionSend",
|
|
104
|
-
"searchBar": "F1KBNa_searchBar",
|
|
105
|
-
"noticeText": "F1KBNa_noticeText",
|
|
106
|
-
"badge": "F1KBNa_badge",
|
|
107
|
-
"rows": "F1KBNa_rows",
|
|
108
|
-
"discussionNote": "F1KBNa_discussionNote",
|
|
109
|
-
"coverPopover": "F1KBNa_coverPopover",
|
|
110
|
-
"coverNoticeGlyph": "F1KBNa_coverNoticeGlyph",
|
|
111
|
-
"diffPath": "F1KBNa_diffPath",
|
|
112
|
-
"markerDel": "F1KBNa_markerDel",
|
|
113
|
-
"colorPickerInput": "F1KBNa_colorPickerInput",
|
|
114
|
-
"treeRow": "F1KBNa_treeRow",
|
|
115
|
-
"blockPosition": "F1KBNa_blockPosition",
|
|
116
|
-
"discussionRangeWrap": "F1KBNa_discussionRangeWrap",
|
|
117
|
-
"coverNotice": "F1KBNa_coverNotice",
|
|
118
|
-
"splitLadd": "F1KBNa_splitLadd",
|
|
119
|
-
"overviewMarker": "F1KBNa_overviewMarker",
|
|
120
|
-
"commentLost": "F1KBNa_commentLost",
|
|
121
|
-
"settingsGroupDesc": "F1KBNa_settingsGroupDesc",
|
|
122
|
-
"quoteLines": "F1KBNa_quoteLines",
|
|
123
|
-
"row": "F1KBNa_row",
|
|
124
|
-
"discussionCompose": "F1KBNa_discussionCompose",
|
|
125
|
-
"chipPresentation": "F1KBNa_chipPresentation",
|
|
126
|
-
"diffPreviewScroll": "F1KBNa_diffPreviewScroll",
|
|
81
|
+
"commentGroupName": "F1KBNa_commentGroupName",
|
|
82
|
+
"gotoAction": "F1KBNa_gotoAction",
|
|
83
|
+
"commentTitle": "F1KBNa_commentTitle",
|
|
84
|
+
"panel": "F1KBNa_panel",
|
|
127
85
|
"divider": "F1KBNa_divider",
|
|
128
|
-
"
|
|
129
|
-
"
|
|
130
|
-
"
|
|
131
|
-
"
|
|
132
|
-
"
|
|
133
|
-
"
|
|
134
|
-
"
|
|
135
|
-
"
|
|
86
|
+
"discussionRangeWrap": "F1KBNa_discussionRangeWrap",
|
|
87
|
+
"gotoBackdrop": "F1KBNa_gotoBackdrop",
|
|
88
|
+
"discussionDots": "F1KBNa_discussionDots",
|
|
89
|
+
"coverCard": "F1KBNa_coverCard",
|
|
90
|
+
"badgeLabel": "F1KBNa_badgeLabel",
|
|
91
|
+
"coverNoticeCard": "F1KBNa_coverNoticeCard",
|
|
92
|
+
"colorPicker": "F1KBNa_colorPicker",
|
|
93
|
+
"detail": "F1KBNa_detail",
|
|
94
|
+
"intraAdd": "F1KBNa_intraAdd",
|
|
95
|
+
"diffHeader": "F1KBNa_diffHeader",
|
|
136
96
|
"quoteCode": "F1KBNa_quoteCode",
|
|
137
|
-
"
|
|
138
|
-
"
|
|
139
|
-
"
|
|
97
|
+
"action": "F1KBNa_action",
|
|
98
|
+
"context": "F1KBNa_context",
|
|
99
|
+
"commentLost": "F1KBNa_commentLost",
|
|
100
|
+
"iconAction": "F1KBNa_iconAction",
|
|
140
101
|
"splitLdel": "F1KBNa_splitLdel",
|
|
141
|
-
"
|
|
142
|
-
"
|
|
143
|
-
"
|
|
144
|
-
"splitHScroll": "F1KBNa_splitHScroll",
|
|
145
|
-
"settingsGroupBody": "F1KBNa_settingsGroupBody",
|
|
146
|
-
"diffStats": "F1KBNa_diffStats",
|
|
147
|
-
"coverHost": "F1KBNa_coverHost",
|
|
148
|
-
"settingsReset": "F1KBNa_settingsReset",
|
|
149
|
-
"mdPreviewFallback": "F1KBNa_mdPreviewFallback",
|
|
102
|
+
"fileList": "F1KBNa_fileList",
|
|
103
|
+
"mirrored": "F1KBNa_mirrored",
|
|
104
|
+
"searchCount": "F1KBNa_searchCount",
|
|
150
105
|
"confirmCard": "F1KBNa_confirmCard",
|
|
151
|
-
"discussionToggle": "F1KBNa_discussionToggle",
|
|
152
|
-
"rowDiscussed": "F1KBNa_rowDiscussed",
|
|
153
|
-
"coverCard": "F1KBNa_coverCard",
|
|
154
|
-
"settingsSelector": "F1KBNa_settingsSelector",
|
|
155
|
-
"pickerTitle": "F1KBNa_pickerTitle",
|
|
156
|
-
"colorPickerPreview": "F1KBNa_colorPickerPreview",
|
|
157
|
-
"headerEntry": "F1KBNa_headerEntry",
|
|
158
|
-
"panelDocked": "F1KBNa_panelDocked",
|
|
159
|
-
"listFold": "F1KBNa_listFold",
|
|
160
|
-
"rowPath": "F1KBNa_rowPath",
|
|
161
|
-
"toggleOn": "F1KBNa_toggleOn",
|
|
162
|
-
"missingHint": "F1KBNa_missingHint",
|
|
163
|
-
"rowFailed": "F1KBNa_rowFailed",
|
|
164
|
-
"mdPreviewDouble": "F1KBNa_mdPreviewDouble",
|
|
165
|
-
"discussionBody": "F1KBNa_discussionBody",
|
|
166
|
-
"detail": "F1KBNa_detail",
|
|
167
|
-
"splitCol": "F1KBNa_splitCol",
|
|
168
|
-
"code": "F1KBNa_code",
|
|
169
|
-
"mdPreviewContent": "F1KBNa_mdPreviewContent",
|
|
170
|
-
"diffPreview": "F1KBNa_diffPreview",
|
|
171
|
-
"quoteLine": "F1KBNa_quoteLine",
|
|
172
|
-
"colorSv": "F1KBNa_colorSv",
|
|
173
|
-
"mdPreviewBody": "F1KBNa_mdPreviewBody",
|
|
174
|
-
"discussionUser": "F1KBNa_discussionUser",
|
|
175
106
|
"addButton": "F1KBNa_addButton",
|
|
176
|
-
"
|
|
107
|
+
"langLabel": "F1KBNa_langLabel",
|
|
108
|
+
"kindTag": "F1KBNa_kindTag",
|
|
109
|
+
"noticeButton": "F1KBNa_noticeButton",
|
|
110
|
+
"bulkActions": "F1KBNa_bulkActions",
|
|
111
|
+
"noteCentered": "F1KBNa_noteCentered",
|
|
112
|
+
"discussionDot": "F1KBNa_discussionDot",
|
|
113
|
+
"add": "F1KBNa_add",
|
|
114
|
+
"mdPreviewBody": "F1KBNa_mdPreviewBody",
|
|
115
|
+
"colorPickerPanel": "F1KBNa_colorPickerPanel",
|
|
116
|
+
"listEmpty": "F1KBNa_listEmpty",
|
|
117
|
+
"addCount": "F1KBNa_addCount",
|
|
118
|
+
"diffFlashShake": "F1KBNa_diffFlashShake",
|
|
119
|
+
"noticeText": "F1KBNa_noticeText",
|
|
177
120
|
"headerEntryCount": "F1KBNa_headerEntryCount",
|
|
178
|
-
"
|
|
179
|
-
"
|
|
180
|
-
"
|
|
181
|
-
"
|
|
182
|
-
"
|
|
121
|
+
"headerEntry": "F1KBNa_headerEntry",
|
|
122
|
+
"searchToggle": "F1KBNa_searchToggle",
|
|
123
|
+
"colorHue": "F1KBNa_colorHue",
|
|
124
|
+
"divergedHint": "F1KBNa_divergedHint",
|
|
125
|
+
"panelFailureText": "F1KBNa_panelFailureText",
|
|
126
|
+
"commentRow": "F1KBNa_commentRow",
|
|
127
|
+
"colorSvCursor": "F1KBNa_colorSvCursor",
|
|
128
|
+
"markerSplitDel": "F1KBNa_markerSplitDel",
|
|
129
|
+
"treeName": "F1KBNa_treeName",
|
|
130
|
+
"diffBodySplit": "F1KBNa_diffBodySplit",
|
|
131
|
+
"expand": "F1KBNa_expand",
|
|
132
|
+
"splitDiscussion": "F1KBNa_splitDiscussion",
|
|
183
133
|
"langSelect": "F1KBNa_langSelect",
|
|
134
|
+
"overviewRulerSplit": "F1KBNa_overviewRulerSplit",
|
|
135
|
+
"pickerNote": "F1KBNa_pickerNote",
|
|
136
|
+
"listHead": "F1KBNa_listHead",
|
|
137
|
+
"discussionSlack": "F1KBNa_discussionSlack",
|
|
138
|
+
"pickerClose": "F1KBNa_pickerClose",
|
|
139
|
+
"searchMatch": "F1KBNa_searchMatch",
|
|
140
|
+
"rowMeta": "F1KBNa_rowMeta",
|
|
141
|
+
"mdPreviewContent": "F1KBNa_mdPreviewContent",
|
|
142
|
+
"discussionCompose": "F1KBNa_discussionCompose",
|
|
143
|
+
"rowFailed": "F1KBNa_rowFailed",
|
|
144
|
+
"discussionHead": "F1KBNa_discussionHead",
|
|
145
|
+
"diffBodyWrap": "F1KBNa_diffBodyWrap",
|
|
146
|
+
"confirmText": "F1KBNa_confirmText",
|
|
147
|
+
"delCount": "F1KBNa_delCount",
|
|
148
|
+
"searchInput": "F1KBNa_searchInput",
|
|
149
|
+
"importNote": "F1KBNa_importNote",
|
|
150
|
+
"splitHScrollRow": "F1KBNa_splitHScrollRow",
|
|
151
|
+
"settingsGroupText": "F1KBNa_settingsGroupText",
|
|
152
|
+
"pickerForm": "F1KBNa_pickerForm",
|
|
153
|
+
"diffPreviewScroll": "F1KBNa_diffPreviewScroll",
|
|
154
|
+
"discussionCode": "F1KBNa_discussionCode",
|
|
155
|
+
"coverPopover": "F1KBNa_coverPopover",
|
|
156
|
+
"group": "F1KBNa_group",
|
|
157
|
+
"splitLadd": "F1KBNa_splitLadd",
|
|
158
|
+
"threadFontProbe": "F1KBNa_threadFontProbe",
|
|
159
|
+
"discussion": "F1KBNa_discussion",
|
|
160
|
+
"gotoInput": "F1KBNa_gotoInput",
|
|
161
|
+
"splitSealed": "F1KBNa_splitSealed",
|
|
162
|
+
"settingsSelector": "F1KBNa_settingsSelector",
|
|
163
|
+
"discussionUser": "F1KBNa_discussionUser",
|
|
164
|
+
"treeRow": "F1KBNa_treeRow",
|
|
165
|
+
"addPath": "F1KBNa_addPath",
|
|
166
|
+
"close": "F1KBNa_close",
|
|
167
|
+
"overviewMarker": "F1KBNa_overviewMarker",
|
|
168
|
+
"colorBackdrop": "F1KBNa_colorBackdrop",
|
|
169
|
+
"states": "F1KBNa_states",
|
|
170
|
+
"gotoLayer": "F1KBNa_gotoLayer",
|
|
171
|
+
"quoteDel": "F1KBNa_quoteDel",
|
|
172
|
+
"coverBackdrop": "F1KBNa_coverBackdrop",
|
|
173
|
+
"colorValue": "F1KBNa_colorValue",
|
|
174
|
+
"tree": "F1KBNa_tree",
|
|
175
|
+
"colorPickerInput": "F1KBNa_colorPickerInput",
|
|
176
|
+
"stepperValue": "F1KBNa_stepperValue",
|
|
177
|
+
"coverHost": "F1KBNa_coverHost",
|
|
178
|
+
"splitRoot": "F1KBNa_splitRoot",
|
|
179
|
+
"discussionBody": "F1KBNa_discussionBody",
|
|
180
|
+
"settingsRow": "F1KBNa_settingsRow",
|
|
181
|
+
"splitHScrollFill": "F1KBNa_splitHScrollFill",
|
|
182
|
+
"importButton": "F1KBNa_importButton",
|
|
184
183
|
"discussionAnswer": "F1KBNa_discussionAnswer",
|
|
185
|
-
"
|
|
184
|
+
"detailEmpty": "F1KBNa_detailEmpty",
|
|
186
185
|
"diff": "F1KBNa_diff",
|
|
187
|
-
"
|
|
188
|
-
"
|
|
189
|
-
"
|
|
190
|
-
"
|
|
191
|
-
"
|
|
192
|
-
"intraDel": "F1KBNa_intraDel",
|
|
193
|
-
"panelFailureRetry": "F1KBNa_panelFailureRetry",
|
|
194
|
-
"diffPreviewTitle": "F1KBNa_diffPreviewTitle",
|
|
195
|
-
"kindTag": "F1KBNa_kindTag",
|
|
196
|
-
"context": "F1KBNa_context",
|
|
197
|
-
"groupHead": "F1KBNa_groupHead",
|
|
198
|
-
"panel": "F1KBNa_panel",
|
|
199
|
-
"bulkActions": "F1KBNa_bulkActions",
|
|
200
|
-
"group": "F1KBNa_group",
|
|
201
|
-
"resizeHandle": "F1KBNa_resizeHandle",
|
|
186
|
+
"vSpacer": "F1KBNa_vSpacer",
|
|
187
|
+
"presentationSelect": "F1KBNa_presentationSelect",
|
|
188
|
+
"gotoLayerRight": "F1KBNa_gotoLayerRight",
|
|
189
|
+
"settingsGroupDesc": "F1KBNa_settingsGroupDesc",
|
|
190
|
+
"stepperButtonUp": "F1KBNa_stepperButtonUp",
|
|
202
191
|
"actionError": "F1KBNa_actionError",
|
|
203
|
-
"
|
|
204
|
-
"
|
|
205
|
-
"
|
|
192
|
+
"colorPickerPopover": "F1KBNa_colorPickerPopover",
|
|
193
|
+
"chipLabel": "F1KBNa_chipLabel",
|
|
194
|
+
"coverButton": "F1KBNa_coverButton",
|
|
195
|
+
"wrapActive": "F1KBNa_wrapActive",
|
|
206
196
|
"markerAdd": "F1KBNa_markerAdd",
|
|
207
|
-
"states": "F1KBNa_states",
|
|
208
|
-
"actionPrimary": "F1KBNa_actionPrimary",
|
|
209
|
-
"discussionCell": "F1KBNa_discussionCell",
|
|
210
|
-
"dockHost": "F1KBNa_dockHost",
|
|
211
|
-
"del": "F1KBNa_del",
|
|
212
|
-
"quoteDel": "F1KBNa_quoteDel",
|
|
213
|
-
"searchCount": "F1KBNa_searchCount",
|
|
214
|
-
"add": "F1KBNa_add",
|
|
215
|
-
"blockActions": "F1KBNa_blockActions",
|
|
216
|
-
"hint": "F1KBNa_hint",
|
|
217
197
|
"splitDivider": "F1KBNa_splitDivider",
|
|
218
|
-
"
|
|
219
|
-
"
|
|
220
|
-
"
|
|
221
|
-
"
|
|
222
|
-
"title": "F1KBNa_title",
|
|
223
|
-
"line": "F1KBNa_line",
|
|
224
|
-
"discussionInput": "F1KBNa_discussionInput",
|
|
225
|
-
"colorSvCursor": "F1KBNa_colorSvCursor",
|
|
226
|
-
"confirmBackdrop": "F1KBNa_confirmBackdrop",
|
|
227
|
-
"blockActionsDivider": "F1KBNa_blockActionsDivider",
|
|
228
|
-
"colorValue": "F1KBNa_colorValue",
|
|
229
|
-
"badgeLabel": "F1KBNa_badgeLabel",
|
|
230
|
-
"diffHeader": "F1KBNa_diffHeader",
|
|
198
|
+
"splitSealedLeft": "F1KBNa_splitSealedLeft",
|
|
199
|
+
"markerDel": "F1KBNa_markerDel",
|
|
200
|
+
"diffStats": "F1KBNa_diffStats",
|
|
201
|
+
"coverNoticeFade": "F1KBNa_coverNoticeFade",
|
|
231
202
|
"diffActions": "F1KBNa_diffActions",
|
|
232
|
-
"
|
|
233
|
-
"
|
|
234
|
-
"pickerCard": "F1KBNa_pickerCard",
|
|
203
|
+
"presentationHost": "F1KBNa_presentationHost",
|
|
204
|
+
"listScroll": "F1KBNa_listScroll",
|
|
235
205
|
"settingsRowDesc": "F1KBNa_settingsRowDesc",
|
|
236
|
-
"
|
|
237
|
-
"
|
|
238
|
-
"action": "F1KBNa_action",
|
|
239
|
-
"rowMeta": "F1KBNa_rowMeta",
|
|
240
|
-
"stepperButtonUp": "F1KBNa_stepperButtonUp",
|
|
241
|
-
"pickerInput": "F1KBNa_pickerInput",
|
|
242
|
-
"listHead": "F1KBNa_listHead",
|
|
243
|
-
"addPath": "F1KBNa_addPath",
|
|
244
|
-
"actionQuietDisabled": "F1KBNa_actionQuietDisabled",
|
|
245
|
-
"colorPickerInputRow": "F1KBNa_colorPickerInputRow",
|
|
246
|
-
"wrapActive": "F1KBNa_wrapActive",
|
|
247
|
-
"settingsGroup": "F1KBNa_settingsGroup",
|
|
248
|
-
"listTab": "F1KBNa_listTab",
|
|
249
|
-
"mdPreviewSingle": "F1KBNa_mdPreviewSingle",
|
|
250
|
-
"presentationSelect": "F1KBNa_presentationSelect",
|
|
251
|
-
"flexSpacer": "F1KBNa_flexSpacer",
|
|
206
|
+
"fileListFloat": "F1KBNa_fileListFloat",
|
|
207
|
+
"missing": "F1KBNa_missing",
|
|
252
208
|
"discussionRange": "F1KBNa_discussionRange",
|
|
253
|
-
"
|
|
209
|
+
"quoteAdd": "F1KBNa_quoteAdd",
|
|
210
|
+
"code": "F1KBNa_code",
|
|
211
|
+
"toggleThumb": "F1KBNa_toggleThumb",
|
|
212
|
+
"quoteLines": "F1KBNa_quoteLines",
|
|
213
|
+
"groupHead": "F1KBNa_groupHead",
|
|
214
|
+
"wrap": "F1KBNa_wrap",
|
|
254
215
|
"floatResizeHandle": "F1KBNa_floatResizeHandle",
|
|
255
|
-
"
|
|
256
|
-
"
|
|
257
|
-
"
|
|
258
|
-
"
|
|
259
|
-
"
|
|
260
|
-
"
|
|
261
|
-
"
|
|
216
|
+
"diffPreviewTitle": "F1KBNa_diffPreviewTitle",
|
|
217
|
+
"title": "F1KBNa_title",
|
|
218
|
+
"treeCaret": "F1KBNa_treeCaret",
|
|
219
|
+
"gotoBox": "F1KBNa_gotoBox",
|
|
220
|
+
"blockActions": "F1KBNa_blockActions",
|
|
221
|
+
"discussionRow": "F1KBNa_discussionRow",
|
|
222
|
+
"gutter": "F1KBNa_gutter",
|
|
223
|
+
"splitCol": "F1KBNa_splitCol",
|
|
224
|
+
"pickerInput": "F1KBNa_pickerInput",
|
|
262
225
|
"confirmActions": "F1KBNa_confirmActions",
|
|
263
|
-
"
|
|
226
|
+
"discussionPin": "F1KBNa_discussionPin",
|
|
227
|
+
"diffFlashFade": "F1KBNa_diffFlashFade",
|
|
228
|
+
"fileListShrink": "F1KBNa_fileListShrink",
|
|
229
|
+
"intraDel": "F1KBNa_intraDel",
|
|
230
|
+
"settingsPage": "F1KBNa_settingsPage",
|
|
231
|
+
"line": "F1KBNa_line",
|
|
232
|
+
"settingsGroupChevron": "F1KBNa_settingsGroupChevron",
|
|
233
|
+
"settingsGroup": "F1KBNa_settingsGroup",
|
|
234
|
+
"diffPreview": "F1KBNa_diffPreview",
|
|
235
|
+
"panelDocked": "F1KBNa_panelDocked",
|
|
236
|
+
"layer": "F1KBNa_layer",
|
|
264
237
|
"header": "F1KBNa_header",
|
|
265
|
-
"
|
|
238
|
+
"colorSwatch": "F1KBNa_colorSwatch",
|
|
239
|
+
"flexSpacer": "F1KBNa_flexSpacer",
|
|
240
|
+
"discussionNote": "F1KBNa_discussionNote",
|
|
241
|
+
"quoteSplit": "F1KBNa_quoteSplit",
|
|
242
|
+
"rowMenuAnchor": "F1KBNa_rowMenuAnchor",
|
|
243
|
+
"rail": "F1KBNa_rail",
|
|
244
|
+
"chip": "F1KBNa_chip",
|
|
245
|
+
"commentTitleEmpty": "F1KBNa_commentTitleEmpty",
|
|
246
|
+
"splitRadd": "F1KBNa_splitRadd",
|
|
247
|
+
"listFold": "F1KBNa_listFold",
|
|
248
|
+
"diffPath": "F1KBNa_diffPath",
|
|
249
|
+
"notice": "F1KBNa_notice",
|
|
250
|
+
"settingsGroupTitle": "F1KBNa_settingsGroupTitle",
|
|
251
|
+
"subline": "F1KBNa_subline",
|
|
252
|
+
"splitDiscussions": "F1KBNa_splitDiscussions",
|
|
253
|
+
"discussionCell": "F1KBNa_discussionCell",
|
|
254
|
+
"discussionSend": "F1KBNa_discussionSend",
|
|
255
|
+
"settingsRowText": "F1KBNa_settingsRowText",
|
|
256
|
+
"colorPickerPreview": "F1KBNa_colorPickerPreview",
|
|
266
257
|
"toggle": "F1KBNa_toggle",
|
|
267
|
-
"
|
|
268
|
-
"
|
|
269
|
-
"
|
|
270
|
-
"
|
|
271
|
-
"
|
|
272
|
-
"
|
|
273
|
-
"
|
|
258
|
+
"badgeCount": "F1KBNa_badgeCount",
|
|
259
|
+
"pickerName": "F1KBNa_pickerName",
|
|
260
|
+
"expandExpanded": "F1KBNa_expandExpanded",
|
|
261
|
+
"quoteLine": "F1KBNa_quoteLine",
|
|
262
|
+
"coverNotice": "F1KBNa_coverNotice",
|
|
263
|
+
"rowPath": "F1KBNa_rowPath",
|
|
264
|
+
"fileListKnobIn": "F1KBNa_fileListKnobIn",
|
|
265
|
+
"listTitle": "F1KBNa_listTitle",
|
|
266
|
+
"mdPreviewFallback": "F1KBNa_mdPreviewFallback",
|
|
267
|
+
"searchMatchCurrent": "F1KBNa_searchMatchCurrent",
|
|
268
|
+
"emptyState": "F1KBNa_emptyState",
|
|
269
|
+
"quoteSplitSide": "F1KBNa_quoteSplitSide",
|
|
270
|
+
"dockHost": "F1KBNa_dockHost",
|
|
271
|
+
"tabCount": "F1KBNa_tabCount",
|
|
272
|
+
"actionQuietDisabled": "F1KBNa_actionQuietDisabled",
|
|
273
|
+
"emptyActions": "F1KBNa_emptyActions",
|
|
274
|
+
"toggleOn": "F1KBNa_toggleOn",
|
|
275
|
+
"rowHead": "F1KBNa_rowHead",
|
|
276
|
+
"mdPreviewDouble": "F1KBNa_mdPreviewDouble",
|
|
277
|
+
"splitSealedRight": "F1KBNa_splitSealedRight",
|
|
278
|
+
"blockActionsDivider": "F1KBNa_blockActionsDivider",
|
|
274
279
|
"settingsGroupHeader": "F1KBNa_settingsGroupHeader",
|
|
275
|
-
"
|
|
280
|
+
"blockFlashShake": "F1KBNa_blockFlashShake",
|
|
281
|
+
"note": "F1KBNa_note",
|
|
282
|
+
"fileListKnob": "F1KBNa_fileListKnob",
|
|
283
|
+
"chipPresentation": "F1KBNa_chipPresentation",
|
|
284
|
+
"diffBody": "F1KBNa_diffBody",
|
|
285
|
+
"settingsRowTitle": "F1KBNa_settingsRowTitle",
|
|
286
|
+
"searchToggleOn": "F1KBNa_searchToggleOn",
|
|
287
|
+
"rows": "F1KBNa_rows",
|
|
288
|
+
"statusBar": "F1KBNa_statusBar",
|
|
289
|
+
"colorPickerInputRow": "F1KBNa_colorPickerInputRow",
|
|
290
|
+
"panelFailureRetry": "F1KBNa_panelFailureRetry",
|
|
291
|
+
"settingsReset": "F1KBNa_settingsReset",
|
|
292
|
+
"statusAction": "F1KBNa_statusAction",
|
|
293
|
+
"colorPickerTrigger": "F1KBNa_colorPickerTrigger",
|
|
294
|
+
"actionPrimary": "F1KBNa_actionPrimary",
|
|
295
|
+
"commentGroup": "F1KBNa_commentGroup",
|
|
296
|
+
"lines": "F1KBNa_lines",
|
|
297
|
+
"mdPreviewWrap": "F1KBNa_mdPreviewWrap",
|
|
298
|
+
"coverNoticeGlyph": "F1KBNa_coverNoticeGlyph"
|
|
276
299
|
};
|
|
277
300
|
//#endregion
|
|
278
301
|
//#region lib/types/client/PathPicker.js
|
|
@@ -1188,6 +1211,7 @@ window.__ModuleLoader__.load({
|
|
|
1188
1211
|
jumpDown: "Ctrl+ArrowDown",
|
|
1189
1212
|
copyRef: "Ctrl+L",
|
|
1190
1213
|
addComment: "Ctrl+K",
|
|
1214
|
+
goto: "Ctrl+G",
|
|
1191
1215
|
openSearch: "Ctrl+F",
|
|
1192
1216
|
searchNext: "F3",
|
|
1193
1217
|
searchPrev: "Shift+F3",
|
|
@@ -2959,9 +2983,9 @@ window.__ModuleLoader__.load({
|
|
|
2959
2983
|
* @param rowCount - how many rows the current model has.
|
|
2960
2984
|
* @returns the re-anchored blocks, in the order they came in.
|
|
2961
2985
|
*/
|
|
2962
|
-
function remapDiscussions(discussions, lineOf, textOf, rowCount) {
|
|
2986
|
+
function remapDiscussions(discussions, lineOf, textOf, rowCount, hasNewLine = () => true) {
|
|
2963
2987
|
const windows = windowCache(textOf, rowCount);
|
|
2964
|
-
return discussions.map((discussion) => remapOne(discussion, lineOf, textOf, rowCount, windows));
|
|
2988
|
+
return discussions.map((discussion) => remapOne(discussion, lineOf, textOf, rowCount, windows, hasNewLine));
|
|
2965
2989
|
}
|
|
2966
2990
|
/** Every row window of one span, indexed by its text, in one pass over the rows. */
|
|
2967
2991
|
function windowIndex(textOf, rowCount, span) {
|
|
@@ -2989,7 +3013,7 @@ window.__ModuleLoader__.load({
|
|
|
2989
3013
|
};
|
|
2990
3014
|
}
|
|
2991
3015
|
/** The body both entry points share: one block, with the row windows read through `windows`. */
|
|
2992
|
-
function remapOne(discussion, lineOf, textOf, rowCount, windows) {
|
|
3016
|
+
function remapOne(discussion, lineOf, textOf, rowCount, windows, hasNewLine) {
|
|
2993
3017
|
const { startLine, endLine } = discussion.anchor;
|
|
2994
3018
|
let start = -1;
|
|
2995
3019
|
let end = -1;
|
|
@@ -3036,29 +3060,63 @@ window.__ModuleLoader__.load({
|
|
|
3036
3060
|
}
|
|
3037
3061
|
});
|
|
3038
3062
|
};
|
|
3039
|
-
|
|
3063
|
+
/** The block live again on `row`..`row + span` (the same object when it was already there). */
|
|
3064
|
+
const live = (row, last) => row === discussion.anchor.start && last === discussion.anchor.end ? clearOutdated(discussion) : clearOutdated({
|
|
3065
|
+
...discussion,
|
|
3066
|
+
anchor: {
|
|
3067
|
+
...discussion.anchor,
|
|
3068
|
+
start: row,
|
|
3069
|
+
end: last
|
|
3070
|
+
}
|
|
3071
|
+
});
|
|
3072
|
+
/**
|
|
3073
|
+
* The window's text with one line of context on each side, in the current model.
|
|
3074
|
+
*
|
|
3075
|
+
* Compared against the context the thread recorded when it was made (see `quoteContext`): that is
|
|
3076
|
+
* what tells a genuine move of the quoted code from another line elsewhere in the file that happens
|
|
3077
|
+
* to read the same.
|
|
3078
|
+
*/
|
|
3079
|
+
const contextAt = (row) => {
|
|
3080
|
+
const parts = [];
|
|
3081
|
+
for (let index = Math.max(0, row - 1); index <= Math.min(rowCount - 1, row + span + 1); index++) parts.push(textOf(index));
|
|
3082
|
+
return parts.join("\n");
|
|
3083
|
+
};
|
|
3084
|
+
if (quote === void 0) {
|
|
3040
3085
|
if (start === -1) return gone();
|
|
3041
|
-
|
|
3042
|
-
|
|
3086
|
+
return live(start, end);
|
|
3087
|
+
}
|
|
3088
|
+
if (start !== -1 && textAt(start) === quote) return live(start, end);
|
|
3089
|
+
if (start !== -1) {
|
|
3090
|
+
const fingerprint = discussion.quoteContext;
|
|
3091
|
+
let found = -1;
|
|
3092
|
+
for (const row of windows(span).get(quote) ?? []) {
|
|
3093
|
+
let current = false;
|
|
3094
|
+
for (let index = row; index <= row + span; index++) if (hasNewLine(index)) {
|
|
3095
|
+
current = true;
|
|
3096
|
+
break;
|
|
3097
|
+
}
|
|
3098
|
+
if (!current) continue;
|
|
3099
|
+
if (fingerprint !== void 0 && contextAt(row) !== fingerprint) continue;
|
|
3100
|
+
if (found === -1 || Math.abs(row - start) < Math.abs(found - start)) found = row;
|
|
3101
|
+
}
|
|
3102
|
+
if (found !== -1) return clearOutdated({
|
|
3043
3103
|
...discussion,
|
|
3044
3104
|
anchor: {
|
|
3045
3105
|
...discussion.anchor,
|
|
3046
|
-
start,
|
|
3047
|
-
end
|
|
3106
|
+
start: found,
|
|
3107
|
+
end: found + span,
|
|
3108
|
+
startLine: lineOf(found) ?? startLine,
|
|
3109
|
+
endLine: lineOf(found + span) ?? endLine
|
|
3048
3110
|
}
|
|
3049
3111
|
});
|
|
3050
3112
|
}
|
|
3051
|
-
|
|
3052
|
-
|
|
3053
|
-
if (found === -1) return start === -1 ? gone() : markOutdated(discussion);
|
|
3054
|
-
return clearOutdated({
|
|
3113
|
+
if (start === -1) return gone();
|
|
3114
|
+
return markOutdated({
|
|
3055
3115
|
...discussion,
|
|
3056
3116
|
anchor: {
|
|
3057
3117
|
...discussion.anchor,
|
|
3058
|
-
start
|
|
3059
|
-
end
|
|
3060
|
-
startLine: lineOf(found) ?? startLine,
|
|
3061
|
-
endLine: lineOf(found + span) ?? endLine
|
|
3118
|
+
start,
|
|
3119
|
+
end
|
|
3062
3120
|
}
|
|
3063
3121
|
});
|
|
3064
3122
|
}
|
|
@@ -19364,7 +19422,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
19364
19422
|
guide: [{
|
|
19365
19423
|
order: DIFF_DOCK_GUIDE_ORDER,
|
|
19366
19424
|
title: () => copy.title(),
|
|
19367
|
-
description: () => copy.guideDescription()
|
|
19425
|
+
description: () => copy.guideDescription(),
|
|
19426
|
+
icon: _deepseek_ai_dsh_client_ui_primitives.IconListPenOutline16
|
|
19368
19427
|
}]
|
|
19369
19428
|
}), "diff-approval: right-sidebar tab type");
|
|
19370
19429
|
return true;
|
|
@@ -19449,6 +19508,82 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
19449
19508
|
if (typeof window === "undefined") return;
|
|
19450
19509
|
window.dispatchEvent(new CustomEvent(COMMENTS_CHANGED_EVENT, { detail: { sessionId } }));
|
|
19451
19510
|
}
|
|
19511
|
+
/**
|
|
19512
|
+
* End one comment, wherever it came from.
|
|
19513
|
+
*
|
|
19514
|
+
* The threads belong to the file detail, which writes them here on every change — but the list
|
|
19515
|
+
* pane shows them all and ends them too, and it has no way to reach into another component's
|
|
19516
|
+
* state. So the list asks the memory, and the detail reads the memory back on the event this
|
|
19517
|
+
* fires (see `COMMENTS_CHANGED_EVENT`): one record, one action, whichever pane the reader used.
|
|
19518
|
+
*
|
|
19519
|
+
* @param sessionId - the session the panel is reviewing; nothing is forgotten without one.
|
|
19520
|
+
* @param fileId - the pending entry the thread hangs in.
|
|
19521
|
+
* @param discussionId - the thread to end; an id that is not there changes nothing.
|
|
19522
|
+
*/
|
|
19523
|
+
function forgetDiscussion(sessionId, fileId, discussionId) {
|
|
19524
|
+
if (sessionId === void 0) return;
|
|
19525
|
+
const before = threads.get(sessionId);
|
|
19526
|
+
const list = before?.[fileId];
|
|
19527
|
+
if (list === void 0) return;
|
|
19528
|
+
const next = list.filter((entry) => entry.id !== discussionId);
|
|
19529
|
+
if (next.length === list.length) return;
|
|
19530
|
+
rememberDiscussions(sessionId, {
|
|
19531
|
+
...before,
|
|
19532
|
+
[fileId]: next
|
|
19533
|
+
});
|
|
19534
|
+
}
|
|
19535
|
+
/**
|
|
19536
|
+
* Drop every thread whose file the list no longer holds.
|
|
19537
|
+
*
|
|
19538
|
+
* A thread is a block of rows in one file's diff, so a file the reader has kept or reverted out of the
|
|
19539
|
+
* list leaves nothing for its comments to hang on: they go with it, and the same path coming back later
|
|
19540
|
+
* in this visit starts clean. A new object is published only when something actually goes, so the panes
|
|
19541
|
+
* that adopt this record (see `COMMENTS_CHANGED_EVENT`) do not re-adopt an equal object on every poll.
|
|
19542
|
+
*
|
|
19543
|
+
* @param sessionId - the session the panel is reviewing; nothing is dropped without one.
|
|
19544
|
+
* @param listed - the pending entry ids the list is holding.
|
|
19545
|
+
*/
|
|
19546
|
+
function forgetDiscussionsNotIn(sessionId, listed) {
|
|
19547
|
+
if (sessionId === void 0) return;
|
|
19548
|
+
const before = threads.get(sessionId);
|
|
19549
|
+
if (before === void 0) return;
|
|
19550
|
+
const held = new Set(listed);
|
|
19551
|
+
const kept = {};
|
|
19552
|
+
let dropped = false;
|
|
19553
|
+
for (const [fileId, list] of Object.entries(before)) if (held.has(fileId)) kept[fileId] = list;
|
|
19554
|
+
else dropped = true;
|
|
19555
|
+
if (!dropped) return;
|
|
19556
|
+
rememberDiscussions(sessionId, kept);
|
|
19557
|
+
}
|
|
19558
|
+
/**
|
|
19559
|
+
* The files this page has been told to stop asking about, by session.
|
|
19560
|
+
*
|
|
19561
|
+
* Keeping or reverting a file asks whether the row should leave the list, and a reader working
|
|
19562
|
+
* through one file's blocks answers that the same way every time. Ticking the box in that prompt is
|
|
19563
|
+
* a fact about this visit rather than a preference — it is not the host's to keep, and a reload
|
|
19564
|
+
* starts clean, exactly like the threads above.
|
|
19565
|
+
*/
|
|
19566
|
+
const quietRemovals = /* @__PURE__ */ new Map();
|
|
19567
|
+
/**
|
|
19568
|
+
* Whether the reader asked not to be asked again about removing one file.
|
|
19569
|
+
* @param sessionId - the session the panel is reviewing; nothing is quiet without one.
|
|
19570
|
+
* @param fileId - the pending entry the question was about.
|
|
19571
|
+
* @returns true when the action should run without the question.
|
|
19572
|
+
*/
|
|
19573
|
+
function removalAskQuiet(sessionId, fileId) {
|
|
19574
|
+
return sessionId === void 0 ? false : quietRemovals.get(sessionId)?.has(fileId) === true;
|
|
19575
|
+
}
|
|
19576
|
+
/**
|
|
19577
|
+
* Stop asking whether one file should leave the list, for the rest of this page.
|
|
19578
|
+
* @param sessionId - the session the panel is reviewing; nothing is recorded without one.
|
|
19579
|
+
* @param fileId - the pending entry the question was about.
|
|
19580
|
+
*/
|
|
19581
|
+
function quietenRemovalAsk(sessionId, fileId) {
|
|
19582
|
+
if (sessionId === void 0) return;
|
|
19583
|
+
const files = quietRemovals.get(sessionId);
|
|
19584
|
+
if (files === void 0) quietRemovals.set(sessionId, /* @__PURE__ */ new Set([fileId]));
|
|
19585
|
+
else files.add(fileId);
|
|
19586
|
+
}
|
|
19452
19587
|
/** This session's record, created on first use. */
|
|
19453
19588
|
function viewOf(sessionId) {
|
|
19454
19589
|
let view = views.get(sessionId);
|
|
@@ -19677,8 +19812,6 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
19677
19812
|
const COMPOSER_HEIGHT_VAR = "--dsh-composer-height";
|
|
19678
19813
|
/** Seat counts as docked when its bottom is this close to the window bottom. */
|
|
19679
19814
|
const DOCKED_TOLERANCE_PX = 48;
|
|
19680
|
-
/** File-list pane width bounds for the manual split drag, in px. */
|
|
19681
|
-
const MIN_LIST_WIDTH_PX = 160;
|
|
19682
19815
|
const MAX_LIST_WIDTH_PX = 560;
|
|
19683
19816
|
/** Inset of the floating file-list card from the code scroll box, in px. */
|
|
19684
19817
|
const FLOAT_LIST_MARGIN_PX = 12;
|
|
@@ -19791,6 +19924,38 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
19791
19924
|
})] })]
|
|
19792
19925
|
});
|
|
19793
19926
|
}
|
|
19927
|
+
/** The go-to-line glyph: an arrow landing on a line of code, drawn on the same 14-grid as
|
|
19928
|
+
* `ViewModeIcon`, `MarkdownModeIcon` and `ReturnIcon` so a toolbar of these reads as one set. The
|
|
19929
|
+
* icon library has no "go to line" mark, and a bare `#` beside three line drawings read as a stray
|
|
19930
|
+
* key rather than a control. */
|
|
19931
|
+
function GotoLineIcon({ size = 14 }) {
|
|
19932
|
+
return (0, react_jsx_runtime.jsxs)("svg", {
|
|
19933
|
+
width: size,
|
|
19934
|
+
height: size,
|
|
19935
|
+
viewBox: "0 0 14 14",
|
|
19936
|
+
fill: "none",
|
|
19937
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
19938
|
+
"aria-hidden": "true",
|
|
19939
|
+
children: [
|
|
19940
|
+
(0, react_jsx_runtime.jsx)("path", {
|
|
19941
|
+
d: "M1.5 10.6h11",
|
|
19942
|
+
stroke: "currentColor",
|
|
19943
|
+
strokeWidth: "1.3"
|
|
19944
|
+
}),
|
|
19945
|
+
(0, react_jsx_runtime.jsx)("path", {
|
|
19946
|
+
d: "M7 1.9v5.9",
|
|
19947
|
+
stroke: "currentColor",
|
|
19948
|
+
strokeWidth: "1.3"
|
|
19949
|
+
}),
|
|
19950
|
+
(0, react_jsx_runtime.jsx)("path", {
|
|
19951
|
+
d: "M4.3 5.2 7 7.9l2.7-2.7",
|
|
19952
|
+
stroke: "currentColor",
|
|
19953
|
+
strokeWidth: "1.3",
|
|
19954
|
+
fill: "none"
|
|
19955
|
+
})
|
|
19956
|
+
]
|
|
19957
|
+
});
|
|
19958
|
+
}
|
|
19794
19959
|
/** Return/enter glyph for the comment button: the key's own corner arrow, drawn on
|
|
19795
19960
|
* MarkdownModeIcon's 14-grid so the two read at the same weight. It is what tells
|
|
19796
19961
|
* the user that Enter sends the comment, without spending a row on the hint. */
|
|
@@ -20083,6 +20248,17 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
20083
20248
|
*/
|
|
20084
20249
|
const THREAD_ROW_PX = 22;
|
|
20085
20250
|
/**
|
|
20251
|
+
* How close to a row's own height a measured block may sit and still count as that row, in px.
|
|
20252
|
+
*
|
|
20253
|
+
* A block whose content is a whole number of rows lands on either side of the pixel grid from one pass
|
|
20254
|
+
* to the next — the browser snaps the paint, so the same block measures 572.0004 one pass and 571.9996
|
|
20255
|
+
* the next. Rounding up without a band reads that as 27 rows and then 26, and every flip is a state
|
|
20256
|
+
* write from a layout effect: React counts those as nested updates and throws at fifty (minified #185,
|
|
20257
|
+
* which took the whole panel down). One pixel is far below any real change — the measurement is a row
|
|
20258
|
+
* grid — so a figure this close to the row below it IS that row.
|
|
20259
|
+
*/
|
|
20260
|
+
const DISCUSSION_ROW_SNAP_PX = 1;
|
|
20261
|
+
/**
|
|
20086
20262
|
* The share of the thread's prose size an inline-code chip is drawn at (mirrors
|
|
20087
20263
|
* `.discussionCode`'s `font-size: 0.875em`, which is the chat's own inline code against its own
|
|
20088
20264
|
* message text). The chip is measured in its own font, not in the prose one — a code face at
|
|
@@ -20258,7 +20434,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
20258
20434
|
* A thread that has not been sent yet has no turn at all: what the reader has typed so far is its
|
|
20259
20435
|
* draft, and that is what the item shows, so a comment being written is not listed as a blank line.
|
|
20260
20436
|
* A thread with neither has nothing to quote — an empty comment box the reader placed and left — and
|
|
20261
|
-
* the caller
|
|
20437
|
+
* the caller names it with the box's own placeholder, so the item says what that box is asking for
|
|
20438
|
+
* rather than claiming a title (see the list).
|
|
20262
20439
|
*
|
|
20263
20440
|
* @param discussion - the thread to name.
|
|
20264
20441
|
* @returns the title, or an empty string when there is nothing to say yet.
|
|
@@ -20333,30 +20510,99 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
20333
20510
|
return run.text;
|
|
20334
20511
|
});
|
|
20335
20512
|
}
|
|
20336
|
-
function DiscussionQuote({ quote, lines, lang, wrap }) {
|
|
20513
|
+
function DiscussionQuote({ quote, lines, lang, wrap, split }) {
|
|
20337
20514
|
/** The diff's own wash for a quoted row, or nothing for context (and for older threads). */
|
|
20338
20515
|
const wash = (kind) => kind === "add" ? ` ${PendingPanel_module_css_default.quoteAdd}` : kind === "del" ? ` ${PendingPanel_module_css_default.quoteDel}` : "";
|
|
20339
|
-
const
|
|
20340
|
-
|
|
20341
|
-
|
|
20342
|
-
|
|
20343
|
-
|
|
20344
|
-
const
|
|
20345
|
-
if (lineRuns === void 0) content.push(text);
|
|
20346
|
-
else for (const run of lineRuns) content.push((0, react_jsx_runtime.jsx)("span", {
|
|
20347
|
-
style: run.style,
|
|
20348
|
-
children: run.text
|
|
20349
|
-
}, content.length));
|
|
20516
|
+
const texts = (0, react.useMemo)(() => quote.split("\n"), [quote]);
|
|
20517
|
+
/** The quoted lines paired the way the split view pairs the file's rows. */
|
|
20518
|
+
const pairs = (0, react.useMemo)(() => {
|
|
20519
|
+
if (!split) return void 0;
|
|
20520
|
+
return computeSideBySideDiff(texts.map((text, index) => {
|
|
20521
|
+
const line = lines?.[index];
|
|
20350
20522
|
return {
|
|
20351
|
-
|
|
20352
|
-
|
|
20523
|
+
text,
|
|
20524
|
+
kind: line?.kind ?? "context",
|
|
20525
|
+
oldLine: line?.old,
|
|
20526
|
+
newLine: line?.new
|
|
20353
20527
|
};
|
|
20354
|
-
});
|
|
20528
|
+
}), true).pairs;
|
|
20355
20529
|
}, [
|
|
20356
|
-
|
|
20530
|
+
split,
|
|
20531
|
+
texts,
|
|
20532
|
+
lines
|
|
20533
|
+
]);
|
|
20534
|
+
/**
|
|
20535
|
+
* One column's lines and the highlighted runs each draws. Highlighted per column rather than from
|
|
20536
|
+
* one window over the quoted rows: a multi-line construct must not light up across the divider,
|
|
20537
|
+
* which is also how the file's own two columns are lit.
|
|
20538
|
+
*/
|
|
20539
|
+
const sides = (0, react.useMemo)(() => {
|
|
20540
|
+
if (pairs === void 0) return void 0;
|
|
20541
|
+
const build = (which) => {
|
|
20542
|
+
const columnLines = pairs.map((pair) => pair[which]?.text ?? "");
|
|
20543
|
+
return {
|
|
20544
|
+
lines: columnLines,
|
|
20545
|
+
runs: highlightWindow(columnLines, lang, 0, columnLines.length)
|
|
20546
|
+
};
|
|
20547
|
+
};
|
|
20548
|
+
return {
|
|
20549
|
+
left: build("left"),
|
|
20550
|
+
right: build("right")
|
|
20551
|
+
};
|
|
20552
|
+
}, [pairs, lang]);
|
|
20553
|
+
/** One line's nodes: the highlighted runs it draws, or its own text when nothing highlighted it. */
|
|
20554
|
+
const nodesOf = (lineRuns, text) => {
|
|
20555
|
+
if (lineRuns === void 0) return [text];
|
|
20556
|
+
const content = [];
|
|
20557
|
+
for (const run of lineRuns) content.push((0, react_jsx_runtime.jsx)("span", {
|
|
20558
|
+
style: run.style,
|
|
20559
|
+
children: run.text
|
|
20560
|
+
}, content.length));
|
|
20561
|
+
return content;
|
|
20562
|
+
};
|
|
20563
|
+
const rows = (0, react.useMemo)(() => {
|
|
20564
|
+
const runs = highlightWindow(texts, lang, 0, texts.length)?.runs;
|
|
20565
|
+
return texts.map((text, index) => ({
|
|
20566
|
+
content: nodesOf(runs?.[index], text),
|
|
20567
|
+
gutter: lines?.[index]
|
|
20568
|
+
}));
|
|
20569
|
+
}, [
|
|
20570
|
+
texts,
|
|
20357
20571
|
lines,
|
|
20358
20572
|
lang
|
|
20359
20573
|
]);
|
|
20574
|
+
if (pairs !== void 0 && sides !== void 0) {
|
|
20575
|
+
/** The tint a pair's two cells wear, the same way the file's columns tint theirs. */
|
|
20576
|
+
const pairWash = (which, kind) => which === "left" ? wash(kind === "context" ? "context" : "del") : wash(kind === "context" ? "context" : "add");
|
|
20577
|
+
return (0, react_jsx_runtime.jsx)("div", {
|
|
20578
|
+
className: `${PendingPanel_module_css_default.quoteLines} ${PendingPanel_module_css_default.quoteSplit}${wrap ? "" : " " + PendingPanel_module_css_default.quoteNoWrap}`,
|
|
20579
|
+
"data-diff-discussion-quote": true,
|
|
20580
|
+
children: ["left", "right"].map((which) => (0, react_jsx_runtime.jsx)("div", {
|
|
20581
|
+
className: PendingPanel_module_css_default.quoteSplitSide,
|
|
20582
|
+
"data-diff-quote-side": which,
|
|
20583
|
+
children: (0, react_jsx_runtime.jsx)("div", {
|
|
20584
|
+
className: PendingPanel_module_css_default.quoteSplitTable,
|
|
20585
|
+
children: pairs.map((pair, index) => (0, react_jsx_runtime.jsxs)("div", {
|
|
20586
|
+
className: `${PendingPanel_module_css_default.quoteLine} ${PendingPanel_module_css_default.quotePair}`,
|
|
20587
|
+
"data-diff-quote-pair": true,
|
|
20588
|
+
children: [(0, react_jsx_runtime.jsx)("span", {
|
|
20589
|
+
className: PendingPanel_module_css_default.gutter,
|
|
20590
|
+
"data-diff-quote-gutter": true,
|
|
20591
|
+
children: pair[which]?.line ?? ""
|
|
20592
|
+
}), (0, react_jsx_runtime.jsx)("span", {
|
|
20593
|
+
className: `${PendingPanel_module_css_default.quoteCode}${pairWash(which, pair.kind)}`,
|
|
20594
|
+
children: (0, react_jsx_runtime.jsx)("span", {
|
|
20595
|
+
className: PendingPanel_module_css_default.quoteText,
|
|
20596
|
+
"data-diff-quote-text": true,
|
|
20597
|
+
"data-diff-quote-side": which,
|
|
20598
|
+
children: nodesOf(sides[which].runs?.runs?.[index], sides[which].lines[index] ?? "")
|
|
20599
|
+
})
|
|
20600
|
+
})]
|
|
20601
|
+
}, index))
|
|
20602
|
+
})
|
|
20603
|
+
}, which))
|
|
20604
|
+
});
|
|
20605
|
+
}
|
|
20360
20606
|
return (0, react_jsx_runtime.jsx)("div", {
|
|
20361
20607
|
className: `${PendingPanel_module_css_default.quoteLines}${wrap ? "" : " " + PendingPanel_module_css_default.quoteNoWrap}`,
|
|
20362
20608
|
"data-diff-discussion-quote": true,
|
|
@@ -20386,6 +20632,191 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
20386
20632
|
}, index))
|
|
20387
20633
|
});
|
|
20388
20634
|
}
|
|
20635
|
+
/** How far outside the viewport a side-by-side thread's card is still drawn, in px: it is a pair's
|
|
20636
|
+
* hop from the edge before the scroll brings it in, and dropping it earlier would flash the card
|
|
20637
|
+
* away at the boundary. */
|
|
20638
|
+
const SPLIT_DISCUSSION_MARGIN_PX = 200;
|
|
20639
|
+
/**
|
|
20640
|
+
* A thread's card: the header (range, fold, ⋯), the quote when the code it was written about is
|
|
20641
|
+
* gone, the turns, and the writing row.
|
|
20642
|
+
*
|
|
20643
|
+
* Every view draws the same card — the single-column code view hangs it in a row of its own below
|
|
20644
|
+
* the rows the thread annotates, and whatever view comes next hangs it under whatever it draws that
|
|
20645
|
+
* anchor as — so it is a component rather than a piece of one view's row stream. What varies per
|
|
20646
|
+
* view is only the wrapper around it and the width it is given.
|
|
20647
|
+
*
|
|
20648
|
+
* @param props - the thread, where it hangs, and the panel's own callbacks.
|
|
20649
|
+
* @returns the card, sized to the rows the panel laid the thread out in.
|
|
20650
|
+
*/
|
|
20651
|
+
function DiscussionBlock({ discussion, label, bodyWidth, lang, menuOpen, asking, t, onToggle, onMenuOpen, onRemove, onDraft, onSend, registerInput, split }) {
|
|
20652
|
+
const rows = discussionRows(discussion);
|
|
20653
|
+
const writingNote = discussion.asking === true && discussion.reply !== void 0 && discussion.reply !== "";
|
|
20654
|
+
const menuItems = [{
|
|
20655
|
+
id: "delete",
|
|
20656
|
+
label: t("action.discussionEnd")
|
|
20657
|
+
}];
|
|
20658
|
+
return (0, react_jsx_runtime.jsxs)("div", {
|
|
20659
|
+
className: PendingPanel_module_css_default.discussion,
|
|
20660
|
+
"data-diff-discussion": true,
|
|
20661
|
+
"data-lost": discussion.lost === true ? "" : void 0,
|
|
20662
|
+
"data-diff-discussion-id": discussion.id,
|
|
20663
|
+
style: {
|
|
20664
|
+
width: Math.max(0, bodyWidth),
|
|
20665
|
+
height: rows * THREAD_ROW_PX
|
|
20666
|
+
},
|
|
20667
|
+
children: [(0, react_jsx_runtime.jsxs)("div", {
|
|
20668
|
+
className: PendingPanel_module_css_default.discussionHead,
|
|
20669
|
+
children: [
|
|
20670
|
+
(0, react_jsx_runtime.jsx)("button", {
|
|
20671
|
+
type: "button",
|
|
20672
|
+
className: PendingPanel_module_css_default.discussionToggle,
|
|
20673
|
+
"data-diff-discussion-toggle": true,
|
|
20674
|
+
"aria-expanded": !discussion.collapsed,
|
|
20675
|
+
"aria-label": t(discussion.collapsed ? "action.discussionExpand" : "action.discussionCollapse"),
|
|
20676
|
+
onClick: () => {
|
|
20677
|
+
onToggle(discussion.id);
|
|
20678
|
+
},
|
|
20679
|
+
children: discussion.collapsed ? (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { size: 12 }) : (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronUpOutline14, { size: 12 })
|
|
20680
|
+
}),
|
|
20681
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
20682
|
+
className: PendingPanel_module_css_default.discussionRangeWrap,
|
|
20683
|
+
children: (0, react_jsx_runtime.jsx)("span", {
|
|
20684
|
+
className: PendingPanel_module_css_default.discussionRange,
|
|
20685
|
+
"data-diff-discussion-range": true,
|
|
20686
|
+
children: label
|
|
20687
|
+
})
|
|
20688
|
+
}),
|
|
20689
|
+
(0, react_jsx_runtime.jsx)("span", { className: PendingPanel_module_css_default.flexSpacer }),
|
|
20690
|
+
(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Menu, {
|
|
20691
|
+
open: menuOpen,
|
|
20692
|
+
portal: true,
|
|
20693
|
+
compact: true,
|
|
20694
|
+
align: "end",
|
|
20695
|
+
items: menuItems,
|
|
20696
|
+
onSelect: (id) => {
|
|
20697
|
+
if (id === "delete") onRemove(discussion.id);
|
|
20698
|
+
onMenuOpen(void 0);
|
|
20699
|
+
},
|
|
20700
|
+
onClose: () => {
|
|
20701
|
+
onMenuOpen(void 0);
|
|
20702
|
+
},
|
|
20703
|
+
anchor: (0, react_jsx_runtime.jsx)("button", {
|
|
20704
|
+
type: "button",
|
|
20705
|
+
className: PendingPanel_module_css_default.discussionToggle,
|
|
20706
|
+
"data-diff-discussion-menu": true,
|
|
20707
|
+
"aria-label": t("action.more"),
|
|
20708
|
+
onClick: () => {
|
|
20709
|
+
onMenuOpen(menuOpen ? void 0 : discussion.id);
|
|
20710
|
+
},
|
|
20711
|
+
children: "⋯"
|
|
20712
|
+
})
|
|
20713
|
+
})
|
|
20714
|
+
]
|
|
20715
|
+
}), !discussion.collapsed && (0, react_jsx_runtime.jsxs)("div", {
|
|
20716
|
+
className: PendingPanel_module_css_default.discussionBody,
|
|
20717
|
+
children: [
|
|
20718
|
+
discussion.lost === true && discussion.quote !== void 0 && discussion.quote !== "" && (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)("p", {
|
|
20719
|
+
className: PendingPanel_module_css_default.discussionNote,
|
|
20720
|
+
"data-diff-discussion-quote-label": true,
|
|
20721
|
+
children: t("discussion.outdatedQuote")
|
|
20722
|
+
}), (0, react_jsx_runtime.jsx)(DiscussionQuote, {
|
|
20723
|
+
quote: discussion.quote,
|
|
20724
|
+
lines: discussion.quoteLines,
|
|
20725
|
+
lang,
|
|
20726
|
+
wrap: discussion.quoteWrap === true,
|
|
20727
|
+
split
|
|
20728
|
+
})] }),
|
|
20729
|
+
discussion.hidden !== void 0 && discussion.hidden > 0 && (0, react_jsx_runtime.jsx)("p", {
|
|
20730
|
+
className: PendingPanel_module_css_default.discussionNote,
|
|
20731
|
+
"data-diff-discussion-hidden": true,
|
|
20732
|
+
children: t("discussion.hidden", { count: discussion.hidden })
|
|
20733
|
+
}),
|
|
20734
|
+
discussion.stopped === true && (discussion.reply === void 0 || discussion.reply === "") && discussion.failed !== true && (0, react_jsx_runtime.jsx)("p", {
|
|
20735
|
+
className: PendingPanel_module_css_default.discussionNote,
|
|
20736
|
+
"data-diff-discussion-stopped": true,
|
|
20737
|
+
children: t("discussion.stopped")
|
|
20738
|
+
}),
|
|
20739
|
+
discussion.messages.map((message, index) => message.role === "user" ? (0, react_jsx_runtime.jsx)("p", {
|
|
20740
|
+
className: PendingPanel_module_css_default.discussionUser,
|
|
20741
|
+
"data-diff-discussion-user": true,
|
|
20742
|
+
children: discussionNodes(message.text)
|
|
20743
|
+
}, `u${index}`) : (0, react_jsx_runtime.jsx)("p", {
|
|
20744
|
+
className: PendingPanel_module_css_default.discussionAnswer,
|
|
20745
|
+
"data-diff-discussion-reply": true,
|
|
20746
|
+
children: discussionNodes(message.text)
|
|
20747
|
+
}, `a${index}`)),
|
|
20748
|
+
discussion.reply !== void 0 && discussion.reply !== "" ? (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)("p", {
|
|
20749
|
+
className: PendingPanel_module_css_default.discussionAnswer,
|
|
20750
|
+
"data-diff-discussion-reply": true,
|
|
20751
|
+
children: discussionNodes(discussion.reply)
|
|
20752
|
+
}), writingNote && (0, react_jsx_runtime.jsxs)("p", {
|
|
20753
|
+
className: PendingPanel_module_css_default.discussionNote,
|
|
20754
|
+
"data-diff-discussion-answering": true,
|
|
20755
|
+
children: [t("discussion.answering"), (0, react_jsx_runtime.jsxs)("span", {
|
|
20756
|
+
className: PendingPanel_module_css_default.discussionDots,
|
|
20757
|
+
"data-diff-discussion-dots": true,
|
|
20758
|
+
"aria-hidden": "true",
|
|
20759
|
+
children: [
|
|
20760
|
+
(0, react_jsx_runtime.jsx)("span", { children: "." }),
|
|
20761
|
+
(0, react_jsx_runtime.jsx)("span", { children: "." }),
|
|
20762
|
+
(0, react_jsx_runtime.jsx)("span", { children: "." })
|
|
20763
|
+
]
|
|
20764
|
+
})]
|
|
20765
|
+
})] }) : discussion.failed === true ? (0, react_jsx_runtime.jsx)("p", {
|
|
20766
|
+
className: PendingPanel_module_css_default.discussionNote,
|
|
20767
|
+
"data-diff-discussion-failed": true,
|
|
20768
|
+
children: t("discussion.failed")
|
|
20769
|
+
}) : discussion.asking === true ? (0, react_jsx_runtime.jsxs)("p", {
|
|
20770
|
+
className: PendingPanel_module_css_default.discussionNote,
|
|
20771
|
+
"data-diff-discussion-asking": true,
|
|
20772
|
+
children: [discussion.queued === true ? t("discussion.queued") : t("discussion.thinking"), (0, react_jsx_runtime.jsxs)("span", {
|
|
20773
|
+
className: PendingPanel_module_css_default.discussionDots,
|
|
20774
|
+
"data-diff-discussion-dots": true,
|
|
20775
|
+
"aria-hidden": "true",
|
|
20776
|
+
children: [
|
|
20777
|
+
(0, react_jsx_runtime.jsx)("span", { children: "." }),
|
|
20778
|
+
(0, react_jsx_runtime.jsx)("span", { children: "." }),
|
|
20779
|
+
(0, react_jsx_runtime.jsx)("span", { children: "." })
|
|
20780
|
+
]
|
|
20781
|
+
})]
|
|
20782
|
+
}) : (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)("div", {
|
|
20783
|
+
className: PendingPanel_module_css_default.discussionSlack,
|
|
20784
|
+
"data-diff-discussion-slack": true,
|
|
20785
|
+
"aria-hidden": "true"
|
|
20786
|
+
}), (0, react_jsx_runtime.jsxs)("div", {
|
|
20787
|
+
className: PendingPanel_module_css_default.discussionCompose,
|
|
20788
|
+
children: [(0, react_jsx_runtime.jsx)("input", {
|
|
20789
|
+
className: PendingPanel_module_css_default.discussionInput,
|
|
20790
|
+
"data-diff-discussion-input": true,
|
|
20791
|
+
ref: (element) => {
|
|
20792
|
+
registerInput(discussion.id, element);
|
|
20793
|
+
},
|
|
20794
|
+
value: discussion.draft,
|
|
20795
|
+
placeholder: t("discussion.placeholder"),
|
|
20796
|
+
onChange: (event) => {
|
|
20797
|
+
onDraft(discussion.id, event.target.value);
|
|
20798
|
+
},
|
|
20799
|
+
onKeyDown: (event) => {
|
|
20800
|
+
if (event.key !== "Enter") return;
|
|
20801
|
+
if (event.nativeEvent.isComposing || event.keyCode === 229) return;
|
|
20802
|
+
event.preventDefault();
|
|
20803
|
+
onSend(discussion.id);
|
|
20804
|
+
}
|
|
20805
|
+
}), (0, react_jsx_runtime.jsxs)("button", {
|
|
20806
|
+
type: "button",
|
|
20807
|
+
className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.actionPrimary} ${PendingPanel_module_css_default.discussionSend}`,
|
|
20808
|
+
"data-diff-discussion-send": true,
|
|
20809
|
+
disabled: asking,
|
|
20810
|
+
onClick: () => {
|
|
20811
|
+
onSend(discussion.id);
|
|
20812
|
+
},
|
|
20813
|
+
children: [t("action.comment"), (0, react_jsx_runtime.jsx)(ReturnIcon, {})]
|
|
20814
|
+
})]
|
|
20815
|
+
})] })
|
|
20816
|
+
]
|
|
20817
|
+
})]
|
|
20818
|
+
});
|
|
20819
|
+
}
|
|
20389
20820
|
/** Chip styling for each intra-line run: removed chars and added chars stand out. */
|
|
20390
20821
|
const INTRA_CLASS = {
|
|
20391
20822
|
same: void 0,
|
|
@@ -20517,6 +20948,40 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
20517
20948
|
"[data-diff-copy]"
|
|
20518
20949
|
].join(", ");
|
|
20519
20950
|
/**
|
|
20951
|
+
* Whether a press landed on a row the live selection already covers — the highlighted text itself,
|
|
20952
|
+
* or the blank space beside it on the same line.
|
|
20953
|
+
*
|
|
20954
|
+
* Both are inside the code view, which `KEEPS_SELECTION` leaves to the browser, and the browser
|
|
20955
|
+
* keeps the selection for neither: inside the highlight is where a drag that extends it would
|
|
20956
|
+
* begin, and the blank beside it is chrome, which it never clears a selection from. So a plain
|
|
20957
|
+
* press there left the highlight and the frame standing over a gesture that plainly ended. This is
|
|
20958
|
+
* the one press in the content the panel has to end itself (see `onPanelMouseDown`).
|
|
20959
|
+
*
|
|
20960
|
+
* @param target - the element the press landed on.
|
|
20961
|
+
* @param live - the window's selection, still the one the reader had.
|
|
20962
|
+
* @returns whether that selection covers the pressed row.
|
|
20963
|
+
*/
|
|
20964
|
+
function pressOnSelectedRow(target, live) {
|
|
20965
|
+
if (live === null || live.isCollapsed) return false;
|
|
20966
|
+
const unified = rowRangeOf(live);
|
|
20967
|
+
const split = unified === void 0 ? splitRowRangeOf(live) : void 0;
|
|
20968
|
+
const range = unified ?? split;
|
|
20969
|
+
if (range === void 0) return false;
|
|
20970
|
+
const row = target.closest("[data-diff-row], [data-diff-split-row]");
|
|
20971
|
+
if (row === null) return false;
|
|
20972
|
+
let index;
|
|
20973
|
+
if (unified !== void 0) {
|
|
20974
|
+
const value = Number(row.dataset.diffRow);
|
|
20975
|
+
index = Number.isFinite(value) ? value : void 0;
|
|
20976
|
+
} else {
|
|
20977
|
+
const info = splitRowInfoAt(target);
|
|
20978
|
+
if (info === void 0 || range.side !== void 0 && info.side !== range.side) return false;
|
|
20979
|
+
index = info.pairIndex;
|
|
20980
|
+
}
|
|
20981
|
+
if (index === void 0) return false;
|
|
20982
|
+
return index >= range.start && index <= range.end;
|
|
20983
|
+
}
|
|
20984
|
+
/**
|
|
20520
20985
|
* Whether a key event came from a text field that owns its own keys (`Esc`,
|
|
20521
20986
|
* cursor moves). The chat composer is the one that matters: the panel leaves it
|
|
20522
20987
|
* alone even while its own search bar is open.
|
|
@@ -20657,6 +21122,22 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
20657
21122
|
}
|
|
20658
21123
|
return block.oldStart <= oldMin && block.oldEnd >= oldMax && block.newStart <= newMin && block.newEnd >= newMax;
|
|
20659
21124
|
}
|
|
21125
|
+
/**
|
|
21126
|
+
* Which change block to focus once the operated one has left the diff.
|
|
21127
|
+
*
|
|
21128
|
+
* The operated block(s) are gone, so the change that followed them slid into the slot they held: focusing
|
|
21129
|
+
* that same index is what recenters and flashes the NEXT change. An operated range that reached the END of
|
|
21130
|
+
* the diff has no such change — every block still pending is above the reader — so the walk wraps to the
|
|
21131
|
+
* first one, the same wrap the prev/next stepping does. Clamping to the last index instead left the focus
|
|
21132
|
+
* pointing past the shorter diff, and then nothing was focused, flashed or scrolled at all.
|
|
21133
|
+
*
|
|
21134
|
+
* @param operated - the index the operated range started at.
|
|
21135
|
+
* @param count - how many blocks the diff holds NOW, after the action.
|
|
21136
|
+
* @returns the block index to focus.
|
|
21137
|
+
*/
|
|
21138
|
+
function blockAfterAction(operated, count) {
|
|
21139
|
+
return operated >= count ? 0 : operated;
|
|
21140
|
+
}
|
|
20660
21141
|
/** Row indices whose text matches `query` under the options; empty for ''. Counted
|
|
20661
21142
|
* through the same matcher the highlights use, so the tally can never disagree
|
|
20662
21143
|
* with what is drawn. */
|
|
@@ -20726,12 +21207,13 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
20726
21207
|
* one side is longer. The gutter and code are top-aligned so sub-lines line up
|
|
20727
21208
|
* across the divider.
|
|
20728
21209
|
*/
|
|
20729
|
-
function SplitSideRow({ index, side, wrapped, runs, kind, isLeft, height, focused, searchHit, searchCurrent, searchQuery, searchOptions, onHover, intra }) {
|
|
21210
|
+
function SplitSideRow({ index, side, wrapped, runs, kind, isLeft, height, focused, discussed, searchHit, searchCurrent, searchQuery, searchOptions, onHover, intra }) {
|
|
20730
21211
|
const tint = isLeft ? kind === "del" || kind === "replace" ? PendingPanel_module_css_default.splitLdel : "" : kind === "add" || kind === "replace" ? PendingPanel_module_css_default.splitRadd : "";
|
|
20731
21212
|
return (0, react_jsx_runtime.jsxs)("div", {
|
|
20732
|
-
className: PendingPanel_module_css_default.line
|
|
21213
|
+
className: `${PendingPanel_module_css_default.line}${discussed ? " " + PendingPanel_module_css_default.rowDiscussed : ""}`,
|
|
20733
21214
|
style: { height },
|
|
20734
21215
|
"data-diff-split-row": true,
|
|
21216
|
+
"data-diff-discussion-band": discussed ? "" : void 0,
|
|
20735
21217
|
"data-diff-split-index": index,
|
|
20736
21218
|
"data-diff-split-side": isLeft ? "left" : "right",
|
|
20737
21219
|
"data-diff-focused": focused ? "" : void 0,
|
|
@@ -20750,7 +21232,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
20750
21232
|
});
|
|
20751
21233
|
}
|
|
20752
21234
|
/** The two-column (side-by-side) whole-file diff view. */
|
|
20753
|
-
const SplitDiff = (0, react.forwardRef)(function SplitDiff({ file, model, runs, langWrap, tabWidthSpaces, busy, t, selection, leadRows, onBlockKeep, onBlockRevert, onWrapToast, onVisibleLines }, ref) {
|
|
21235
|
+
const SplitDiff = (0, react.forwardRef)(function SplitDiff({ file, model, runs, langWrap, tabWidthSpaces, busy, t, selection, leadRows, onBlockKeep, onBlockRevert, onWrapToast, onVisibleLines, discussions, renderDiscussion, selectionComment, rulerRuns, gotoDialog }, ref) {
|
|
20754
21236
|
const ROW_HEIGHT_PX = diffLineHeight();
|
|
20755
21237
|
const NAV_ANCHOR_TOLERANCE_PX = ROW_HEIGHT_PX / 4;
|
|
20756
21238
|
const { pairs, pairOfRow } = (0, react.useMemo)(() => computeSideBySideDiff(model.diff.rows, true), [model]);
|
|
@@ -20768,6 +21250,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
20768
21250
|
return map;
|
|
20769
21251
|
}, [model, pairOfRow]);
|
|
20770
21252
|
const bodyRef = (0, react.useRef)(null);
|
|
21253
|
+
const splitRootRef = (0, react.useRef)(null);
|
|
20771
21254
|
const [scrollTop, setScrollTop] = (0, react.useState)(0);
|
|
20772
21255
|
const [viewportH, setViewportH] = (0, react.useState)(0);
|
|
20773
21256
|
const [bodyWidth, setBodyWidth] = (0, react.useState)(0);
|
|
@@ -20868,15 +21351,100 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
20868
21351
|
if (pairWrapped === null) return null;
|
|
20869
21352
|
return pairWrapped.map((w) => Math.max(w.left?.length ?? 1, w.right?.length ?? 1) * ROW_HEIGHT_PX);
|
|
20870
21353
|
}, [pairWrapped]);
|
|
21354
|
+
/** The model rows a thread annotates: the wash their halves wear (see `rowDiscussed`). */
|
|
21355
|
+
const discussedRows = (0, react.useMemo)(() => {
|
|
21356
|
+
const set = /* @__PURE__ */ new Set();
|
|
21357
|
+
for (const discussion of discussions ?? []) {
|
|
21358
|
+
if (discussion.lost === true) continue;
|
|
21359
|
+
for (let row = Math.max(0, discussion.anchor.start); row <= Math.min(discussion.anchor.end, model.diff.rows.length - 1); row++) set.add(row);
|
|
21360
|
+
}
|
|
21361
|
+
return set;
|
|
21362
|
+
}, [discussions, model]);
|
|
21363
|
+
/**
|
|
21364
|
+
* The pairs that wear the wash: a pair does when either of its rows is one a thread annotates. Per
|
|
21365
|
+
* pair rather than per half, because a commented ADDED line has no old-side row at all — asking each
|
|
21366
|
+
* half about its own row left the empty half bare, and the band is what says the pair carries a
|
|
21367
|
+
* thread. Both halves take it from either row, the way the single-column view washes the whole row.
|
|
21368
|
+
*/
|
|
21369
|
+
const discussedPairs = (0, react.useMemo)(() => {
|
|
21370
|
+
const set = /* @__PURE__ */ new Set();
|
|
21371
|
+
for (const [pair, rows] of pairRowIndices) {
|
|
21372
|
+
const left = rows.left === void 0 ? false : discussedRows.has(rows.left);
|
|
21373
|
+
const right = rows.right === void 0 ? false : discussedRows.has(rows.right);
|
|
21374
|
+
if (left || right) set.add(pair);
|
|
21375
|
+
}
|
|
21376
|
+
return set;
|
|
21377
|
+
}, [pairRowIndices, discussedRows]);
|
|
21378
|
+
/** The threads that hang under each pair, by the row their anchor ends in. */
|
|
21379
|
+
const pairDiscussions = (0, react.useMemo)(() => {
|
|
21380
|
+
const map = /* @__PURE__ */ new Map();
|
|
21381
|
+
for (const discussion of discussions ?? []) {
|
|
21382
|
+
const pair = pairOfRow.get(discussion.anchor.end) ?? pairOfRow.get(discussion.anchor.start);
|
|
21383
|
+
if (pair === void 0) continue;
|
|
21384
|
+
const list = map.get(pair);
|
|
21385
|
+
if (list === void 0) map.set(pair, [discussion]);
|
|
21386
|
+
else list.push(discussion);
|
|
21387
|
+
}
|
|
21388
|
+
return map;
|
|
21389
|
+
}, [discussions, pairOfRow]);
|
|
21390
|
+
/**
|
|
21391
|
+
* The height a pair holds for the threads hanging under it, in px.
|
|
21392
|
+
*
|
|
21393
|
+
* A thread's rows are the thread's own (see `THREAD_ROW_PX`), not the code's, so a block off the
|
|
21394
|
+
* code's grid still lands exactly where the height table says. Both columns reserve this much —
|
|
21395
|
+
* the cards themselves are drawn over both (see the layer below) — which is what keeps the two
|
|
21396
|
+
* halves from drifting apart under a thread either of them shows.
|
|
21397
|
+
*/
|
|
21398
|
+
const discussionPx = (0, react.useCallback)((k) => (pairDiscussions.get(k) ?? []).reduce((px, discussion) => px + discussionRows(discussion) * THREAD_ROW_PX, 0), [pairDiscussions]);
|
|
20871
21399
|
const pairOffsets = (0, react.useMemo)(() => {
|
|
20872
|
-
if (pairHeights === null) return null;
|
|
20873
|
-
const offs = new Array(
|
|
21400
|
+
if (pairHeights === null && pairDiscussions.size === 0) return null;
|
|
21401
|
+
const offs = new Array(pairCount + 1);
|
|
20874
21402
|
offs[0] = 0;
|
|
20875
|
-
for (let i = 0; i <
|
|
21403
|
+
for (let i = 0; i < pairCount; i++) offs[i + 1] = offs[i] + (pairHeights === null ? ROW_HEIGHT_PX : pairHeights[i] ?? ROW_HEIGHT_PX) + discussionPx(i);
|
|
20876
21404
|
return offs;
|
|
20877
|
-
}, [
|
|
21405
|
+
}, [
|
|
21406
|
+
pairHeights,
|
|
21407
|
+
pairCount,
|
|
21408
|
+
discussionPx,
|
|
21409
|
+
pairDiscussions
|
|
21410
|
+
]);
|
|
20878
21411
|
const totalHeight = pairOffsets === null ? pairCount * ROW_HEIGHT_PX : pairOffsets[pairCount] ?? 0;
|
|
20879
21412
|
const off = (k) => pairOffsets === null ? k * ROW_HEIGHT_PX : pairOffsets[Math.max(0, Math.min(k, pairCount))] ?? 0;
|
|
21413
|
+
/**
|
|
21414
|
+
* The overview ruler's markers, in the height table's own units: a run's rows are mapped to the PAIRS
|
|
21415
|
+
* they sit in, because pairs are what this view's offsets measure. A change that renders on both sides
|
|
21416
|
+
* — a del pair with the add beside it — lands in the same band and contributes both markers, exactly
|
|
21417
|
+
* like the preview's double column: the ruler says "this stretch changed", and which side changed is
|
|
21418
|
+
* what the two columns themselves show.
|
|
21419
|
+
*/
|
|
21420
|
+
const rulerMarkersNow = (0, react.useMemo)(() => {
|
|
21421
|
+
if (totalHeight <= 0 || pairCount === 0) return [];
|
|
21422
|
+
const at = (k) => pairOffsets === null ? k * ROW_HEIGHT_PX : pairOffsets[Math.max(0, Math.min(k, pairCount))] ?? 0;
|
|
21423
|
+
return rulerRuns.flatMap((run) => {
|
|
21424
|
+
let first = -1;
|
|
21425
|
+
let last = -1;
|
|
21426
|
+
for (let row = run.start; row <= run.end; row++) {
|
|
21427
|
+
const pair = pairOfRow.get(row);
|
|
21428
|
+
if (pair === void 0) continue;
|
|
21429
|
+
if (first === -1) first = pair;
|
|
21430
|
+
last = pair;
|
|
21431
|
+
}
|
|
21432
|
+
if (first === -1) return [];
|
|
21433
|
+
const top = pairOffsets === null ? first / pairCount : at(first) / totalHeight;
|
|
21434
|
+
const bottom = pairOffsets === null ? (last + 1) / pairCount : at(last + 1) / totalHeight;
|
|
21435
|
+
return [{
|
|
21436
|
+
top: top * 100,
|
|
21437
|
+
height: Math.max(0, bottom - top) * 100,
|
|
21438
|
+
kind: run.kind
|
|
21439
|
+
}];
|
|
21440
|
+
});
|
|
21441
|
+
}, [
|
|
21442
|
+
rulerRuns,
|
|
21443
|
+
pairOfRow,
|
|
21444
|
+
pairCount,
|
|
21445
|
+
pairOffsets,
|
|
21446
|
+
totalHeight
|
|
21447
|
+
]);
|
|
20880
21448
|
const pairHeightAt = (k) => pairHeights === null ? ROW_HEIGHT_PX : pairHeights[k] ?? ROW_HEIGHT_PX;
|
|
20881
21449
|
const widestSide = (0, react.useMemo)(() => {
|
|
20882
21450
|
let left = 0;
|
|
@@ -20910,11 +21478,49 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
20910
21478
|
tabWidthSpaces,
|
|
20911
21479
|
bodyWidth
|
|
20912
21480
|
]);
|
|
21481
|
+
const ctrlHeldRef = (0, react.useRef)(false);
|
|
21482
|
+
(0, react.useEffect)(() => {
|
|
21483
|
+
const track = (event) => {
|
|
21484
|
+
ctrlHeldRef.current = event.ctrlKey || event.metaKey;
|
|
21485
|
+
};
|
|
21486
|
+
const release = () => {
|
|
21487
|
+
ctrlHeldRef.current = false;
|
|
21488
|
+
};
|
|
21489
|
+
window.addEventListener("keydown", track);
|
|
21490
|
+
window.addEventListener("keyup", track);
|
|
21491
|
+
window.addEventListener("blur", release);
|
|
21492
|
+
return () => {
|
|
21493
|
+
window.removeEventListener("keydown", track);
|
|
21494
|
+
window.removeEventListener("keyup", track);
|
|
21495
|
+
window.removeEventListener("blur", release);
|
|
21496
|
+
};
|
|
21497
|
+
}, []);
|
|
21498
|
+
/** A strip offset this view wrote itself, so the follow-up scroll event is not read as a new drag. */
|
|
21499
|
+
const mirroredRef = (0, react.useRef)(void 0);
|
|
20913
21500
|
const onHScroll = (0, react.useCallback)((side) => {
|
|
20914
21501
|
const strip = side === "left" ? leftHScrollRef.current : rightHScrollRef.current;
|
|
20915
|
-
|
|
20916
|
-
|
|
20917
|
-
|
|
21502
|
+
if (strip === null) return;
|
|
21503
|
+
const mirrored = mirroredRef.current;
|
|
21504
|
+
const follows = mirrored !== void 0 && mirrored.side === side && mirrored.value === strip.scrollLeft;
|
|
21505
|
+
if (follows) mirroredRef.current = void 0;
|
|
21506
|
+
const move = (which, offset) => {
|
|
21507
|
+
const col = which === "left" ? leftColRef.current : rightColRef.current;
|
|
21508
|
+
if (col !== null) col.scrollLeft = offset;
|
|
21509
|
+
const quotes = splitRootRef.current?.querySelectorAll(`[data-diff-quote-text][data-diff-quote-side="${which}"]`);
|
|
21510
|
+
for (const text of quotes ?? []) text.scrollLeft = offset;
|
|
21511
|
+
};
|
|
21512
|
+
move(side, strip.scrollLeft);
|
|
21513
|
+
if (follows || !ctrlHeldRef.current) return;
|
|
21514
|
+
const otherSide = side === "left" ? "right" : "left";
|
|
21515
|
+
const otherStrip = otherSide === "left" ? leftHScrollRef.current : rightHScrollRef.current;
|
|
21516
|
+
move(otherSide, strip.scrollLeft);
|
|
21517
|
+
if (otherStrip !== null && otherStrip.scrollLeft !== strip.scrollLeft) {
|
|
21518
|
+
mirroredRef.current = {
|
|
21519
|
+
side: otherSide,
|
|
21520
|
+
value: strip.scrollLeft
|
|
21521
|
+
};
|
|
21522
|
+
otherStrip.scrollLeft = strip.scrollLeft;
|
|
21523
|
+
}
|
|
20918
21524
|
}, []);
|
|
20919
21525
|
const searchMatches = (0, react.useMemo)(() => searchPairs(pairs, searchQuery, search.options), [
|
|
20920
21526
|
pairs,
|
|
@@ -21008,15 +21614,17 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
21008
21614
|
if (body.scrollTop !== clamped) body.scrollTop = clamped;
|
|
21009
21615
|
setScrollTop(clamped);
|
|
21010
21616
|
};
|
|
21617
|
+
const blockCountRef = (0, react.useRef)(0);
|
|
21618
|
+
blockCountRef.current = model.blocks.length;
|
|
21011
21619
|
const handleBlockAction = async (action) => {
|
|
21012
21620
|
const operated = hoveredBlock ?? hoveredBlockRef.current;
|
|
21013
21621
|
if (operated === void 0) return;
|
|
21014
21622
|
const range = blockRanges[operated];
|
|
21015
21623
|
if (range === void 0) return;
|
|
21016
21624
|
await (action === "keep" ? onBlockKeep(file.sessionId, file.id, range) : onBlockRevert(file.sessionId, file.id, range));
|
|
21017
|
-
const count =
|
|
21625
|
+
const count = blockCountRef.current;
|
|
21018
21626
|
if (count === 0) return;
|
|
21019
|
-
const next =
|
|
21627
|
+
const next = blockAfterAction(operated, count);
|
|
21020
21628
|
setFocus(next);
|
|
21021
21629
|
setHoveredBlock(void 0);
|
|
21022
21630
|
bumpFlash(false);
|
|
@@ -21091,8 +21699,30 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
21091
21699
|
goSearch(direction);
|
|
21092
21700
|
return true;
|
|
21093
21701
|
};
|
|
21702
|
+
/**
|
|
21703
|
+
* The row this view was asked to land on — the comments list's jump into a file that is already open —
|
|
21704
|
+
* and whether it is a thread's own BOX rather than a place in the code. The centering effect below
|
|
21705
|
+
* lands it at the pair that row is in (or at the box hanging under that pair) rather than at its
|
|
21706
|
+
* block's first pair, which is the precision the single-column view has; spent once, like every
|
|
21707
|
+
* landing.
|
|
21708
|
+
*/
|
|
21709
|
+
const landingRowRef = (0, react.useRef)(void 0);
|
|
21710
|
+
/** A row this view was asked to frame and land on rather than a whole block (a go-to-line). */
|
|
21711
|
+
const flashRowRef = (0, react.useRef)(void 0);
|
|
21712
|
+
const land = (0, react.useCallback)((row, toCard = false, rowFlash = false) => {
|
|
21713
|
+
landingRowRef.current = {
|
|
21714
|
+
row,
|
|
21715
|
+
toCard
|
|
21716
|
+
};
|
|
21717
|
+
const pair = pairOfRow.get(row);
|
|
21718
|
+
const block = pair === void 0 ? void 0 : blockIndexByPair.get(pair);
|
|
21719
|
+
if (block !== void 0) setFocus(block);
|
|
21720
|
+
flashRowRef.current = rowFlash ? row : void 0;
|
|
21721
|
+
setFlashKey((key) => key + 1);
|
|
21722
|
+
}, [pairOfRow, blockIndexByPair]);
|
|
21094
21723
|
(0, react.useImperativeHandle)(ref, () => ({
|
|
21095
21724
|
jump,
|
|
21725
|
+
land,
|
|
21096
21726
|
openSearch,
|
|
21097
21727
|
toggleSearch,
|
|
21098
21728
|
closeSearch,
|
|
@@ -21101,6 +21731,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
21101
21731
|
toggleMatchWholeWord
|
|
21102
21732
|
}), [
|
|
21103
21733
|
jump,
|
|
21734
|
+
land,
|
|
21104
21735
|
openSearch,
|
|
21105
21736
|
toggleSearch,
|
|
21106
21737
|
closeSearch,
|
|
@@ -21114,7 +21745,10 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
21114
21745
|
if (block === void 0) return;
|
|
21115
21746
|
const body = bodyRef.current;
|
|
21116
21747
|
if (body === null) return;
|
|
21117
|
-
const
|
|
21748
|
+
const landed = landingRowRef.current;
|
|
21749
|
+
landingRowRef.current = void 0;
|
|
21750
|
+
const from = landed === void 0 ? block.start : pairOfRow.get(landed.row) ?? block.start;
|
|
21751
|
+
const target = off(from) + (landed?.toCard === true ? pairHeightAt(from) : 0) - leadRows * ROW_HEIGHT_PX;
|
|
21118
21752
|
const clamped = Math.max(0, Math.min(target, body.scrollHeight - body.clientHeight));
|
|
21119
21753
|
if (body.scrollTop !== clamped) body.scrollTop = clamped;
|
|
21120
21754
|
setScrollTop(clamped);
|
|
@@ -21143,22 +21777,186 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
21143
21777
|
};
|
|
21144
21778
|
const blockRanges = (0, react.useMemo)(() => model.blocks.map((block) => blockRangesOf(model.diff.rows, block)), [model]);
|
|
21145
21779
|
const focusedBlock = blockOfPair[focus];
|
|
21146
|
-
const
|
|
21147
|
-
const
|
|
21780
|
+
const flashRow = flashRowRef.current;
|
|
21781
|
+
const flashTop = flashRow !== void 0 ? Math.max(0, off(pairOfRow.get(flashRow) ?? flashRow) - scrollTop) : focusedBlock === void 0 ? 0 : Math.max(0, off(focusedBlock.start) - scrollTop);
|
|
21782
|
+
const flashBottom = flashRow !== void 0 ? Math.min(viewportH > 0 ? viewportH : Number.POSITIVE_INFINITY, off((pairOfRow.get(flashRow) ?? flashRow) + 1) - scrollTop) : focusedBlock === void 0 ? 0 : Math.min(viewportH > 0 ? viewportH : Number.POSITIVE_INFINITY, off(focusedBlock.end + 1) - scrollTop);
|
|
21148
21783
|
const flashHeight = Math.max(0, flashBottom - flashTop);
|
|
21149
21784
|
const blockActionsTop = hoveredBlock === void 0 || blockOfPair[hoveredBlock] === void 0 ? 0 : Math.max(0, Math.min(off(blockOfPair[hoveredBlock].end + 1) - scrollTop, Math.max(0, viewportH - BLOCK_ACTIONS_FRAME_PX)));
|
|
21785
|
+
/**
|
|
21786
|
+
* How a press in the side-by-side view makes a selection. Left to the browser, a drag that crosses
|
|
21787
|
+
* the divider takes in the rest of the column it began in and then the other one upwards — the
|
|
21788
|
+
* pointer's own position decides that, and the selection cannot be written to stop it (a write under
|
|
21789
|
+
* a live drag makes the browser drop the drag instead). An editor has no such problem because a
|
|
21790
|
+
* pointer there is only ever a coordinate: it computes the position inside the editor, so a drag
|
|
21791
|
+
* cannot leave it, which is how VS Code's own text keeps a selection inside its box. The same is
|
|
21792
|
+
* done here for the column the press began in: x is taken inside that column's code cell, so
|
|
21793
|
+
* dragging past the divider keeps the row the pointer is on and the line numbers never join the
|
|
21794
|
+
* selection, and y is taken inside the scroller, which is scrolled here when the pointer leaves it.
|
|
21795
|
+
* Double and triple clicks are still the browser's (`detail` above one), so word and line selection
|
|
21796
|
+
* are unchanged.
|
|
21797
|
+
*
|
|
21798
|
+
* Touch cannot be driven this way — the platform owns the long press, and preventing the touch would
|
|
21799
|
+
* take the scroll with it — so there the other column is simply made unselectable while the press
|
|
21800
|
+
* lasts (see `.splitSealed`), which stops the caret from entering it at all; the cost is that the
|
|
21801
|
+
* caret then resolves to the nearest selectable position rather than to the row under the finger.
|
|
21802
|
+
*/
|
|
21803
|
+
(0, react.useEffect)(() => {
|
|
21804
|
+
const root = splitRootRef.current;
|
|
21805
|
+
const scroller = bodyRef.current;
|
|
21806
|
+
if (root === null || scroller === null) return;
|
|
21807
|
+
const caretApi = document;
|
|
21808
|
+
const canDrive = caretApi.caretRangeFromPoint !== void 0 || caretApi.caretPositionFromPoint !== void 0;
|
|
21809
|
+
let drag = null;
|
|
21810
|
+
let frame = 0;
|
|
21811
|
+
let point = {
|
|
21812
|
+
x: 0,
|
|
21813
|
+
y: 0
|
|
21814
|
+
};
|
|
21815
|
+
let pointerType;
|
|
21816
|
+
/** The position a point names inside `column`: its row for y, and that row's code cell for x. */
|
|
21817
|
+
const positionIn = (column, clientX, clientY) => {
|
|
21818
|
+
const rows = column.querySelectorAll("[data-diff-split-row]");
|
|
21819
|
+
if (rows.length === 0) return void 0;
|
|
21820
|
+
let row = rows[rows.length - 1];
|
|
21821
|
+
for (const candidate of rows) if (clientY < candidate.getBoundingClientRect().bottom) {
|
|
21822
|
+
row = candidate;
|
|
21823
|
+
break;
|
|
21824
|
+
}
|
|
21825
|
+
const box = row.getBoundingClientRect();
|
|
21826
|
+
const y = Math.min(Math.max(clientY, box.top + 1), box.bottom - 1);
|
|
21827
|
+
const code = row.querySelector("[data-diff-code]");
|
|
21828
|
+
if (code === null) return void 0;
|
|
21829
|
+
const cell = code.getBoundingClientRect();
|
|
21830
|
+
const x = Math.min(Math.max(clientX, cell.left + 1), cell.right - 1);
|
|
21831
|
+
const found = caretAtPoint(x, y);
|
|
21832
|
+
if (found !== void 0 && code.contains(found.node)) return found;
|
|
21833
|
+
const edges = textEdgesOf(code);
|
|
21834
|
+
if (edges === void 0) return void 0;
|
|
21835
|
+
return x < (cell.left + cell.right) / 2 ? {
|
|
21836
|
+
node: edges.first,
|
|
21837
|
+
offset: 0
|
|
21838
|
+
} : {
|
|
21839
|
+
node: edges.last,
|
|
21840
|
+
offset: edges.last.length
|
|
21841
|
+
};
|
|
21842
|
+
};
|
|
21843
|
+
const apply = () => {
|
|
21844
|
+
if (drag === null) return;
|
|
21845
|
+
const selection = window.getSelection();
|
|
21846
|
+
const extent = positionIn(drag.column, point.x, point.y);
|
|
21847
|
+
if (selection === null || extent === void 0) return;
|
|
21848
|
+
selection.setBaseAndExtent(drag.anchor.node, drag.anchor.offset, extent.node, extent.offset);
|
|
21849
|
+
};
|
|
21850
|
+
/** One pass per frame: the position first, then a scroll if the pointer is outside the scroller. */
|
|
21851
|
+
const tick = () => {
|
|
21852
|
+
frame = 0;
|
|
21853
|
+
if (drag === null) return;
|
|
21854
|
+
const box = scroller.getBoundingClientRect();
|
|
21855
|
+
const out = point.y < box.top ? point.y - box.top : point.y > box.bottom ? point.y - box.bottom : 0;
|
|
21856
|
+
if (out !== 0) {
|
|
21857
|
+
const step = Math.min(ROW_HEIGHT_PX * 3, Math.max(ROW_HEIGHT_PX, Math.abs(out) / 3));
|
|
21858
|
+
scroller.scrollTop += Math.sign(out) * step;
|
|
21859
|
+
}
|
|
21860
|
+
apply();
|
|
21861
|
+
if (out !== 0) frame = window.requestAnimationFrame(tick);
|
|
21862
|
+
};
|
|
21863
|
+
/** The column a node sits in, or undefined for anything else in the view (a card, a frame). */
|
|
21864
|
+
const columnOf = (target) => {
|
|
21865
|
+
const row = target.closest("[data-diff-split-row]");
|
|
21866
|
+
if (row === null) return void 0;
|
|
21867
|
+
const left = leftColRef.current;
|
|
21868
|
+
const right = rightColRef.current;
|
|
21869
|
+
if (left !== null && left.contains(row)) return left;
|
|
21870
|
+
return right !== null && right.contains(row) ? right : void 0;
|
|
21871
|
+
};
|
|
21872
|
+
const onPointerDown = (event) => {
|
|
21873
|
+
pointerType = event.pointerType;
|
|
21874
|
+
if (event.pointerType === "mouse") return;
|
|
21875
|
+
const target = event.target;
|
|
21876
|
+
if (!(target instanceof Element) || columnOf(target) === void 0) return;
|
|
21877
|
+
const sealed = PendingPanel_module_css_default.splitSealed;
|
|
21878
|
+
const side = PendingPanel_module_css_default.splitSealedLeft;
|
|
21879
|
+
const other = PendingPanel_module_css_default.splitSealedRight;
|
|
21880
|
+
if (sealed === void 0 || side === void 0 || other === void 0) return;
|
|
21881
|
+
document.body.classList.add(sealed, target.closest("[data-diff-split-side=\"left\"]") !== null ? side : other);
|
|
21882
|
+
};
|
|
21883
|
+
const onMouseDown = (event) => {
|
|
21884
|
+
if (!canDrive) return;
|
|
21885
|
+
if (pointerType !== void 0 && pointerType !== "mouse") return;
|
|
21886
|
+
if (event.button !== 0 || event.detail !== 1 || event.shiftKey || event.ctrlKey || event.metaKey || event.altKey) return;
|
|
21887
|
+
const target = event.target;
|
|
21888
|
+
if (!(target instanceof Element)) return;
|
|
21889
|
+
const column = columnOf(target);
|
|
21890
|
+
if (column === void 0) return;
|
|
21891
|
+
const anchor = positionIn(column, event.clientX, event.clientY);
|
|
21892
|
+
if (anchor === void 0) return;
|
|
21893
|
+
event.preventDefault();
|
|
21894
|
+
scroller.focus();
|
|
21895
|
+
point = {
|
|
21896
|
+
x: event.clientX,
|
|
21897
|
+
y: event.clientY
|
|
21898
|
+
};
|
|
21899
|
+
drag = {
|
|
21900
|
+
column,
|
|
21901
|
+
anchor
|
|
21902
|
+
};
|
|
21903
|
+
apply();
|
|
21904
|
+
};
|
|
21905
|
+
const onMove = (event) => {
|
|
21906
|
+
if (drag === null) return;
|
|
21907
|
+
point = {
|
|
21908
|
+
x: event.clientX,
|
|
21909
|
+
y: event.clientY
|
|
21910
|
+
};
|
|
21911
|
+
if (frame === 0) frame = window.requestAnimationFrame(tick);
|
|
21912
|
+
};
|
|
21913
|
+
const release = () => {
|
|
21914
|
+
const sealed = PendingPanel_module_css_default.splitSealed;
|
|
21915
|
+
const side = PendingPanel_module_css_default.splitSealedLeft;
|
|
21916
|
+
const other = PendingPanel_module_css_default.splitSealedRight;
|
|
21917
|
+
if (sealed !== void 0 && side !== void 0 && other !== void 0) document.body.classList.remove(sealed, side, other);
|
|
21918
|
+
};
|
|
21919
|
+
const stop = () => {
|
|
21920
|
+
drag = null;
|
|
21921
|
+
release();
|
|
21922
|
+
if (frame !== 0) {
|
|
21923
|
+
window.cancelAnimationFrame(frame);
|
|
21924
|
+
frame = 0;
|
|
21925
|
+
}
|
|
21926
|
+
};
|
|
21927
|
+
root.addEventListener("pointerdown", onPointerDown, true);
|
|
21928
|
+
root.addEventListener("mousedown", onMouseDown, true);
|
|
21929
|
+
document.addEventListener("pointermove", onMove, true);
|
|
21930
|
+
document.addEventListener("pointerup", stop, true);
|
|
21931
|
+
document.addEventListener("pointercancel", stop, true);
|
|
21932
|
+
document.addEventListener("touchend", release, true);
|
|
21933
|
+
document.addEventListener("touchcancel", release, true);
|
|
21934
|
+
window.addEventListener("blur", stop);
|
|
21935
|
+
return () => {
|
|
21936
|
+
root.removeEventListener("pointerdown", onPointerDown, true);
|
|
21937
|
+
root.removeEventListener("mousedown", onMouseDown, true);
|
|
21938
|
+
document.removeEventListener("pointermove", onMove, true);
|
|
21939
|
+
document.removeEventListener("pointerup", stop, true);
|
|
21940
|
+
document.removeEventListener("pointercancel", stop, true);
|
|
21941
|
+
document.removeEventListener("touchend", release, true);
|
|
21942
|
+
document.removeEventListener("touchcancel", release, true);
|
|
21943
|
+
window.removeEventListener("blur", stop);
|
|
21944
|
+
stop();
|
|
21945
|
+
};
|
|
21946
|
+
}, []);
|
|
21150
21947
|
return (0, react_jsx_runtime.jsxs)("div", {
|
|
21151
21948
|
className: PendingPanel_module_css_default.splitRoot,
|
|
21949
|
+
ref: splitRootRef,
|
|
21152
21950
|
onMouseLeave: () => setHoveredBlock(void 0),
|
|
21153
21951
|
children: [
|
|
21154
|
-
(0, react_jsx_runtime.
|
|
21952
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
21155
21953
|
className: `${PendingPanel_module_css_default.diffBody} ${PendingPanel_module_css_default.diffBodySplit}`,
|
|
21156
21954
|
ref: bodyRef,
|
|
21157
21955
|
tabIndex: 0,
|
|
21158
21956
|
onScroll,
|
|
21159
21957
|
style: { tabSize: tabWidthSpaces },
|
|
21160
21958
|
"data-diff-body": true,
|
|
21161
|
-
children: (0, react_jsx_runtime.jsxs)("div", {
|
|
21959
|
+
children: [(0, react_jsx_runtime.jsxs)("div", {
|
|
21162
21960
|
className: PendingPanel_module_css_default.splitCols,
|
|
21163
21961
|
children: [
|
|
21164
21962
|
(0, react_jsx_runtime.jsx)("div", {
|
|
@@ -21178,7 +21976,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
21178
21976
|
const index = start + offset;
|
|
21179
21977
|
const leftRuns = pair.left === void 0 ? void 0 : runs?.oldRuns?.[(pair.left.line ?? 0) - 1];
|
|
21180
21978
|
const sideIndex = pairRowIndices.get(index);
|
|
21181
|
-
return (0, react_jsx_runtime.jsx)(SplitSideRow, {
|
|
21979
|
+
return (0, react_jsx_runtime.jsxs)(react.Fragment, { children: [(0, react_jsx_runtime.jsx)(SplitSideRow, {
|
|
21182
21980
|
index,
|
|
21183
21981
|
side: pair.left,
|
|
21184
21982
|
wrapped: pairWrapped?.[index]?.left,
|
|
@@ -21192,8 +21990,14 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
21192
21990
|
searchQuery,
|
|
21193
21991
|
searchOptions: search.options,
|
|
21194
21992
|
onHover: () => onPairHover(index),
|
|
21195
|
-
intra: sideIndex?.left === void 0 ? void 0 : model.intra.get(sideIndex.left)
|
|
21196
|
-
|
|
21993
|
+
intra: sideIndex?.left === void 0 ? void 0 : model.intra.get(sideIndex.left),
|
|
21994
|
+
discussed: discussedPairs.has(index)
|
|
21995
|
+
}), discussionPx(index) > 0 && (0, react_jsx_runtime.jsx)("div", {
|
|
21996
|
+
className: PendingPanel_module_css_default.vSpacer,
|
|
21997
|
+
"data-diff-discussion-space": discussionPx(index),
|
|
21998
|
+
style: { height: discussionPx(index) },
|
|
21999
|
+
"aria-hidden": "true"
|
|
22000
|
+
})] }, index);
|
|
21197
22001
|
}),
|
|
21198
22002
|
end < pairCount && (0, react_jsx_runtime.jsx)("div", {
|
|
21199
22003
|
className: PendingPanel_module_css_default.vSpacer,
|
|
@@ -21221,7 +22025,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
21221
22025
|
const index = start + offset;
|
|
21222
22026
|
const rightRuns = pair.right === void 0 ? void 0 : runs?.newRuns?.[(pair.right.line ?? 0) - 1];
|
|
21223
22027
|
const sideIndex = pairRowIndices.get(index);
|
|
21224
|
-
return (0, react_jsx_runtime.jsx)(SplitSideRow, {
|
|
22028
|
+
return (0, react_jsx_runtime.jsxs)(react.Fragment, { children: [(0, react_jsx_runtime.jsx)(SplitSideRow, {
|
|
21225
22029
|
index,
|
|
21226
22030
|
side: pair.right,
|
|
21227
22031
|
wrapped: pairWrapped?.[index]?.right,
|
|
@@ -21235,8 +22039,14 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
21235
22039
|
searchQuery,
|
|
21236
22040
|
searchOptions: search.options,
|
|
21237
22041
|
onHover: () => onPairHover(index),
|
|
21238
|
-
intra: sideIndex?.right === void 0 ? void 0 : model.intra.get(sideIndex.right)
|
|
21239
|
-
|
|
22042
|
+
intra: sideIndex?.right === void 0 ? void 0 : model.intra.get(sideIndex.right),
|
|
22043
|
+
discussed: discussedPairs.has(index)
|
|
22044
|
+
}), discussionPx(index) > 0 && (0, react_jsx_runtime.jsx)("div", {
|
|
22045
|
+
className: PendingPanel_module_css_default.vSpacer,
|
|
22046
|
+
"data-diff-discussion-space": discussionPx(index),
|
|
22047
|
+
style: { height: discussionPx(index) },
|
|
22048
|
+
"aria-hidden": "true"
|
|
22049
|
+
})] }, index);
|
|
21240
22050
|
}),
|
|
21241
22051
|
end < pairCount && (0, react_jsx_runtime.jsx)("div", {
|
|
21242
22052
|
className: PendingPanel_module_css_default.vSpacer,
|
|
@@ -21247,7 +22057,50 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
21247
22057
|
})
|
|
21248
22058
|
})
|
|
21249
22059
|
]
|
|
21250
|
-
})
|
|
22060
|
+
}), (0, react_jsx_runtime.jsx)("div", {
|
|
22061
|
+
className: PendingPanel_module_css_default.splitDiscussions,
|
|
22062
|
+
"data-diff-split-discussions": true,
|
|
22063
|
+
style: {
|
|
22064
|
+
"--dsh-quote-width-left": `${widestSide.left}ch`,
|
|
22065
|
+
"--dsh-quote-width-right": `${widestSide.right}ch`
|
|
22066
|
+
},
|
|
22067
|
+
children: [...pairDiscussions.entries()].map(([pair, list]) => {
|
|
22068
|
+
const top = off(pair) + pairHeightAt(pair);
|
|
22069
|
+
const height = discussionPx(pair);
|
|
22070
|
+
if (top - scrollTop > viewportH + SPLIT_DISCUSSION_MARGIN_PX || top + height - scrollTop < -200) return null;
|
|
22071
|
+
return (0, react_jsx_runtime.jsx)("div", {
|
|
22072
|
+
className: PendingPanel_module_css_default.splitDiscussion,
|
|
22073
|
+
"data-discussion-pair": pair,
|
|
22074
|
+
style: {
|
|
22075
|
+
top,
|
|
22076
|
+
width: bodyWidth,
|
|
22077
|
+
height
|
|
22078
|
+
},
|
|
22079
|
+
children: list.map((discussion) => (0, react_jsx_runtime.jsx)(react.Fragment, { children: renderDiscussion?.(discussion, bodyWidth, true) }, discussion.id))
|
|
22080
|
+
}, pair);
|
|
22081
|
+
})
|
|
22082
|
+
})]
|
|
22083
|
+
}),
|
|
22084
|
+
rulerMarkersNow.length > 0 && (0, react_jsx_runtime.jsx)("div", {
|
|
22085
|
+
className: `${PendingPanel_module_css_default.overviewRuler} ${PendingPanel_module_css_default.overviewRulerSplit}`,
|
|
22086
|
+
"data-diff-approval-ruler": true,
|
|
22087
|
+
"aria-hidden": "true",
|
|
22088
|
+
children: rulerMarkersNow.map((marker, index) => (0, react_jsx_runtime.jsx)("div", {
|
|
22089
|
+
className: `${PendingPanel_module_css_default.overviewMarker} ${marker.kind === "del" ? `${PendingPanel_module_css_default.markerDel} ${PendingPanel_module_css_default.markerSplitDel}` : `${PendingPanel_module_css_default.markerAdd} ${PendingPanel_module_css_default.markerSplitAdd}`}`,
|
|
22090
|
+
"data-diff-ruler-marker": marker.kind,
|
|
22091
|
+
"data-diff-ruler-side": marker.kind === "del" ? "left" : "right",
|
|
22092
|
+
style: {
|
|
22093
|
+
top: `${marker.top}%`,
|
|
22094
|
+
height: `${marker.height}%`
|
|
22095
|
+
}
|
|
22096
|
+
}, index))
|
|
22097
|
+
}),
|
|
22098
|
+
gotoDialog,
|
|
22099
|
+
selectionComment !== void 0 && selection !== void 0 && (0, react_jsx_runtime.jsx)("div", {
|
|
22100
|
+
className: PendingPanel_module_css_default.blockActions,
|
|
22101
|
+
"data-diff-selection-actions": true,
|
|
22102
|
+
style: { top: Math.max(0, Math.min(off(selection.end + 1) - scrollTop, Math.max(0, viewportH - 32))) },
|
|
22103
|
+
children: selectionComment
|
|
21251
22104
|
}),
|
|
21252
22105
|
(0, react_jsx_runtime.jsxs)("div", {
|
|
21253
22106
|
className: PendingPanel_module_css_default.splitHScrollRow,
|
|
@@ -21492,10 +22345,48 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
21492
22345
|
side: side === "left" ? "old" : "new"
|
|
21493
22346
|
};
|
|
21494
22347
|
}
|
|
22348
|
+
/** The first and last text node inside `root`, or undefined when it holds no text. */
|
|
22349
|
+
function textEdgesOf(root) {
|
|
22350
|
+
const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);
|
|
22351
|
+
const first = walker.nextNode();
|
|
22352
|
+
if (!(first instanceof Text)) return void 0;
|
|
22353
|
+
let last = first;
|
|
22354
|
+
for (let node = walker.nextNode(); node !== null; node = walker.nextNode()) if (node instanceof Text) last = node;
|
|
22355
|
+
return {
|
|
22356
|
+
first,
|
|
22357
|
+
last
|
|
22358
|
+
};
|
|
22359
|
+
}
|
|
22360
|
+
/**
|
|
22361
|
+
* The text position a point names, in whichever of the two spellings the browser has — or undefined
|
|
22362
|
+
* when it has neither, which is when the panel has to leave the selection to the browser (see the
|
|
22363
|
+
* split view's own drag).
|
|
22364
|
+
* @param x - client X of the point.
|
|
22365
|
+
* @param y - client Y of the point.
|
|
22366
|
+
* @returns the position, or undefined when the browser cannot resolve one.
|
|
22367
|
+
*/
|
|
22368
|
+
function caretAtPoint(x, y) {
|
|
22369
|
+
const api = document;
|
|
22370
|
+
const range = api.caretRangeFromPoint?.(x, y);
|
|
22371
|
+
if (range !== void 0 && range !== null) return {
|
|
22372
|
+
node: range.startContainer,
|
|
22373
|
+
offset: range.startOffset
|
|
22374
|
+
};
|
|
22375
|
+
const position = api.caretPositionFromPoint?.(x, y);
|
|
22376
|
+
return position === void 0 || position === null ? void 0 : {
|
|
22377
|
+
node: position.offsetNode,
|
|
22378
|
+
offset: position.offset
|
|
22379
|
+
};
|
|
22380
|
+
}
|
|
21495
22381
|
/**
|
|
21496
22382
|
* Derive the selected split pair range per side (a left-column selection
|
|
21497
|
-
* references the old file, a right-column selection the new file).
|
|
21498
|
-
*
|
|
22383
|
+
* references the old file, a right-column selection the new file). The two ends
|
|
22384
|
+
* can only disagree about the side when the selection was not made by the split
|
|
22385
|
+
* view's own drag, which cannot leave its column (see `SplitDiff`) — a keyboard
|
|
22386
|
+
* selection onto the neighbouring column, say, or a touch press. The range then
|
|
22387
|
+
* belongs to the column the selection began in and covers the pairs both ends
|
|
22388
|
+
* name: the pairs are the same list in both halves, so that is the range a
|
|
22389
|
+
* selection that stayed in that half would have made.
|
|
21499
22390
|
*/
|
|
21500
22391
|
function splitRowRangeOf(selection) {
|
|
21501
22392
|
if (selection === null || selection.isCollapsed || selection.rangeCount === 0) return void 0;
|
|
@@ -21503,7 +22394,6 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
21503
22394
|
const startInfo = splitRowInfoAt(range.startContainer);
|
|
21504
22395
|
const endInfo = splitRowInfoAt(range.endContainer);
|
|
21505
22396
|
if (startInfo === void 0 || endInfo === void 0) return void 0;
|
|
21506
|
-
if (startInfo.side !== endInfo.side) return void 0;
|
|
21507
22397
|
let start = startInfo.pairIndex;
|
|
21508
22398
|
let end = endInfo.pairIndex;
|
|
21509
22399
|
if (lineOffsetAt(range.startContainer, range.startOffset) >= lineLengthAt(range.startContainer)) start += 1;
|
|
@@ -21512,7 +22402,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
21512
22402
|
return {
|
|
21513
22403
|
start,
|
|
21514
22404
|
end,
|
|
21515
|
-
side: startInfo.side
|
|
22405
|
+
side: splitRowInfoAt(selection.anchorNode)?.side ?? startInfo.side
|
|
21516
22406
|
};
|
|
21517
22407
|
}
|
|
21518
22408
|
/** The code cell in `node`'s visual row, a sibling of its gutter cells. A
|
|
@@ -21726,7 +22616,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
21726
22616
|
});
|
|
21727
22617
|
}
|
|
21728
22618
|
/** The selected file's diff, actions, jump controls, and copy toolbar. */
|
|
21729
|
-
function PendingDiff({ file, busy, workspacePath, jumpSignal, undoFlash, landingTop, landingTick, landingRow, failedMessage, commentSkill, onPasteReference, onAskAgent, watchChat, onToast, t, onAddTypedPath, onKeep, onRevert, onRefreshVcs, onBlockKeep, onBlockRevert, onOpen, onPreviewImage }) {
|
|
22619
|
+
function PendingDiff({ file, busy, workspacePath, jumpSignal, undoFlash, landingTop, landingTick, landingRow, landingCard, onLanded, failedMessage, commentSkill, onPasteReference, onAskAgent, watchChat, onToast, t, onAddTypedPath, onKeep, onRevert, onRefreshVcs, onBlockKeep, onBlockRevert, onOpen, onPreviewImage }) {
|
|
21730
22620
|
/** The path being typed into the header field; null shows the open file's own path. */
|
|
21731
22621
|
const [pathDraft, setPathDraft] = (0, react.useState)(null);
|
|
21732
22622
|
const [langOverride, setLangOverride] = (0, react.useState)(void 0);
|
|
@@ -21797,7 +22687,52 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
21797
22687
|
file.newText,
|
|
21798
22688
|
splitView
|
|
21799
22689
|
]);
|
|
21800
|
-
const
|
|
22690
|
+
const splitModel = (0, react.useMemo)(() => splitView ? computeSideBySideDiff(model.diff.rows, true) : null, [splitView, model]);
|
|
22691
|
+
const splitPairs = splitModel?.pairs ?? null;
|
|
22692
|
+
/**
|
|
22693
|
+
* Which model row each pair holds on each side: the side-by-side view selects PAIRS and names one
|
|
22694
|
+
* column (see `splitRowRangeOf`), while everything that reads a selection as lines — the anchor a
|
|
22695
|
+
* comment is written to, and the "this range already has a thread" test — speaks rows.
|
|
22696
|
+
*/
|
|
22697
|
+
const pairRows = (0, react.useMemo)(() => {
|
|
22698
|
+
const map = /* @__PURE__ */ new Map();
|
|
22699
|
+
if (splitModel === null) return map;
|
|
22700
|
+
model.diff.rows.forEach((row, rowIndex) => {
|
|
22701
|
+
const pair = splitModel.pairOfRow.get(rowIndex);
|
|
22702
|
+
if (pair === void 0) return;
|
|
22703
|
+
const entry = map.get(pair) ?? {};
|
|
22704
|
+
if (row.kind !== "add") entry.old = rowIndex;
|
|
22705
|
+
if (row.kind !== "del") entry.new = rowIndex;
|
|
22706
|
+
map.set(pair, entry);
|
|
22707
|
+
});
|
|
22708
|
+
return map;
|
|
22709
|
+
}, [splitModel, model]);
|
|
22710
|
+
/**
|
|
22711
|
+
* The rows a selection names, whichever view made it: the pair range of a side-by-side selection
|
|
22712
|
+
* mapped to that column's rows, and a single-column range left as it is.
|
|
22713
|
+
*
|
|
22714
|
+
* Only the NEW side can be named. A thread is anchored to new-file lines — those are what survive
|
|
22715
|
+
* the model being rebuilt, and what its reference label shows — so a left-column selection (the
|
|
22716
|
+
* old file, code that may not exist any more) has nothing to anchor to: it reads as no rows, and
|
|
22717
|
+
* the comment is not offered on it.
|
|
22718
|
+
*
|
|
22719
|
+
* @param range - the selection to read.
|
|
22720
|
+
* @returns the same lines as a row range, or undefined when the view named none.
|
|
22721
|
+
*/
|
|
22722
|
+
const selectionRows = (range) => {
|
|
22723
|
+
if (range === void 0) return void 0;
|
|
22724
|
+
if (!splitView || range.side === void 0 || splitModel === null) return range;
|
|
22725
|
+
if (range.side !== "new") return void 0;
|
|
22726
|
+
const rows = [];
|
|
22727
|
+
for (let index = range.start; index <= range.end; index++) {
|
|
22728
|
+
const row = pairRows.get(index)?.new;
|
|
22729
|
+
if (row !== void 0) rows.push(row);
|
|
22730
|
+
}
|
|
22731
|
+
return rows.length === 0 ? void 0 : {
|
|
22732
|
+
start: Math.min(...rows),
|
|
22733
|
+
end: Math.max(...rows)
|
|
22734
|
+
};
|
|
22735
|
+
};
|
|
21801
22736
|
(0, react.useEffect)(() => {
|
|
21802
22737
|
if (!previewActive) return;
|
|
21803
22738
|
const body = mdPreviewBodyRef.current;
|
|
@@ -21880,6 +22815,11 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
21880
22815
|
const [scrollTop, setScrollTop] = (0, react.useState)(0);
|
|
21881
22816
|
const [viewportHeight, setViewportHeight] = (0, react.useState)(0);
|
|
21882
22817
|
const [bodyWidth, setBodyWidth] = (0, react.useState)(0);
|
|
22818
|
+
/** The go-to-line dialog: whether it is up, and what has been typed into it. */
|
|
22819
|
+
const [gotoOpen, setGotoOpen] = (0, react.useState)(false);
|
|
22820
|
+
const [gotoDraft, setGotoDraft] = (0, react.useState)("");
|
|
22821
|
+
/** The row a go-to-line flashed: its box frames that one row instead of the block around it. */
|
|
22822
|
+
const flashRowRef = (0, react.useRef)(void 0);
|
|
21883
22823
|
const [hScrollbarPx, setHScrollbarPx] = (0, react.useState)(0);
|
|
21884
22824
|
const [hoveredBlock, setHoveredBlock] = (0, react.useState)(void 0);
|
|
21885
22825
|
const [selection, setSelection] = (0, react.useState)(void 0);
|
|
@@ -21898,12 +22838,9 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
21898
22838
|
[file.id]: update(all[file.id] ?? EMPTY_DISCUSSIONS)
|
|
21899
22839
|
}));
|
|
21900
22840
|
};
|
|
21901
|
-
/** Which block's overflow menu is open, if any.
|
|
22841
|
+
/** Which block's overflow menu is open, if any. The card builds the menu's own row (see
|
|
22842
|
+
* `DiscussionBlock`): finishing a thread takes the block, and its rows, away. */
|
|
21902
22843
|
const [discussionMenuFor, setDiscussionMenuFor] = (0, react.useState)(void 0);
|
|
21903
|
-
const discussionMenuItems = (0, react.useMemo)(() => [{
|
|
21904
|
-
id: "delete",
|
|
21905
|
-
label: t("action.discussionEnd")
|
|
21906
|
-
}], [t]);
|
|
21907
22844
|
/** The session's chat, watched so a discussion can show the answer it asked for. */
|
|
21908
22845
|
const [chat, setChat] = (0, react.useState)({
|
|
21909
22846
|
running: false,
|
|
@@ -21947,6 +22884,14 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
21947
22884
|
const landingTopRef = (0, react.useRef)(void 0);
|
|
21948
22885
|
/** The model row a jump to a comment asked for, spent the same way and by the same effect. */
|
|
21949
22886
|
const landingRowRef = (0, react.useRef)(void 0);
|
|
22887
|
+
/** Whether that row is a thread's own box rather than a place in the code (see `landingCard`). */
|
|
22888
|
+
const landingCardRef = (0, react.useRef)(false);
|
|
22889
|
+
/** The latest `onLanded`, for the landing effect: it says the ask has been taken, and the panel
|
|
22890
|
+
* then spends it so a pane that mounts later cannot take it again. Read through a ref because the
|
|
22891
|
+
* panel hands a fresh closure on every render, and re-running the landing effect for that would
|
|
22892
|
+
* place the file twice. */
|
|
22893
|
+
const onLandedRef = (0, react.useRef)(onLanded);
|
|
22894
|
+
onLandedRef.current = onLanded;
|
|
21950
22895
|
const selectionTextRef = (0, react.useRef)("");
|
|
21951
22896
|
const [copied, setCopied] = (0, react.useState)(false);
|
|
21952
22897
|
const [searchOpen, setSearchOpen] = (0, react.useState)(false);
|
|
@@ -21962,16 +22907,6 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
21962
22907
|
previewFlashPendingRef.current = true;
|
|
21963
22908
|
};
|
|
21964
22909
|
(0, react.useEffect)(() => {
|
|
21965
|
-
landingTopRef.current = landingTop;
|
|
21966
|
-
landingRowRef.current = landingRow;
|
|
21967
|
-
if (landingRow !== void 0) {
|
|
21968
|
-
setFocus(blockIndexAtOffset(offsetOf(landingRow)));
|
|
21969
|
-
bumpFlash(false);
|
|
21970
|
-
} else if (landingTop === void 0) {
|
|
21971
|
-
setFocus(0);
|
|
21972
|
-
bumpFlash(false);
|
|
21973
|
-
} else setFocus(blockIndexAtOffset(landingTop));
|
|
21974
|
-
setScrollTick((tick) => tick + 1);
|
|
21975
22910
|
bodyRef.current?.focus();
|
|
21976
22911
|
setHoveredBlock(void 0);
|
|
21977
22912
|
setSelection(void 0);
|
|
@@ -21981,11 +22916,44 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
21981
22916
|
setSearchOpen(false);
|
|
21982
22917
|
setSearchQuery("");
|
|
21983
22918
|
setSearchIndex(0);
|
|
22919
|
+
}, [file.id]);
|
|
22920
|
+
const landedFileRef = (0, react.useRef)(void 0);
|
|
22921
|
+
/** The file the placement effect below has decided the opening place for (see `placedFileRef`). */
|
|
22922
|
+
const placedFileRef = (0, react.useRef)(void 0);
|
|
22923
|
+
(0, react.useEffect)(() => {
|
|
22924
|
+
const landing = (landingTick ?? 0) > 0;
|
|
22925
|
+
const opened = landedFileRef.current !== file.id;
|
|
22926
|
+
landedFileRef.current = file.id;
|
|
22927
|
+
placedFileRef.current = file.id;
|
|
22928
|
+
if (!landing && !opened) return;
|
|
22929
|
+
if (landing) {
|
|
22930
|
+
landingTopRef.current = landingTop;
|
|
22931
|
+
landingRowRef.current = landingRow;
|
|
22932
|
+
landingCardRef.current = landingCard === true;
|
|
22933
|
+
if (landingRow !== void 0) {
|
|
22934
|
+
setFocus(blockIndexAtOffset(offsetOf(landingRow)));
|
|
22935
|
+
bumpFlash(false);
|
|
22936
|
+
} else if (landingTop === void 0) {
|
|
22937
|
+
setFocus(0);
|
|
22938
|
+
bumpFlash(false);
|
|
22939
|
+
} else setFocus(blockIndexAtOffset(landingTop));
|
|
22940
|
+
setScrollTick((tick) => tick + 1);
|
|
22941
|
+
onLandedRef.current?.();
|
|
22942
|
+
return;
|
|
22943
|
+
}
|
|
22944
|
+
landingRowRef.current = void 0;
|
|
22945
|
+
landingCardRef.current = false;
|
|
22946
|
+
const offset = panelFileOffset(file.sessionId, file.id);
|
|
22947
|
+
if (offset === void 0) return;
|
|
22948
|
+
landingTopRef.current = offset;
|
|
22949
|
+
setFocus(blockIndexAtOffset(offset));
|
|
22950
|
+
setScrollTick((tick) => tick + 1);
|
|
21984
22951
|
}, [
|
|
21985
22952
|
file.id,
|
|
21986
22953
|
landingTop,
|
|
21987
22954
|
landingTick,
|
|
21988
|
-
landingRow
|
|
22955
|
+
landingRow,
|
|
22956
|
+
landingCard
|
|
21989
22957
|
]);
|
|
21990
22958
|
(0, react.useEffect)(() => {
|
|
21991
22959
|
if (undoFlash === 0) return;
|
|
@@ -22522,16 +23490,35 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
22522
23490
|
* row per quoted line whatever the width.
|
|
22523
23491
|
* @returns the occupied row count (whole).
|
|
22524
23492
|
*/
|
|
22525
|
-
const quoteRowsOf = (0, react.useCallback)((quote, wrap) => {
|
|
22526
|
-
|
|
22527
|
-
|
|
23493
|
+
const quoteRowsOf = (0, react.useCallback)((quote, lines, wrap, split) => {
|
|
23494
|
+
const texts = quote.split("\n");
|
|
23495
|
+
if (!split) {
|
|
23496
|
+
if (!wrap) return texts.length;
|
|
23497
|
+
const measure = makeMeasurer(codeFontOf());
|
|
23498
|
+
const width = Math.max(0, bodyWidth - discussionRightInsetPx) - WRAP_GUTTERS_PX;
|
|
23499
|
+
if (measure === void 0) return texts.length;
|
|
23500
|
+
const wrapping = width - measure("0");
|
|
23501
|
+
if (wrapping <= 0) return texts.length;
|
|
23502
|
+
const tabPx = tabWidthSpaces * measure(" ");
|
|
23503
|
+
return texts.reduce((rows, line) => rows + Math.max(1, wrapInto(line, wrapping, measure, tabPx).length), 0);
|
|
23504
|
+
}
|
|
23505
|
+
const pairs = computeSideBySideDiff(texts.map((text, index) => {
|
|
23506
|
+
const line = lines?.[index];
|
|
23507
|
+
return {
|
|
23508
|
+
text,
|
|
23509
|
+
kind: line?.kind ?? "context",
|
|
23510
|
+
oldLine: line?.old,
|
|
23511
|
+
newLine: line?.new
|
|
23512
|
+
};
|
|
23513
|
+
}), true).pairs;
|
|
23514
|
+
if (!wrap) return pairs.length;
|
|
22528
23515
|
const measure = makeMeasurer(codeFontOf());
|
|
22529
|
-
|
|
22530
|
-
|
|
22531
|
-
|
|
22532
|
-
if (wrapping <= 0) return lines.length;
|
|
23516
|
+
if (measure === void 0) return pairs.length;
|
|
23517
|
+
const wrapping = Math.max(0, (bodyWidth - 1) / 2) - WRAP_GUTTERS_PX / 2 - measure("0");
|
|
23518
|
+
if (wrapping <= 0) return pairs.length;
|
|
22533
23519
|
const tabPx = tabWidthSpaces * measure(" ");
|
|
22534
|
-
|
|
23520
|
+
const rowsIn = (text) => text === void 0 ? 1 : Math.max(1, wrapInto(text, wrapping, measure, tabPx).length);
|
|
23521
|
+
return pairs.reduce((count, pair) => count + Math.max(rowsIn(pair.left?.text), rowsIn(pair.right?.text)), 0);
|
|
22535
23522
|
}, [
|
|
22536
23523
|
bodyWidth,
|
|
22537
23524
|
discussionRightInsetPx,
|
|
@@ -22560,13 +23547,27 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
22560
23547
|
* @returns the messages to render, the hidden count, and the body height.
|
|
22561
23548
|
*/
|
|
22562
23549
|
const roundLimit = discussionRoundLimit();
|
|
23550
|
+
/**
|
|
23551
|
+
* Rows a thread's own rendered height corrected the model to, by thread id.
|
|
23552
|
+
*
|
|
23553
|
+
* The rows a block reserves are meant to BE the rows it draws, and the wrap model above is how
|
|
23554
|
+
* they are worked out — but a wrap model that is off by a row or by ten shows up as air under the
|
|
23555
|
+
* writing row (or as a clipped turn), and this one demonstrably is: the same answer has measured
|
|
23556
|
+
* 7, 11, 25 and 35 rows in different sessions at the same width. So the block's own rendered
|
|
23557
|
+
* height is read back after every render and the reservation is corrected to it — the same
|
|
23558
|
+
* "measure it, do not reason about it" rule the code view's wrapped rows follow. The map only
|
|
23559
|
+
* ever holds what was measured, and an entry stops changing once the drawing settles.
|
|
23560
|
+
*/
|
|
23561
|
+
const [rowFix, setRowFix] = (0, react.useState)({});
|
|
22563
23562
|
const layoutDiscussion = (0, react.useCallback)((discussion) => {
|
|
22564
23563
|
const answer = discussion.reply === void 0 ? void 0 : stripBlankLines(discussion.reply);
|
|
22565
23564
|
const stoppedNote = discussion.stopped === true && (answer === void 0 || answer === "") && discussion.failed !== true;
|
|
22566
|
-
const
|
|
23565
|
+
const outdatedRows = discussion.lost === true && discussion.quote !== void 0 && discussion.quote !== "" ? 1 + quoteRowsOf(discussion.quote, discussion.quoteLines, langWrap, splitView) * (ROW_HEIGHT_PX / THREAD_ROW_PX) : 0;
|
|
23566
|
+
const writingNote = discussion.asking === true && answer !== void 0 && answer !== "";
|
|
23567
|
+
const trailing = outdatedRows + (answer !== void 0 && answer !== "" ? messageSizeOf({
|
|
22567
23568
|
role: "assistant",
|
|
22568
23569
|
text: answer
|
|
22569
|
-
}) : discussion.failed === true || discussion.asking === true ? 1 : 2 + (stoppedNote ? 1 : 0));
|
|
23570
|
+
}) + (writingNote ? 1 : 0) : discussion.failed === true || discussion.asking === true ? 1 : 2 + (stoppedNote ? 1 : 0));
|
|
22570
23571
|
const tail = discussionRounds(discussion.messages, roundLimit, messageSizeOf);
|
|
22571
23572
|
return {
|
|
22572
23573
|
messages: tail.messages,
|
|
@@ -22578,7 +23579,9 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
22578
23579
|
quoteRowsOf,
|
|
22579
23580
|
messageSizeOf,
|
|
22580
23581
|
roundLimit,
|
|
22581
|
-
ROW_HEIGHT_PX
|
|
23582
|
+
ROW_HEIGHT_PX,
|
|
23583
|
+
bodyWidth,
|
|
23584
|
+
splitView
|
|
22582
23585
|
]);
|
|
22583
23586
|
/**
|
|
22584
23587
|
* The discussions as the render will draw them: the body height the measurement
|
|
@@ -22591,15 +23594,20 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
22591
23594
|
const laid = layoutDiscussion(discussion);
|
|
22592
23595
|
return {
|
|
22593
23596
|
...discussion,
|
|
22594
|
-
bodyRows: laid.rows,
|
|
23597
|
+
bodyRows: rowFix[discussion.id] ?? laid.rows,
|
|
22595
23598
|
hidden: laid.hidden,
|
|
23599
|
+
quoteWrap: langWrap,
|
|
22596
23600
|
messages: laid.messages.map((message) => ({
|
|
22597
23601
|
...message,
|
|
22598
23602
|
text: discussionText(message)
|
|
22599
23603
|
})),
|
|
22600
23604
|
...discussion.reply === void 0 ? {} : { reply: stripBlankLines(discussion.reply) }
|
|
22601
23605
|
};
|
|
22602
|
-
}), [
|
|
23606
|
+
}), [
|
|
23607
|
+
discussions,
|
|
23608
|
+
layoutDiscussion,
|
|
23609
|
+
rowFix
|
|
23610
|
+
]);
|
|
22603
23611
|
const discussionExtras = (0, react.useMemo)(() => discussionRowExtras(laidDiscussions, rows.length), [laidDiscussions, rows.length]);
|
|
22604
23612
|
const discussionsAtRow = (0, react.useMemo)(() => {
|
|
22605
23613
|
const byRow = /* @__PURE__ */ new Map();
|
|
@@ -22681,6 +23689,16 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
22681
23689
|
(0, react.useEffect)(() => {
|
|
22682
23690
|
rememberDiscussions(file.sessionId, discussionsByFile);
|
|
22683
23691
|
}, [file.sessionId, discussionsByFile]);
|
|
23692
|
+
(0, react.useEffect)(() => {
|
|
23693
|
+
const changed = () => {
|
|
23694
|
+
const next = rememberedDiscussions(file.sessionId);
|
|
23695
|
+
setDiscussionsByFile((all) => all === next ? all : next);
|
|
23696
|
+
};
|
|
23697
|
+
window.addEventListener(COMMENTS_CHANGED_EVENT, changed);
|
|
23698
|
+
return () => {
|
|
23699
|
+
window.removeEventListener(COMMENTS_CHANGED_EVENT, changed);
|
|
23700
|
+
};
|
|
23701
|
+
}, [file.sessionId]);
|
|
22684
23702
|
/** Patch one discussion in place, without touching the others or the file key. */
|
|
22685
23703
|
const updateDiscussion = (0, react.useCallback)((id, patch) => {
|
|
22686
23704
|
setDiscussionsByFile((all) => {
|
|
@@ -22873,7 +23891,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
22873
23891
|
const next = remapDiscussions(list, (row) => {
|
|
22874
23892
|
const entry = model.diff.rows[row];
|
|
22875
23893
|
return entry?.newLine ?? entry?.oldLine;
|
|
22876
|
-
}, (row) => model.diff.rows[row]?.text ?? "", model.diff.rows.length);
|
|
23894
|
+
}, (row) => model.diff.rows[row]?.text ?? "", model.diff.rows.length, (row) => model.diff.rows[row]?.newLine !== void 0);
|
|
22877
23895
|
return next.some((discussion, index) => discussion !== list[index]) ? {
|
|
22878
23896
|
...all,
|
|
22879
23897
|
[file.id]: next
|
|
@@ -22927,32 +23945,35 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
22927
23945
|
/** Start a discussion on the current selection (no-op on a range that has one). */
|
|
22928
23946
|
const addDiscussion = () => {
|
|
22929
23947
|
if (!commentMode) return;
|
|
22930
|
-
|
|
22931
|
-
if (
|
|
22932
|
-
|
|
22933
|
-
const
|
|
23948
|
+
const range = selectionRows(selection);
|
|
23949
|
+
if (range === void 0) return;
|
|
23950
|
+
if (discussionOverlapping(discussions, range) !== void 0) return;
|
|
23951
|
+
const first = model.diff.rows[range.start];
|
|
23952
|
+
const last = model.diff.rows[range.end] ?? first;
|
|
22934
23953
|
const startLine = first?.newLine ?? first?.oldLine;
|
|
22935
23954
|
if (startLine === void 0) return;
|
|
22936
23955
|
const endLine = last?.newLine ?? last?.oldLine ?? startLine;
|
|
22937
23956
|
const body = bodyRef.current;
|
|
22938
|
-
if (body !== null && offsetOf(
|
|
23957
|
+
if (body !== null && offsetOf(range.start) - body.scrollTop < 0) pendingScrollShiftRef.current += 66;
|
|
22939
23958
|
const id = `discussion-${Date.now().toString(36)}-${discussions.length}`;
|
|
22940
|
-
const quoted = model.diff.rows.slice(
|
|
23959
|
+
const quoted = model.diff.rows.slice(range.start, range.end + 1);
|
|
22941
23960
|
const quote = quoted.map((row) => row.text).join("\n");
|
|
22942
23961
|
const quoteLines = quoted.map((row) => ({
|
|
22943
23962
|
old: row.oldLine,
|
|
22944
23963
|
new: row.newLine,
|
|
22945
23964
|
kind: row.kind
|
|
22946
23965
|
}));
|
|
23966
|
+
const quoteContext = model.diff.rows.slice(Math.max(0, range.start - 1), Math.min(model.diff.rows.length, range.end + 2)).map((row) => row.text).join("\n");
|
|
22947
23967
|
setDiscussions((current) => [...current, {
|
|
22948
23968
|
id,
|
|
22949
23969
|
anchor: {
|
|
22950
|
-
start:
|
|
22951
|
-
end:
|
|
23970
|
+
start: range.start,
|
|
23971
|
+
end: range.end,
|
|
22952
23972
|
startLine,
|
|
22953
23973
|
endLine
|
|
22954
23974
|
},
|
|
22955
23975
|
quote,
|
|
23976
|
+
quoteContext,
|
|
22956
23977
|
quoteLines,
|
|
22957
23978
|
messages: [],
|
|
22958
23979
|
draft: "",
|
|
@@ -23154,29 +24175,99 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
23154
24175
|
previewActive,
|
|
23155
24176
|
splitView
|
|
23156
24177
|
]);
|
|
24178
|
+
const widthMovedRef = (0, react.useRef)(false);
|
|
24179
|
+
(0, react.useLayoutEffect)(() => {
|
|
24180
|
+
const body = bodyRef.current;
|
|
24181
|
+
if (body === null) return;
|
|
24182
|
+
const width = body.clientWidth;
|
|
24183
|
+
widthMovedRef.current = width !== bodyWidth;
|
|
24184
|
+
if (width !== bodyWidth) setBodyWidth(width);
|
|
24185
|
+
});
|
|
24186
|
+
const rowFixRef = (0, react.useRef)(rowFix);
|
|
24187
|
+
rowFixRef.current = rowFix;
|
|
24188
|
+
const fitWidthRef = (0, react.useRef)(0);
|
|
24189
|
+
const [, bumpFixTick] = (0, react.useReducer)((n) => n + 1, 0);
|
|
24190
|
+
const fixTickArmedRef = (0, react.useRef)(false);
|
|
24191
|
+
(0, react.useLayoutEffect)(() => {
|
|
24192
|
+
const cardWidth = document.querySelector("[data-diff-discussion]")?.getBoundingClientRect().width ?? 0;
|
|
24193
|
+
const settled = cardWidth > 0 && Math.abs(cardWidth - fitWidthRef.current) <= 1;
|
|
24194
|
+
fitWidthRef.current = cardWidth;
|
|
24195
|
+
if (!settled) {
|
|
24196
|
+
if (cardWidth > 0 && !widthMovedRef.current && !fixTickArmedRef.current) {
|
|
24197
|
+
const armed = bodyRef.current?.clientWidth ?? 0;
|
|
24198
|
+
fixTickArmedRef.current = true;
|
|
24199
|
+
requestAnimationFrame(() => {
|
|
24200
|
+
fixTickArmedRef.current = false;
|
|
24201
|
+
if ((bodyRef.current?.clientWidth ?? 0) !== armed) return;
|
|
24202
|
+
bumpFixTick();
|
|
24203
|
+
});
|
|
24204
|
+
}
|
|
24205
|
+
return;
|
|
24206
|
+
}
|
|
24207
|
+
const next = { ...rowFixRef.current };
|
|
24208
|
+
let changed = false;
|
|
24209
|
+
for (const card of document.querySelectorAll("[data-diff-discussion]")) {
|
|
24210
|
+
const id = card.dataset.diffDiscussionId;
|
|
24211
|
+
const body = card.children[1];
|
|
24212
|
+
const last = body?.lastElementChild;
|
|
24213
|
+
if (id === void 0 || body === void 0 || last === null || last === void 0) continue;
|
|
24214
|
+
const slack = body.querySelector("[data-diff-discussion-slack]");
|
|
24215
|
+
const drawn = last.getBoundingClientRect().bottom + (Number.parseFloat(getComputedStyle(last).marginBottom) || 0) - body.getBoundingClientRect().top - (slack?.getBoundingClientRect().height ?? 0);
|
|
24216
|
+
if (drawn <= 0) continue;
|
|
24217
|
+
const want = Math.max(1, Math.ceil((drawn - DISCUSSION_ROW_SNAP_PX) / THREAD_ROW_PX));
|
|
24218
|
+
if (next[id] !== want) {
|
|
24219
|
+
next[id] = want;
|
|
24220
|
+
changed = true;
|
|
24221
|
+
}
|
|
24222
|
+
}
|
|
24223
|
+
if (changed) setRowFix(next);
|
|
24224
|
+
});
|
|
24225
|
+
/**
|
|
24226
|
+
* Move the code view to one offset, and take the page's memory with it.
|
|
24227
|
+
*
|
|
24228
|
+
* The memory is what a pane that remounts under the reader resumes (see the landing effect), so it
|
|
24229
|
+
* has to follow every write the panel itself makes — a jump included. Mirroring only the reader's
|
|
24230
|
+
* own scrolls would leave a remount resuming the place they left rather than the place the jump
|
|
24231
|
+
* put them, which is the same "it moved on its own" the memory exists to stop.
|
|
24232
|
+
*
|
|
24233
|
+
* @param body - the code view's scroll box.
|
|
24234
|
+
* @param offset - the offset to settle it at.
|
|
24235
|
+
*/
|
|
24236
|
+
const applyScrollTop = (body, offset) => {
|
|
24237
|
+
if (body.scrollTop !== offset) body.scrollTop = offset;
|
|
24238
|
+
setScrollTop(offset);
|
|
24239
|
+
rememberPanelView(file.sessionId, {
|
|
24240
|
+
fileId: file.id,
|
|
24241
|
+
scrollTop: offset
|
|
24242
|
+
});
|
|
24243
|
+
};
|
|
23157
24244
|
(0, react.useLayoutEffect)(() => {
|
|
23158
24245
|
if (rowCount === 0) return;
|
|
24246
|
+
if (placedFileRef.current !== file.id) return;
|
|
23159
24247
|
const resumed = landingTopRef.current;
|
|
23160
24248
|
if (resumed !== void 0) {
|
|
23161
24249
|
landingTopRef.current = void 0;
|
|
23162
24250
|
if (!previewActive) {
|
|
23163
24251
|
const resumeBody = bodyRef.current;
|
|
23164
|
-
if (resumeBody !== null)
|
|
23165
|
-
const clamped = Math.max(0, Math.min(resumed, resumeBody.scrollHeight - resumeBody.clientHeight));
|
|
23166
|
-
if (resumeBody.scrollTop !== clamped) resumeBody.scrollTop = clamped;
|
|
23167
|
-
setScrollTop(clamped);
|
|
23168
|
-
}
|
|
24252
|
+
if (resumeBody !== null) applyScrollTop(resumeBody, Math.max(0, Math.min(resumed, resumeBody.scrollHeight - resumeBody.clientHeight)));
|
|
23169
24253
|
}
|
|
23170
24254
|
return;
|
|
23171
24255
|
}
|
|
23172
24256
|
const row = landingRowRef.current;
|
|
23173
24257
|
if (row !== void 0 && !previewActive) {
|
|
24258
|
+
const toCard = landingCardRef.current;
|
|
23174
24259
|
landingRowRef.current = void 0;
|
|
24260
|
+
landingCardRef.current = false;
|
|
24261
|
+
flashRowRef.current = void 0;
|
|
24262
|
+
if (splitView) {
|
|
24263
|
+
splitDiffRef.current?.land(row, toCard);
|
|
24264
|
+
return;
|
|
24265
|
+
}
|
|
23175
24266
|
const rowBody = bodyRef.current;
|
|
23176
24267
|
if (rowBody !== null) {
|
|
23177
|
-
const
|
|
23178
|
-
|
|
23179
|
-
|
|
24268
|
+
const cardTop = offsetOf(row + 1) - (discussionExtras.get(row) ?? 0) * THREAD_ROW_PX;
|
|
24269
|
+
const target = toCard ? cardTop : offsetOf(row);
|
|
24270
|
+
applyScrollTop(rowBody, Math.max(0, Math.min(target - leadRows * ROW_HEIGHT_PX, rowBody.scrollHeight - rowBody.clientHeight)));
|
|
23180
24271
|
}
|
|
23181
24272
|
return;
|
|
23182
24273
|
}
|
|
@@ -23193,9 +24284,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
23193
24284
|
const body = bodyRef.current;
|
|
23194
24285
|
if (body === null) return;
|
|
23195
24286
|
const target = offsetOf(block.start) - leadRows * ROW_HEIGHT_PX;
|
|
23196
|
-
|
|
23197
|
-
if (body.scrollTop !== clamped) body.scrollTop = clamped;
|
|
23198
|
-
setScrollTop(clamped);
|
|
24287
|
+
applyScrollTop(body, Math.max(0, Math.min(target, body.scrollHeight - body.clientHeight)));
|
|
23199
24288
|
}, [
|
|
23200
24289
|
scrollTick,
|
|
23201
24290
|
offsetsFromWrap,
|
|
@@ -23243,6 +24332,133 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
23243
24332
|
};
|
|
23244
24333
|
const jumpBlockRef = (0, react.useRef)(jumpBlock);
|
|
23245
24334
|
jumpBlockRef.current = jumpBlock;
|
|
24335
|
+
/**
|
|
24336
|
+
* Go to a line of the file as it reads NOW: the row carrying that new-file line, because the old side
|
|
24337
|
+
* of the diff is not a place a reader can be sent (its numbers belong to text that is already gone) —
|
|
24338
|
+
* a number that only exists there is answered with a note instead. Both views take it the way a comment
|
|
24339
|
+
* jump does: the split view through its own handle, one column through the height table, with the
|
|
24340
|
+
* configured lead rows above it and the block it lands in flashed.
|
|
24341
|
+
*/
|
|
24342
|
+
const gotoLine = (line) => {
|
|
24343
|
+
const row = model.diff.rows.findIndex((entry) => entry.newLine === line);
|
|
24344
|
+
if (row === -1) {
|
|
24345
|
+
onToast(t("panel.gotoMissing", { line }));
|
|
24346
|
+
return;
|
|
24347
|
+
}
|
|
24348
|
+
if (splitView && !previewActive) {
|
|
24349
|
+
splitDiffRef.current?.land(row, false, true);
|
|
24350
|
+
return;
|
|
24351
|
+
}
|
|
24352
|
+
bumpFlash(false);
|
|
24353
|
+
flashRowRef.current = row;
|
|
24354
|
+
setFocus(blockIndexAtOffset(offsetOf(row)));
|
|
24355
|
+
const body = bodyRef.current;
|
|
24356
|
+
if (body === null) return;
|
|
24357
|
+
applyScrollTop(body, Math.max(0, Math.min(offsetOf(row) - leadRows * ROW_HEIGHT_PX, body.scrollHeight - body.clientHeight)));
|
|
24358
|
+
};
|
|
24359
|
+
(0, react.useEffect)(() => {
|
|
24360
|
+
const onKeyDown = (event) => {
|
|
24361
|
+
if (!matchesShortcut(event, keybindingOf("goto"))) return;
|
|
24362
|
+
if (isTextFieldEvent(event) || pathPickerOpen()) return;
|
|
24363
|
+
event.preventDefault();
|
|
24364
|
+
setGotoDraft("");
|
|
24365
|
+
setGotoOpen(true);
|
|
24366
|
+
};
|
|
24367
|
+
window.addEventListener("keydown", onKeyDown, true);
|
|
24368
|
+
return () => {
|
|
24369
|
+
window.removeEventListener("keydown", onKeyDown, true);
|
|
24370
|
+
};
|
|
24371
|
+
}, []);
|
|
24372
|
+
/**
|
|
24373
|
+
* The popup's one answer. Enter and the 确定 button both run this, so the key and the press are literally
|
|
24374
|
+
* the same action: the number is read, the popup closes, and a number the current side does not have is
|
|
24375
|
+
* answered with a note instead of a jump (see `gotoLine`).
|
|
24376
|
+
*/
|
|
24377
|
+
const submitGoto = () => {
|
|
24378
|
+
const line = Number.parseInt(gotoDraft.trim(), 10);
|
|
24379
|
+
setGotoOpen(false);
|
|
24380
|
+
if (Number.isFinite(line) && line > 0) gotoLine(line);
|
|
24381
|
+
};
|
|
24382
|
+
/**
|
|
24383
|
+
* The go-to popup, centred on the code view: the layer fills that view's own box (the single column's
|
|
24384
|
+
* wrapper, or the side-by-side view's root, which is why it is handed to `SplitDiff` there), and the
|
|
24385
|
+
* parts wear the search bar's recipe (see `.gotoBox` / `.gotoInput`). Side by side there are two code
|
|
24386
|
+
* boxes rather than one, and the one being read is the right pane: the layer is cut back to that half
|
|
24387
|
+
* (`splitView`, see `.gotoLayerRight`), which is what `data-diff-goto-pane` records for the tests. A
|
|
24388
|
+
* press anywhere dismisses it — the layer catches the presses inside the code view, the full-window
|
|
24389
|
+
* catcher the rest — while the bar itself stops them. Escape, Cancel and focus leaving the popup leave
|
|
24390
|
+
* everything as it was.
|
|
24391
|
+
*/
|
|
24392
|
+
const gotoDialog = !gotoOpen || previewActive ? null : (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)("div", {
|
|
24393
|
+
className: PendingPanel_module_css_default.gotoBackdrop,
|
|
24394
|
+
"data-diff-goto-backdrop": true,
|
|
24395
|
+
"aria-hidden": "true",
|
|
24396
|
+
onClick: () => {
|
|
24397
|
+
setGotoOpen(false);
|
|
24398
|
+
}
|
|
24399
|
+
}), (0, react_jsx_runtime.jsx)("div", {
|
|
24400
|
+
className: `${PendingPanel_module_css_default.gotoLayer}${splitView ? ` ${PendingPanel_module_css_default.gotoLayerRight}` : ""}`,
|
|
24401
|
+
"data-diff-goto-layer": true,
|
|
24402
|
+
"data-diff-goto-pane": splitView ? "right" : "code",
|
|
24403
|
+
onClick: () => {
|
|
24404
|
+
setGotoOpen(false);
|
|
24405
|
+
},
|
|
24406
|
+
children: (0, react_jsx_runtime.jsxs)("div", {
|
|
24407
|
+
role: "dialog",
|
|
24408
|
+
"aria-label": t("action.goto"),
|
|
24409
|
+
"data-diff-goto-dialog": true,
|
|
24410
|
+
className: PendingPanel_module_css_default.gotoBox,
|
|
24411
|
+
onClick: (event) => {
|
|
24412
|
+
event.stopPropagation();
|
|
24413
|
+
},
|
|
24414
|
+
onBlur: (event) => {
|
|
24415
|
+
if (event.relatedTarget instanceof Node && event.currentTarget.contains(event.relatedTarget)) return;
|
|
24416
|
+
setGotoOpen(false);
|
|
24417
|
+
},
|
|
24418
|
+
children: [
|
|
24419
|
+
(0, react_jsx_runtime.jsx)("input", {
|
|
24420
|
+
className: PendingPanel_module_css_default.gotoInput,
|
|
24421
|
+
"data-diff-goto-input": true,
|
|
24422
|
+
value: gotoDraft,
|
|
24423
|
+
autoFocus: true,
|
|
24424
|
+
inputMode: "numeric",
|
|
24425
|
+
spellCheck: false,
|
|
24426
|
+
autoComplete: "off",
|
|
24427
|
+
"aria-label": t("action.goto"),
|
|
24428
|
+
placeholder: t("action.goto"),
|
|
24429
|
+
onChange: (event) => {
|
|
24430
|
+
setGotoDraft(event.target.value);
|
|
24431
|
+
},
|
|
24432
|
+
onKeyDown: (event) => {
|
|
24433
|
+
if (event.key === "Escape") {
|
|
24434
|
+
event.preventDefault();
|
|
24435
|
+
setGotoOpen(false);
|
|
24436
|
+
return;
|
|
24437
|
+
}
|
|
24438
|
+
if (event.key !== "Enter") return;
|
|
24439
|
+
event.preventDefault();
|
|
24440
|
+
submitGoto();
|
|
24441
|
+
}
|
|
24442
|
+
}),
|
|
24443
|
+
(0, react_jsx_runtime.jsx)("button", {
|
|
24444
|
+
type: "button",
|
|
24445
|
+
className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.actionPrimary} ${PendingPanel_module_css_default.gotoAction}`,
|
|
24446
|
+
"data-diff-goto-go": true,
|
|
24447
|
+
onClick: submitGoto,
|
|
24448
|
+
children: t("action.gotoGo")
|
|
24449
|
+
}),
|
|
24450
|
+
(0, react_jsx_runtime.jsx)("button", {
|
|
24451
|
+
type: "button",
|
|
24452
|
+
className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.gotoAction}`,
|
|
24453
|
+
"data-diff-goto-cancel": true,
|
|
24454
|
+
onClick: () => {
|
|
24455
|
+
setGotoOpen(false);
|
|
24456
|
+
},
|
|
24457
|
+
children: t("action.gotoCancel")
|
|
24458
|
+
})
|
|
24459
|
+
]
|
|
24460
|
+
})
|
|
24461
|
+
})] });
|
|
23246
24462
|
const stepBlock = (direction) => {
|
|
23247
24463
|
const count = model.blocks.length;
|
|
23248
24464
|
if (count === 0) return;
|
|
@@ -23252,11 +24468,13 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
23252
24468
|
setScrollTick((tick) => tick + 1);
|
|
23253
24469
|
bumpFlash(false);
|
|
23254
24470
|
};
|
|
24471
|
+
const blockCountRef = (0, react.useRef)(0);
|
|
24472
|
+
blockCountRef.current = model.blocks.length;
|
|
23255
24473
|
const runBlockAction = async (action, range, operated) => {
|
|
23256
24474
|
await (action === "keep" ? onBlockKeep(file.sessionId, file.id, range) : onBlockRevert(file.sessionId, file.id, range));
|
|
23257
|
-
const count =
|
|
24475
|
+
const count = blockCountRef.current;
|
|
23258
24476
|
if (count === 0) return;
|
|
23259
|
-
const next =
|
|
24477
|
+
const next = blockAfterAction(operated, count);
|
|
23260
24478
|
setFocus(next);
|
|
23261
24479
|
setHoveredBlock(void 0);
|
|
23262
24480
|
setScrollTick((tick) => tick + 1);
|
|
@@ -23306,6 +24524,10 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
23306
24524
|
const body = bodyRef.current;
|
|
23307
24525
|
if (body === null) return;
|
|
23308
24526
|
syncQuoteScroll(body);
|
|
24527
|
+
rememberPanelView(file.sessionId, {
|
|
24528
|
+
fileId: file.id,
|
|
24529
|
+
scrollTop: body.scrollTop
|
|
24530
|
+
});
|
|
23309
24531
|
setScrollTop(body.scrollTop);
|
|
23310
24532
|
setViewportHeight(body.clientHeight);
|
|
23311
24533
|
const count = model.blocks.length;
|
|
@@ -23432,9 +24654,59 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
23432
24654
|
window.removeEventListener(COMMENT_MODE_CHANGED_EVENT, onCommentMode);
|
|
23433
24655
|
};
|
|
23434
24656
|
}, []);
|
|
23435
|
-
|
|
23436
|
-
|
|
23437
|
-
|
|
24657
|
+
/**
|
|
24658
|
+
* One thread's card, as every view draws it. The views differ only in where the card hangs and
|
|
24659
|
+
* how wide the thing it hangs in is, so the card itself is built in exactly one place (see
|
|
24660
|
+
* `DiscussionBlock`): the single-column row stream, and whatever view comes next.
|
|
24661
|
+
*/
|
|
24662
|
+
const renderDiscussion = (0, react.useCallback)((discussion, width, split) => (0, react_jsx_runtime.jsx)(DiscussionBlock, {
|
|
24663
|
+
discussion,
|
|
24664
|
+
label: discussionLineRange(discussion.anchor),
|
|
24665
|
+
bodyWidth: width,
|
|
24666
|
+
lang,
|
|
24667
|
+
menuOpen: discussionMenuFor === discussion.id,
|
|
24668
|
+
asking: askingId !== void 0,
|
|
24669
|
+
split,
|
|
24670
|
+
t,
|
|
24671
|
+
onToggle: toggleDiscussion,
|
|
24672
|
+
onMenuOpen: setDiscussionMenuFor,
|
|
24673
|
+
onRemove: removeDiscussion,
|
|
24674
|
+
onDraft: (id, value) => {
|
|
24675
|
+
setDiscussions((current) => current.map((entry) => entry.id === id ? {
|
|
24676
|
+
...entry,
|
|
24677
|
+
draft: value
|
|
24678
|
+
} : entry));
|
|
24679
|
+
},
|
|
24680
|
+
onSend: sendDiscussion,
|
|
24681
|
+
registerInput: (id, element) => {
|
|
24682
|
+
if (element === null) discussionInputEls.current.delete(id);
|
|
24683
|
+
else discussionInputEls.current.set(id, element);
|
|
24684
|
+
}
|
|
24685
|
+
}), [
|
|
24686
|
+
discussionMenuFor,
|
|
24687
|
+
askingId,
|
|
24688
|
+
t,
|
|
24689
|
+
lang,
|
|
24690
|
+
toggleDiscussion,
|
|
24691
|
+
removeDiscussion,
|
|
24692
|
+
sendDiscussion,
|
|
24693
|
+
discussionLineRange
|
|
24694
|
+
]);
|
|
24695
|
+
/**
|
|
24696
|
+
* The lines a selection names, whichever view made it, or undefined when it names none this panel
|
|
24697
|
+
* can comment on — a side-by-side selection of the LEFT column is the old file, and a thread is
|
|
24698
|
+
* anchored to new-file lines. The frame (and the chord) hang off this, so the left column simply
|
|
24699
|
+
* offers nothing.
|
|
24700
|
+
*/
|
|
24701
|
+
const selectionRowRange = selectionRows(selection);
|
|
24702
|
+
/**
|
|
24703
|
+
* Whether those lines already carry a thread: the comment is withheld then (a row belongs to one
|
|
24704
|
+
* annotation at most).
|
|
24705
|
+
*/
|
|
24706
|
+
const selectionHasDiscussion = selectionRowRange !== void 0 && discussionOverlapping(discussions, selectionRowRange) !== void 0;
|
|
24707
|
+
const frameForSelection = selectionRowRange !== void 0 ? selectionFrame({
|
|
24708
|
+
coversBlocks: !splitView && selectionRange !== void 0,
|
|
24709
|
+
hasDiscussion: selectionHasDiscussion
|
|
23438
24710
|
}) : void 0;
|
|
23439
24711
|
const selectionCommentOffered = commentMode && frameForSelection?.comment === true;
|
|
23440
24712
|
const selectionFrameVisible = frameForSelection !== void 0 && (frameForSelection.keepRevert || selectionCommentOffered);
|
|
@@ -23567,8 +24839,9 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
23567
24839
|
const scrollbarWidth = scroller.offsetWidth - scroller.clientWidth;
|
|
23568
24840
|
return Math.max(0, scroller.clientWidth - (scrollbarWidth > 0 ? 0 : OVERVIEW_RULER_WIDTH_PX));
|
|
23569
24841
|
})();
|
|
23570
|
-
const
|
|
23571
|
-
const
|
|
24842
|
+
const flashRow = flashRowRef.current;
|
|
24843
|
+
const flashTop = flashRow !== void 0 ? Math.max(0, offsetOf(flashRow) - scrollTop) : focusedBlock === void 0 ? 0 : Math.max(0, offsetOf(focusedBlock.start) - scrollTop);
|
|
24844
|
+
const flashBottom = flashRow !== void 0 ? Math.min(viewportHeight > 0 ? viewportHeight : Number.POSITIVE_INFINITY, offsetOf(flashRow + 1) - scrollTop) : focusedBlock === void 0 ? 0 : Math.min(viewportHeight > 0 ? viewportHeight : Number.POSITIVE_INFINITY, offsetOf(focusedBlock.end + 1) - scrollTop);
|
|
23572
24845
|
const flashHeight = Math.max(0, flashBottom - flashTop);
|
|
23573
24846
|
const previewFlashNow = previewActive ? previewFlashBox(previewFlash, previewScrollTopRef.current) : void 0;
|
|
23574
24847
|
const searchBar = searchOpen ? (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -23851,6 +25124,25 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
23851
25124
|
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconSearchOutline16, { size: 14 })
|
|
23852
25125
|
})
|
|
23853
25126
|
}),
|
|
25127
|
+
previewActive ? null : (0, react_jsx_runtime.jsx)("span", {
|
|
25128
|
+
className: PendingPanel_module_css_default.gotoHost,
|
|
25129
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
25130
|
+
label: withChord(t("action.goto"), "goto"),
|
|
25131
|
+
side: "bottom",
|
|
25132
|
+
delayMs: 500,
|
|
25133
|
+
children: (0, react_jsx_runtime.jsx)("button", {
|
|
25134
|
+
type: "button",
|
|
25135
|
+
className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.iconAction}`,
|
|
25136
|
+
"data-diff-goto": true,
|
|
25137
|
+
"aria-label": t("action.goto"),
|
|
25138
|
+
onClick: () => {
|
|
25139
|
+
setGotoDraft("");
|
|
25140
|
+
setGotoOpen(true);
|
|
25141
|
+
},
|
|
25142
|
+
children: (0, react_jsx_runtime.jsx)(GotoLineIcon, {})
|
|
25143
|
+
})
|
|
25144
|
+
})
|
|
25145
|
+
}),
|
|
23854
25146
|
(0, react_jsx_runtime.jsx)("span", { className: PendingPanel_module_css_default.divider }),
|
|
23855
25147
|
(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
23856
25148
|
label: t(splitView ? "action.viewUnified" : "action.viewSplit"),
|
|
@@ -24101,7 +25393,22 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
24101
25393
|
onBlockKeep,
|
|
24102
25394
|
onBlockRevert,
|
|
24103
25395
|
onWrapToast: (text) => onToast(text),
|
|
24104
|
-
onVisibleLines: onSplitVisibleLines
|
|
25396
|
+
onVisibleLines: onSplitVisibleLines,
|
|
25397
|
+
discussions: laidDiscussions,
|
|
25398
|
+
renderDiscussion,
|
|
25399
|
+
rulerRuns: rulerMarkers,
|
|
25400
|
+
gotoDialog,
|
|
25401
|
+
selectionComment: splitView && selectionCommentOffered ? (0, react_jsx_runtime.jsxs)("button", {
|
|
25402
|
+
type: "button",
|
|
25403
|
+
className: PendingPanel_module_css_default.action,
|
|
25404
|
+
"data-diff-selection-comment": true,
|
|
25405
|
+
onClick: addDiscussion,
|
|
25406
|
+
children: [t("action.comment"), commentChord !== "" && (0, react_jsx_runtime.jsx)("span", {
|
|
25407
|
+
className: PendingPanel_module_css_default.actionChord,
|
|
25408
|
+
"data-diff-selection-comment-chord": true,
|
|
25409
|
+
children: commentChord
|
|
25410
|
+
})]
|
|
25411
|
+
}) : void 0
|
|
24105
25412
|
}) : (0, react_jsx_runtime.jsxs)("div", {
|
|
24106
25413
|
className: PendingPanel_module_css_default.diffBodyWrap,
|
|
24107
25414
|
ref: bodyWrapRef,
|
|
@@ -24166,153 +25473,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
24166
25473
|
children: (0, react_jsx_runtime.jsx)("div", {
|
|
24167
25474
|
className: PendingPanel_module_css_default.discussionPin,
|
|
24168
25475
|
style: { marginLeft: -88 },
|
|
24169
|
-
children: (
|
|
24170
|
-
className: PendingPanel_module_css_default.discussion,
|
|
24171
|
-
"data-diff-discussion": true,
|
|
24172
|
-
"data-lost": discussion.lost === true ? "" : void 0,
|
|
24173
|
-
style: {
|
|
24174
|
-
width: Math.max(0, bodyWidth),
|
|
24175
|
-
height: rows * THREAD_ROW_PX
|
|
24176
|
-
},
|
|
24177
|
-
children: [(0, react_jsx_runtime.jsxs)("div", {
|
|
24178
|
-
className: PendingPanel_module_css_default.discussionHead,
|
|
24179
|
-
children: [
|
|
24180
|
-
(0, react_jsx_runtime.jsx)("button", {
|
|
24181
|
-
type: "button",
|
|
24182
|
-
className: PendingPanel_module_css_default.discussionToggle,
|
|
24183
|
-
"data-diff-discussion-toggle": true,
|
|
24184
|
-
"aria-expanded": !discussion.collapsed,
|
|
24185
|
-
"aria-label": t(discussion.collapsed ? "action.discussionExpand" : "action.discussionCollapse"),
|
|
24186
|
-
onClick: () => {
|
|
24187
|
-
toggleDiscussion(discussion.id);
|
|
24188
|
-
},
|
|
24189
|
-
children: discussion.collapsed ? (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { size: 12 }) : (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronUpOutline14, { size: 12 })
|
|
24190
|
-
}),
|
|
24191
|
-
(0, react_jsx_runtime.jsx)("span", {
|
|
24192
|
-
className: PendingPanel_module_css_default.discussionRangeWrap,
|
|
24193
|
-
children: (0, react_jsx_runtime.jsx)("span", {
|
|
24194
|
-
className: PendingPanel_module_css_default.discussionRange,
|
|
24195
|
-
"data-diff-discussion-range": true,
|
|
24196
|
-
children: discussionLineRange(discussion.anchor)
|
|
24197
|
-
})
|
|
24198
|
-
}),
|
|
24199
|
-
(0, react_jsx_runtime.jsx)("span", { className: PendingPanel_module_css_default.flexSpacer }),
|
|
24200
|
-
(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Menu, {
|
|
24201
|
-
open: discussionMenuFor === discussion.id,
|
|
24202
|
-
portal: true,
|
|
24203
|
-
compact: true,
|
|
24204
|
-
align: "end",
|
|
24205
|
-
items: discussionMenuItems,
|
|
24206
|
-
onSelect: (id) => {
|
|
24207
|
-
if (id === "delete") removeDiscussion(discussion.id);
|
|
24208
|
-
setDiscussionMenuFor(void 0);
|
|
24209
|
-
},
|
|
24210
|
-
onClose: () => {
|
|
24211
|
-
setDiscussionMenuFor(void 0);
|
|
24212
|
-
},
|
|
24213
|
-
anchor: (0, react_jsx_runtime.jsx)("button", {
|
|
24214
|
-
type: "button",
|
|
24215
|
-
className: PendingPanel_module_css_default.discussionToggle,
|
|
24216
|
-
"data-diff-discussion-menu": true,
|
|
24217
|
-
"aria-label": t("action.more"),
|
|
24218
|
-
onClick: () => {
|
|
24219
|
-
setDiscussionMenuFor((current) => current === discussion.id ? void 0 : discussion.id);
|
|
24220
|
-
},
|
|
24221
|
-
children: "⋯"
|
|
24222
|
-
})
|
|
24223
|
-
})
|
|
24224
|
-
]
|
|
24225
|
-
}), !discussion.collapsed && (0, react_jsx_runtime.jsxs)("div", {
|
|
24226
|
-
className: PendingPanel_module_css_default.discussionBody,
|
|
24227
|
-
children: [
|
|
24228
|
-
discussion.lost === true && discussion.quote !== void 0 && discussion.quote !== "" && (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)("p", {
|
|
24229
|
-
className: PendingPanel_module_css_default.discussionNote,
|
|
24230
|
-
"data-diff-discussion-quote-label": true,
|
|
24231
|
-
children: t("discussion.outdatedQuote")
|
|
24232
|
-
}), (0, react_jsx_runtime.jsx)(DiscussionQuote, {
|
|
24233
|
-
quote: discussion.quote,
|
|
24234
|
-
lines: discussion.quoteLines,
|
|
24235
|
-
lang,
|
|
24236
|
-
wrap: langWrap
|
|
24237
|
-
})] }),
|
|
24238
|
-
discussion.hidden !== void 0 && discussion.hidden > 0 && (0, react_jsx_runtime.jsx)("p", {
|
|
24239
|
-
className: PendingPanel_module_css_default.discussionNote,
|
|
24240
|
-
"data-diff-discussion-hidden": true,
|
|
24241
|
-
children: t("discussion.hidden", { count: discussion.hidden })
|
|
24242
|
-
}),
|
|
24243
|
-
discussion.stopped === true && (discussion.reply === void 0 || discussion.reply === "") && discussion.failed !== true && (0, react_jsx_runtime.jsx)("p", {
|
|
24244
|
-
className: PendingPanel_module_css_default.discussionNote,
|
|
24245
|
-
"data-diff-discussion-stopped": true,
|
|
24246
|
-
children: t("discussion.stopped")
|
|
24247
|
-
}),
|
|
24248
|
-
discussion.messages.map((message, index) => message.role === "user" ? (0, react_jsx_runtime.jsx)("p", {
|
|
24249
|
-
className: PendingPanel_module_css_default.discussionUser,
|
|
24250
|
-
"data-diff-discussion-user": true,
|
|
24251
|
-
children: discussionNodes(message.text)
|
|
24252
|
-
}, `u${index}`) : (0, react_jsx_runtime.jsx)("p", {
|
|
24253
|
-
className: PendingPanel_module_css_default.discussionAnswer,
|
|
24254
|
-
"data-diff-discussion-reply": true,
|
|
24255
|
-
children: discussionNodes(message.text)
|
|
24256
|
-
}, `a${index}`)),
|
|
24257
|
-
discussion.reply !== void 0 && discussion.reply !== "" ? (0, react_jsx_runtime.jsx)("p", {
|
|
24258
|
-
className: PendingPanel_module_css_default.discussionAnswer,
|
|
24259
|
-
"data-diff-discussion-reply": true,
|
|
24260
|
-
children: discussionNodes(discussion.reply)
|
|
24261
|
-
}) : discussion.failed === true ? (0, react_jsx_runtime.jsx)("p", {
|
|
24262
|
-
className: PendingPanel_module_css_default.discussionNote,
|
|
24263
|
-
"data-diff-discussion-failed": true,
|
|
24264
|
-
children: t("discussion.failed")
|
|
24265
|
-
}) : discussion.asking === true ? (0, react_jsx_runtime.jsxs)("p", {
|
|
24266
|
-
className: PendingPanel_module_css_default.discussionNote,
|
|
24267
|
-
"data-diff-discussion-asking": true,
|
|
24268
|
-
children: [discussion.queued === true ? t("discussion.queued") : t("discussion.thinking"), (0, react_jsx_runtime.jsxs)("span", {
|
|
24269
|
-
className: PendingPanel_module_css_default.discussionDots,
|
|
24270
|
-
"data-diff-discussion-dots": true,
|
|
24271
|
-
"aria-hidden": "true",
|
|
24272
|
-
children: [
|
|
24273
|
-
(0, react_jsx_runtime.jsx)("span", { children: "." }),
|
|
24274
|
-
(0, react_jsx_runtime.jsx)("span", { children: "." }),
|
|
24275
|
-
(0, react_jsx_runtime.jsx)("span", { children: "." })
|
|
24276
|
-
]
|
|
24277
|
-
})]
|
|
24278
|
-
}) : (0, react_jsx_runtime.jsxs)("div", {
|
|
24279
|
-
className: PendingPanel_module_css_default.discussionCompose,
|
|
24280
|
-
children: [(0, react_jsx_runtime.jsx)("input", {
|
|
24281
|
-
className: PendingPanel_module_css_default.discussionInput,
|
|
24282
|
-
"data-diff-discussion-input": true,
|
|
24283
|
-
ref: (element) => {
|
|
24284
|
-
if (element === null) discussionInputEls.current.delete(discussion.id);
|
|
24285
|
-
else discussionInputEls.current.set(discussion.id, element);
|
|
24286
|
-
},
|
|
24287
|
-
value: discussion.draft,
|
|
24288
|
-
placeholder: t("discussion.placeholder"),
|
|
24289
|
-
onChange: (event) => {
|
|
24290
|
-
const value = event.target.value;
|
|
24291
|
-
setDiscussions((current) => current.map((entry) => entry.id === discussion.id ? {
|
|
24292
|
-
...entry,
|
|
24293
|
-
draft: value
|
|
24294
|
-
} : entry));
|
|
24295
|
-
},
|
|
24296
|
-
onKeyDown: (event) => {
|
|
24297
|
-
if (event.key !== "Enter") return;
|
|
24298
|
-
if (event.nativeEvent.isComposing || event.keyCode === 229) return;
|
|
24299
|
-
event.preventDefault();
|
|
24300
|
-
sendDiscussion(discussion.id);
|
|
24301
|
-
}
|
|
24302
|
-
}), (0, react_jsx_runtime.jsxs)("button", {
|
|
24303
|
-
type: "button",
|
|
24304
|
-
className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.actionPrimary} ${PendingPanel_module_css_default.discussionSend}`,
|
|
24305
|
-
"data-diff-discussion-send": true,
|
|
24306
|
-
disabled: askingId !== void 0,
|
|
24307
|
-
onClick: () => {
|
|
24308
|
-
sendDiscussion(discussion.id);
|
|
24309
|
-
},
|
|
24310
|
-
children: [t("action.comment"), (0, react_jsx_runtime.jsx)(ReturnIcon, {})]
|
|
24311
|
-
})]
|
|
24312
|
-
})
|
|
24313
|
-
]
|
|
24314
|
-
})]
|
|
24315
|
-
}, discussion.id)
|
|
25476
|
+
children: renderDiscussion(discussion, bodyWidth, false)
|
|
24316
25477
|
})
|
|
24317
25478
|
})
|
|
24318
25479
|
]
|
|
@@ -24440,6 +25601,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
24440
25601
|
}
|
|
24441
25602
|
}, flashKey),
|
|
24442
25603
|
searchBar,
|
|
25604
|
+
gotoDialog,
|
|
24443
25605
|
rulerMarkers.length > 0 && (0, react_jsx_runtime.jsx)("div", {
|
|
24444
25606
|
className: PendingPanel_module_css_default.overviewRuler,
|
|
24445
25607
|
"data-diff-approval-ruler": true,
|
|
@@ -24605,14 +25767,17 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
24605
25767
|
*/
|
|
24606
25768
|
const [landing, setLanding] = (0, react.useState)(void 0);
|
|
24607
25769
|
/** Ask the diff to land on one file: its first change unless `top` says where, or the row a jump
|
|
24608
|
-
* to a comment names (which lands the way a change-block jump does, see `landingRow`).
|
|
25770
|
+
* to a comment names (which lands the way a change-block jump does, see `landingRow`). `card` lands
|
|
25771
|
+
* the thread's own box instead of the rows it named, which is what an outdated comment needs: the
|
|
25772
|
+
* code it was written about is gone, so the position its numbers point at says nothing.
|
|
24609
25773
|
* The nonce makes the request an event rather than a value, so re-clicking the
|
|
24610
25774
|
* chip for the file already open lands on its first change again. */
|
|
24611
|
-
const landOn = (fileId, top, row) => {
|
|
25775
|
+
const landOn = (fileId, top, row, card) => {
|
|
24612
25776
|
setLanding((prev) => ({
|
|
24613
25777
|
fileId,
|
|
24614
25778
|
top,
|
|
24615
25779
|
row,
|
|
25780
|
+
card,
|
|
24616
25781
|
n: (prev?.n ?? 0) + 1
|
|
24617
25782
|
}));
|
|
24618
25783
|
};
|
|
@@ -24684,6 +25849,29 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
24684
25849
|
n: (prev?.n ?? 0) + 1
|
|
24685
25850
|
}));
|
|
24686
25851
|
};
|
|
25852
|
+
/**
|
|
25853
|
+
* The host says it cannot write the pending state to disk. Said ONCE per distinct message: that file
|
|
25854
|
+
* is what makes the list survive a restart, so a reader who is never told simply finds the list gone
|
|
25855
|
+
* later with nothing to explain it (issue #6) — but the field rides every poll, and a filesystem that
|
|
25856
|
+
* keeps failing must not toast on each one. The host retracts the field once a write works, and that
|
|
25857
|
+
* retraction is what arms the marker again: the same disk failing twice, with a working spell between,
|
|
25858
|
+
* is news the second time too.
|
|
25859
|
+
*/
|
|
25860
|
+
const persistToastRef = (0, react.useRef)(void 0);
|
|
25861
|
+
(0, react.useEffect)(() => {
|
|
25862
|
+
const message = snapshot.persistError;
|
|
25863
|
+
if (message === void 0) {
|
|
25864
|
+
persistToastRef.current = void 0;
|
|
25865
|
+
return;
|
|
25866
|
+
}
|
|
25867
|
+
if (message === persistToastRef.current) return;
|
|
25868
|
+
persistToastRef.current = message;
|
|
25869
|
+
showCopyToast(t("panel.persistFailed"));
|
|
25870
|
+
}, [
|
|
25871
|
+
snapshot.persistError,
|
|
25872
|
+
showCopyToast,
|
|
25873
|
+
t
|
|
25874
|
+
]);
|
|
24687
25875
|
const handleOpenFileRef = (0, react.useRef)();
|
|
24688
25876
|
handleOpenFileRef.current = (path) => {
|
|
24689
25877
|
const entry = snapshot.files.find((file) => diffPathsMatch(path, file.path, snapshot.workspacePath));
|
|
@@ -24724,8 +25912,21 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
24724
25912
|
* choice rides the same block RPC as its `removeWhenResolved` flag. */
|
|
24725
25913
|
const [blockPrompt, setBlockPrompt] = (0, react.useState)(null);
|
|
24726
25914
|
const [filePrompt, setFilePrompt] = (0, react.useState)(null);
|
|
25915
|
+
/** The confirm dialog's own checkbox: stop asking about this file for the rest of the page. */
|
|
25916
|
+
const [quietRemoval, setQuietRemoval] = (0, react.useState)(false);
|
|
25917
|
+
/**
|
|
25918
|
+
* Record the confirm dialog's checkbox, if it was ticked, and put it back for the next dialog.
|
|
25919
|
+
* The tick is about the questions still to come, not about the answer just given: the button the
|
|
25920
|
+
* reader presses is the answer, and it runs either way.
|
|
25921
|
+
*/
|
|
25922
|
+
const settleRemovalAsk = (id) => {
|
|
25923
|
+
if (quietRemoval) quietenRemovalAsk(current, id);
|
|
25924
|
+
setQuietRemoval(false);
|
|
25925
|
+
};
|
|
24727
25926
|
/** The file list row whose action menu is open, and where the right-click landed. */
|
|
24728
25927
|
const [rowMenu, setRowMenu] = (0, react.useState)(null);
|
|
25928
|
+
/** The comments-tab item whose menu is open, if any: which thread, and where the press landed. */
|
|
25929
|
+
const [commentMenu, setCommentMenu] = (0, react.useState)(null);
|
|
24729
25930
|
/** Whether the add-path dialog is open. One dialog covers both shapes: what
|
|
24730
25931
|
* the browser settles on decides whether a file or a directory is added. */
|
|
24731
25932
|
const [addOpen, setAddOpen] = (0, react.useState)(false);
|
|
@@ -24746,8 +25947,9 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
24746
25947
|
/** The chord's on-screen echo: the edge just flipped, and a nonce so a repeat
|
|
24747
25948
|
* restarts the notice instead of re-rendering the same one. */
|
|
24748
25949
|
const [coverNotice, setCoverNotice] = (0, react.useState)(null);
|
|
24749
|
-
/** File-list pane width, adjustable by dragging the divider.
|
|
24750
|
-
|
|
25950
|
+
/** File-list pane width, adjustable by dragging the divider. It opens AT the floor, which is the
|
|
25951
|
+
* width the bulk footer needs for its three labels, so a fresh pane cannot wrap them either. */
|
|
25952
|
+
const [listWidth, setListWidth] = (0, react.useState)(260);
|
|
24751
25953
|
/** Whether the floating (collapsed) file list is currently shown. */
|
|
24752
25954
|
const [floatOpen, setFloatOpen] = (0, react.useState)(false);
|
|
24753
25955
|
/** Whether the file list is always folded, whatever the width allows. */
|
|
@@ -25004,6 +26206,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
25004
26206
|
const blockKeepWithPrompt = (sessionId, id, block, removeWhenResolved) => {
|
|
25005
26207
|
const file = files.find((entry) => entry.id === id);
|
|
25006
26208
|
if (removeWhenResolved === void 0 && file !== void 0 && blockResolvesWholeFile(file, block)) {
|
|
26209
|
+
if (removalAskQuiet(current, id)) return onBlockKeep(sessionId, id, block, false);
|
|
25007
26210
|
setBlockPrompt({
|
|
25008
26211
|
action: "keep",
|
|
25009
26212
|
sessionId,
|
|
@@ -25017,6 +26220,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
25017
26220
|
const blockRevertWithPrompt = (sessionId, id, block, removeWhenResolved) => {
|
|
25018
26221
|
const file = files.find((entry) => entry.id === id);
|
|
25019
26222
|
if (removeWhenResolved === void 0 && file !== void 0 && blockResolvesWholeFile(file, block)) {
|
|
26223
|
+
if (removalAskQuiet(current, id)) return onBlockRevert(sessionId, id, block, false);
|
|
25020
26224
|
setBlockPrompt({
|
|
25021
26225
|
action: "revert",
|
|
25022
26226
|
sessionId,
|
|
@@ -25029,6 +26233,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
25029
26233
|
};
|
|
25030
26234
|
const keepWithPrompt = (sessionId, id, keepListed) => {
|
|
25031
26235
|
if (keepListed === void 0 && confirmFileRemoveEnabled()) {
|
|
26236
|
+
if (removalAskQuiet(current, id)) return onKeep(sessionId, id, true);
|
|
25032
26237
|
setFilePrompt({
|
|
25033
26238
|
action: "keep",
|
|
25034
26239
|
sessionId,
|
|
@@ -25040,6 +26245,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
25040
26245
|
};
|
|
25041
26246
|
const revertWithPrompt = (sessionId, id, keepListed) => {
|
|
25042
26247
|
if (keepListed === void 0 && confirmFileRemoveEnabled()) {
|
|
26248
|
+
if (removalAskQuiet(current, id)) return onRevert(sessionId, id, true);
|
|
25043
26249
|
setFilePrompt({
|
|
25044
26250
|
action: "revert",
|
|
25045
26251
|
sessionId,
|
|
@@ -25388,36 +26594,95 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
25388
26594
|
};
|
|
25389
26595
|
const selectedFile = files.find((file) => file.id === selected);
|
|
25390
26596
|
/**
|
|
25391
|
-
*
|
|
25392
|
-
*
|
|
25393
|
-
*
|
|
25394
|
-
*
|
|
25395
|
-
*
|
|
26597
|
+
* A file that leaves the list takes its comments with it: the reader who kept or reverted that file
|
|
26598
|
+
* out of the list is done with it, and a thread is a block of rows in a diff the list no longer
|
|
26599
|
+
* holds — so the rows it was written about are gone with the entry (see `forgetDiscussionsNotIn`).
|
|
26600
|
+
*
|
|
26601
|
+
* Only a list that has actually been READ may say a file is gone. An unread panel, a connection
|
|
26602
|
+
* reset (`read` goes back to false, with the files) and a sessionless page all publish an empty
|
|
26603
|
+
* list, and none of those means the reader finished with the files it names.
|
|
26604
|
+
*/
|
|
26605
|
+
const listedIds = (0, react.useMemo)(() => files.map((file) => file.id), [files]);
|
|
26606
|
+
(0, react.useEffect)(() => {
|
|
26607
|
+
if (current === void 0 || !snapshot.read) return;
|
|
26608
|
+
forgetDiscussionsNotIn(current, listedIds);
|
|
26609
|
+
}, [
|
|
26610
|
+
current,
|
|
26611
|
+
snapshot.read,
|
|
26612
|
+
listedIds
|
|
26613
|
+
]);
|
|
26614
|
+
/**
|
|
26615
|
+
* Every comment the session's files carry, grouped by the file it hangs in: what the comments tab
|
|
26616
|
+
* shows. The session is the scope — every file of it that is still in the list, whether or not the
|
|
26617
|
+
* reader has opened it, and however many files that is — and the file is what the comments are
|
|
26618
|
+
* grouped by, under the file's own name.
|
|
26619
|
+
*
|
|
26620
|
+
* A comment IS a block of rows in one file, so its label is the lines it names — the `path:lines`
|
|
26621
|
+
* reference the thread's own header wears, with the path left off (the group above IS that file) and
|
|
26622
|
+
* nothing in front of the numbers, which are the whole label at that point. Its title is the first
|
|
26623
|
+
* sentence of what the reader asked (the first turn is the annotation; later ones are follow-ups), and
|
|
26624
|
+
* an outdated one says so — the same state the block itself is wearing (see `[data-lost]`). Within a
|
|
26625
|
+
* group the comments keep the order their rows run, and the groups keep the list's own order (the file
|
|
26626
|
+
* name).
|
|
25396
26627
|
*
|
|
25397
26628
|
* The threads are held by the file detail, which is one mount at a time, so they are read back
|
|
25398
|
-
* out of the memory the two share, and re-read whenever they change (`commentsTick`).
|
|
26629
|
+
* out of the memory the two share, and re-read whenever they change (`commentsTick`). A file with
|
|
26630
|
+
* no threads is left out rather than shown with nothing under it.
|
|
25399
26631
|
*/
|
|
25400
|
-
const
|
|
26632
|
+
const commentGroups = (0, react.useMemo)(() => {
|
|
25401
26633
|
const threads = rememberedDiscussions(current);
|
|
25402
|
-
return files.
|
|
25403
|
-
id: discussion.id,
|
|
26634
|
+
return files.map((file) => ({
|
|
25404
26635
|
fileId: file.id,
|
|
25405
|
-
|
|
25406
|
-
|
|
25407
|
-
|
|
25408
|
-
|
|
25409
|
-
|
|
26636
|
+
name: basenameOf(file.path),
|
|
26637
|
+
path: file.path,
|
|
26638
|
+
entries: (threads[file.id] ?? []).map((discussion) => {
|
|
26639
|
+
const written = commentTitle(discussion);
|
|
26640
|
+
const empty = written === "";
|
|
26641
|
+
return {
|
|
26642
|
+
id: discussion.id,
|
|
26643
|
+
fileId: file.id,
|
|
26644
|
+
row: discussion.anchor.start,
|
|
26645
|
+
end: discussion.anchor.end,
|
|
26646
|
+
label: `[${lineRangeLabel(discussion.anchor.startLine, discussion.anchor.endLine)}]`,
|
|
26647
|
+
title: empty ? t("discussion.placeholder") : written,
|
|
26648
|
+
empty,
|
|
26649
|
+
lost: discussion.lost === true
|
|
26650
|
+
};
|
|
26651
|
+
})
|
|
26652
|
+
})).filter((group) => group.entries.length > 0);
|
|
25410
26653
|
}, [
|
|
25411
26654
|
files,
|
|
25412
26655
|
current,
|
|
25413
|
-
snapshot.workspacePath,
|
|
25414
26656
|
commentsTick,
|
|
25415
26657
|
t
|
|
25416
26658
|
]);
|
|
25417
|
-
/**
|
|
25418
|
-
const
|
|
26659
|
+
/** The same comments, flat: what the tab counts and what says whether there are any. */
|
|
26660
|
+
const commentEntries = (0, react.useMemo)(() => commentGroups.flatMap((group) => group.entries), [commentGroups]);
|
|
26661
|
+
/** Open the file a comment hangs in and land on the comment: the rows it names, or — for an outdated
|
|
26662
|
+
* thread, whose code is gone — its own box, which is the only place that says anything. */
|
|
26663
|
+
const jumpToComment = (fileId, row, card = false) => {
|
|
25419
26664
|
if (fileId !== selected) setSelected(fileId);
|
|
25420
|
-
landOn(fileId, void 0, row);
|
|
26665
|
+
landOn(fileId, void 0, row, card);
|
|
26666
|
+
};
|
|
26667
|
+
/**
|
|
26668
|
+
* The comment menu's rows: the one action a thread has, named exactly as the block's own
|
|
26669
|
+
* overflow menu names it — ending a comment is one thing, and the pane it is asked from must
|
|
26670
|
+
* not look like it does something else.
|
|
26671
|
+
*/
|
|
26672
|
+
const commentMenuItems = (0, react.useMemo)(() => [{
|
|
26673
|
+
id: "close",
|
|
26674
|
+
label: t("action.discussionEnd")
|
|
26675
|
+
}], [t]);
|
|
26676
|
+
/**
|
|
26677
|
+
* End one comment from the list. The threads belong to the file detail, so the list does not
|
|
26678
|
+
* reach into its state: it forgets the thread in the page's memory, and the detail picks that
|
|
26679
|
+
* up (see `forgetDiscussion`), which is also what takes the block out of the open file.
|
|
26680
|
+
*/
|
|
26681
|
+
const runCommentMenu = (id) => {
|
|
26682
|
+
const target = commentMenu;
|
|
26683
|
+
setCommentMenu(null);
|
|
26684
|
+
if (target === null || id !== "close") return;
|
|
26685
|
+
forgetDiscussion(current, target.fileId, target.id);
|
|
25421
26686
|
};
|
|
25422
26687
|
/**
|
|
25423
26688
|
* The folded card's own box, derived from the measured one, or undefined while
|
|
@@ -25452,7 +26717,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
25452
26717
|
setListTab("pending");
|
|
25453
26718
|
},
|
|
25454
26719
|
children: t("panel.tab.pending")
|
|
25455
|
-
}), (0, react_jsx_runtime.
|
|
26720
|
+
}), (0, react_jsx_runtime.jsxs)("button", {
|
|
25456
26721
|
type: "button",
|
|
25457
26722
|
role: "tab",
|
|
25458
26723
|
className: PendingPanel_module_css_default.listTab,
|
|
@@ -25461,7 +26726,11 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
25461
26726
|
onClick: () => {
|
|
25462
26727
|
setListTab("comments");
|
|
25463
26728
|
},
|
|
25464
|
-
children: t("panel.tab.comments")
|
|
26729
|
+
children: [(0, react_jsx_runtime.jsx)("span", { children: t("panel.tab.comments") }), commentEntries.length > 0 && (0, react_jsx_runtime.jsx)("span", {
|
|
26730
|
+
className: PendingPanel_module_css_default.tabCount,
|
|
26731
|
+
"data-diff-list-count": true,
|
|
26732
|
+
children: commentEntries.length
|
|
26733
|
+
})]
|
|
25465
26734
|
})]
|
|
25466
26735
|
}) : (0, react_jsx_runtime.jsx)("h3", {
|
|
25467
26736
|
className: PendingPanel_module_css_default.listTitle,
|
|
@@ -25492,43 +26761,72 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
25492
26761
|
className: PendingPanel_module_css_default.listEmpty,
|
|
25493
26762
|
"data-diff-comments-empty": true,
|
|
25494
26763
|
children: t("panel.commentsEmpty")
|
|
25495
|
-
}) : (0, react_jsx_runtime.jsx)("
|
|
25496
|
-
className: PendingPanel_module_css_default.rows,
|
|
26764
|
+
}) : (0, react_jsx_runtime.jsx)("div", {
|
|
25497
26765
|
"data-diff-comment-list": true,
|
|
25498
|
-
children:
|
|
25499
|
-
className: PendingPanel_module_css_default.
|
|
25500
|
-
|
|
25501
|
-
|
|
25502
|
-
|
|
25503
|
-
|
|
25504
|
-
|
|
25505
|
-
|
|
25506
|
-
|
|
25507
|
-
|
|
25508
|
-
|
|
25509
|
-
|
|
25510
|
-
|
|
25511
|
-
|
|
25512
|
-
|
|
25513
|
-
|
|
25514
|
-
|
|
25515
|
-
|
|
25516
|
-
|
|
25517
|
-
className: PendingPanel_module_css_default.
|
|
25518
|
-
"data-diff-comment-
|
|
25519
|
-
|
|
25520
|
-
|
|
25521
|
-
|
|
25522
|
-
|
|
25523
|
-
|
|
25524
|
-
|
|
25525
|
-
|
|
25526
|
-
|
|
25527
|
-
|
|
25528
|
-
|
|
25529
|
-
|
|
25530
|
-
|
|
25531
|
-
|
|
26766
|
+
children: commentGroups.map((group) => (0, react_jsx_runtime.jsxs)("div", {
|
|
26767
|
+
className: PendingPanel_module_css_default.commentGroup,
|
|
26768
|
+
"data-diff-comment-group": group.fileId,
|
|
26769
|
+
children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
26770
|
+
label: group.path,
|
|
26771
|
+
delayMs: 500,
|
|
26772
|
+
maxWidth: 560,
|
|
26773
|
+
children: (0, react_jsx_runtime.jsx)("h4", {
|
|
26774
|
+
className: PendingPanel_module_css_default.commentGroupName,
|
|
26775
|
+
"data-diff-comment-group-name": true,
|
|
26776
|
+
children: group.name
|
|
26777
|
+
})
|
|
26778
|
+
}), (0, react_jsx_runtime.jsx)("ul", {
|
|
26779
|
+
className: PendingPanel_module_css_default.rows,
|
|
26780
|
+
children: group.entries.map((entry) => (0, react_jsx_runtime.jsx)("li", {
|
|
26781
|
+
className: PendingPanel_module_css_default.row,
|
|
26782
|
+
children: (0, react_jsx_runtime.jsx)("div", {
|
|
26783
|
+
role: "button",
|
|
26784
|
+
tabIndex: 0,
|
|
26785
|
+
className: PendingPanel_module_css_default.commentRow,
|
|
26786
|
+
"data-diff-comment-link": entry.id,
|
|
26787
|
+
"data-mobile-nav-copy": "1",
|
|
26788
|
+
onClick: () => {
|
|
26789
|
+
jumpToComment(entry.fileId, entry.lost ? entry.end : entry.row, entry.lost);
|
|
26790
|
+
},
|
|
26791
|
+
onContextMenu: (event) => {
|
|
26792
|
+
event.preventDefault();
|
|
26793
|
+
setCommentMenu({
|
|
26794
|
+
id: entry.id,
|
|
26795
|
+
fileId: entry.fileId,
|
|
26796
|
+
x: event.clientX,
|
|
26797
|
+
y: event.clientY
|
|
26798
|
+
});
|
|
26799
|
+
},
|
|
26800
|
+
onKeyDown: (event) => {
|
|
26801
|
+
if (event.key !== "Enter" && event.key !== " ") return;
|
|
26802
|
+
event.preventDefault();
|
|
26803
|
+
jumpToComment(entry.fileId, entry.lost ? entry.end : entry.row, entry.lost);
|
|
26804
|
+
},
|
|
26805
|
+
children: (0, react_jsx_runtime.jsxs)("span", {
|
|
26806
|
+
className: PendingPanel_module_css_default.commentHead,
|
|
26807
|
+
children: [
|
|
26808
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
26809
|
+
className: entry.empty ? `${PendingPanel_module_css_default.commentTitle} ${PendingPanel_module_css_default.commentTitleEmpty}` : PendingPanel_module_css_default.commentTitle,
|
|
26810
|
+
"data-diff-comment-title": true,
|
|
26811
|
+
"data-diff-comment-empty": entry.empty ? "" : void 0,
|
|
26812
|
+
children: entry.title
|
|
26813
|
+
}),
|
|
26814
|
+
entry.lost && (0, react_jsx_runtime.jsx)("span", {
|
|
26815
|
+
className: PendingPanel_module_css_default.commentLost,
|
|
26816
|
+
"data-diff-comment-lost": true,
|
|
26817
|
+
children: t("panel.commentOutdated")
|
|
26818
|
+
}),
|
|
26819
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
26820
|
+
className: PendingPanel_module_css_default.commentLabel,
|
|
26821
|
+
"data-diff-comment-label": true,
|
|
26822
|
+
children: entry.label
|
|
26823
|
+
})
|
|
26824
|
+
]
|
|
26825
|
+
})
|
|
26826
|
+
})
|
|
26827
|
+
}, entry.id))
|
|
26828
|
+
})]
|
|
26829
|
+
}, group.fileId))
|
|
25532
26830
|
})
|
|
25533
26831
|
}) : (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)("div", {
|
|
25534
26832
|
className: PendingPanel_module_css_default.listScroll,
|
|
@@ -25718,7 +27016,9 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
25718
27016
|
if (event.target instanceof Element && event.target.closest("[data-diff-path-input]") !== null) return;
|
|
25719
27017
|
if (document.querySelector("[data-diff-approval-cover-popover]") !== null) return;
|
|
25720
27018
|
const target = event.target;
|
|
25721
|
-
|
|
27019
|
+
const inPanel = target instanceof Node && panelRef.current?.contains(target) === true;
|
|
27020
|
+
if (inPanel && document.querySelector("[data-diff-searchbar]") !== null) return;
|
|
27021
|
+
if (inPanel && document.querySelector("[data-diff-goto-dialog]") !== null) return;
|
|
25722
27022
|
event.preventDefault();
|
|
25723
27023
|
closePanel();
|
|
25724
27024
|
};
|
|
@@ -25741,7 +27041,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
25741
27041
|
event.preventDefault();
|
|
25742
27042
|
const startX = event.clientX;
|
|
25743
27043
|
const startWidth = listWidth;
|
|
25744
|
-
const cap = floatMode && floatBox !== null ? Math.max(
|
|
27044
|
+
const cap = floatMode && floatBox !== null ? Math.max(260, floatBox.width - 24) : MAX_LIST_WIDTH_PX;
|
|
25745
27045
|
try {
|
|
25746
27046
|
event.currentTarget.setPointerCapture(event.pointerId);
|
|
25747
27047
|
} catch {}
|
|
@@ -25750,7 +27050,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
25750
27050
|
let latest = startWidth;
|
|
25751
27051
|
let pending = 0;
|
|
25752
27052
|
const onMove = (move) => {
|
|
25753
|
-
latest = Math.min(Math.max(startWidth + (move.clientX - startX),
|
|
27053
|
+
latest = Math.min(Math.max(startWidth + (move.clientX - startX), 260), cap);
|
|
25754
27054
|
if (pending !== 0) return;
|
|
25755
27055
|
pending = requestAnimationFrame(() => {
|
|
25756
27056
|
pending = 0;
|
|
@@ -25775,19 +27075,25 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
25775
27075
|
};
|
|
25776
27076
|
/**
|
|
25777
27077
|
* End the text selection when the press lands on the panel's chrome — blank space, a label, the
|
|
25778
|
-
* toolbar, the file list.
|
|
27078
|
+
* toolbar, the file list — or on a row the selection already covers (see `pressOnSelectedRow`).
|
|
25779
27079
|
*
|
|
25780
27080
|
* The chrome is `user-select: none` (see `.panel`), and a press on such an area is one the
|
|
25781
27081
|
* browser does NOT clear the selection for: the highlight stayed up, and so did the selection
|
|
25782
|
-
* frame that goes with it, over a gesture that plainly ended.
|
|
25783
|
-
*
|
|
25784
|
-
*
|
|
27082
|
+
* frame that goes with it, over a gesture that plainly ended. The same is true inside the code
|
|
27083
|
+
* view when the press lands on the selection's own row, which is the one content press the panel
|
|
27084
|
+
* ends itself. What IS content is otherwise left to the browser — which is also what keeps a drag
|
|
27085
|
+
* started on chrome able to select the code it runs into, since dropping the ranges first costs
|
|
27086
|
+
* the drag nothing.
|
|
25785
27087
|
*/
|
|
25786
27088
|
const onPanelMouseDown = (event) => {
|
|
25787
27089
|
const target = event.target;
|
|
25788
27090
|
if (!(target instanceof Element)) return;
|
|
25789
|
-
if (target.closest(KEEPS_SELECTION) !== null) return;
|
|
25790
27091
|
const live = window.getSelection();
|
|
27092
|
+
if (target.closest("[data-diff-selection-actions], [data-diff-copy]") === null && pressOnSelectedRow(target, live)) {
|
|
27093
|
+
if (typeof live?.removeAllRanges === "function") live.removeAllRanges();
|
|
27094
|
+
return;
|
|
27095
|
+
}
|
|
27096
|
+
if (target.closest(KEEPS_SELECTION) !== null) return;
|
|
25791
27097
|
if (typeof live?.removeAllRanges === "function") live.removeAllRanges();
|
|
25792
27098
|
};
|
|
25793
27099
|
const content = (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
@@ -25976,6 +27282,10 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
25976
27282
|
landingTop: landing !== void 0 && landing.fileId === selectedFile.id ? landing.top : void 0,
|
|
25977
27283
|
landingTick: landing !== void 0 && landing.fileId === selectedFile.id ? landing.n : 0,
|
|
25978
27284
|
landingRow: landing !== void 0 && landing.fileId === selectedFile.id ? landing.row : void 0,
|
|
27285
|
+
landingCard: landing !== void 0 && landing.fileId === selectedFile.id ? landing.card : void 0,
|
|
27286
|
+
onLanded: () => {
|
|
27287
|
+
setLanding((current) => current === void 0 ? current : void 0);
|
|
27288
|
+
},
|
|
25979
27289
|
failedMessage: failed.get(selectedFile.id),
|
|
25980
27290
|
commentSkill: snapshot.commentSkill,
|
|
25981
27291
|
onPasteReference,
|
|
@@ -26025,33 +27335,50 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
26025
27335
|
className: PendingPanel_module_css_default.confirmCard,
|
|
26026
27336
|
role: "dialog",
|
|
26027
27337
|
"aria-modal": "true",
|
|
26028
|
-
children: [
|
|
26029
|
-
|
|
26030
|
-
|
|
26031
|
-
|
|
26032
|
-
|
|
26033
|
-
|
|
26034
|
-
|
|
26035
|
-
|
|
26036
|
-
"
|
|
26037
|
-
|
|
26038
|
-
|
|
26039
|
-
|
|
26040
|
-
|
|
26041
|
-
|
|
26042
|
-
|
|
26043
|
-
|
|
26044
|
-
|
|
26045
|
-
|
|
26046
|
-
|
|
26047
|
-
|
|
26048
|
-
|
|
26049
|
-
|
|
26050
|
-
|
|
26051
|
-
|
|
26052
|
-
|
|
26053
|
-
|
|
26054
|
-
|
|
27338
|
+
children: [
|
|
27339
|
+
(0, react_jsx_runtime.jsx)("p", {
|
|
27340
|
+
className: PendingPanel_module_css_default.confirmText,
|
|
27341
|
+
children: t("panel.resolvedAsk", { file: basenameOf(promptFile.path) })
|
|
27342
|
+
}),
|
|
27343
|
+
(0, react_jsx_runtime.jsxs)("label", {
|
|
27344
|
+
className: PendingPanel_module_css_default.pickerCheck,
|
|
27345
|
+
title: t("panel.removalQuietHint"),
|
|
27346
|
+
children: [(0, react_jsx_runtime.jsx)("input", {
|
|
27347
|
+
type: "checkbox",
|
|
27348
|
+
"data-diff-confirm-quiet": true,
|
|
27349
|
+
checked: quietRemoval,
|
|
27350
|
+
onChange: (event) => {
|
|
27351
|
+
setQuietRemoval(event.target.checked);
|
|
27352
|
+
}
|
|
27353
|
+
}), t("panel.removalQuiet")]
|
|
27354
|
+
}),
|
|
27355
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
27356
|
+
className: PendingPanel_module_css_default.confirmActions,
|
|
27357
|
+
children: [(0, react_jsx_runtime.jsx)("button", {
|
|
27358
|
+
type: "button",
|
|
27359
|
+
className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.actionPrimary}`,
|
|
27360
|
+
"data-diff-confirm-remove": true,
|
|
27361
|
+
onClick: () => {
|
|
27362
|
+
setBlockPrompt(null);
|
|
27363
|
+
const { action, sessionId, id, block } = blockPrompt;
|
|
27364
|
+
settleRemovalAsk(id);
|
|
27365
|
+
action === "keep" ? onBlockKeep(sessionId, id, block, true) : onBlockRevert(sessionId, id, block, true);
|
|
27366
|
+
},
|
|
27367
|
+
children: t("row.dismiss")
|
|
27368
|
+
}), (0, react_jsx_runtime.jsx)("button", {
|
|
27369
|
+
type: "button",
|
|
27370
|
+
className: PendingPanel_module_css_default.action,
|
|
27371
|
+
"data-diff-confirm-keep": true,
|
|
27372
|
+
onClick: () => {
|
|
27373
|
+
setBlockPrompt(null);
|
|
27374
|
+
const { action, sessionId, id, block } = blockPrompt;
|
|
27375
|
+
settleRemovalAsk(id);
|
|
27376
|
+
action === "keep" ? onBlockKeep(sessionId, id, block, false) : onBlockRevert(sessionId, id, block, false);
|
|
27377
|
+
},
|
|
27378
|
+
children: t("panel.keepInList")
|
|
27379
|
+
})]
|
|
27380
|
+
})
|
|
27381
|
+
]
|
|
26055
27382
|
})
|
|
26056
27383
|
}),
|
|
26057
27384
|
filePrompt !== null && promptEntry !== void 0 && (0, react_jsx_runtime.jsx)("div", {
|
|
@@ -26061,33 +27388,50 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
26061
27388
|
className: PendingPanel_module_css_default.confirmCard,
|
|
26062
27389
|
role: "dialog",
|
|
26063
27390
|
"aria-modal": "true",
|
|
26064
|
-
children: [
|
|
26065
|
-
|
|
26066
|
-
|
|
26067
|
-
|
|
26068
|
-
|
|
26069
|
-
|
|
26070
|
-
|
|
26071
|
-
|
|
26072
|
-
"
|
|
26073
|
-
|
|
26074
|
-
|
|
26075
|
-
|
|
26076
|
-
|
|
26077
|
-
|
|
26078
|
-
|
|
26079
|
-
|
|
26080
|
-
|
|
26081
|
-
|
|
26082
|
-
|
|
26083
|
-
|
|
26084
|
-
|
|
26085
|
-
|
|
26086
|
-
|
|
26087
|
-
|
|
26088
|
-
|
|
26089
|
-
|
|
26090
|
-
|
|
27391
|
+
children: [
|
|
27392
|
+
(0, react_jsx_runtime.jsx)("p", {
|
|
27393
|
+
className: PendingPanel_module_css_default.confirmText,
|
|
27394
|
+
children: t(filePrompt.action === "keep" ? "panel.fileKeptAsk" : "panel.fileRevertedAsk", { file: basenameOf(promptEntry.path) })
|
|
27395
|
+
}),
|
|
27396
|
+
(0, react_jsx_runtime.jsxs)("label", {
|
|
27397
|
+
className: PendingPanel_module_css_default.pickerCheck,
|
|
27398
|
+
title: t("panel.removalQuietHint"),
|
|
27399
|
+
children: [(0, react_jsx_runtime.jsx)("input", {
|
|
27400
|
+
type: "checkbox",
|
|
27401
|
+
"data-diff-file-confirm-quiet": true,
|
|
27402
|
+
checked: quietRemoval,
|
|
27403
|
+
onChange: (event) => {
|
|
27404
|
+
setQuietRemoval(event.target.checked);
|
|
27405
|
+
}
|
|
27406
|
+
}), t("panel.removalQuiet")]
|
|
27407
|
+
}),
|
|
27408
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
27409
|
+
className: PendingPanel_module_css_default.confirmActions,
|
|
27410
|
+
children: [(0, react_jsx_runtime.jsx)("button", {
|
|
27411
|
+
type: "button",
|
|
27412
|
+
className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.actionPrimary}`,
|
|
27413
|
+
"data-diff-file-confirm-remove": true,
|
|
27414
|
+
onClick: () => {
|
|
27415
|
+
setFilePrompt(null);
|
|
27416
|
+
const { action, sessionId, id } = filePrompt;
|
|
27417
|
+
settleRemovalAsk(id);
|
|
27418
|
+
action === "keep" ? onKeep(sessionId, id, false) : onRevert(sessionId, id, false);
|
|
27419
|
+
},
|
|
27420
|
+
children: t("row.dismiss")
|
|
27421
|
+
}), (0, react_jsx_runtime.jsx)("button", {
|
|
27422
|
+
type: "button",
|
|
27423
|
+
className: PendingPanel_module_css_default.action,
|
|
27424
|
+
"data-diff-file-confirm-keep": true,
|
|
27425
|
+
onClick: () => {
|
|
27426
|
+
setFilePrompt(null);
|
|
27427
|
+
const { action, sessionId, id } = filePrompt;
|
|
27428
|
+
settleRemovalAsk(id);
|
|
27429
|
+
action === "keep" ? onKeep(sessionId, id, true) : onRevert(sessionId, id, true);
|
|
27430
|
+
},
|
|
27431
|
+
children: t("panel.keepInList")
|
|
27432
|
+
})]
|
|
27433
|
+
})
|
|
27434
|
+
]
|
|
26091
27435
|
})
|
|
26092
27436
|
}),
|
|
26093
27437
|
rowMenu !== null && (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Menu, {
|
|
@@ -26102,6 +27446,18 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
26102
27446
|
getAnchorRect: () => new DOMRect(rowMenu.x, rowMenu.y, 0, 0),
|
|
26103
27447
|
anchor: (0, react_jsx_runtime.jsx)("span", { className: PendingPanel_module_css_default.rowMenuAnchor })
|
|
26104
27448
|
}),
|
|
27449
|
+
commentMenu !== null && (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Menu, {
|
|
27450
|
+
open: true,
|
|
27451
|
+
portal: true,
|
|
27452
|
+
compact: true,
|
|
27453
|
+
items: commentMenuItems,
|
|
27454
|
+
onSelect: runCommentMenu,
|
|
27455
|
+
onClose: () => {
|
|
27456
|
+
setCommentMenu(null);
|
|
27457
|
+
},
|
|
27458
|
+
getAnchorRect: () => new DOMRect(commentMenu.x, commentMenu.y, 0, 0),
|
|
27459
|
+
anchor: (0, react_jsx_runtime.jsx)("span", { className: PendingPanel_module_css_default.rowMenuAnchor })
|
|
27460
|
+
}),
|
|
26105
27461
|
addOpen && current !== void 0 && (0, react_jsx_runtime.jsx)(PathPicker, {
|
|
26106
27462
|
rootPath: snapshot.workspacePath,
|
|
26107
27463
|
onBrowse: (path) => onBrowse(current, path),
|
|
@@ -27347,15 +28703,19 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
27347
28703
|
const redoCleared = value.redoCleared;
|
|
27348
28704
|
const skill = value.commentSkill;
|
|
27349
28705
|
const commentSkill = typeof skill === "string" && skill.length > 0 ? skill : void 0;
|
|
28706
|
+
const persisted = value.persistError;
|
|
28707
|
+
const persistError = typeof persisted === "string" && persisted.length > 0 ? persisted : void 0;
|
|
27350
28708
|
return redoCleared === true ? {
|
|
27351
28709
|
files,
|
|
27352
28710
|
workspacePath,
|
|
27353
28711
|
redoCleared: true,
|
|
27354
|
-
commentSkill
|
|
28712
|
+
commentSkill,
|
|
28713
|
+
persistError
|
|
27355
28714
|
} : {
|
|
27356
28715
|
files,
|
|
27357
28716
|
workspacePath,
|
|
27358
|
-
commentSkill
|
|
28717
|
+
commentSkill,
|
|
28718
|
+
persistError
|
|
27359
28719
|
};
|
|
27360
28720
|
}
|
|
27361
28721
|
/** Narrow one action endpoint's value; a malformed wire value is an action failure. */
|
|
@@ -27611,13 +28971,14 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
27611
28971
|
return;
|
|
27612
28972
|
}
|
|
27613
28973
|
try {
|
|
27614
|
-
const { files, workspacePath, redoCleared: cleared, commentSkill } = await port.list(sessionId);
|
|
28974
|
+
const { files, workspacePath, redoCleared: cleared, commentSkill, persistError } = await port.list(sessionId);
|
|
27615
28975
|
if (cleared) redoCleared = true;
|
|
27616
28976
|
publish({
|
|
27617
28977
|
read: true,
|
|
27618
28978
|
files,
|
|
27619
28979
|
workspacePath,
|
|
27620
28980
|
commentSkill,
|
|
28981
|
+
persistError,
|
|
27621
28982
|
busy: EMPTY_BUSY,
|
|
27622
28983
|
failed: failedOf(snapshot)
|
|
27623
28984
|
});
|
|
@@ -27627,6 +28988,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
27627
28988
|
files: snapshot.files,
|
|
27628
28989
|
workspacePath: snapshot.workspacePath,
|
|
27629
28990
|
commentSkill: snapshot.commentSkill,
|
|
28991
|
+
persistError: snapshot.persistError,
|
|
27630
28992
|
error: error instanceof Error ? error.message : String(error),
|
|
27631
28993
|
busy: snapshot.busy,
|
|
27632
28994
|
failed: failedOf(snapshot)
|
|
@@ -27976,6 +29338,32 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
27976
29338
|
}
|
|
27977
29339
|
return texts;
|
|
27978
29340
|
}
|
|
29341
|
+
/** Whether two node lists say the same thing (the transcript is rebuilt on every read). */
|
|
29342
|
+
function sameNodes(left, right) {
|
|
29343
|
+
return left.length === right.length && left.every((node, index) => {
|
|
29344
|
+
const other = right[index];
|
|
29345
|
+
return node.kind === other.kind && node.text === other.text && node.interrupted === other.interrupted;
|
|
29346
|
+
});
|
|
29347
|
+
}
|
|
29348
|
+
/** Whether two waiting-prompt lists say the same thing. */
|
|
29349
|
+
function sameQueued(left, right) {
|
|
29350
|
+
return left === right || left !== void 0 && right !== void 0 && left.length === right.length && left.every((text, index) => text === right[index]);
|
|
29351
|
+
}
|
|
29352
|
+
/** Whether a freshly read view says anything the consumer has not already been told. */
|
|
29353
|
+
function sameView(left, right) {
|
|
29354
|
+
return left !== void 0 && left.running === right.running && left.partial === right.partial && left.error === right.error && sameQueued(left.queued, right.queued) && sameNodes(left.nodes, right.nodes);
|
|
29355
|
+
}
|
|
29356
|
+
/**
|
|
29357
|
+
* How often a watched session's turn state is re-read, in ms.
|
|
29358
|
+
*
|
|
29359
|
+
* The transcript arrives by subscription, but `running` and the queue are read from the session
|
|
29360
|
+
* snapshot, which the chat target does not publish: a turn that ends without another transcript change
|
|
29361
|
+
* (the answer already written, nothing more to say) left the consumer holding `running: true` — which is
|
|
29362
|
+
* how a comment sat at "答复中" long after its session was done. The panel cannot ask for a re-read, so
|
|
29363
|
+
* the bridge does. What a tick costs is a snapshot read and the node walk behind it; what it must NOT
|
|
29364
|
+
* cost is a delivery, and `sameView` is what stops one (see `watch`).
|
|
29365
|
+
*/
|
|
29366
|
+
const TURN_STATE_REFRESH_MS = 1e3;
|
|
27979
29367
|
/**
|
|
27980
29368
|
* Build the bridge over the client context. Every verb takes the session it
|
|
27981
29369
|
* addresses, so one bridge serves whichever session the panel is showing.
|
|
@@ -27996,6 +29384,20 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
27996
29384
|
return;
|
|
27997
29385
|
}
|
|
27998
29386
|
};
|
|
29387
|
+
/**
|
|
29388
|
+
* Subscribe to the session LIST store — the one observable the host documents as carrying a session's
|
|
29389
|
+
* `running` state (`SessionSummary.running`, fed by the controller's running-state change).
|
|
29390
|
+
* @param listener - called on every list-store change.
|
|
29391
|
+
* @returns the unsubscribe, or undefined on a build without the store.
|
|
29392
|
+
*/
|
|
29393
|
+
const watchList = (listener) => {
|
|
29394
|
+
try {
|
|
29395
|
+
const stop = ctx.get("sessions")?.list?.subscribe?.(listener);
|
|
29396
|
+
return typeof stop === "function" ? stop : void 0;
|
|
29397
|
+
} catch {
|
|
29398
|
+
return;
|
|
29399
|
+
}
|
|
29400
|
+
};
|
|
27999
29401
|
const ask = (sessionId, text) => {
|
|
28000
29402
|
const target = scoped(sessionId);
|
|
28001
29403
|
if (target === void 0) return false;
|
|
@@ -28066,21 +29468,34 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
28066
29468
|
};
|
|
28067
29469
|
};
|
|
28068
29470
|
const watch = (sessionId, listener) => {
|
|
28069
|
-
|
|
29471
|
+
const target = scoped(sessionId);
|
|
29472
|
+
if (target === void 0) {
|
|
28070
29473
|
listener(currentView(sessionId));
|
|
28071
29474
|
return () => {};
|
|
28072
29475
|
}
|
|
28073
29476
|
const unsubscribes = [];
|
|
29477
|
+
let delivered;
|
|
28074
29478
|
const notify = () => {
|
|
28075
|
-
|
|
29479
|
+
const view = currentView(sessionId);
|
|
29480
|
+
if (sameView(delivered, view)) return;
|
|
29481
|
+
delivered = view;
|
|
29482
|
+
listener(view);
|
|
28076
29483
|
};
|
|
29484
|
+
try {
|
|
29485
|
+
const stopSession = target.binding?.session?.subscribe?.(notify);
|
|
29486
|
+
if (typeof stopSession === "function") unsubscribes.push(stopSession);
|
|
29487
|
+
} catch {}
|
|
29488
|
+
const stopList = watchList(notify);
|
|
29489
|
+
if (stopList !== void 0) unsubscribes.push(stopList);
|
|
28077
29490
|
try {
|
|
28078
29491
|
const stop = ctx.get("uiConversation")?.binding?.(sessionId)?.target?.("chat")?.subscribe?.(notify);
|
|
28079
29492
|
if (typeof stop === "function") unsubscribes.push(stop);
|
|
28080
29493
|
} catch {}
|
|
28081
29494
|
notify();
|
|
29495
|
+
const refresh = unsubscribes.length > 0 ? void 0 : window.setInterval(notify, TURN_STATE_REFRESH_MS);
|
|
28082
29496
|
return () => {
|
|
28083
29497
|
for (const stop of unsubscribes) stop();
|
|
29498
|
+
if (refresh !== void 0) window.clearInterval(refresh);
|
|
28084
29499
|
};
|
|
28085
29500
|
};
|
|
28086
29501
|
return {
|
|
@@ -28171,7 +29586,6 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
28171
29586
|
"panel.tab.comments": "评论",
|
|
28172
29587
|
"panel.commentsEmpty": "当前打开的文件里还没有评论",
|
|
28173
29588
|
"panel.commentOutdated": "已过期",
|
|
28174
|
-
"panel.commentEmptyTitle": "(未填写)",
|
|
28175
29589
|
"panel.aria": "待处理改动",
|
|
28176
29590
|
"panel.stats": "+{added} -{removed}",
|
|
28177
29591
|
"panel.blockPosition": "第 {current}/{total} 块",
|
|
@@ -28215,6 +29629,12 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
28215
29629
|
"panel.discussionRoundsDesc": "一条评论里保留最近几轮(你问一句、Agent 答一句算一轮),更早的整轮省略。默认 2 轮,范围 1–10。",
|
|
28216
29630
|
"panel.quickSummonDesc": "用键盘快捷键打开/关闭差异面板。点击右侧按钮后按下新的按键组合即可修改。",
|
|
28217
29631
|
"panel.recordShortcut": "按下快捷键…",
|
|
29632
|
+
"panel.key.goto": "转到行",
|
|
29633
|
+
"action.goto": "转到行",
|
|
29634
|
+
"action.gotoGo": "确定",
|
|
29635
|
+
"action.gotoCancel": "取消",
|
|
29636
|
+
"panel.gotoMissing": "第 {line} 行不在当前文件中",
|
|
29637
|
+
"panel.persistFailed": "待处理改动无法写入磁盘,重启宿主后可能丢失。",
|
|
28218
29638
|
"settings.keybindings": "快捷键",
|
|
28219
29639
|
"settings.keybindingsDesc": "展开后可配置各项操作的按键组合。",
|
|
28220
29640
|
"settings.comment": "评论",
|
|
@@ -28259,6 +29679,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
28259
29679
|
"discussion.promptRuleSkill": "(这是一条代码批注:先加载 {skill} skill,按它的规则回答。)",
|
|
28260
29680
|
"discussion.thinking": "思考中",
|
|
28261
29681
|
"discussion.queued": "排队等待中",
|
|
29682
|
+
"discussion.answering": "答复中",
|
|
28262
29683
|
"discussion.outdatedQuote": "评论代码已过期:",
|
|
28263
29684
|
"discussion.hidden": "更早的 {count} 条已省略",
|
|
28264
29685
|
"discussion.failed": "这次提问失败了,可以再试一次。",
|
|
@@ -28335,6 +29756,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
28335
29756
|
"status.missing": "该改动已不存在",
|
|
28336
29757
|
"panel.resolvedAsk": "「{file}」的所有改动都已处理,是否从列表移除?",
|
|
28337
29758
|
"panel.keepInList": "保留在列表",
|
|
29759
|
+
"panel.removalQuiet": "当前会话内不再询问该文件",
|
|
29760
|
+
"panel.removalQuietHint": "本次浏览器访问内有效:刷新页面后会重新询问。",
|
|
28338
29761
|
"panel.fileKeptAsk": "「{file}」的改动已全部保留,是否从列表移出?",
|
|
28339
29762
|
"panel.fileRevertedAsk": "「{file}」的改动已全部回退,是否从列表移出?",
|
|
28340
29763
|
"panel.confirmFileRemove": "处理整文件后询问是否移出列表",
|
|
@@ -28384,7 +29807,6 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
28384
29807
|
"panel.tab.comments": "Comments",
|
|
28385
29808
|
"panel.commentsEmpty": "No comments in the open files yet",
|
|
28386
29809
|
"panel.commentOutdated": "Outdated",
|
|
28387
|
-
"panel.commentEmptyTitle": "(not written yet)",
|
|
28388
29810
|
"panel.aria": "Pending changes",
|
|
28389
29811
|
"panel.stats": "+{added} -{removed}",
|
|
28390
29812
|
"panel.blockPosition": "{current}/{total}",
|
|
@@ -28428,6 +29850,12 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
28428
29850
|
"panel.discussionRoundsDesc": "How many rounds a comment keeps (one question and the answer to it); older rounds are left out. Default 2, range 1-10.",
|
|
28429
29851
|
"panel.quickSummonDesc": "Open or close the diff panel with a keyboard shortcut. Click the button and press a new chord to change it.",
|
|
28430
29852
|
"panel.recordShortcut": "Press keys…",
|
|
29853
|
+
"panel.key.goto": "Go to line",
|
|
29854
|
+
"action.goto": "Go to line",
|
|
29855
|
+
"action.gotoGo": "Go",
|
|
29856
|
+
"action.gotoCancel": "Cancel",
|
|
29857
|
+
"panel.gotoMissing": "Line {line} is not in the current file",
|
|
29858
|
+
"panel.persistFailed": "Pending changes could not be written to disk, so they may be lost when the host restarts.",
|
|
28431
29859
|
"settings.keybindings": "Shortcuts",
|
|
28432
29860
|
"settings.keybindingsDesc": "Expand to configure the key combo for each action.",
|
|
28433
29861
|
"settings.comment": "Comments",
|
|
@@ -28472,6 +29900,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
28472
29900
|
"discussion.promptRuleSkill": "(This is a comment on a few diff lines: load the {skill} skill first and answer by its rules.)",
|
|
28473
29901
|
"discussion.thinking": "Thinking",
|
|
28474
29902
|
"discussion.queued": "Queued",
|
|
29903
|
+
"discussion.answering": "Replying",
|
|
28475
29904
|
"discussion.outdatedQuote": "Commented code is outdated:",
|
|
28476
29905
|
"discussion.hidden": "{count} earlier turns omitted",
|
|
28477
29906
|
"discussion.failed": "That question failed; you can try again.",
|
|
@@ -28548,6 +29977,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
28548
29977
|
"status.missing": "This change no longer exists",
|
|
28549
29978
|
"panel.resolvedAsk": "All changes in \"{file}\" are resolved. Remove it from the list?",
|
|
28550
29979
|
"panel.keepInList": "Keep in list",
|
|
29980
|
+
"panel.removalQuiet": "Stop asking about this file in this session",
|
|
29981
|
+
"panel.removalQuietHint": "For this browser visit only — a reload asks again.",
|
|
28551
29982
|
"panel.fileKeptAsk": "All changes in \"{file}\" are kept. Remove it from the list?",
|
|
28552
29983
|
"panel.fileRevertedAsk": "All changes in \"{file}\" are reverted. Remove it from the list?",
|
|
28553
29984
|
"panel.confirmFileRemove": "Ask after a whole-file keep/revert",
|