From 309fb176eb6b783977ed1178bdb999542a95eafb Mon Sep 17 00:00:00 2001
From: Alex Ross <38270282+alexr00@users.noreply.github.com>
Date: Wed, 7 Oct 2026 12:27:44 +0200
Subject: [PATCH 1/2] Fix alignment in the PR checks view
---
webviews/components/merge.tsx | 14 ++--
webviews/editorWebview/index.css | 7 +-
webviews/editorWebview/test/overview.test.tsx | 70 ++++++++++++++++++-
3 files changed, 80 insertions(+), 11 deletions(-)
diff --git a/webviews/components/merge.tsx b/webviews/components/merge.tsx
index b13faf6ca2..edb7fa16c9 100644
--- a/webviews/components/merge.tsx
+++ b/webviews/components/merge.tsx
@@ -705,14 +705,12 @@ const StatusCheckDetails = ({ statuses }: { statuses: PullRequestCheckStatus[] }
Details
- ) : null}
- {s.isCheckRun && s.databaseId ? (
- s.state === CheckState.Failure ? (
-
- ) :
- ) : null}
+ ) : Details}
+ {s.isCheckRun && s.databaseId && s.state === CheckState.Failure ? (
+
+ ) : }
))}
diff --git a/webviews/editorWebview/index.css b/webviews/editorWebview/index.css
index 90b10eccd0..4d74f5222d 100644
--- a/webviews/editorWebview/index.css
+++ b/webviews/editorWebview/index.css
@@ -380,8 +380,13 @@ body .comment-container .review-comment-header {
gap: 4px;
}
+.status-check-link-placeholder {
+ visibility: hidden;
+}
+
+.status-check .icon-button,
.view-check-logs-placeholder {
- width: 20px;
+ flex: 0 0 22px;
}
#merge-on-github {
diff --git a/webviews/editorWebview/test/overview.test.tsx b/webviews/editorWebview/test/overview.test.tsx
index b8d4243c8d..763392c297 100644
--- a/webviews/editorWebview/test/overview.test.tsx
+++ b/webviews/editorWebview/test/overview.test.tsx
@@ -8,10 +8,10 @@ import * as React from 'react';
import { cleanup, fireEvent, render, wait, waitForElement } from 'react-testing-library';
import { createSandbox, SinonSandbox } from 'sinon';
-import { GithubItemStateEnum, PullRequestMergeability } from '../../../src/github/interface';
+import { PullRequestBuilder } from './builder/pullRequest';
+import { CheckState, GithubItemStateEnum, PullRequestCheckStatus, PullRequestMergeability } from '../../../src/github/interface';
import { PRContext, default as PullRequestContext } from '../../common/context';
import { Overview } from '../overview';
-import { PullRequestBuilder } from './builder/pullRequest';
describe('Overview', function () {
let sinon: SinonSandbox;
@@ -60,6 +60,72 @@ describe('Overview', function () {
assert.strictEqual(openOnGitHub.callCount, 2);
});
+ it('reserves details and log action slots for every status check', async function () {
+ const cases: Pick[] = [
+ { state: CheckState.Failure, isCheckRun: false, databaseId: undefined },
+ { state: CheckState.Failure, isCheckRun: true, databaseId: 1 },
+ { state: CheckState.Pending, isCheckRun: true, databaseId: 2 },
+ { state: CheckState.Success, isCheckRun: true, databaseId: 3 },
+ { state: CheckState.Neutral, isCheckRun: true, databaseId: 4 },
+ { state: CheckState.Unknown, isCheckRun: true, databaseId: 5 },
+ { state: CheckState.Failure, isCheckRun: true, databaseId: null },
+ { state: CheckState.Failure, isCheckRun: true, databaseId: undefined },
+ { state: CheckState.Failure, isCheckRun: true, databaseId: 0 },
+ ];
+ const statuses: PullRequestCheckStatus[] = cases.map((check, index) => ({
+ ...check,
+ id: `check-${index}`,
+ context: `Check ${index}`,
+ description: null,
+ workflowName: undefined,
+ event: undefined,
+ url: undefined,
+ avatarUrl: undefined,
+ targetUrl: index === cases.length - 1 ? null : `https://example.com/checks/${index}`,
+ isRequired: index % 2 === 0,
+ }));
+ const pr = new PullRequestBuilder().status(status => status.state(CheckState.Failure).statuses(statuses)).build();
+ const context = new PRContext(pr);
+ const viewCheckLogs = sinon.stub(context, 'viewCheckLogs').resolves();
+ const out = render(
+
+
+ ,
+ );
+
+ const rows = out.container.querySelectorAll('.status-check');
+ assert.strictEqual(rows.length, statuses.length);
+ for (const status of statuses) {
+ const row = [...rows].find(row => row.querySelector('.status-check-detail-text')?.textContent?.trim() === status.context);
+ assert(row);
+ const actions = row.lastElementChild;
+ assert(actions);
+ assert.strictEqual(actions.querySelector('.label')?.textContent ?? null, status.isRequired ? 'Required' : null);
+ assert.strictEqual(actions.querySelector('a')?.getAttribute('href') ?? null, status.targetUrl);
+ const linkPlaceholder = actions.querySelector('.status-check-link-placeholder');
+ if (status.targetUrl) {
+ assert.strictEqual(linkPlaceholder, null);
+ } else {
+ assert(linkPlaceholder);
+ assert.strictEqual(linkPlaceholder.textContent, 'Details');
+ assert.strictEqual(linkPlaceholder.getAttribute('aria-hidden'), 'true');
+ }
+ const slot = actions.lastElementChild;
+ assert(slot);
+ if (status.isCheckRun && status.databaseId && status.state === CheckState.Failure) {
+ assert.strictEqual(slot.getAttribute('title'), 'View Logs');
+ assert.strictEqual(actions.querySelector('.view-check-logs-placeholder'), null);
+ fireEvent.click(slot);
+ await wait(() => assert(viewCheckLogs.calledOnceWithExactly(status)));
+ } else {
+ assert(slot.classList.contains('view-check-logs-placeholder'));
+ assert.strictEqual(slot.getAttribute('aria-hidden'), 'true');
+ assert.strictEqual(actions.querySelector('button'), null);
+ }
+ }
+ assert.strictEqual(viewCheckLogs.callCount, 1);
+ });
+
it('shows the stack position and ordered pull requests in the merge section', async function () {
const pr = new PullRequestBuilder().number(794).stack({
position: 2,
From edc5bf6a448fa50bff7aa1dbf1b0b76df4584f3d Mon Sep 17 00:00:00 2001
From: Alex Ross <38270282+alexr00@users.noreply.github.com>
Date: Wed, 7 Oct 2026 18:01:25 +0200
Subject: [PATCH 2/2] CCR
---
webviews/common/common.css | 4 ++
webviews/editorWebview/index.css | 4 --
webviews/editorWebview/test/overview.test.tsx | 37 +++++++++++++++++++
3 files changed, 41 insertions(+), 4 deletions(-)
diff --git a/webviews/common/common.css b/webviews/common/common.css
index e627c12ff9..891b88e33c 100644
--- a/webviews/common/common.css
+++ b/webviews/common/common.css
@@ -376,6 +376,10 @@ body img.avatar {
margin-right: 0;
}
+.status-check-link-placeholder {
+ visibility: hidden;
+}
+
.automerge-section {
display: flex;
}
diff --git a/webviews/editorWebview/index.css b/webviews/editorWebview/index.css
index 4d74f5222d..6877797ca3 100644
--- a/webviews/editorWebview/index.css
+++ b/webviews/editorWebview/index.css
@@ -380,10 +380,6 @@ body .comment-container .review-comment-header {
gap: 4px;
}
-.status-check-link-placeholder {
- visibility: hidden;
-}
-
.status-check .icon-button,
.view-check-logs-placeholder {
flex: 0 0 22px;
diff --git a/webviews/editorWebview/test/overview.test.tsx b/webviews/editorWebview/test/overview.test.tsx
index 763392c297..cc30d6280f 100644
--- a/webviews/editorWebview/test/overview.test.tsx
+++ b/webviews/editorWebview/test/overview.test.tsx
@@ -4,12 +4,15 @@
*--------------------------------------------------------------------------------------------*/
import { default as assert } from 'assert';
+import { readFileSync } from 'fs';
+import * as path from 'path';
import * as React from 'react';
import { cleanup, fireEvent, render, wait, waitForElement } from 'react-testing-library';
import { createSandbox, SinonSandbox } from 'sinon';
import { PullRequestBuilder } from './builder/pullRequest';
import { CheckState, GithubItemStateEnum, PullRequestCheckStatus, PullRequestMergeability } from '../../../src/github/interface';
+import { Overview as ActivityBarOverview } from '../../activityBarView/overview';
import { PRContext, default as PullRequestContext } from '../../common/context';
import { Overview } from '../overview';
@@ -126,6 +129,40 @@ describe('Overview', function () {
assert.strictEqual(viewCheckLogs.callCount, 1);
});
+ it('keeps Details placeholders invisible in both PR overviews using shared styles', function () {
+ const status: PullRequestCheckStatus = {
+ id: 'missing-details', state: CheckState.Failure, context: 'Check without details',
+ description: null, targetUrl: null, workflowName: undefined, event: undefined,
+ url: undefined, avatarUrl: undefined, isRequired: false, isCheckRun: false, databaseId: undefined,
+ };
+ const pr = new PullRequestBuilder().status(checks => checks.state(CheckState.Failure).statuses([status])).build();
+ const sharedCss = readFileSync(path.resolve('webviews', 'common', 'common.css'), 'utf8');
+ const placeholderRule = /^\.status-check-link-placeholder\s*\{[^}]*\}/m.exec(sharedCss);
+ assert(placeholderRule);
+ const sharedStyles = document.createElement('style');
+ sharedStyles.textContent = placeholderRule[0];
+ document.head.appendChild(sharedStyles);
+ try {
+ for (const Component of [Overview, ActivityBarOverview]) {
+ const out = render(
+
+
+ ,
+ );
+ const placeholder = out.container.querySelector('.status-check-link-placeholder');
+ assert(placeholder);
+ assert.strictEqual(placeholder.textContent, 'Details');
+ assert.strictEqual(placeholder.getAttribute('aria-hidden'), 'true');
+ const style = window.getComputedStyle(placeholder);
+ assert.strictEqual(style.visibility, 'hidden');
+ assert.notStrictEqual(style.display, 'none');
+ out.unmount();
+ }
+ } finally {
+ sharedStyles.remove();
+ }
+ });
+
it('shows the stack position and ordered pull requests in the merge section', async function () {
const pr = new PullRequestBuilder().number(794).stack({
position: 2,