Skip to content

preview updates (mock electron api, wos checks)#2986

Open
sawka wants to merge 9 commits intomainfrom
sawka/preview-updates
Open

preview updates (mock electron api, wos checks)#2986
sawka wants to merge 9 commits intomainfrom
sawka/preview-updates

Conversation

@sawka
Copy link
Member

@sawka sawka commented Mar 5, 2026

No description provided.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 5, 2026

Walkthrough

This pull request introduces a preview mode feature for the application. The changes add infrastructure to support a preview environment including a mock Electron API layer, preview-specific window type initialization gating, mock object handling in the WaveObj store, and refactored initialization flow using global state management. Additionally, the telemetry update function is propagated as a prop through the onboarding component, and supporting type definitions are extended to include an isPreview flag. The ESLint configuration is also updated to broaden unused variable ignore patterns.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive No description was provided by the author, making it impossible to assess relevance to the changeset. Add a pull request description explaining the purpose and scope of these preview-related updates to improve clarity for reviewers.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main changes: introducing a mock Electron API for preview environments and adding WaveObj storage checks in the wos module.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch sawka/preview-updates

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@cloudflare-workers-and-pages
Copy link

Deploying waveterm with  Cloudflare Pages  Cloudflare Pages

Latest commit: 00a1d26
Status: ✅  Deploy successful!
Preview URL: https://e86a82dd.waveterm.pages.dev
Branch Preview URL: https://sawka-preview-updates.waveterm.pages.dev

View logs

@kilo-code-bot
Copy link
Contributor

