@samitouri / QOS-React-1 / commits / e7984651e4

[playground] Allow accordion tabs to open on error (#34844)

There was a bug where the other output passes (aside from the "Output" tab) were unable to open on compiler error. This PR still allows for the "Output" tab to automatically open on error, but also allows other tabs to be opened. https://github.com/user-attachments/assets/157bf5d6-c289-46fd-bafb-073c2e0ff52b

Eugene Choi committed Oct 14, 2025 at 15:07 UTC e7984651e4f123d8112f5abab39782ee70d8f4aa
3 files changed +21 -14
compiler/apps/playground/components/AccordionWindow.tsx
+1 -4
@@ -22,7 +22,6 @@ export default function AccordionWindow(props: {
22 tabsOpen: Set<string>;
23 setTabsOpen: (newTab: Set<string>) => void;
24 changedPasses: Set<string>;
25 - isFailure: boolean;
25 }): React.ReactElement {
26 return (
27 <div className="flex-1 min-w-[550px] sm:min-w-0">
@@ -36,7 +35,6 @@ export default function AccordionWindow(props: {
35 tabsOpen={props.tabsOpen}
36 setTabsOpen={props.setTabsOpen}
37 hasChanged={props.changedPasses.has(name)}
39 - isFailure={props.isFailure}
38 />
39 );
40 })}
@@ -51,7 +49,6 @@ function AccordionWindowItem({
49 tabsOpen,
50 setTabsOpen,
51 hasChanged,
54 - isFailure,
52 }: {
53 name: string;
54 tabs: TabsRecord;
@@ -61,7 +58,7 @@ function AccordionWindowItem({
58 isFailure: boolean;
59 }): React.ReactElement {
60 const id = useId();
64 - const isShow = isFailure ? name === 'Output' : tabsOpen.has(name);
61 + const isShow = tabsOpen.has(name);
62
63 const transitionName = `accordion-window-item-${id}`;
64
compiler/apps/playground/components/Editor/Output.tsx
+18 -4
@@ -27,6 +27,8 @@ import {
27 useState,
28 Suspense,
29 unstable_ViewTransition as ViewTransition,
30 + unstable_addTransitionType as addTransitionType,
31 + startTransition,
32 } from 'react';
33 import AccordionWindow from '../AccordionWindow';
34 import TabbedWindow from '../TabbedWindow';
@@ -35,6 +37,7 @@ import {BabelFileResult} from '@babel/core';
37 import {
38 CONFIG_PANEL_TRANSITION,
39 TOGGLE_INTERNALS_TRANSITION,
40 + EXPAND_ACCORDION_TRANSITION,
41 } from '../../lib/transitionTypes';
42 import {LRUCache} from 'lru-cache';
43
@@ -265,8 +268,22 @@ function OutputContent({store, compilerOutput}: Props): JSX.Element {
268 * Update the active tab back to the output or errors tab when the compilation state
269 * changes between success/failure.
270 */
268 -
271 + const [previousOutputKind, setPreviousOutputKind] = useState(
272 + compilerOutput.kind,
273 + );
274 const isFailure = compilerOutput.kind !== 'ok';
275 +
276 + if (compilerOutput.kind !== previousOutputKind) {
277 + setPreviousOutputKind(compilerOutput.kind);
278 + if (isFailure) {
279 + startTransition(() => {
280 + addTransitionType(EXPAND_ACCORDION_TRANSITION);
281 + setTabsOpen(prev => new Set(prev).add('Output'));
282 + setActiveTab('Output');
283 + });
284 + }
285 + }
286 +
287 const changedPasses: Set<string> = new Set(['Output', 'HIR']); // Initial and final passes should always be bold
288 let lastResult: string = '';
289 for (const [passName, results] of compilerOutput.results) {
@@ -295,8 +312,6 @@ function OutputContent({store, compilerOutput}: Props): JSX.Element {
312 tabs={tabs}
313 activeTab={activeTab}
314 onTabChange={setActiveTab}
298 - // Display the Output tab on compilation failure
299 - activeTabOverride={isFailure ? 'Output' : undefined}
315 />
316 </ViewTransition>
317 );
@@ -315,7 +330,6 @@ function OutputContent({store, compilerOutput}: Props): JSX.Element {
330 tabsOpen={tabsOpen}
331 tabs={tabs}
332 changedPasses={changedPasses}
318 - isFailure={isFailure}
333 />
334 </ViewTransition>
335 );
compiler/apps/playground/components/TabbedWindow.tsx
+2 -6
@@ -17,15 +17,11 @@ export default function TabbedWindow({
17 tabs,
18 activeTab,
19 onTabChange,
20 - activeTabOverride,
20 }: {
21 tabs: Map<string, React.ReactNode>;
22 activeTab: string;
23 onTabChange: (tab: string) => void;
25 - activeTabOverride?: string;
24 }): React.ReactElement {
27 - const currentActiveTab = activeTabOverride ? activeTabOverride : activeTab;
28 -
25 const id = useId();
26 const transitionName = `tab-highlight-${id}`;
27
@@ -41,7 +37,7 @@ export default function TabbedWindow({
37 <div className="flex flex-col h-full max-w-full">
38 <div className="flex p-2 flex-shrink-0">
39 {Array.from(tabs.keys()).map(tab => {
44 - const isActive = currentActiveTab === tab;
40 + const isActive = activeTab === tab;
41 return (
42 <button
43 key={tab}
@@ -77,7 +73,7 @@ export default function TabbedWindow({
73 })}
74 </div>
75 <div className="flex-1 overflow-hidden w-full h-full">
80 - {tabs.get(currentActiveTab)}
76 + {tabs.get(activeTab)}
77 </div>
78 </div>
79 </div>