Skip to content

Commit ec8778c

Browse files
committed
fix: cosmetic improvements to CTI view
1 parent 31a84a5 commit ec8778c

File tree

1 file changed

+81
-98
lines changed

1 file changed

+81
-98
lines changed

widget/src/verificationResults.tsx

Lines changed: 81 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -122,13 +122,17 @@ const StatePanel: React.FC<{
122122
title: string;
123123
fields: Record<string, unknown>;
124124
changes?: Map<string, ChangeInfo>;
125-
}> = ({ title, fields, changes }) => {
125+
statusIndicator?: React.ReactNode;
126+
}> = ({ title, fields, changes, statusIndicator }) => {
126127
const entries = Object.entries(fields);
127128

128129
return (
129130
<div className="cex-state-panel">
130131
<div className="cex-state-header">
131-
{title}
132+
<span>{title}</span>
133+
{statusIndicator && (
134+
<span className="cex-state-status">{statusIndicator}</span>
135+
)}
132136
</div>
133137
<div className="cex-state-body">
134138
{entries.length === 0 ? (
@@ -148,12 +152,13 @@ const StatePanel: React.FC<{
148152
/** Structured counterexample view with side-by-side pre/post states */
149153
const StructuredCexView: React.FC<{
150154
data: StructuredJson;
155+
property: string;
151156
headerRightContent?: React.ReactNode;
152-
}> = ({ data, headerRightContent }) => {
157+
}> = ({ data, property, headerRightContent }) => {
153158
const { preState, postState, label, instantiation } = data;
154159

155160
// State for toolbar features
156-
const [showRemovals, setShowRemovals] = React.useState(true);
161+
const [showRemovals, setShowRemovals] = React.useState(false);
157162
const [hiddenFields, setHiddenFields] = React.useState<Set<string>>(new Set());
158163
const [showFilterPanel, setShowFilterPanel] = React.useState(false);
159164
const [isWideEnough, setIsWideEnough] = React.useState(true);
@@ -166,7 +171,7 @@ const StructuredCexView: React.FC<{
166171

167172
const observer = new ResizeObserver((entries) => {
168173
for (const entry of entries) {
169-
// Hide transition row when width < 600px (approximately when panels stack)
174+
// Stack panels vertically when width < 600px
170175
setIsWideEnough(entry.contentRect.width >= 600);
171176
}
172177
});
@@ -306,34 +311,33 @@ const StructuredCexView: React.FC<{
306311
</div>
307312
)}
308313

309-
{/* Induction counterexample transition visualization (hidden when narrow) */}
314+
{/* Centered action chip above panels (when side-by-side) */}
310315
{isWideEnough && (
311-
<div className="cex-transition-row">
312-
<div className="cex-transition-column">
313-
<div className="cex-transition-state cex-transition-pre">
314-
<span className="cex-transition-icon cex-icon-valid"></span>
315-
<span className="cex-transition-label">Satisfies invariant</span>
316-
</div>
317-
<div className="cex-connector-line" />
318-
</div>
319-
<div className="cex-transition-center">
320-
<span className="cex-action-chip">{formatActionLabel(label)}</span>
321-
</div>
322-
<div className="cex-transition-column">
323-
<div className="cex-connector-line" />
324-
<div className="cex-transition-state cex-transition-post">
325-
<span className="cex-transition-icon cex-icon-invalid"></span>
326-
<span className="cex-transition-label">Violates invariant</span>
327-
</div>
328-
</div>
316+
<div className="cex-action-row">
317+
<span className="cex-action-chip">{formatActionLabel(label)}</span>
329318
</div>
330319
)}
331320

332-
{/* Side-by-side state panels */}
333-
<div className="cex-states-container">
334-
<StatePanel title="Pre-State" fields={filteredPreState} />
321+
{/* Side-by-side or stacked state panels */}
322+
<div className={`cex-states-container ${!isWideEnough ? 'cex-states-stacked' : ''}`}>
323+
<StatePanel
324+
title="Pre-State"
325+
fields={filteredPreState}
326+
statusIndicator={<span className="cex-status-valid">✓ Satisfies all invariants </span>}
327+
/>
328+
{/* Narrow view: centered action chip between stacked panels */}
329+
{!isWideEnough && filteredPostState && (
330+
<div className="cex-narrow-action">
331+
<span className="cex-action-chip">{formatActionLabel(label)}</span>
332+
</div>
333+
)}
335334
{filteredPostState && (
336-
<StatePanel title="Post-State" fields={filteredPostState} changes={filteredChanges} />
335+
<StatePanel
336+
title="Post-State"
337+
fields={filteredPostState}
338+
changes={filteredChanges}
339+
statusIndicator={<span className="cex-status-invalid">✗ Violates <span className="cex-property-name">{property}</span></span>}
340+
/>
337341
)}
338342
</div>
339343

@@ -571,6 +575,7 @@ const PropertyRow: React.FC<PropertyRowProps> = ({ vc, alternativeVC }) => {
571575
{activeCounterexample.structuredJson && !showRawHtml ? (
572576
<StructuredCexView
573577
data={activeCounterexample.structuredJson}
578+
property={vc.metadata.property}
574579
headerRightContent={
575580
<>
576581
<button
@@ -1208,92 +1213,27 @@ const VerificationResultsView: React.FC<VerificationResultsProps> = ({ results }
12081213
align-items: center;
12091214
gap: 4px;
12101215
padding: 3px 10px;
1211-
background: var(--vscode-badge-background, rgba(0, 122, 204, 0.15));
1216+
background: var(--vscode-activityBarBadge-background);
1217+
color: var(--vscode-activityBarBadge-foreground);
12121218
border-radius: 12px;
12131219
font-size: 12px;
12141220
}
12151221
12161222
.cex-instantiation-key {
1217-
color: var(--vscode-descriptionForeground);
1223+
color: var(--vscode-activityBarBadge-foreground);
12181224
font-weight: 500;
12191225
}
12201226
12211227
.cex-instantiation-eq {
1222-
color: var(--vscode-descriptionForeground);
1228+
color: var(--vscode-activityBarBadge-foreground);
12231229
opacity: 0.6;
12241230
}
12251231
12261232
.cex-instantiation-val {
1227-
color: var(--vscode-foreground);
1233+
color: var(--vscode-activityBarBadge-foreground);
12281234
font-weight: 500;
12291235
}
12301236
1231-
.cex-transition-row {
1232-
display: flex;
1233-
align-items: center;
1234-
gap: 16px;
1235-
margin-bottom: 12px;
1236-
}
1237-
1238-
.cex-transition-column {
1239-
flex: 1;
1240-
min-width: 280px;
1241-
display: flex;
1242-
align-items: center;
1243-
justify-content: center;
1244-
}
1245-
1246-
.cex-connector-line {
1247-
flex: 1;
1248-
height: 2px;
1249-
background: var(--vscode-panel-border);
1250-
opacity: 0.4;
1251-
}
1252-
1253-
.cex-transition-center {
1254-
flex-shrink: 0;
1255-
display: flex;
1256-
align-items: center;
1257-
justify-content: center;
1258-
}
1259-
1260-
.cex-transition-state {
1261-
display: inline-flex;
1262-
align-items: center;
1263-
gap: 6px;
1264-
padding: 8px 16px;
1265-
border-radius: 6px;
1266-
font-size: 12px;
1267-
font-weight: 500;
1268-
}
1269-
1270-
.cex-transition-pre {
1271-
background: var(--vscode-diffEditor-insertedTextBackground, rgba(0, 180, 0, 0.15));
1272-
border: 1px solid var(--vscode-diffEditor-insertedLineBackground, rgba(0, 180, 0, 0.3));
1273-
}
1274-
1275-
.cex-transition-post {
1276-
background: var(--vscode-diffEditor-removedTextBackground, rgba(255, 80, 80, 0.15));
1277-
border: 1px solid var(--vscode-diffEditor-removedLineBackground, rgba(255, 80, 80, 0.3));
1278-
}
1279-
1280-
.cex-transition-icon {
1281-
font-size: 14px;
1282-
font-weight: 700;
1283-
}
1284-
1285-
.cex-icon-valid {
1286-
color: var(--vscode-testing-iconPassed, #4caf50);
1287-
}
1288-
1289-
.cex-icon-invalid {
1290-
color: var(--vscode-testing-iconFailed, #f44336);
1291-
}
1292-
1293-
.cex-transition-label {
1294-
color: var(--vscode-foreground);
1295-
}
1296-
12971237
.cex-action-chip {
12981238
display: inline-block;
12991239
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
@@ -1312,6 +1252,26 @@ const VerificationResultsView: React.FC<VerificationResultsProps> = ({ results }
13121252
flex-wrap: wrap;
13131253
}
13141254
1255+
.cex-states-container.cex-states-stacked {
1256+
flex-direction: column;
1257+
}
1258+
1259+
.cex-narrow-action {
1260+
display: flex;
1261+
justify-content: center;
1262+
align-items: center;
1263+
padding: 8px 0;
1264+
width: 100%;
1265+
}
1266+
1267+
.cex-action-row {
1268+
display: flex;
1269+
justify-content: center;
1270+
align-items: center;
1271+
padding: 12px 0;
1272+
margin-bottom: 12px;
1273+
}
1274+
13151275
.cex-state-panel {
13161276
flex: 1;
13171277
min-width: 280px;
@@ -1323,6 +1283,9 @@ const VerificationResultsView: React.FC<VerificationResultsProps> = ({ results }
13231283
}
13241284
13251285
.cex-state-header {
1286+
display: flex;
1287+
justify-content: space-between;
1288+
align-items: center;
13261289
font-weight: 600;
13271290
font-size: 12px;
13281291
padding: 8px 12px;
@@ -1333,6 +1296,26 @@ const VerificationResultsView: React.FC<VerificationResultsProps> = ({ results }
13331296
letter-spacing: 0.5px;
13341297
}
13351298
1299+
.cex-state-status {
1300+
font-size: 10px;
1301+
font-weight: 500;
1302+
text-transform: none;
1303+
letter-spacing: normal;
1304+
}
1305+
1306+
.cex-status-valid {
1307+
color: var(--vscode-testing-iconPassed, #4caf50);
1308+
}
1309+
1310+
.cex-status-invalid {
1311+
color: var(--vscode-testing-iconFailed, #f44336);
1312+
}
1313+
1314+
.cex-property-name {
1315+
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
1316+
font-weight: 600;
1317+
}
1318+
13361319
.cex-state-body {
13371320
padding: 8px;
13381321
}

0 commit comments

Comments
 (0)