kilo-code-bot bot commented Mar 5, 2026

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Files Reviewed (7 files)
  • eslint.config.js — ESLint ignore pattern broadened from ^_$ to ^_[a-z0-9]*$
  • frontend/app/onboarding/onboarding.tsx — Dependency injection of telemetryUpdateFn prop
  • frontend/app/store/client-model.ts — Copyright year update + newline fix
  • frontend/app/store/global-atoms.ts — Preview window type detection added
  • frontend/app/store/wos.ts — Null guard for webEndpoint + preview mock object support
  • frontend/preview/preview-electron-api.ts — New stub Electron API for preview mode
  • frontend/preview/preview.tsx — Full GlobalInitOptions initialization for preview
  • frontend/preview/previews/onboarding.preview.tsx — Updated to pass no-op telemetryUpdateFn
  • frontend/types/custom.d.ts — Added isPreview? field to GlobalInitOptions

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@frontend/preview/preview-electron-api.ts`:
- Around line 4-61: The previewElectronApi object is missing the required async
method setIsActive defined by the ElectronApi interface; add setIsActive: () =>
Promise<void> to previewElectronApi (e.g., implement a stub that returns
Promise.resolve() or an async no-op) so the object satisfies the type
contract—update the previewElectronApi declaration to include this method
alongside the other functions.

In `@frontend/preview/preview.tsx`:
- Line 138: Replace the unsafe cast "{} as FullConfigType" used in
globalStore.set(getAtoms().fullConfigAtom, {} as FullConfigType) with a
structurally complete default that matches FullConfigType (e.g., include default
presets array and default settings object or use an exported
DEFAULT_FULL_CONFIG). Update the initialization so fullConfig.presets and
fullConfig.settings are defined (either create and use a DEFAULT_FULL_CONFIG
constant or import an existing default) before calling globalStore.set to avoid
runtime property access errors.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: e8547e9e-3db6-401b-ac3e-86e84238962c

📥 Commits

Reviewing files that changed from the base of the PR and between 1a1cd85 and 00a1d26.

📒 Files selected for processing (9)
  • eslint.config.js
  • frontend/app/onboarding/onboarding.tsx
  • frontend/app/store/client-model.ts
  • frontend/app/store/global-atoms.ts
  • frontend/app/store/wos.ts
  • frontend/preview/preview-electron-api.ts
  • frontend/preview/preview.tsx
  • frontend/preview/previews/onboarding.preview.tsx
  • frontend/types/custom.d.ts

Comment on lines +4 to +61
const previewElectronApi: ElectronApi = {
getAuthKey: () => "",
getIsDev: () => false,
getCursorPoint: () => ({ x: 0, y: 0 } as Electron.Point),
getPlatform: () => "darwin",
getEnv: (_varName: string) => "",
getUserName: () => "",
getHostName: () => "",
getDataDir: () => "",
getConfigDir: () => "",
getHomeDir: () => "",
getWebviewPreload: () => "",
getAboutModalDetails: () => ({} as AboutModalDetails),
getZoomFactor: () => 1.0,
showWorkspaceAppMenu: (_workspaceId: string) => {},
showBuilderAppMenu: (_builderId: string) => {},
showContextMenu: (_workspaceId: string, _menu: ElectronContextMenuItem[]) => {},
onContextMenuClick: (_callback: (id: string | null) => void) => {},
onNavigate: (_callback: (url: string) => void) => {},
onIframeNavigate: (_callback: (url: string) => void) => {},
downloadFile: (_path: string) => {},
openExternal: (_url: string) => {},
onFullScreenChange: (_callback: (isFullScreen: boolean) => void) => {},
onZoomFactorChange: (_callback: (zoomFactor: number) => void) => {},
onUpdaterStatusChange: (_callback: (status: UpdaterStatus) => void) => {},
getUpdaterStatus: () => "up-to-date",
getUpdaterChannel: () => "",
installAppUpdate: () => {},
onMenuItemAbout: (_callback: () => void) => {},
updateWindowControlsOverlay: (_rect: Dimensions) => {},
onReinjectKey: (_callback: (waveEvent: WaveKeyboardEvent) => void) => {},
setWebviewFocus: (_focusedId: number) => {},
registerGlobalWebviewKeys: (_keys: string[]) => {},
onControlShiftStateUpdate: (_callback: (state: boolean) => void) => {},
createWorkspace: () => {},
switchWorkspace: (_workspaceId: string) => {},
deleteWorkspace: (_workspaceId: string) => {},
setActiveTab: (_tabId: string) => {},
createTab: () => {},
closeTab: (_workspaceId: string, _tabId: string, _confirmClose: boolean) => Promise.resolve(false),
setWindowInitStatus: (_status: "ready" | "wave-ready") => {},
onWaveInit: (_callback: (initOpts: WaveInitOpts) => void) => {},
onBuilderInit: (_callback: (initOpts: BuilderInitOpts) => void) => {},
sendLog: (_log: string) => {},
onQuicklook: (_filePath: string) => {},
openNativePath: (_filePath: string) => {},
captureScreenshot: (_rect: Electron.Rectangle) => Promise.resolve(""),
setKeyboardChordMode: () => {},
clearWebviewStorage: (_webContentsId: number) => Promise.resolve(),
setWaveAIOpen: (_isOpen: boolean) => {},
closeBuilderWindow: () => {},
incrementTermCommands: (_opts?: { isRemote?: boolean; isWsl?: boolean; isDurable?: boolean }) => {},
nativePaste: () => {},
openBuilder: (_appId?: string) => {},
setBuilderWindowAppId: (_appId: string) => {},
doRefresh: () => {},
saveTextFile: (_fileName: string, _content: string) => Promise.resolve(false),
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
python - <<'PY'
import re, pathlib

type_src = pathlib.Path("frontend/types/custom.d.ts").read_text()
mock_src = pathlib.Path("frontend/preview/preview-electron-api.ts").read_text()

type_block = re.search(r'type ElectronApi = \{(.*?)\n\s*\};', type_src, re.S)
mock_block = re.search(r'const previewElectronApi:\s*ElectronApi\s*=\s*\{(.*?)\n\};', mock_src, re.S)

if not type_block or not mock_block:
    raise SystemExit("Could not locate ElectronApi type or previewElectronApi object.")

type_members = set(re.findall(r'^\s*([A-Za-z_]\w*)\s*[:(]', type_block.group(1), re.M))
mock_members = set(re.findall(r'^\s*([A-Za-z_]\w*)\s*:', mock_block.group(1), re.M))

print("Missing members in previewElectronApi:", sorted(type_members - mock_members))
print("Extra members in previewElectronApi:", sorted(mock_members - type_members))
PY

Repository: wavetermdev/waveterm

Length of output: 158


🏁 Script executed:

cat frontend/types/custom.d.ts | grep -A 500 "type ElectronApi"

Repository: wavetermdev/waveterm

Length of output: 14237


🏁 Script executed:

find . -path ".kilocode/skills/electron-api/SKILL.md" -o -path ".kilocode/skills/electron-api/*" | head -20

Repository: wavetermdev/waveterm

Length of output: 46


Implement missing setIsActive method in previewElectronApi.

The object declared as type ElectronApi at line 4 is missing the setIsActive: () => Promise<void> method required by the type contract in frontend/types/custom.d.ts.

Fix
 const previewElectronApi: ElectronApi = {
     doRefresh: () => {},
     saveTextFile: (_fileName: string, _content: string) => Promise.resolve(false),
+    setIsActive: () => Promise.resolve(),
 };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const previewElectronApi: ElectronApi = {
getAuthKey: () => "",
getIsDev: () => false,
getCursorPoint: () => ({ x: 0, y: 0 } as Electron.Point),
getPlatform: () => "darwin",
getEnv: (_varName: string) => "",
getUserName: () => "",
getHostName: () => "",
getDataDir: () => "",
getConfigDir: () => "",
getHomeDir: () => "",
getWebviewPreload: () => "",
getAboutModalDetails: () => ({} as AboutModalDetails),
getZoomFactor: () => 1.0,
showWorkspaceAppMenu: (_workspaceId: string) => {},
showBuilderAppMenu: (_builderId: string) => {},
showContextMenu: (_workspaceId: string, _menu: ElectronContextMenuItem[]) => {},
onContextMenuClick: (_callback: (id: string | null) => void) => {},
onNavigate: (_callback: (url: string) => void) => {},
onIframeNavigate: (_callback: (url: string) => void) => {},
downloadFile: (_path: string) => {},
openExternal: (_url: string) => {},
onFullScreenChange: (_callback: (isFullScreen: boolean) => void) => {},
onZoomFactorChange: (_callback: (zoomFactor: number) => void) => {},
onUpdaterStatusChange: (_callback: (status: UpdaterStatus) => void) => {},
getUpdaterStatus: () => "up-to-date",
getUpdaterChannel: () => "",
installAppUpdate: () => {},
onMenuItemAbout: (_callback: () => void) => {},
updateWindowControlsOverlay: (_rect: Dimensions) => {},
onReinjectKey: (_callback: (waveEvent: WaveKeyboardEvent) => void) => {},
setWebviewFocus: (_focusedId: number) => {},
registerGlobalWebviewKeys: (_keys: string[]) => {},
onControlShiftStateUpdate: (_callback: (state: boolean) => void) => {},
createWorkspace: () => {},
switchWorkspace: (_workspaceId: string) => {},
deleteWorkspace: (_workspaceId: string) => {},
setActiveTab: (_tabId: string) => {},
createTab: () => {},
closeTab: (_workspaceId: string, _tabId: string, _confirmClose: boolean) => Promise.resolve(false),
setWindowInitStatus: (_status: "ready" | "wave-ready") => {},
onWaveInit: (_callback: (initOpts: WaveInitOpts) => void) => {},
onBuilderInit: (_callback: (initOpts: BuilderInitOpts) => void) => {},
sendLog: (_log: string) => {},
onQuicklook: (_filePath: string) => {},
openNativePath: (_filePath: string) => {},
captureScreenshot: (_rect: Electron.Rectangle) => Promise.resolve(""),
setKeyboardChordMode: () => {},
clearWebviewStorage: (_webContentsId: number) => Promise.resolve(),
setWaveAIOpen: (_isOpen: boolean) => {},
closeBuilderWindow: () => {},
incrementTermCommands: (_opts?: { isRemote?: boolean; isWsl?: boolean; isDurable?: boolean }) => {},
nativePaste: () => {},
openBuilder: (_appId?: string) => {},
setBuilderWindowAppId: (_appId: string) => {},
doRefresh: () => {},
saveTextFile: (_fileName: string, _content: string) => Promise.resolve(false),
};
const previewElectronApi: ElectronApi = {
getAuthKey: () => "",
getIsDev: () => false,
getCursorPoint: () => ({ x: 0, y: 0 } as Electron.Point),
getPlatform: () => "darwin",
getEnv: (_varName: string) => "",
getUserName: () => "",
getHostName: () => "",
getDataDir: () => "",
getConfigDir: () => "",
getHomeDir: () => "",
getWebviewPreload: () => "",
getAboutModalDetails: () => ({} as AboutModalDetails),
getZoomFactor: () => 1.0,
showWorkspaceAppMenu: (_workspaceId: string) => {},
showBuilderAppMenu: (_builderId: string) => {},
showContextMenu: (_workspaceId: string, _menu: ElectronContextMenuItem[]) => {},
onContextMenuClick: (_callback: (id: string | null) => void) => {},
onNavigate: (_callback: (url: string) => void) => {},
onIframeNavigate: (_callback: (url: string) => void) => {},
downloadFile: (_path: string) => {},
openExternal: (_url: string) => {},
onFullScreenChange: (_callback: (isFullScreen: boolean) => void) => {},
onZoomFactorChange: (_callback: (zoomFactor: number) => void) => {},
onUpdaterStatusChange: (_callback: (status: UpdaterStatus) => void) => {},
getUpdaterStatus: () => "up-to-date",
getUpdaterChannel: () => "",
installAppUpdate: () => {},
onMenuItemAbout: (_callback: () => void) => {},
updateWindowControlsOverlay: (_rect: Dimensions) => {},
onReinjectKey: (_callback: (waveEvent: WaveKeyboardEvent) => void) => {},
setWebviewFocus: (_focusedId: number) => {},
registerGlobalWebviewKeys: (_keys: string[]) => {},
onControlShiftStateUpdate: (_callback: (state: boolean) => void) => {},
createWorkspace: () => {},
switchWorkspace: (_workspaceId: string) => {},
deleteWorkspace: (_workspaceId: string) => {},
setActiveTab: (_tabId: string) => {},
createTab: () => {},
closeTab: (_workspaceId: string, _tabId: string, _confirmClose: boolean) => Promise.resolve(false),
setWindowInitStatus: (_status: "ready" | "wave-ready") => {},
onWaveInit: (_callback: (initOpts: WaveInitOpts) => void) => {},
onBuilderInit: (_callback: (initOpts: BuilderInitOpts) => void) => {},
sendLog: (_log: string) => {},
onQuicklook: (_filePath: string) => {},
openNativePath: (_filePath: string) => {},
captureScreenshot: (_rect: Electron.Rectangle) => Promise.resolve(""),
setKeyboardChordMode: () => {},
clearWebviewStorage: (_webContentsId: number) => Promise.resolve(),
setWaveAIOpen: (_isOpen: boolean) => {},
closeBuilderWindow: () => {},
incrementTermCommands: (_opts?: { isRemote?: boolean; isWsl?: boolean; isDurable?: boolean }) => {},
nativePaste: () => {},
openBuilder: (_appId?: string) => {},
setBuilderWindowAppId: (_appId: string) => {},
doRefresh: () => {},
saveTextFile: (_fileName: string, _content: string) => Promise.resolve(false),
setIsActive: () => Promise.resolve(),
};
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/preview/preview-electron-api.ts` around lines 4 - 61, The
previewElectronApi object is missing the required async method setIsActive
defined by the ElectronApi interface; add setIsActive: () => Promise<void> to
previewElectronApi (e.g., implement a stub that returns Promise.resolve() or an
async no-op) so the object satisfies the type contract—update the
previewElectronApi declaration to include this method alongside the other
functions.

