Skip to content

Commit f610e63

Browse files
committed
better typing for FE. remove a lot of explicit type casts, fix ts errors
1 parent 4f47279 commit f610e63

17 files changed

Lines changed: 110 additions & 124 deletions

File tree

emain/emain-menu.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright 2025, Command Line Inc.
22
// SPDX-License-Identifier: Apache-2.0
33

4-
import { waveEventSubscribe } from "@/app/store/wps";
4+
import { waveEventSubscribeSingle } from "@/app/store/wps";
55
import { RpcApi } from "@/app/store/wshclientapi";
66
import * as electron from "electron";
77
import { fireAndForget } from "../frontend/util/util";
@@ -385,7 +385,7 @@ export function makeAndSetAppMenu() {
385385
}
386386

387387
function initMenuEventSubscriptions() {
388-
waveEventSubscribe({
388+
waveEventSubscribeSingle({
389389
eventType: "workspace:update",
390390
handler: makeAndSetAppMenu,
391391
});

frontend/app/store/global.ts

Lines changed: 49 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import { globalStore } from "./jotaiStore";
3131
import { modalsModel } from "./modalmodel";
3232
import { ClientService, ObjectService } from "./services";
3333
import * as WOS from "./wos";
34-
import { getFileSubject, waveEventSubscribe } from "./wps";
34+
import { getFileSubject, waveEventSubscribeSingle } from "./wps";
3535

3636
let atoms: GlobalAtomsType;
3737
let globalEnvironment: "electron" | "renderer";
@@ -198,65 +198,56 @@ function initGlobalAtoms(initOpts: GlobalInitOptions) {
198198
}
199199

200200
function initGlobalWaveEventSubs(initOpts: WaveInitOpts) {
201-
waveEventSubscribe(
202-
{
203-
eventType: "waveobj:update",
204-
handler: (event) => {
205-
// console.log("waveobj:update wave event handler", event);
206-
const update: WaveObjUpdate = event.data;
207-
WOS.updateWaveObject(update);
208-
},
201+
waveEventSubscribeSingle({
202+
eventType: "waveobj:update",
203+
handler: (event) => {
204+
// console.log("waveobj:update wave event handler", event);
205+
WOS.updateWaveObject(event.data);
209206
},
210-
{
211-
eventType: "config",
212-
handler: (event) => {
213-
// console.log("config wave event handler", event);
214-
const fullConfig = (event.data as WatcherUpdate).fullconfig;
215-
globalStore.set(atoms.fullConfigAtom, fullConfig);
216-
},
207+
});
208+
waveEventSubscribeSingle({
209+
eventType: "config",
210+
handler: (event) => {
211+
// console.log("config wave event handler", event);
212+
globalStore.set(atoms.fullConfigAtom, event.data.fullconfig);
217213
},
218-
{
219-
eventType: "waveai:modeconfig",
220-
handler: (event) => {
221-
const modeConfigs = (event.data as AIModeConfigUpdate).configs;
222-
globalStore.set(atoms.waveaiModeConfigAtom, modeConfigs);
223-
},
214+
});
215+
waveEventSubscribeSingle({
216+
eventType: "waveai:modeconfig",
217+
handler: (event) => {
218+
globalStore.set(atoms.waveaiModeConfigAtom, event.data.configs);
224219
},
225-
{
226-
eventType: "userinput",
227-
handler: (event) => {
228-
// console.log("userinput event handler", event);
229-
const data: UserInputRequest = event.data;
230-
modalsModel.pushModal("UserInputModal", { ...data });
231-
},
232-
scope: initOpts.windowId,
220+
});
221+
waveEventSubscribeSingle({
222+
eventType: "userinput",
223+
handler: (event) => {
224+
// console.log("userinput event handler", event);
225+
modalsModel.pushModal("UserInputModal", { ...event.data });
233226
},
234-
{
235-
eventType: "blockfile",
236-
handler: (event) => {
237-
// console.log("blockfile event update", event);
238-
const fileData: WSFileEventData = event.data;
239-
const fileSubject = getFileSubject(fileData.zoneid, fileData.filename);
240-
if (fileSubject != null) {
241-
fileSubject.next(fileData);
242-
}
243-
},
227+
scope: initOpts.windowId,
228+
});
229+
waveEventSubscribeSingle({
230+
eventType: "blockfile",
231+
handler: (event) => {
232+
// console.log("blockfile event update", event);
233+
const fileSubject = getFileSubject(event.data.zoneid, event.data.filename);
234+
if (fileSubject != null) {
235+
fileSubject.next(event.data);
236+
}
244237
},
245-
{
246-
eventType: "waveai:ratelimit",
247-
handler: (event) => {
248-
const rateLimitInfo: RateLimitInfo = event.data;
249-
globalStore.set(atoms.waveAIRateLimitInfoAtom, rateLimitInfo);
250-
},
238+
});
239+
waveEventSubscribeSingle({
240+
eventType: "waveai:ratelimit",
241+
handler: (event) => {
242+
globalStore.set(atoms.waveAIRateLimitInfoAtom, event.data);
251243
},
252-
{
253-
eventType: "tab:indicator",
254-
handler: (event) => {
255-
const data: TabIndicatorEventData = event.data;
256-
setTabIndicatorInternal(data.tabid, data.indicator);
257-
},
258-
}
259-
);
244+
});
245+
waveEventSubscribeSingle({
246+
eventType: "tab:indicator",
247+
handler: (event) => {
248+
setTabIndicatorInternal(event.data.tabid, event.data.indicator);
249+
},
250+
});
260251
}
261252

262253
const blockCache = new Map<string, Map<string, any>>();
@@ -762,11 +753,11 @@ async function loadTabIndicators() {
762753
}
763754

764755
function subscribeToConnEvents() {
765-
waveEventSubscribe({
756+
waveEventSubscribeSingle({
766757
eventType: "connchange",
767-
handler: (event: WaveEvent) => {
758+
handler: (event) => {
768759
try {
769-
const connStatus = event.data as ConnStatus;
760+
const connStatus = event.data;
770761
if (connStatus == null || isBlank(connStatus.connection)) {
771762
return;
772763
}
@@ -852,7 +843,7 @@ function setTabIndicator(tabId: string, indicator: TabIndicator) {
852843
data: {
853844
tabid: tabId,
854845
indicator: indicator,
855-
} as TabIndicatorEventData,
846+
},
856847
};
857848
fireAndForget(() => RpcApi.EventPublishCommand(TabRpcClient, eventData));
858849
}

frontend/app/store/wos.ts

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

44
// WaveObjectStore
55

6-
import { waveEventSubscribe } from "@/app/store/wps";
6+
import { waveEventSubscribeSingle } from "@/app/store/wps";
77
import { getWebServerEndpoint } from "@/util/endpoints";
88
import { fetch } from "@/util/fetchutil";
99
import { fireAndForget } from "@/util/util";
@@ -79,7 +79,7 @@ function debugLogBackendCall(methodName: string, durationStr: string, args: any[
7979
}
8080

8181
function wpsSubscribeToObject(oref: string): () => void {
82-
return waveEventSubscribe({
82+
return waveEventSubscribeSingle({
8383
eventType: "waveobj:update",
8484
scope: oref,
8585
handler: (event) => {

frontend/app/store/wps.ts

Lines changed: 25 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,19 @@ function setWpsRpcClient(client: WshClient) {
1212
WpsRpcClient = client;
1313
}
1414

15-
type WaveEventSubject = {
16-
handler: (event: WaveEvent) => void;
15+
type WaveEventSubject<T extends WaveEventName = WaveEventName> = {
16+
handler: (event: Extract<WaveEvent, { event: T }>) => void;
1717
scope?: string;
1818
};
1919

20-
type WaveEventSubjectContainer = WaveEventSubject & {
20+
type WaveEventSubjectContainer = {
21+
handler: (event: WaveEvent) => void;
22+
scope?: string;
2123
id: string;
2224
};
2325

24-
type WaveEventSubscription = WaveEventSubject & {
25-
eventType: string;
26+
type WaveEventSubscription<T extends WaveEventName = WaveEventName> = WaveEventSubject<T> & {
27+
eventType: T;
2628
};
2729

2830
type WaveEventUnsubscribe = {
@@ -58,29 +60,25 @@ function updateWaveEventSub(eventType: string) {
5860
RpcApi.EventSubCommand(WpsRpcClient, subreq, { noresponse: true });
5961
}
6062

61-
function waveEventSubscribe(...subscriptions: WaveEventSubscription[]): () => void {
62-
const unsubs: WaveEventUnsubscribe[] = [];
63-
const eventTypeSet = new Set<string>();
64-
for (const subscription of subscriptions) {
65-
// console.log("waveEventSubscribe", subscription);
66-
if (subscription.handler == null) {
67-
return;
68-
}
69-
const id: string = crypto.randomUUID();
70-
let subjects = waveEventSubjects.get(subscription.eventType);
71-
if (subjects == null) {
72-
subjects = [];
73-
waveEventSubjects.set(subscription.eventType, subjects);
74-
}
75-
const subcont: WaveEventSubjectContainer = { id, handler: subscription.handler, scope: subscription.scope };
76-
subjects.push(subcont);
77-
unsubs.push({ id, eventType: subscription.eventType });
78-
eventTypeSet.add(subscription.eventType);
63+
function waveEventSubscribeSingle<T extends WaveEventName>(subscription: WaveEventSubscription<T>): () => void {
64+
// console.log("waveEventSubscribeSingle", subscription);
65+
if (subscription.handler == null) {
66+
return () => {};
7967
}
80-
for (const eventType of eventTypeSet) {
81-
updateWaveEventSub(eventType);
68+
const id: string = crypto.randomUUID();
69+
let subjects = waveEventSubjects.get(subscription.eventType);
70+
if (subjects == null) {
71+
subjects = [];
72+
waveEventSubjects.set(subscription.eventType, subjects);
8273
}
83-
return () => waveEventUnsubscribe(...unsubs);
74+
const subcont: WaveEventSubjectContainer = {
75+
id,
76+
handler: subscription.handler as (event: WaveEvent) => void,
77+
scope: subscription.scope,
78+
};
79+
subjects.push(subcont);
80+
updateWaveEventSub(subscription.eventType);
81+
return () => waveEventUnsubscribe({ id, eventType: subscription.eventType });
8482
}
8583

8684
function waveEventUnsubscribe(...unsubscribes: WaveEventUnsubscribe[]) {
@@ -149,7 +147,7 @@ export {
149147
getFileSubject,
150148
handleWaveEvent,
151149
setWpsRpcClient,
152-
waveEventSubscribe,
150+
waveEventSubscribeSingle,
153151
waveEventUnsubscribe,
154152
wpsReconnectHandler,
155153
};

frontend/app/tab/workspaceswitcher.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import { IconButton } from "../element/iconbutton";
2121
import { atoms, getApi } from "../store/global";
2222
import { WorkspaceService } from "../store/services";
2323
import { getObjectValue, makeORef } from "../store/wos";
24-
import { waveEventSubscribe } from "../store/wps";
24+
import { waveEventSubscribeSingle } from "../store/wps";
2525
import { WorkspaceEditor } from "./workspaceeditor";
2626
import "./workspaceswitcher.scss";
2727

@@ -59,7 +59,7 @@ const WorkspaceSwitcher = forwardRef<HTMLDivElement>((_, ref) => {
5959

6060
useEffect(
6161
() =>
62-
waveEventSubscribe({
62+
waveEventSubscribeSingle({
6363
eventType: "workspace:update",
6464
handler: () => fireAndForget(updateWorkspaceList),
6565
}),

frontend/app/view/sysinfo/sysinfo.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import * as jotai from "jotai";
1313
import * as React from "react";
1414

1515
import { useDimensionsWithExistingRef } from "@/app/hook/useDimensions";
16-
import { waveEventSubscribe } from "@/app/store/wps";
16+
import { waveEventSubscribeSingle } from "@/app/store/wps";
1717
import { RpcApi } from "@/app/store/wshclientapi";
1818
import { TabRpcClient } from "@/app/store/wshrpcutil";
1919
import { atoms } from "@/store/global";
@@ -80,8 +80,8 @@ for (let i = 0; i < 32; i++) {
8080
DefaultPlotMeta[`cpu:${i}`] = defaultCpuMeta(`Core ${i}`);
8181
}
8282

83-
function convertWaveEventToDataItem(event: WaveEvent): DataItem {
84-
const eventData: TimeSeriesData = event.data;
83+
function convertWaveEventToDataItem(event: Extract<WaveEvent, { event: "sysinfo" }>): DataItem {
84+
const eventData = event.data;
8585
if (eventData == null || eventData.ts == null || eventData.values == null) {
8686
return null;
8787
}
@@ -360,7 +360,7 @@ function SysinfoView({ model, blockId }: SysinfoViewProps) {
360360
}
361361
}, [connStatus.status, connName]);
362362
React.useEffect(() => {
363-
const unsubFn = waveEventSubscribe({
363+
const unsubFn = waveEventSubscribeSingle({
364364
eventType: "sysinfo",
365365
scope: connName,
366366
handler: (event) => {

frontend/app/view/term/term-model.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { BlockNodeModel } from "@/app/block/blocktypes";
66
import { appHandleKeyDown } from "@/app/store/keymodel";
77
import { modalsModel } from "@/app/store/modalmodel";
88
import type { TabModel } from "@/app/store/tab-model";
9-
import { waveEventSubscribe } from "@/app/store/wps";
9+
import { waveEventSubscribeSingle } from "@/app/store/wps";
1010
import { RpcApi } from "@/app/store/wshclientapi";
1111
import { makeFeBlockRouteId } from "@/app/store/wshrouter";
1212
import { DefaultRouter, TabRpcClient } from "@/app/store/wshrpcutil";
@@ -330,12 +330,11 @@ export class TermViewModel implements ViewModel {
330330
initialShellProcStatus.then((rts) => {
331331
this.updateShellProcStatus(rts);
332332
});
333-
this.shellProcStatusUnsubFn = waveEventSubscribe({
333+
this.shellProcStatusUnsubFn = waveEventSubscribeSingle({
334334
eventType: "controllerstatus",
335335
scope: WOS.makeORef("block", blockId),
336336
handler: (event) => {
337-
let bcRTS: BlockControllerRuntimeStatus = event.data;
338-
this.updateShellProcStatus(bcRTS);
337+
this.updateShellProcStatus(event.data);
339338
},
340339
});
341340
this.shellProcStatus = jotai.atom((get) => {
@@ -364,7 +363,7 @@ export class TermViewModel implements ViewModel {
364363
.catch((error) => {
365364
console.log("error getting initial block job status", error);
366365
});
367-
this.blockJobStatusUnsubFn = waveEventSubscribe({
366+
this.blockJobStatusUnsubFn = waveEventSubscribeSingle({
368367
eventType: "block:jobstatus",
369368
scope: `block:${blockId}`,
370369
handler: (event) => {

frontend/app/view/term/term.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import type { BlockNodeModel } from "@/app/block/blocktypes";
66
import { Search, useSearch } from "@/app/element/search";
77
import { ContextMenuModel } from "@/app/store/contextmenu";
88
import { useTabModel } from "@/app/store/tab-model";
9-
import { waveEventSubscribe } from "@/app/store/wps";
9+
import { waveEventSubscribeSingle } from "@/app/store/wps";
1010
import { RpcApi } from "@/app/store/wshclientapi";
1111
import { TabRpcClient } from "@/app/store/wshrpcutil";
1212
import type { TermViewModel } from "@/app/view/term/term-model";
@@ -55,7 +55,7 @@ const TermResyncHandler = React.memo(({ blockId, model }: TerminalViewProps) =>
5555

5656
const TermVDomToolbarNode = ({ vdomBlockId, blockId, model }: TerminalViewProps & { vdomBlockId: string }) => {
5757
React.useEffect(() => {
58-
const unsub = waveEventSubscribe({
58+
const unsub = waveEventSubscribeSingle({
5959
eventType: "blockclose",
6060
scope: WOS.makeORef("block", vdomBlockId),
6161
handler: (event) => {
@@ -98,7 +98,7 @@ const TermVDomToolbarNode = ({ vdomBlockId, blockId, model }: TerminalViewProps
9898

9999
const TermVDomNodeSingleId = ({ vdomBlockId, blockId, model }: TerminalViewProps & { vdomBlockId: string }) => {
100100
React.useEffect(() => {
101-
const unsub = waveEventSubscribe({
101+
const unsub = waveEventSubscribeSingle({
102102
eventType: "blockclose",
103103
scope: WOS.makeORef("block", vdomBlockId),
104104
handler: (event) => {

0 commit comments

Comments
 (0)