waveterm/frontend/app/waveenv/waveenv.ts
Copilot ecccad6ea1
TabBar full preview + much more FE mocking via WaveEnv to enable it (#3028)
Large PR that extends WaveEnv mocking to fully cover the (complicated) TabBar implementation.  Also includes a full preview of the tab bar in the preview server with lots of controls to simulate different scenarios.

As a result of this mocking, also fixed a bunch of dependencies, and layout errors, random bugs, and visual UX bugs in the tab bar, making it more robust.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: sawka <2722291+sawka@users.noreply.github.com>
Co-authored-by: sawka <mike@commandline.dev>
2026-03-11 13:54:12 -07:00

93 lines
3.2 KiB
TypeScript

// Copyright 2026, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
import type { AllServiceImpls } from "@/app/store/services";
import { RpcApiType } from "@/app/store/wshclientapi";
import { Atom, PrimitiveAtom } from "jotai";
import React from "react";
export type BlockMetaKeyAtomFnType<Keys extends keyof MetaType = keyof MetaType> = <T extends Keys>(
blockId: string,
key: T
) => Atom<MetaType[T]>;
export type ConnConfigKeyAtomFnType<Keys extends keyof ConnKeywords = keyof ConnKeywords> = <T extends Keys>(
connName: string,
key: T
) => Atom<ConnKeywords[T]>;
export type SettingsKeyAtomFnType<Keys extends keyof SettingsType = keyof SettingsType> = <T extends Keys>(
key: T
) => Atom<SettingsType[T]>;
type OmitNever<T> = {
[K in keyof T as [T[K]] extends [never] ? never : K]: T[K];
};
type Subset<T, U> = OmitNever<{
[K in keyof T]: K extends keyof U ? T[K] : never;
}>;
type ComplexWaveEnvKeys = {
rpc: WaveEnv["rpc"];
electron: WaveEnv["electron"];
atoms: WaveEnv["atoms"];
wos: WaveEnv["wos"];
services: WaveEnv["services"];
};
type WaveEnvMockFields = {
isMock: WaveEnv["isMock"];
mockSetWaveObj: WaveEnv["mockSetWaveObj"];
mockModels: WaveEnv["mockModels"];
};
export type WaveEnvSubset<T> = WaveEnvMockFields &
OmitNever<{
[K in keyof T]: K extends keyof ComplexWaveEnvKeys
? Subset<T[K], ComplexWaveEnvKeys[K]>
: K extends keyof WaveEnv
? T[K]
: never;
}>;
// default implementation for production is in ./waveenvimpl.ts
export type WaveEnv = {
isMock: boolean;
electron: ElectronApi;
rpc: RpcApiType;
platform: NodeJS.Platform;
isDev: () => boolean;
isWindows: () => boolean;
isMacOS: () => boolean;
atoms: GlobalAtomsType;
createBlock: (blockDef: BlockDef, magnified?: boolean, ephemeral?: boolean) => Promise<string>;
services: typeof AllServiceImpls;
callBackendService: (service: string, method: string, args: any[], noUIContext?: boolean) => Promise<any>;
showContextMenu: (menu: ContextMenuItem[], e: React.MouseEvent) => void;
getConnStatusAtom: (conn: string) => PrimitiveAtom<ConnStatus>;
getLocalHostDisplayNameAtom: () => Atom<string>;
wos: {
getWaveObjectAtom: <T extends WaveObj>(oref: string) => Atom<T>;
getWaveObjectLoadingAtom: (oref: string) => Atom<boolean>;
isWaveObjectNullAtom: (oref: string) => Atom<boolean>;
useWaveObjectValue: <T extends WaveObj>(oref: string) => [T, boolean];
};
getSettingsKeyAtom: SettingsKeyAtomFnType;
getBlockMetaKeyAtom: BlockMetaKeyAtomFnType;
getConnConfigKeyAtom: ConnConfigKeyAtomFnType;
// the mock fields are only usable in the preview server (may be be null or throw errors in production)
mockSetWaveObj: <T extends WaveObj>(oref: string, obj: T) => void;
mockModels: Map<any, any>;
};
export const WaveEnvContext = React.createContext<WaveEnv>(null);
type EnvContract<T> = {
[K in keyof T]?: T[K] extends (...args: any[]) => any ? T[K] : T[K] extends object ? EnvContract<T[K]> : T[K];
};
export function useWaveEnv<T extends EnvContract<WaveEnv> = WaveEnv>(): T {
return React.useContext(WaveEnvContext) as T;
}