[playground] Persist open tabs on compiler error (#34673)

This change allows it so that tabs that were open before a compiler
error are automatically opened again when the error is resolved. Quality
of life change for those especially working with the advanced view of
the playground.


https://github.com/user-attachments/assets/cd2dc117-e6fc-4f57-a08f-259757c4f5e8
This commit is contained in:
Eugene Choi
2025-10-01 21:26:16 -04:00
committed by GitHub
parent 79ca5ae855
commit f7254efc5c
3 changed files with 20 additions and 11 deletions

View File

@@ -23,6 +23,7 @@ export default function AccordionWindow(props: {
tabsOpen: Set<string>;
setTabsOpen: (newTab: Set<string>) => void;
changedPasses: Set<string>;
isFailure: boolean;
}): React.ReactElement {
return (
<div className="flex-1 min-w-[550px] sm:min-w-0">
@@ -36,6 +37,7 @@ export default function AccordionWindow(props: {
tabsOpen={props.tabsOpen}
setTabsOpen={props.setTabsOpen}
hasChanged={props.changedPasses.has(name)}
isFailure={props.isFailure}
/>
);
})}
@@ -50,15 +52,17 @@ function AccordionWindowItem({
tabsOpen,
setTabsOpen,
hasChanged,
isFailure,
}: {
name: string;
tabs: TabsRecord;
tabsOpen: Set<string>;
setTabsOpen: (newTab: Set<string>) => void;
hasChanged: boolean;
isFailure: boolean;
}): React.ReactElement {
const id = useId();
const isShow = tabsOpen.has(name);
const isShow = isFailure ? name === 'Output' : tabsOpen.has(name);
const transitionName = `accordion-window-item-${id}`;

View File

@@ -265,14 +265,8 @@ function OutputContent({store, compilerOutput}: Props): JSX.Element {
* Update the active tab back to the output or errors tab when the compilation state
* changes between success/failure.
*/
const [previousOutputKind, setPreviousOutputKind] = useState(
compilerOutput.kind,
);
if (compilerOutput.kind !== previousOutputKind) {
setPreviousOutputKind(compilerOutput.kind);
setTabsOpen(new Set(['Output']));
setActiveTab('Output');
}
const isFailure = compilerOutput.kind !== 'ok';
const changedPasses: Set<string> = new Set(['Output', 'HIR']); // Initial and final passes should always be bold
let lastResult: string = '';
for (const [passName, results] of compilerOutput.results) {
@@ -301,6 +295,8 @@ function OutputContent({store, compilerOutput}: Props): JSX.Element {
tabs={tabs}
activeTab={activeTab}
onTabChange={setActiveTab}
// Display the Output tab on compilation failure
activeTabOverride={isFailure ? 'Output' : undefined}
/>
</ViewTransition>
);
@@ -319,6 +315,7 @@ function OutputContent({store, compilerOutput}: Props): JSX.Element {
tabsOpen={tabsOpen}
tabs={tabs}
changedPasses={changedPasses}
isFailure={isFailure}
/>
</ViewTransition>
);

View File

@@ -17,11 +17,15 @@ export default function TabbedWindow({
tabs,
activeTab,
onTabChange,
activeTabOverride,
}: {
tabs: Map<string, React.ReactNode>;
activeTab: string;
onTabChange: (tab: string) => void;
activeTabOverride?: string;
}): React.ReactElement {
const currentActiveTab = activeTabOverride ? activeTabOverride : activeTab;
const id = useId();
const transitionName = `tab-highlight-${id}`;
@@ -37,7 +41,7 @@ export default function TabbedWindow({
<div className="flex flex-col h-full max-w-full">
<div className="flex p-2 flex-shrink-0">
{Array.from(tabs.keys()).map(tab => {
const isActive = activeTab === tab;
const isActive = currentActiveTab === tab;
return (
<button
key={tab}
@@ -49,6 +53,8 @@ export default function TabbedWindow({
{isActive && (
<ViewTransition
name={transitionName}
enter={{default: 'none'}}
exit={{default: 'none'}}
share={{
[TOGGLE_TAB_TRANSITION]: 'tab-highlight',
default: 'none',
@@ -58,6 +64,8 @@ export default function TabbedWindow({
</ViewTransition>
)}
<ViewTransition
enter={{default: 'none'}}
exit={{default: 'none'}}
update={{
[TOGGLE_TAB_TRANSITION]: 'tab-text',
default: 'none',
@@ -69,7 +77,7 @@ export default function TabbedWindow({
})}
</div>
<div className="flex-1 overflow-hidden w-full h-full">
{tabs.get(activeTab)}
{tabs.get(currentActiveTab)}
</div>
</div>
</div>