mirror of
https://github.com/esengine/DeepSeek-Reasonix.git
synced 2026-11-07 10:45:59 -10:00
fix(studio): the jump buttons go straight to the ends; Shift+click steps through expanded blocks
This commit is contained in:
1 parent
0fe09f3a1d
commit
d3e45aff25
8 files changed
+84
-10
No files matched your search
@@ -141,6 +141,7 @@ jobs:
|
||||
node perf/stickyfold.mjs
|
||||
node perf/crumb.mjs
|
||||
node perf/hoverradius.mjs
|
||||
node perf/jump-ends.mjs
|
||||
node perf/modelrows.mjs
|
||||
node perf/explorersize.mjs
|
||||
node perf/rowhit.mjs
|
||||
|
||||
@@ -78,6 +78,7 @@ node perf/sidebar.mjs # 侧栏开关只有一个且位置不变(图标栏
|
||||
node perf/stickyfold.mjs # 展开的长执行过程:滚动时头部吸在顶部、有自己的底(浅/深)
|
||||
node perf/crumb.mjs # 标题栏里会话标题紧跟项目名,长名字也不溢出(宽/窄)
|
||||
node perf/hoverradius.mjs # 输入框底行的按钮悬停时圆角和底色一致(浅/深)
|
||||
node perf/jump-ends.mjs # 回到顶部/跳到最新按钮一次点击直达两端(中间有展开块也一样)
|
||||
node perf/sessionrows.mjs # 会话行样式:34px、无额外行间距、单行省略;本机/远程、悬浮/焦点、浅/深、窄/宽
|
||||
node perf/start.mjs # 经工作台标签/边缘把手打开工作台先出入口页(文件/改动/浏览器),不替人开浏览器;标题栏 Browser 按钮仍直达浏览器(浅/深 × 宽/窄)
|
||||
```
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
// The two floating buttons are named for the ends they go to ("back to top", "jump to latest"),
|
||||
// so one click has to arrive there, whatever expanded blocks lie between. Where a scroller ends up
|
||||
// is a property of the render, so it is read from the browser.
|
||||
import { chromium } from "playwright";
|
||||
|
||||
const BASE = process.env.PERF_URL ?? "http://localhost:4399/perf.html?pref=zh&ws=2&sess=6&turns=40";
|
||||
const fails = [];
|
||||
const check = (name, ok, detail = "") => {
|
||||
console.log(`${ok ? " ok" : "FAIL"} ${name}${detail ? " — " + detail : ""}`);
|
||||
if (!ok) fails.push(name);
|
||||
};
|
||||
|
||||
const browser = await chromium.launch();
|
||||
try {
|
||||
const page = await browser.newPage({ viewport: { width: 1100, height: 760 } });
|
||||
await page.goto(BASE, { waitUntil: "networkidle" });
|
||||
await page.waitForSelector('[data-pane="flow"]');
|
||||
const geometry = () => page.locator('[data-pane="flow"]').evaluate((el) => ({ top: Math.round(el.scrollTop), room: Math.round(el.scrollHeight - el.clientHeight - el.scrollTop) }));
|
||||
await page.locator('[data-pane="flow"]').evaluate((el) => { el.scrollTop = Math.round((el.scrollHeight - el.clientHeight) / 2); });
|
||||
await page.waitForSelector('.scrolljump button[data-value="up"]');
|
||||
await page.waitForSelector('.scrolljump button[data-value="down"]');
|
||||
await page.evaluate(() => document.querySelectorAll("details.tool-disclosure, details.think").forEach((d) => { d.open = true; }));
|
||||
await page.waitForTimeout(200);
|
||||
const open = await page.locator("details.tool-disclosure[open], details.think[open]").count();
|
||||
check("there are expanded blocks between the middle and each end", open >= 2, `${open} expanded blocks`);
|
||||
check("the conversation is long enough to scroll", (await geometry()).top > 0 && (await geometry()).room > 0);
|
||||
|
||||
await page.click('.scrolljump button[data-value="up"]');
|
||||
await page.waitForTimeout(400);
|
||||
const atTop = await geometry();
|
||||
check("one click on the top button reaches the top", atTop.top <= 1, `scrollTop ${atTop.top}`);
|
||||
|
||||
await page.locator('[data-pane="flow"]').evaluate((el) => { el.scrollTop = Math.round((el.scrollHeight - el.clientHeight) / 2); });
|
||||
await page.waitForSelector('.scrolljump button[data-value="down"]');
|
||||
await page.click('.scrolljump button[data-value="down"]');
|
||||
await page.waitForTimeout(800);
|
||||
const atEnd = await geometry();
|
||||
check("one click on the latest button reaches the end", atEnd.room <= 2, `${atEnd.room}px from the end`);
|
||||
await page.close();
|
||||
} finally {
|
||||
await browser.close();
|
||||
}
|
||||
if (fails.length) {
|
||||
console.error(`\n${fails.length} failed: ${fails.join("; ")}`);
|
||||
process.exit(1);
|
||||
}
|
||||
@@ -16,6 +16,8 @@ export const EN_SETTINGS: Record<string, string> = {
|
||||
"用 {name} 打开": "Open with {name}",
|
||||
"回到会话顶部": "Back to top",
|
||||
"跳到最新": "Jump to latest",
|
||||
"回到会话顶部(Shift+点击:上一个展开的块)": "Back to top (Shift+click: previous expanded block)",
|
||||
"跳到最新(Shift+点击:下一个展开的块)": "Jump to latest (Shift+click: next expanded block)",
|
||||
"首字时间": "Time to first token",
|
||||
"关闭其他浏览器标签": "Close other browser tabs",
|
||||
"关闭右侧浏览器标签": "Close browser tabs to the right",
|
||||
|
||||
@@ -12,7 +12,7 @@ export function ScrollJump({ scroll, flow, active, onJump }: {
|
||||
scroll: RefObject<HTMLDivElement | null>;
|
||||
flow: RefObject<HTMLDivElement | null>;
|
||||
active: boolean;
|
||||
onJump: (dir: Direction) => void;
|
||||
onJump: (dir: Direction, step: boolean) => void;
|
||||
}) {
|
||||
const [shown, setShown] = useState(NONE);
|
||||
useEffect(() => {
|
||||
@@ -47,12 +47,12 @@ export function ScrollJump({ scroll, flow, active, onJump }: {
|
||||
<div className="scrolljump">
|
||||
<div>
|
||||
{shown.up && (
|
||||
<button type="button" data-action="transcript.scroll" data-value="up" aria-label={t("回到会话顶部")} title={t("回到会话顶部")} onClick={() => onJump("up")}>
|
||||
<button type="button" data-action="transcript.scroll" data-value="up" aria-label={t("回到会话顶部")} title={t("回到会话顶部(Shift+点击:上一个展开的块)")} onClick={(e) => onJump("up", e.shiftKey)}>
|
||||
<StudioIcon name="down" />
|
||||
</button>
|
||||
)}
|
||||
{shown.down && (
|
||||
<button type="button" data-action="transcript.scroll" data-value="down" aria-label={t("跳到最新")} title={t("跳到最新")} onClick={() => onJump("down")}>
|
||||
<button type="button" data-action="transcript.scroll" data-value="down" aria-label={t("跳到最新")} title={t("跳到最新(Shift+点击:下一个展开的块)")} onClick={(e) => onJump("down", e.shiftKey)}>
|
||||
<StudioIcon name="down" />
|
||||
</button>
|
||||
)}
|
||||
|
||||
@@ -360,12 +360,20 @@ export function Transcript({ items, port, entering, onEntered, revision, waiting
|
||||
follow();
|
||||
}, [follow]);
|
||||
|
||||
// The nearest expanded call or thought in that direction, else the very end:
|
||||
// one jump should not cross a whole stretch of context the reader has opened.
|
||||
// The button goes to the end it names. Held with Shift it steps to the nearest
|
||||
// expanded call or thought in that direction instead, else the end: a jump
|
||||
// that should not cross a whole stretch of context the reader has opened.
|
||||
const jumpToward = useCallback(
|
||||
(dir: Direction) => {
|
||||
(dir: Direction, step: boolean) => {
|
||||
const root = scroll.current;
|
||||
if (!root) return;
|
||||
if (!step) {
|
||||
if (dir === "down") return resume();
|
||||
landing.current++;
|
||||
release();
|
||||
root.scrollTop = 0;
|
||||
return;
|
||||
}
|
||||
const base = root.getBoundingClientRect().top - root.scrollTop;
|
||||
const tops = [...root.querySelectorAll<HTMLElement>("details.tool-disclosure[open], details.think[open]")].map((el) => el.getBoundingClientRect().top - base);
|
||||
const to = landingOf(dir, tops, root.scrollTop, root.clientHeight, root.scrollHeight);
|
||||
|
||||
@@ -68,22 +68,36 @@ describe("the transcript's jump buttons", () => {
|
||||
expect(down()).toBeNull();
|
||||
});
|
||||
|
||||
it("goes to the nearest expanded call or thought before it goes to the end", async () => {
|
||||
it("goes straight to the end the button names, past any expanded block", async () => {
|
||||
const { geometry, settle, expanded } = draw();
|
||||
expanded("tool-disclosure", 1900);
|
||||
expanded("think", 2700);
|
||||
geometry.top = 1000;
|
||||
await settle();
|
||||
fireEvent.click(down()!);
|
||||
expect(geometry.top).toBe(5000);
|
||||
geometry.top = 3000;
|
||||
await settle();
|
||||
fireEvent.click(up()!);
|
||||
expect(geometry.top).toBe(0);
|
||||
});
|
||||
|
||||
it("steps to the nearest expanded call or thought when Shift is held", async () => {
|
||||
const { geometry, settle, expanded } = draw();
|
||||
expanded("tool-disclosure", 1900);
|
||||
expanded("think", 2700);
|
||||
geometry.top = 1000;
|
||||
await settle();
|
||||
|
||||
fireEvent.click(down()!);
|
||||
fireEvent.click(down()!, { shiftKey: true });
|
||||
expect(geometry.top).toBe(1900 - 8);
|
||||
await settle();
|
||||
|
||||
fireEvent.click(down()!);
|
||||
fireEvent.click(down()!, { shiftKey: true });
|
||||
expect(geometry.top).toBe(2700 - 8);
|
||||
await settle();
|
||||
|
||||
fireEvent.click(up()!);
|
||||
fireEvent.click(up()!, { shiftKey: true });
|
||||
expect(geometry.top).toBe(1900 - 8);
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
- 修复:对话右下角“回到会话顶部/跳到最新”按钮一次点击直达两端;原来的“逐个展开块”跳法改为按住 Shift 点击。关联 #13326、#13229。
|
||||
- Fixed: the jump-to-top and jump-to-latest buttons now go straight to the ends in one click; the old step through expanded blocks is Shift+click. Refs #13326, #13229.
|
||||
Reference in new issue
Block a user