Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion frontend/app/aipanel/aipanelinput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,20 @@ export interface AIPanelInputRef {
export const AIPanelInput = memo(({ onSubmit, status, model }: AIPanelInputProps) => {
const [input, setInput] = useAtom(model.inputAtom);
const isFocused = useAtomValue(model.isWaveAIFocusedAtom);
const isChatEmpty = useAtomValue(model.isChatEmptyAtom);
const textareaRef = useRef<HTMLTextAreaElement>(null);
const fileInputRef = useRef<HTMLInputElement>(null);
const isPanelOpen = useAtomValue(model.getPanelVisibleAtom());

let placeholder: string;
if (!isChatEmpty) {
placeholder = "Continue...";
} else if (model.inBuilder) {
placeholder = "What would you like to build...";
} else {
placeholder = "Ask Wave AI anything...";
}

const resizeTextarea = useCallback(() => {
const textarea = textareaRef.current;
if (!textarea) return;
Expand Down Expand Up @@ -141,7 +151,7 @@ export const AIPanelInput = memo(({ onSubmit, status, model }: AIPanelInputProps
onKeyDown={handleKeyDown}
onFocus={handleFocus}
onBlur={handleBlur}
placeholder={model.inBuilder ? "What would you like to build..." : "Ask Wave AI anything..."}
placeholder={placeholder}
className={cn(
"w-full text-white px-2 py-2 pr-5 focus:outline-none resize-none overflow-auto bg-zinc-800/50"
)}
Expand Down
8 changes: 4 additions & 4 deletions frontend/app/aipanel/waveai-model.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export class WaveAIModel {
codeBlockMaxWidth!: jotai.Atom<number>;
inputAtom: jotai.PrimitiveAtom<string> = jotai.atom("");
isLoadingChatAtom: jotai.PrimitiveAtom<boolean> = jotai.atom(false);
isChatEmpty: boolean = true;
isChatEmptyAtom: jotai.PrimitiveAtom<boolean> = jotai.atom(true);
isWaveAIFocusedAtom!: jotai.Atom<boolean>;
panelVisibleAtom!: jotai.Atom<boolean>;
restoreBackupModalToolCallId: jotai.PrimitiveAtom<string | null> = jotai.atom(null) as jotai.PrimitiveAtom<
Expand Down Expand Up @@ -271,7 +271,7 @@ export class WaveAIModel {
this.useChatStop?.();
this.clearFiles();
this.clearError();
this.isChatEmpty = true;
globalStore.set(this.isChatEmptyAtom, true);
const newChatId = crypto.randomUUID();
globalStore.set(this.chatId, newChatId);

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

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

this.isChatEmpty = false;
globalStore.set(this.isChatEmptyAtom, false);
globalStore.set(this.inputAtom, "");
this.clearFiles();
}
Expand Down
3 changes: 2 additions & 1 deletion frontend/app/block/blockutil.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0

import { NumActiveConnColors } from "@/app/block/blockframe";
import { getConnStatusAtom } from "@/app/store/global";
import { getConnStatusAtom, recordTEvent } from "@/app/store/global";
import * as util from "@/util/util";
import clsx from "clsx";
import * as jotai from "jotai";
Expand Down Expand Up @@ -168,6 +168,7 @@ export const ConnectionButton = React.memo(
const connColorNum = computeConnColorNum(connStatus);
let color = `var(--conn-icon-color-${connColorNum})`;
const clickHandler = function () {
recordTEvent("action:other", { "action:type": "conndropdown", "action:initiator": "mouse" });
setConnModalOpen(true);
};
let titleText = null;
Expand Down
2 changes: 1 addition & 1 deletion frontend/app/onboarding/onboarding-common.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2025, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0

export const CurrentOnboardingVersion = "v0.13.0";
export const CurrentOnboardingVersion = "v0.13.1";
7 changes: 7 additions & 0 deletions frontend/app/onboarding/onboarding-upgrade-patch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { UpgradeOnboardingModal_v0_12_1_Content } from "./onboarding-upgrade-v01
import { UpgradeOnboardingModal_v0_12_2_Content } from "./onboarding-upgrade-v0122";
import { UpgradeOnboardingModal_v0_12_3_Content } from "./onboarding-upgrade-v0123";
import { UpgradeOnboardingModal_v0_13_0_Content } from "./onboarding-upgrade-v0130";
import { UpgradeOnboardingModal_v0_13_1_Content } from "./onboarding-upgrade-v0131";

interface VersionConfig {
version: string;
Expand Down Expand Up @@ -48,6 +49,12 @@ const versions: VersionConfig[] = [
version: "v0.13.0",
content: () => <UpgradeOnboardingModal_v0_13_0_Content />,
prevText: "Prev (v0.12.5)",
nextText: "Next (v0.13.1)",
},
{
version: "v0.13.1",
content: () => <UpgradeOnboardingModal_v0_13_1_Content />,
prevText: "Prev (v0.13.0)",
},
];

Expand Down
86 changes: 86 additions & 0 deletions frontend/app/onboarding/onboarding-upgrade-v0131.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Copyright 2025, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0

const UpgradeOnboardingModal_v0_13_1_Content = () => {
return (
<div className="flex flex-col items-start gap-6 w-full mb-4 unselectable">
<div className="text-secondary leading-relaxed">
<p className="mb-0">
Wave v0.13.1 focuses on Windows platform improvements, Wave AI visual updates, and enhanced
terminal navigation.
</p>
</div>

<div className="flex w-full items-start gap-4">
<div className="flex-shrink-0">
<i className="text-[24px] text-accent fa-brands fa-windows"></i>
</div>
<div className="flex flex-col items-start gap-2 flex-1">
<div className="text-foreground text-base font-semibold leading-[18px]">
Windows Platform Enhancements
</div>
<div className="text-secondary leading-5">
<ul className="list-disc list-outside space-y-1 pl-5">
<li>
<strong>Integrated Window Layout</strong> - Cleaner interface with controls integrated
into the tab-bar header
</li>
<li>
<strong>Git Bash Auto-Detection</strong> - Automatically detects Git Bash installations
</li>
<li>
<strong>SSH Agent Fallback</strong> - Improved SSH agent support on Windows
</li>
<li>
<strong>Updated Focus Keybinding</strong> - Wave AI focus key changed to Alt:0 on
Windows
</li>
</ul>
</div>
</div>
</div>

<div className="flex w-full items-start gap-4">
<div className="flex-shrink-0">
<i className="text-[24px] text-accent fa-solid fa-sparkles"></i>
</div>
<div className="flex flex-col items-start gap-2 flex-1">
<div className="text-foreground text-base font-semibold leading-[18px]">Wave AI Updates</div>
<div className="text-secondary leading-5">
<ul className="list-disc list-outside space-y-1 pl-5">
<li>
<strong>Refreshed Visual Design</strong> - Complete UI refresh with transparency
support for custom backgrounds
</li>
<li>
<strong>BYOK Without Telemetry</strong> - Wave AI now works with bring-your-own-key and
local models without requiring telemetry
</li>
</ul>
</div>
</div>
</div>

<div className="flex w-full items-start gap-4">
<div className="flex-shrink-0">
<i className="text-[24px] text-accent fa-solid fa-terminal"></i>
</div>
<div className="flex flex-col items-start gap-2 flex-1">
<div className="text-foreground text-base font-semibold leading-[18px]">Terminal Improvements</div>
<div className="text-secondary leading-5">
<ul className="list-disc list-outside space-y-1 pl-5">
<li>
<strong>New Scrolling Keybindings</strong> - Added Shift+Home, Shift+End,
Shift+PageUp, and Shift+PageDown for better navigation
</li>
</ul>
</div>
</div>
</div>
</div>
);
};

UpgradeOnboardingModal_v0_13_1_Content.displayName = "UpgradeOnboardingModal_v0_13_1_Content";

export { UpgradeOnboardingModal_v0_13_1_Content };
6 changes: 4 additions & 2 deletions frontend/app/store/keymodel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
getFocusedBlockId,
getSettingsKeyAtom,
globalStore,
recordTEvent,
refocusNode,
replaceBlock,
WOS,
Expand Down Expand Up @@ -146,7 +147,7 @@ function uxCloseBlock(blockId: string) {
const isAIPanelOpen = workspaceLayoutModel.getAIPanelVisible();
if (isAIPanelOpen && getStaticTabBlockCount() === 1) {
const aiModel = WaveAIModel.getInstance();
const shouldSwitchToAI = !aiModel.isChatEmpty || aiModel.hasNonEmptyInput();
const shouldSwitchToAI = !globalStore.get(aiModel.isChatEmptyAtom) || aiModel.hasNonEmptyInput();
if (shouldSwitchToAI) {
replaceBlock(blockId, { meta: { view: "launcher" } }, false);
setTimeout(() => WaveAIModel.getInstance().focusInput(), 50);
Expand Down Expand Up @@ -184,7 +185,7 @@ function genericClose() {
const isAIPanelOpen = workspaceLayoutModel.getAIPanelVisible();
if (isAIPanelOpen && getStaticTabBlockCount() === 1) {
const aiModel = WaveAIModel.getInstance();
const shouldSwitchToAI = !aiModel.isChatEmpty || aiModel.hasNonEmptyInput();
const shouldSwitchToAI = !globalStore.get(aiModel.isChatEmptyAtom) || aiModel.hasNonEmptyInput();
if (shouldSwitchToAI) {
const layoutModel = getLayoutModelForStaticTab();
const focusedNode = globalStore.get(layoutModel.focusedNode);
Expand Down Expand Up @@ -580,6 +581,7 @@ function registerGlobalKeys() {
globalKeyMap.set("Cmd:g", () => {
const bcm = getBlockComponentModel(getFocusedBlockInStaticTab());
if (bcm.openSwitchConnection != null) {
recordTEvent("action:other", { "action:type": "conndropdown", "action:initiator": "keyboard" });
bcm.openSwitchConnection();
return true;
}
Expand Down
6 changes: 4 additions & 2 deletions frontend/app/view/preview/preview-edit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ function CodeEditPreview({ model }: SpecializedViewProps) {
function onMount(editor: MonacoTypes.editor.IStandaloneCodeEditor, monaco: Monaco): () => void {
model.monacoRef.current = editor;

editor.onKeyDown((e: MonacoTypes.IKeyboardEvent) => {
const keyDownDisposer = editor.onKeyDown((e: MonacoTypes.IKeyboardEvent) => {
const waveEvent = adaptFromReactOrNativeKeyEvent(e.browserEvent);
const handled = tryReinjectKey(waveEvent);
if (handled) {
Expand All @@ -90,7 +90,9 @@ function CodeEditPreview({ model }: SpecializedViewProps) {
editor.focus();
}

return null;
return () => {
keyDownDisposer.dispose();
};
}

return (
Expand Down
17 changes: 15 additions & 2 deletions frontend/app/view/waveconfig/waveconfig.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@

import { Tooltip } from "@/app/element/tooltip";
import { globalStore } from "@/app/store/jotaiStore";
import { tryReinjectKey } from "@/app/store/keymodel";
import { CodeEditor } from "@/app/view/codeeditor/codeeditor";
import type { ConfigFile, WaveConfigViewModel } from "@/app/view/waveconfig/waveconfig-model";
import { checkKeyPressed, keydownWrapper } from "@/util/keyutil";
import { adaptFromReactOrNativeKeyEvent, checkKeyPressed, keydownWrapper } from "@/util/keyutil";
import { cn } from "@/util/util";
import { useAtom, useAtomValue } from "jotai";
import type * as MonacoTypes from "monaco-editor/esm/vs/editor/editor.api";
import { memo, useCallback, useEffect, useRef } from "react";
import { debounce } from "throttle-debounce";

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

const handleEditorMount = useCallback(
(editor) => {
(editor: MonacoTypes.editor.IStandaloneCodeEditor) => {
model.editorRef.current = editor;

const keyDownDisposer = editor.onKeyDown((e: MonacoTypes.IKeyboardEvent) => {
const waveEvent = adaptFromReactOrNativeKeyEvent(e.browserEvent);
const handled = tryReinjectKey(waveEvent);
if (handled) {
e.stopPropagation();
e.preventDefault();
}
});

const isFocused = globalStore.get(model.nodeModel.isFocused);
if (isFocused) {
editor.focus();
}
return () => {
keyDownDisposer.dispose();
model.editorRef.current = null;
};
},
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading