Skip to content

Commit 1e820e5

Browse files
authored
v0.13.1 updates -- onboarding, small fixes (#2689)
1 parent 6b26c25 commit 1e820e5

File tree

10 files changed

+136
-15
lines changed

10 files changed

+136
-15
lines changed

frontend/app/aipanel/aipanelinput.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,20 @@ export interface AIPanelInputRef {
2424
export const AIPanelInput = memo(({ onSubmit, status, model }: AIPanelInputProps) => {
2525
const [input, setInput] = useAtom(model.inputAtom);
2626
const isFocused = useAtomValue(model.isWaveAIFocusedAtom);
27+
const isChatEmpty = useAtomValue(model.isChatEmptyAtom);
2728
const textareaRef = useRef<HTMLTextAreaElement>(null);
2829
const fileInputRef = useRef<HTMLInputElement>(null);
2930
const isPanelOpen = useAtomValue(model.getPanelVisibleAtom());
3031

32+
let placeholder: string;
33+
if (!isChatEmpty) {
34+
placeholder = "Continue...";
35+
} else if (model.inBuilder) {
36+
placeholder = "What would you like to build...";
37+
} else {
38+
placeholder = "Ask Wave AI anything...";
39+
}
40+
3141
const resizeTextarea = useCallback(() => {
3242
const textarea = textareaRef.current;
3343
if (!textarea) return;
@@ -141,7 +151,7 @@ export const AIPanelInput = memo(({ onSubmit, status, model }: AIPanelInputProps
141151
onKeyDown={handleKeyDown}
142152
onFocus={handleFocus}
143153
onBlur={handleBlur}
144-
placeholder={model.inBuilder ? "What would you like to build..." : "Ask Wave AI anything..."}
154+
placeholder={placeholder}
145155
className={cn(
146156
"w-full text-white px-2 py-2 pr-5 focus:outline-none resize-none overflow-auto bg-zinc-800/50"
147157
)}

frontend/app/aipanel/waveai-model.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ export class WaveAIModel {
6666
codeBlockMaxWidth!: jotai.Atom<number>;
6767
inputAtom: jotai.PrimitiveAtom<string> = jotai.atom("");
6868
isLoadingChatAtom: jotai.PrimitiveAtom<boolean> = jotai.atom(false);
69-
isChatEmpty: boolean = true;
69+
isChatEmptyAtom: jotai.PrimitiveAtom<boolean> = jotai.atom(true);
7070
isWaveAIFocusedAtom!: jotai.Atom<boolean>;
7171
panelVisibleAtom!: jotai.Atom<boolean>;
7272
restoreBackupModalToolCallId: jotai.PrimitiveAtom<string | null> = jotai.atom(null) as jotai.PrimitiveAtom<
@@ -271,7 +271,7 @@ export class WaveAIModel {
271271
this.useChatStop?.();
272272
this.clearFiles();
273273
this.clearError();
274-
this.isChatEmpty = true;
274+
globalStore.set(this.isChatEmptyAtom, true);
275275
const newChatId = crypto.randomUUID();
276276
globalStore.set(this.chatId, newChatId);
277277

@@ -450,7 +450,7 @@ export class WaveAIModel {
450450
try {
451451
const chatData = await RpcApi.GetWaveAIChatCommand(TabRpcClient, { chatid: chatIdValue });
452452
const messages: UIMessage[] = chatData?.messages ?? [];
453-
this.isChatEmpty = messages.length === 0;
453+
globalStore.set(this.isChatEmptyAtom, messages.length === 0);
454454
return messages as WaveUIMessage[]; // this is safe just different RPC type vs the FE type, but they are compatible
455455
} catch (error) {
456456
console.error("Failed to load chat:", error);
@@ -523,7 +523,7 @@ export class WaveAIModel {
523523

524524
this.useChatSendMessage?.({ parts: uiMessageParts });
525525

526-
this.isChatEmpty = false;
526+
globalStore.set(this.isChatEmptyAtom, false);
527527
globalStore.set(this.inputAtom, "");
528528
this.clearFiles();
529529
}

frontend/app/block/blockutil.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// SPDX-License-Identifier: Apache-2.0
33

44
import { NumActiveConnColors } from "@/app/block/blockframe";
5-
import { getConnStatusAtom } from "@/app/store/global";
5+
import { getConnStatusAtom, recordTEvent } from "@/app/store/global";
66
import * as util from "@/util/util";
77
import clsx from "clsx";
88
import * as jotai from "jotai";
@@ -168,6 +168,7 @@ export const ConnectionButton = React.memo(
168168
const connColorNum = computeConnColorNum(connStatus);
169169
let color = `var(--conn-icon-color-${connColorNum})`;
170170
const clickHandler = function () {
171+
recordTEvent("action:other", { "action:type": "conndropdown", "action:initiator": "mouse" });
171172
setConnModalOpen(true);
172173
};
173174
let titleText = null;
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
// Copyright 2025, Command Line Inc.
22
// SPDX-License-Identifier: Apache-2.0
33

4-
export const CurrentOnboardingVersion = "v0.13.0";
4+
export const CurrentOnboardingVersion = "v0.13.1";

frontend/app/onboarding/onboarding-upgrade-patch.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { UpgradeOnboardingModal_v0_12_1_Content } from "./onboarding-upgrade-v01
1818
import { UpgradeOnboardingModal_v0_12_2_Content } from "./onboarding-upgrade-v0122";
1919
import { UpgradeOnboardingModal_v0_12_3_Content } from "./onboarding-upgrade-v0123";
2020
import { UpgradeOnboardingModal_v0_13_0_Content } from "./onboarding-upgrade-v0130";
21+
import { UpgradeOnboardingModal_v0_13_1_Content } from "./onboarding-upgrade-v0131";
2122

2223
interface VersionConfig {
2324
version: string;
@@ -48,6 +49,12 @@ const versions: VersionConfig[] = [
4849
version: "v0.13.0",
4950
content: () => <UpgradeOnboardingModal_v0_13_0_Content />,
5051
prevText: "Prev (v0.12.5)",
52+
nextText: "Next (v0.13.1)",
53+
},
54+
{
55+
version: "v0.13.1",
56+
content: () => <UpgradeOnboardingModal_v0_13_1_Content />,
57+
prevText: "Prev (v0.13.0)",
5158
},
5259
];
5360

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
// Copyright 2025, Command Line Inc.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
const UpgradeOnboardingModal_v0_13_1_Content = () => {
5+
return (
6+
<div className="flex flex-col items-start gap-6 w-full mb-4 unselectable">
7+
<div className="text-secondary leading-relaxed">
8+
<p className="mb-0">
9+
Wave v0.13.1 focuses on Windows platform improvements, Wave AI visual updates, and enhanced
10+
terminal navigation.
11+
</p>
12+
</div>
13+
14+
<div className="flex w-full items-start gap-4">
15+
<div className="flex-shrink-0">
16+
<i className="text-[24px] text-accent fa-brands fa-windows"></i>
17+
</div>
18+
<div className="flex flex-col items-start gap-2 flex-1">
19+
<div className="text-foreground text-base font-semibold leading-[18px]">
20+
Windows Platform Enhancements
21+
</div>
22+
<div className="text-secondary leading-5">
23+
<ul className="list-disc list-outside space-y-1 pl-5">
24+
<li>
25+
<strong>Integrated Window Layout</strong> - Cleaner interface with controls integrated
26+
into the tab-bar header
27+
</li>
28+
<li>
29+
<strong>Git Bash Auto-Detection</strong> - Automatically detects Git Bash installations
30+
</li>
31+
<li>
32+
<strong>SSH Agent Fallback</strong> - Improved SSH agent support on Windows
33+
</li>
34+
<li>
35+
<strong>Updated Focus Keybinding</strong> - Wave AI focus key changed to Alt:0 on
36+
Windows
37+
</li>
38+
</ul>
39+
</div>
40+
</div>
41+
</div>
42+
43+
<div className="flex w-full items-start gap-4">
44+
<div className="flex-shrink-0">
45+
<i className="text-[24px] text-accent fa-solid fa-sparkles"></i>
46+
</div>
47+
<div className="flex flex-col items-start gap-2 flex-1">
48+
<div className="text-foreground text-base font-semibold leading-[18px]">Wave AI Updates</div>
49+
<div className="text-secondary leading-5">
50+
<ul className="list-disc list-outside space-y-1 pl-5">
51+
<li>
52+
<strong>Refreshed Visual Design</strong> - Complete UI refresh with transparency
53+
support for custom backgrounds
54+
</li>
55+
<li>
56+
<strong>BYOK Without Telemetry</strong> - Wave AI now works with bring-your-own-key and
57+
local models without requiring telemetry
58+
</li>
59+
</ul>
60+
</div>
61+
</div>
62+
</div>
63+
64+
<div className="flex w-full items-start gap-4">
65+
<div className="flex-shrink-0">
66+
<i className="text-[24px] text-accent fa-solid fa-terminal"></i>
67+
</div>
68+
<div className="flex flex-col items-start gap-2 flex-1">
69+
<div className="text-foreground text-base font-semibold leading-[18px]">Terminal Improvements</div>
70+
<div className="text-secondary leading-5">
71+
<ul className="list-disc list-outside space-y-1 pl-5">
72+
<li>
73+
<strong>New Scrolling Keybindings</strong> - Added Shift+Home, Shift+End,
74+
Shift+PageUp, and Shift+PageDown for better navigation
75+
</li>
76+
</ul>
77+
</div>
78+
</div>
79+
</div>
80+
</div>
81+
);
82+
};
83+
84+
UpgradeOnboardingModal_v0_13_1_Content.displayName = "UpgradeOnboardingModal_v0_13_1_Content";
85+
86+
export { UpgradeOnboardingModal_v0_13_1_Content };

frontend/app/store/keymodel.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
getFocusedBlockId,
1616
getSettingsKeyAtom,
1717
globalStore,
18+
recordTEvent,
1819
refocusNode,
1920
replaceBlock,
2021
WOS,
@@ -146,7 +147,7 @@ function uxCloseBlock(blockId: string) {
146147
const isAIPanelOpen = workspaceLayoutModel.getAIPanelVisible();
147148
if (isAIPanelOpen && getStaticTabBlockCount() === 1) {
148149
const aiModel = WaveAIModel.getInstance();
149-
const shouldSwitchToAI = !aiModel.isChatEmpty || aiModel.hasNonEmptyInput();
150+
const shouldSwitchToAI = !globalStore.get(aiModel.isChatEmptyAtom) || aiModel.hasNonEmptyInput();
150151
if (shouldSwitchToAI) {
151152
replaceBlock(blockId, { meta: { view: "launcher" } }, false);
152153
setTimeout(() => WaveAIModel.getInstance().focusInput(), 50);
@@ -184,7 +185,7 @@ function genericClose() {
184185
const isAIPanelOpen = workspaceLayoutModel.getAIPanelVisible();
185186
if (isAIPanelOpen && getStaticTabBlockCount() === 1) {
186187
const aiModel = WaveAIModel.getInstance();
187-
const shouldSwitchToAI = !aiModel.isChatEmpty || aiModel.hasNonEmptyInput();
188+
const shouldSwitchToAI = !globalStore.get(aiModel.isChatEmptyAtom) || aiModel.hasNonEmptyInput();
188189
if (shouldSwitchToAI) {
189190
const layoutModel = getLayoutModelForStaticTab();
190191
const focusedNode = globalStore.get(layoutModel.focusedNode);
@@ -580,6 +581,7 @@ function registerGlobalKeys() {
580581
globalKeyMap.set("Cmd:g", () => {
581582
const bcm = getBlockComponentModel(getFocusedBlockInStaticTab());
582583
if (bcm.openSwitchConnection != null) {
584+
recordTEvent("action:other", { "action:type": "conndropdown", "action:initiator": "keyboard" });
583585
bcm.openSwitchConnection();
584586
return true;
585587
}

frontend/app/view/preview/preview-edit.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ function CodeEditPreview({ model }: SpecializedViewProps) {
7676
function onMount(editor: MonacoTypes.editor.IStandaloneCodeEditor, monaco: Monaco): () => void {
7777
model.monacoRef.current = editor;
7878

79-
editor.onKeyDown((e: MonacoTypes.IKeyboardEvent) => {
79+
const keyDownDisposer = editor.onKeyDown((e: MonacoTypes.IKeyboardEvent) => {
8080
const waveEvent = adaptFromReactOrNativeKeyEvent(e.browserEvent);
8181
const handled = tryReinjectKey(waveEvent);
8282
if (handled) {
@@ -90,7 +90,9 @@ function CodeEditPreview({ model }: SpecializedViewProps) {
9090
editor.focus();
9191
}
9292

93-
return null;
93+
return () => {
94+
keyDownDisposer.dispose();
95+
};
9496
}
9597

9698
return (

frontend/app/view/waveconfig/waveconfig.tsx

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@
33

44
import { Tooltip } from "@/app/element/tooltip";
55
import { globalStore } from "@/app/store/jotaiStore";
6+
import { tryReinjectKey } from "@/app/store/keymodel";
67
import { CodeEditor } from "@/app/view/codeeditor/codeeditor";
78
import type { ConfigFile, WaveConfigViewModel } from "@/app/view/waveconfig/waveconfig-model";
8-
import { checkKeyPressed, keydownWrapper } from "@/util/keyutil";
9+
import { adaptFromReactOrNativeKeyEvent, checkKeyPressed, keydownWrapper } from "@/util/keyutil";
910
import { cn } from "@/util/util";
1011
import { useAtom, useAtomValue } from "jotai";
12+
import type * as MonacoTypes from "monaco-editor/esm/vs/editor/editor.api";
1113
import { memo, useCallback, useEffect, useRef } from "react";
1214
import { debounce } from "throttle-debounce";
1315

@@ -106,13 +108,24 @@ const WaveConfigView = memo(({ blockId, model }: ViewComponentProps<WaveConfigVi
106108
);
107109

108110
const handleEditorMount = useCallback(
109-
(editor) => {
111+
(editor: MonacoTypes.editor.IStandaloneCodeEditor) => {
110112
model.editorRef.current = editor;
113+
114+
const keyDownDisposer = editor.onKeyDown((e: MonacoTypes.IKeyboardEvent) => {
115+
const waveEvent = adaptFromReactOrNativeKeyEvent(e.browserEvent);
116+
const handled = tryReinjectKey(waveEvent);
117+
if (handled) {
118+
e.stopPropagation();
119+
e.preventDefault();
120+
}
121+
});
122+
111123
const isFocused = globalStore.get(model.nodeModel.isFocused);
112124
if (isFocused) {
113125
editor.focus();
114126
}
115127
return () => {
128+
keyDownDisposer.dispose();
116129
model.editorRef.current = null;
117130
};
118131
},

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)