Skip to content

Commit 0e70f97

Browse files
committed
Restore '>>' in MC panel's counterexample to navigate to the linked action (#481)
Signed-off-by: Federico Ponzi <me@fponzi.me>
1 parent 42f604e commit 0e70f97

File tree

4 files changed

+76
-35
lines changed

4 files changed

+76
-35
lines changed

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/webview/checkResultView/common.tsx

Lines changed: 39 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,18 @@ const tableCellClass = (alignRight: boolean) =>
2121

2222
type ButtonProps = React.ButtonHTMLAttributes<HTMLButtonElement>;
2323

24-
export const VSCodeLink = React.memo(({children, style, className, ...rest}: ButtonProps) => (
25-
<button
26-
type="button"
27-
className={className}
28-
style={{...baseLinkStyle, ...style}}
29-
{...rest}>
30-
{children}
31-
</button>
32-
));
24+
export const VSCodeLink = React.forwardRef<HTMLButtonElement, ButtonProps>(
25+
({children, style, className, ...rest}: ButtonProps, ref) => (
26+
<button
27+
ref={ref}
28+
type="button"
29+
className={className}
30+
style={{...baseLinkStyle, ...style}}
31+
{...rest}>
32+
{children}
33+
</button>
34+
)
35+
);
3336

3437
export const EmptyLine = () => <div style={{marginTop: '1em'}}/>;
3538

@@ -47,33 +50,35 @@ export const CodePositionLink = React.memo(({line, filepath, position}: CodePosi
4750
}
4851

4952
const location = {'line': position.line, 'character': position.character};
50-
const stopEvent = (event: React.MouseEvent<HTMLButtonElement>) => {
51-
event.preventDefault();
52-
event.stopPropagation();
53-
const nativeEvent = event.nativeEvent as {stopImmediatePropagation?: () => void};
54-
nativeEvent.stopImmediatePropagation?.();
55-
};
56-
57-
const openFileAtLocation = (event: React.MouseEvent<HTMLButtonElement>) => {
58-
stopEvent(event);
59-
const treeItem = event.currentTarget.closest('vscode-tree-item') as HTMLElement & {open?: boolean} | null;
60-
if (treeItem) {
61-
if (typeof treeItem.open === 'boolean') {
62-
treeItem.open = true;
63-
} else {
64-
treeItem.setAttribute('open', '');
65-
}
53+
const buttonRef = React.useRef<HTMLButtonElement>(null);
54+
55+
React.useEffect(() => {
56+
const button = buttonRef.current;
57+
if (!button) {
58+
return;
6659
}
67-
vscode.openFile(filepath, location);
68-
};
69-
const handleMouseDown = (event: React.MouseEvent<HTMLButtonElement>) => stopEvent(event);
70-
const handleClickCapture = (event: React.MouseEvent<HTMLButtonElement>) => stopEvent(event);
60+
61+
const handleNativeClick = (event: MouseEvent) => {
62+
event.preventDefault();
63+
event.stopPropagation();
64+
65+
const treeItem = button.closest('vscode-tree-item') as HTMLElement & {open?: boolean} | null;
66+
if (treeItem) {
67+
if (typeof treeItem.open === 'boolean') {
68+
treeItem.open = true;
69+
} else {
70+
treeItem.setAttribute('open', '');
71+
}
72+
}
73+
vscode.openFile(filepath, location);
74+
};
75+
76+
button.addEventListener('click', handleNativeClick, true);
77+
return () => button.removeEventListener('click', handleNativeClick, true);
78+
}, [filepath, position.line, position.character]);
79+
7180
return (
72-
<VSCodeLink
73-
onClick={openFileAtLocation}
74-
onClickCapture={handleClickCapture}
75-
onMouseDown={handleMouseDown}
76-
onPointerDown={handleMouseDown}>
81+
<VSCodeLink ref={buttonRef}>
7782
{line}
7883
</VSCodeLink>
7984
);

tests/fixtures/playwright/public/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
<script>
3737
(function () {
3838
const messages = [];
39+
window.__testMessages = messages; // Expose for Playwright tests
3940
let state = undefined;
4041
window.acquireVsCodeApi = function () {
4142
return {

tests/playwright/error-trace.spec.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,41 @@ const test = base.extend<Fixtures>({
1818
});
1919

2020
test.describe('Check Result webview fixture', () => {
21+
test('action link click posts openFile message without toggling tree-item', async ({ page, fixtureServer }) => {
22+
await page.goto(fixtureServer.endpoint, { waitUntil: 'networkidle' });
23+
await page.addStyleTag({
24+
content: '* { transition-duration: 0s !important; animation-duration: 0s !important; }'
25+
});
26+
27+
const state = page.locator('vscode-tree-item#state-1');
28+
await state.waitFor({ state: 'visible' });
29+
30+
// Clear any existing messages and record the initial state
31+
await page.evaluate(() => {
32+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
33+
(window as any).__testMessages.length = 0;
34+
});
35+
const openBefore = await state.evaluate((el: Element) => el.hasAttribute('open'));
36+
expect(openBefore).toBe(true);
37+
38+
// Click the action link (">>" button)
39+
const actionLink = page.locator('vscode-tree-item#state-1 .error-trace-title button');
40+
await expect(actionLink).toHaveCount(1);
41+
await actionLink.click();
42+
43+
// Verify: openFile message was posted
44+
const messages = await page.evaluate(() => {
45+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
46+
return (window as any).__testMessages as Array<{ command: string }>;
47+
});
48+
const openFileMsg = messages.find((m: { command: string }) => m.command === 'openFile');
49+
expect(openFileMsg).toBeDefined();
50+
51+
// Verify: Tree-item should still be open (not toggled/collapsed)
52+
const openAfter = await state.evaluate((el: Element) => el.hasAttribute('open'));
53+
expect(openAfter).toBe(openBefore);
54+
});
55+
2156
test('error trace tree wraps text and link does not collapse state', async ({ page, fixtureServer }) => {
2257
page.on('console', msg => {
2358
if (msg.type() === 'error') {

0 commit comments

Comments
 (0)