Skip to content

Commit abdb4d9

Browse files
committed
fixed issue with waveai panel growing on refresh
1 parent a6062c2 commit abdb4d9

2 files changed

Lines changed: 39 additions & 32 deletions

File tree

frontend/app/workspace/workspace-layout-model.ts

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import * as WOS from "@/app/store/wos";
88
import { RpcApi } from "@/app/store/wshclientapi";
99
import { TabRpcClient } from "@/app/store/wshrpcutil";
1010
import { getLayoutModelForStaticTab } from "@/layout/lib/layoutModelHooks";
11-
import { atoms, getApi, getOrefMetaKeyAtom, recordTEvent, refocusNode } from "@/store/global";
11+
import { atoms, getApi, getOrefMetaKeyAtom, getSettingsKeyAtom, recordTEvent, refocusNode } from "@/store/global";
1212
import debug from "debug";
1313
import * as jotai from "jotai";
1414
import { debounce } from "lodash-es";
@@ -44,6 +44,7 @@ class WorkspaceLayoutModel {
4444
innerPanelGroupRef: ImperativePanelGroupHandle | null;
4545
panelContainerRef: HTMLDivElement | null;
4646
aiPanelWrapperRef: HTMLDivElement | null;
47+
vtabPanelWrapperRef: HTMLDivElement | null;
4748
panelVisibleAtom: jotai.PrimitiveAtom<boolean>;
4849
vtabVisibleAtom: jotai.PrimitiveAtom<boolean>;
4950

@@ -55,8 +56,8 @@ class WorkspaceLayoutModel {
5556
private initialized: boolean = false;
5657
private transitionTimeoutRef: NodeJS.Timeout | null = null;
5758
private focusTimeoutRef: NodeJS.Timeout | null = null;
58-
private debouncedPersistAIWidth: (width: number) => void;
59-
private debouncedPersistVTabWidth: (width: number) => void;
59+
private debouncedPersistAIWidth: () => void;
60+
private debouncedPersistVTabWidth: () => void;
6061

6162
private constructor() {
6263
this.aiPanelRef = null;
@@ -65,19 +66,24 @@ class WorkspaceLayoutModel {
6566
this.innerPanelGroupRef = null;
6667
this.panelContainerRef = null;
6768
this.aiPanelWrapperRef = null;
69+
this.vtabPanelWrapperRef = null;
6870
this.inResize = false;
6971
this.aiPanelVisible = false;
7072
this.aiPanelWidth = null;
7173
this.vtabWidth = VTabBar_DefaultWidth;
7274
this.vtabVisible = false;
7375
this.panelVisibleAtom = jotai.atom(false);
7476
this.vtabVisibleAtom = jotai.atom(false);
77+
this.initializeFromMeta();
7578

7679
this.handleWindowResize = this.handleWindowResize.bind(this);
7780
this.handleOuterPanelLayout = this.handleOuterPanelLayout.bind(this);
7881
this.handleInnerPanelLayout = this.handleInnerPanelLayout.bind(this);
7982

80-
this.debouncedPersistAIWidth = debounce((width: number) => {
83+
this.debouncedPersistAIWidth = debounce(() => {
84+
if (!this.aiPanelVisible) return;
85+
const width = this.aiPanelWrapperRef?.offsetWidth;
86+
if (width == null || width <= 0) return;
8187
try {
8288
RpcApi.SetMetaCommand(TabRpcClient, {
8389
oref: WOS.makeORef("tab", this.getTabId()),
@@ -88,7 +94,10 @@ class WorkspaceLayoutModel {
8894
}
8995
}, 300);
9096

91-
this.debouncedPersistVTabWidth = debounce((width: number) => {
97+
this.debouncedPersistVTabWidth = debounce(() => {
98+
if (!this.vtabVisible) return;
99+
const width = this.vtabPanelWrapperRef?.offsetWidth;
100+
if (width == null || width <= 0) return;
92101
try {
93102
RpcApi.SetMetaCommand(TabRpcClient, {
94103
oref: WOS.makeORef("workspace", this.getWorkspaceId()),
@@ -130,8 +139,6 @@ class WorkspaceLayoutModel {
130139
}
131140

132141
private initializeFromMeta(): void {
133-
if (this.initialized) return;
134-
this.initialized = true;
135142
try {
136143
const savedVisible = globalStore.get(this.getPanelOpenAtom());
137144
const savedAIWidth = globalStore.get(this.getPanelWidthAtom());
@@ -146,6 +153,10 @@ class WorkspaceLayoutModel {
146153
if (savedVTabWidth != null && savedVTabWidth > 0) {
147154
this.vtabWidth = savedVTabWidth;
148155
}
156+
const tabBarPosition = globalStore.get(getSettingsKeyAtom("app:tabbar")) ?? "top";
157+
const showLeftTabBar = tabBarPosition === "left" && !isBuilderWindow();
158+
this.vtabVisible = showLeftTabBar;
159+
globalStore.set(this.vtabVisibleAtom, showLeftTabBar);
149160
} catch (e) {
150161
console.warn("Failed to initialize from tab meta:", e);
151162
}
@@ -154,7 +165,6 @@ class WorkspaceLayoutModel {
154165
// ---- Resolved width getters (always clamped) ----
155166

156167
private getResolvedAIWidth(windowWidth: number): number {
157-
this.initializeFromMeta();
158168
let w = this.aiPanelWidth;
159169
if (w == null) {
160170
w = Math.max(AIPanel_DefaultWidth, windowWidth * AIPanel_DefaultWidthRatio);
@@ -164,7 +174,6 @@ class WorkspaceLayoutModel {
164174
}
165175

166176
private getResolvedVTabWidth(): number {
167-
this.initializeFromMeta();
168177
return clampVTabWidth(this.vtabWidth);
169178
}
170179

@@ -218,17 +227,14 @@ class WorkspaceLayoutModel {
218227
if (this.vtabVisible && this.aiPanelVisible) {
219228
// vtab stays constant, aipanel absorbs the change
220229
const vtabW = this.getResolvedVTabWidth();
221-
const newAIW = clampAIPanelWidth(newLeftGroupPx - vtabW, windowWidth);
222-
this.aiPanelWidth = newAIW;
223-
this.debouncedPersistAIWidth(newAIW);
230+
this.aiPanelWidth = clampAIPanelWidth(newLeftGroupPx - vtabW, windowWidth);
231+
this.debouncedPersistAIWidth();
224232
} else if (this.vtabVisible) {
225-
const clamped = clampVTabWidth(newLeftGroupPx);
226-
this.vtabWidth = clamped;
227-
this.debouncedPersistVTabWidth(clamped);
233+
this.vtabWidth = clampVTabWidth(newLeftGroupPx);
234+
this.debouncedPersistVTabWidth();
228235
} else if (this.aiPanelVisible) {
229-
const clamped = clampAIPanelWidth(newLeftGroupPx, windowWidth);
230-
this.aiPanelWidth = clamped;
231-
this.debouncedPersistAIWidth(clamped);
236+
this.aiPanelWidth = clampAIPanelWidth(newLeftGroupPx, windowWidth);
237+
this.debouncedPersistAIWidth();
232238
}
233239

234240
this.commitLayouts(windowWidth);
@@ -249,11 +255,11 @@ class WorkspaceLayoutModel {
249255

250256
if (clampedVTab !== this.vtabWidth) {
251257
this.vtabWidth = clampedVTab;
252-
this.debouncedPersistVTabWidth(clampedVTab);
258+
this.debouncedPersistVTabWidth();
253259
}
254260
if (newAIW !== this.aiPanelWidth) {
255261
this.aiPanelWidth = newAIW;
256-
this.debouncedPersistAIWidth(newAIW);
262+
this.debouncedPersistAIWidth();
257263
}
258264

259265
this.commitLayouts(windowWidth);
@@ -280,6 +286,7 @@ class WorkspaceLayoutModel {
280286
panelContainerRef: HTMLDivElement,
281287
aiPanelWrapperRef: HTMLDivElement,
282288
vtabPanelRef?: ImperativePanelHandle,
289+
vtabPanelWrapperRef?: HTMLDivElement,
283290
showLeftTabBar?: boolean
284291
): void {
285292
this.aiPanelRef = aiPanelRef;
@@ -288,6 +295,7 @@ class WorkspaceLayoutModel {
288295
this.innerPanelGroupRef = innerPanelGroupRef;
289296
this.panelContainerRef = panelContainerRef;
290297
this.aiPanelWrapperRef = aiPanelWrapperRef;
298+
this.vtabPanelWrapperRef = vtabPanelWrapperRef ?? null;
291299
this.vtabVisible = showLeftTabBar ?? false;
292300
globalStore.set(this.vtabVisibleAtom, this.vtabVisible);
293301
this.syncPanelCollapse();
@@ -342,7 +350,6 @@ class WorkspaceLayoutModel {
342350
// ---- Public getters ----
343351

344352
getAIPanelVisible(): boolean {
345-
this.initializeFromMeta();
346353
return this.aiPanelVisible;
347354
}
348355

@@ -353,15 +360,13 @@ class WorkspaceLayoutModel {
353360
// ---- Initial percentage helpers (used by workspace.tsx for defaultSize) ----
354361

355362
getLeftGroupInitialPercentage(windowWidth: number, showLeftTabBar: boolean): number {
356-
this.initializeFromMeta();
357363
const vtabW = showLeftTabBar && !isBuilderWindow() ? this.getResolvedVTabWidth() : 0;
358364
const aiW = this.aiPanelVisible ? this.getResolvedAIWidth(windowWidth) : 0;
359365
return ((vtabW + aiW) / windowWidth) * 100;
360366
}
361367

362368
getInnerVTabInitialPercentage(windowWidth: number, showLeftTabBar: boolean): number {
363369
if (!showLeftTabBar || isBuilderWindow()) return 0;
364-
this.initializeFromMeta();
365370
const vtabW = this.getResolvedVTabWidth();
366371
const aiW = this.aiPanelVisible ? this.getResolvedAIWidth(windowWidth) : 0;
367372
const total = vtabW + aiW;
@@ -370,7 +375,6 @@ class WorkspaceLayoutModel {
370375
}
371376

372377
getInnerAIPanelInitialPercentage(windowWidth: number, showLeftTabBar: boolean): number {
373-
this.initializeFromMeta();
374378
const vtabW = showLeftTabBar && !isBuilderWindow() ? this.getResolvedVTabWidth() : 0;
375379
const aiW = this.aiPanelVisible ? this.getResolvedAIWidth(windowWidth) : 0;
376380
const total = vtabW + aiW;

frontend/app/workspace/workspace.tsx

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ const WorkspaceElem = memo(() => {
4646
const tabBarPosition = useAtomValue(getSettingsKeyAtom("app:tabbar")) ?? "top";
4747
const showLeftTabBar = tabBarPosition === "left";
4848
const aiPanelVisible = useAtomValue(workspaceLayoutModel.panelVisibleAtom);
49-
const vtabVisible = useAtomValue(workspaceLayoutModel.vtabVisibleAtom);
5049
const windowWidth = window.innerWidth;
5150
const leftGroupInitialPct = workspaceLayoutModel.getLeftGroupInitialPercentage(windowWidth, showLeftTabBar);
5251
const innerVTabInitialPct = workspaceLayoutModel.getInnerVTabInitialPercentage(windowWidth, showLeftTabBar);
@@ -57,6 +56,7 @@ const WorkspaceElem = memo(() => {
5756
const vtabPanelRef = useRef<ImperativePanelHandle>(null);
5857
const panelContainerRef = useRef<HTMLDivElement>(null);
5958
const aiPanelWrapperRef = useRef<HTMLDivElement>(null);
59+
const vtabPanelWrapperRef = useRef<HTMLDivElement>(null);
6060

6161
// showLeftTabBar is passed as a seed value only; subsequent changes are handled by setShowLeftTabBar below.
6262
// Do NOT add showLeftTabBar as a dep here — re-registering refs on config changes would redundantly re-run commitLayouts.
@@ -75,6 +75,7 @@ const WorkspaceElem = memo(() => {
7575
panelContainerRef.current,
7676
aiPanelWrapperRef.current,
7777
vtabPanelRef.current ?? undefined,
78+
vtabPanelWrapperRef.current ?? undefined,
7879
showLeftTabBar
7980
);
8081
}
@@ -85,24 +86,24 @@ const WorkspaceElem = memo(() => {
8586
getApi().setWaveAIOpen(isVisible);
8687
}, []);
8788

88-
useEffect(() => {
89-
workspaceLayoutModel.setShowLeftTabBar(showLeftTabBar);
90-
}, [showLeftTabBar]);
91-
9289
useEffect(() => {
9390
window.addEventListener("resize", workspaceLayoutModel.handleWindowResize);
9491
return () => window.removeEventListener("resize", workspaceLayoutModel.handleWindowResize);
9592
}, []);
9693

94+
useEffect(() => {
95+
workspaceLayoutModel.setShowLeftTabBar(showLeftTabBar);
96+
}, [showLeftTabBar]);
97+
9798
useEffect(() => {
9899
const handleFocus = () => workspaceLayoutModel.syncVTabWidthFromMeta();
99100
window.addEventListener("focus", handleFocus);
100101
return () => window.removeEventListener("focus", handleFocus);
101102
}, []);
102103

103-
const innerHandleVisible = vtabVisible && aiPanelVisible;
104+
const innerHandleVisible = showLeftTabBar && aiPanelVisible;
104105
const innerHandleClass = `bg-transparent hover:bg-zinc-500/20 transition-colors ${innerHandleVisible ? "w-0.5" : "w-0 pointer-events-none"}`;
105-
const outerHandleVisible = vtabVisible || aiPanelVisible;
106+
const outerHandleVisible = showLeftTabBar || aiPanelVisible;
106107
const outerHandleClass = `bg-transparent hover:bg-zinc-500/20 transition-colors ${outerHandleVisible ? "w-0.5" : "w-0 pointer-events-none"}`;
107108

108109
return (
@@ -129,7 +130,9 @@ const WorkspaceElem = memo(() => {
129130
order={0}
130131
className="overflow-hidden"
131132
>
132-
{showLeftTabBar && <VTabBar workspace={ws} />}
133+
<div ref={vtabPanelWrapperRef} className="w-full h-full">
134+
{showLeftTabBar && <VTabBar workspace={ws} />}
135+
</div>
133136
</Panel>
134137
<PanelResizeHandle className={innerHandleClass} />
135138
<Panel

0 commit comments

Comments
 (0)