isPreview: true,
} as GlobalInitOptions;
initGlobalAtoms(initOpts);
globalStore.set(getAtoms().fullConfigAtom, {} as FullConfigType);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Initialize fullConfigAtom with a structurally safe default, not {}.

Line 138 sets {} as FullConfigType; preview components that read fullConfig.presets/fullConfig.settings directly can throw at runtime.

🔧 Proposed fix
-    globalStore.set(getAtoms().fullConfigAtom, {} as FullConfigType);
+    globalStore.set(
+        getAtoms().fullConfigAtom,
+        {
+            settings: {},
+            presets: {},
+            connections: {},
+        } as FullConfigType
+    );
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
globalStore.set(getAtoms().fullConfigAtom, {} as FullConfigType);
globalStore.set(
getAtoms().fullConfigAtom,
{
settings: {},
presets: {},
connections: {},
} as FullConfigType
);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/preview/preview.tsx` at line 138, Replace the unsafe cast "{} as
FullConfigType" used in globalStore.set(getAtoms().fullConfigAtom, {} as
FullConfigType) with a structurally complete default that matches FullConfigType
(e.g., include default presets array and default settings object or use an
exported DEFAULT_FULL_CONFIG). Update the initialization so fullConfig.presets
and fullConfig.settings are defined (either create and use a DEFAULT_FULL_CONFIG
constant or import an existing default) before calling globalStore.set to avoid
runtime property access errors.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants