mirror of
https://github.com/wavetermdev/waveterm.git
synced 2025-01-31 23:11:28 +01:00
Auditing async usage in frontend code (#1402)
I found a lot of places where asyncs weren't being properly wrapped or awaited
This commit is contained in:
parent
297e2b627f
commit
7a61f25331
@ -165,7 +165,7 @@ export class WaveBrowserWindow extends BaseWindow {
|
||||
}
|
||||
focusedWaveWindow = this;
|
||||
console.log("focus win", this.waveWindowId);
|
||||
fireAndForget(async () => await ClientService.FocusWindow(this.waveWindowId));
|
||||
fireAndForget(() => ClientService.FocusWindow(this.waveWindowId));
|
||||
setWasInFg(true);
|
||||
setWasActive(true);
|
||||
});
|
||||
@ -235,7 +235,7 @@ export class WaveBrowserWindow extends BaseWindow {
|
||||
}
|
||||
if (this.deleteAllowed) {
|
||||
console.log("win removing window from backend DB", this.waveWindowId);
|
||||
fireAndForget(async () => await WindowService.CloseWindow(this.waveWindowId, true));
|
||||
fireAndForget(() => WindowService.CloseWindow(this.waveWindowId, true));
|
||||
}
|
||||
for (const tabView of this.allTabViews.values()) {
|
||||
tabView?.destroy();
|
||||
|
@ -368,7 +368,7 @@ electron.ipcMain.on("quicklook", (event, filePath: string) => {
|
||||
|
||||
electron.ipcMain.on("open-native-path", (event, filePath: string) => {
|
||||
console.log("open-native-path", filePath);
|
||||
fireAndForget(async () =>
|
||||
fireAndForget(() =>
|
||||
electron.shell.openPath(filePath).then((excuse) => {
|
||||
if (excuse) console.error(`Failed to open ${filePath} in native application: ${excuse}`);
|
||||
})
|
||||
|
@ -96,7 +96,7 @@ export class Updater {
|
||||
body: "A new version of Wave Terminal is ready to install.",
|
||||
});
|
||||
updateNotification.on("click", () => {
|
||||
fireAndForget(() => this.promptToInstallUpdate());
|
||||
fireAndForget(this.promptToInstallUpdate.bind(this));
|
||||
});
|
||||
updateNotification.show();
|
||||
});
|
||||
@ -188,7 +188,7 @@ export class Updater {
|
||||
if (allWindows.length > 0) {
|
||||
await dialog.showMessageBox(focusedWaveWindow ?? allWindows[0], dialogOpts).then(({ response }) => {
|
||||
if (response === 0) {
|
||||
fireAndForget(async () => this.installUpdate());
|
||||
fireAndForget(this.installUpdate.bind(this));
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -210,7 +210,7 @@ export function getResolvedUpdateChannel(): string {
|
||||
return isDev() ? "dev" : (autoUpdater.channel ?? "latest");
|
||||
}
|
||||
|
||||
ipcMain.on("install-app-update", () => fireAndForget(() => updater?.promptToInstallUpdate()));
|
||||
ipcMain.on("install-app-update", () => fireAndForget(updater?.promptToInstallUpdate.bind(updater)));
|
||||
ipcMain.on("get-app-update-status", (event) => {
|
||||
event.returnValue = updater?.status;
|
||||
});
|
||||
|
@ -12,6 +12,7 @@ import { FlexiModal } from "./modal";
|
||||
import { QuickTips } from "@/app/element/quicktips";
|
||||
import { atoms, getApi } from "@/app/store/global";
|
||||
import { modalsModel } from "@/app/store/modalmodel";
|
||||
import { fireAndForget } from "@/util/util";
|
||||
import { atom, PrimitiveAtom, useAtom, useAtomValue, useSetAtom } from "jotai";
|
||||
import "./tos.scss";
|
||||
|
||||
@ -20,25 +21,22 @@ const pageNumAtom: PrimitiveAtom<number> = atom<number>(1);
|
||||
const ModalPage1 = () => {
|
||||
const settings = useAtomValue(atoms.settingsAtom);
|
||||
const clientData = useAtomValue(atoms.client);
|
||||
const [tosOpen, setTosOpen] = useAtom(modalsModel.tosOpen);
|
||||
const [telemetryEnabled, setTelemetryEnabled] = useState<boolean>(!!settings["telemetry:enabled"]);
|
||||
const setPageNum = useSetAtom(pageNumAtom);
|
||||
|
||||
const acceptTos = () => {
|
||||
if (!clientData.tosagreed) {
|
||||
services.ClientService.AgreeTos();
|
||||
fireAndForget(services.ClientService.AgreeTos);
|
||||
}
|
||||
setPageNum(2);
|
||||
};
|
||||
|
||||
const setTelemetry = (value: boolean) => {
|
||||
services.ClientService.TelemetryUpdate(value)
|
||||
.then(() => {
|
||||
fireAndForget(() =>
|
||||
services.ClientService.TelemetryUpdate(value).then(() => {
|
||||
setTelemetryEnabled(value);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("failed to set telemetry:", error);
|
||||
});
|
||||
);
|
||||
};
|
||||
|
||||
const label = telemetryEnabled ? "Telemetry Enabled" : "Telemetry Disabled";
|
||||
|
@ -5,9 +5,9 @@ import { Modal } from "@/app/modals/modal";
|
||||
import { Markdown } from "@/element/markdown";
|
||||
import { modalsModel } from "@/store/modalmodel";
|
||||
import * as keyutil from "@/util/keyutil";
|
||||
import { UserInputService } from "../store/services";
|
||||
|
||||
import { fireAndForget } from "@/util/util";
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
import { UserInputService } from "../store/services";
|
||||
import "./userinputmodal.scss";
|
||||
|
||||
const UserInputModal = (userInputRequest: UserInputRequest) => {
|
||||
@ -16,33 +16,39 @@ const UserInputModal = (userInputRequest: UserInputRequest) => {
|
||||
const checkboxRef = useRef<HTMLInputElement>();
|
||||
|
||||
const handleSendErrResponse = useCallback(() => {
|
||||
UserInputService.SendUserInputResponse({
|
||||
type: "userinputresp",
|
||||
requestid: userInputRequest.requestid,
|
||||
errormsg: "Canceled by the user",
|
||||
});
|
||||
fireAndForget(() =>
|
||||
UserInputService.SendUserInputResponse({
|
||||
type: "userinputresp",
|
||||
requestid: userInputRequest.requestid,
|
||||
errormsg: "Canceled by the user",
|
||||
})
|
||||
);
|
||||
modalsModel.popModal();
|
||||
}, [responseText, userInputRequest]);
|
||||
|
||||
const handleSendText = useCallback(() => {
|
||||
UserInputService.SendUserInputResponse({
|
||||
type: "userinputresp",
|
||||
requestid: userInputRequest.requestid,
|
||||
text: responseText,
|
||||
checkboxstat: checkboxRef?.current?.checked ?? false,
|
||||
});
|
||||
fireAndForget(() =>
|
||||
UserInputService.SendUserInputResponse({
|
||||
type: "userinputresp",
|
||||
requestid: userInputRequest.requestid,
|
||||
text: responseText,
|
||||
checkboxstat: checkboxRef?.current?.checked ?? false,
|
||||
})
|
||||
);
|
||||
modalsModel.popModal();
|
||||
}, [responseText, userInputRequest]);
|
||||
console.log("bar");
|
||||
|
||||
const handleSendConfirm = useCallback(
|
||||
(response: boolean) => {
|
||||
UserInputService.SendUserInputResponse({
|
||||
type: "userinputresp",
|
||||
requestid: userInputRequest.requestid,
|
||||
confirm: response,
|
||||
checkboxstat: checkboxRef?.current?.checked ?? false,
|
||||
});
|
||||
fireAndForget(() =>
|
||||
UserInputService.SendUserInputResponse({
|
||||
type: "userinputresp",
|
||||
requestid: userInputRequest.requestid,
|
||||
confirm: response,
|
||||
checkboxstat: checkboxRef?.current?.checked ?? false,
|
||||
})
|
||||
);
|
||||
modalsModel.popModal();
|
||||
},
|
||||
[userInputRequest]
|
||||
|
@ -19,6 +19,7 @@ import {
|
||||
} from "@/layout/index";
|
||||
import { getLayoutModelForStaticTab } from "@/layout/lib/layoutModelHooks";
|
||||
import * as keyutil from "@/util/keyutil";
|
||||
import { fireAndForget } from "@/util/util";
|
||||
import * as jotai from "jotai";
|
||||
|
||||
const simpleControlShiftAtom = jotai.atom(false);
|
||||
@ -83,7 +84,7 @@ function genericClose(tabId: string) {
|
||||
return;
|
||||
}
|
||||
const layoutModel = getLayoutModelForTab(tabAtom);
|
||||
layoutModel.closeFocusedNode();
|
||||
fireAndForget(layoutModel.closeFocusedNode.bind(layoutModel));
|
||||
}
|
||||
|
||||
function switchBlockByBlockNum(index: number) {
|
||||
|
@ -6,6 +6,7 @@
|
||||
import { waveEventSubscribe } from "@/app/store/wps";
|
||||
import { getWebServerEndpoint } from "@/util/endpoints";
|
||||
import { fetch } from "@/util/fetchutil";
|
||||
import { fireAndForget } from "@/util/util";
|
||||
import { atom, Atom, Getter, PrimitiveAtom, Setter, useAtomValue } from "jotai";
|
||||
import { useEffect } from "react";
|
||||
import { globalStore } from "./jotaiStore";
|
||||
@ -301,7 +302,7 @@ function setObjectValue<T extends WaveObj>(value: T, setFn?: Setter, pushToServe
|
||||
}
|
||||
setFn(wov.dataAtom, { value: value, loading: false });
|
||||
if (pushToServer) {
|
||||
ObjectService.UpdateObject(value, false);
|
||||
fireAndForget(() => ObjectService.UpdateObject(value, false));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@ import { RpcApi } from "@/app/store/wshclientapi";
|
||||
import { TabRpcClient } from "@/app/store/wshrpcutil";
|
||||
import { Button } from "@/element/button";
|
||||
import { ContextMenuModel } from "@/store/contextmenu";
|
||||
import { fireAndForget } from "@/util/util";
|
||||
import { clsx } from "clsx";
|
||||
import { forwardRef, memo, useCallback, useEffect, useImperativeHandle, useRef, useState } from "react";
|
||||
import { ObjectService } from "../store/services";
|
||||
@ -72,14 +73,21 @@ const Tab = memo(
|
||||
};
|
||||
}, []);
|
||||
|
||||
const handleRenameTab = (event) => {
|
||||
const selectEditableText = useCallback(() => {
|
||||
if (editableRef.current) {
|
||||
const range = document.createRange();
|
||||
const selection = window.getSelection();
|
||||
range.selectNodeContents(editableRef.current);
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(range);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const handleRenameTab: React.MouseEventHandler<HTMLDivElement> = (event) => {
|
||||
event?.stopPropagation();
|
||||
setIsEditable(true);
|
||||
editableTimeoutRef.current = setTimeout(() => {
|
||||
if (editableRef.current) {
|
||||
editableRef.current.focus();
|
||||
document.execCommand("selectAll", false);
|
||||
}
|
||||
selectEditableText();
|
||||
}, 0);
|
||||
};
|
||||
|
||||
@ -88,20 +96,14 @@ const Tab = memo(
|
||||
newText = newText || originalName;
|
||||
editableRef.current.innerText = newText;
|
||||
setIsEditable(false);
|
||||
ObjectService.UpdateTabName(id, newText);
|
||||
fireAndForget(() => ObjectService.UpdateTabName(id, newText));
|
||||
setTimeout(() => refocusNode(null), 10);
|
||||
};
|
||||
|
||||
const handleKeyDown = (event) => {
|
||||
const handleKeyDown: React.KeyboardEventHandler<HTMLDivElement> = (event) => {
|
||||
if ((event.metaKey || event.ctrlKey) && event.key === "a") {
|
||||
event.preventDefault();
|
||||
if (editableRef.current) {
|
||||
const range = document.createRange();
|
||||
const selection = window.getSelection();
|
||||
range.selectNodeContents(editableRef.current);
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(range);
|
||||
}
|
||||
selectEditableText();
|
||||
return;
|
||||
}
|
||||
// this counts glyphs, not characters
|
||||
@ -150,7 +152,10 @@ const Tab = memo(
|
||||
let menu: ContextMenuItem[] = [
|
||||
{ label: isPinned ? "Unpin Tab" : "Pin Tab", click: () => onPinChange() },
|
||||
{ label: "Rename Tab", click: () => handleRenameTab(null) },
|
||||
{ label: "Copy TabId", click: () => navigator.clipboard.writeText(id) },
|
||||
{
|
||||
label: "Copy TabId",
|
||||
click: () => fireAndForget(() => navigator.clipboard.writeText(id)),
|
||||
},
|
||||
{ type: "separator" },
|
||||
];
|
||||
const fullConfig = globalStore.get(atoms.fullConfigAtom);
|
||||
@ -175,10 +180,11 @@ const Tab = memo(
|
||||
}
|
||||
submenu.push({
|
||||
label: preset["display:name"] ?? presetName,
|
||||
click: () => {
|
||||
ObjectService.UpdateObjectMeta(oref, preset);
|
||||
RpcApi.ActivityCommand(TabRpcClient, { settabtheme: 1 });
|
||||
},
|
||||
click: () =>
|
||||
fireAndForget(async () => {
|
||||
await ObjectService.UpdateObjectMeta(oref, preset);
|
||||
await RpcApi.ActivityCommand(TabRpcClient, { settabtheme: 1 });
|
||||
}),
|
||||
});
|
||||
}
|
||||
menu.push({ label: "Backgrounds", type: "submenu", submenu }, { type: "separator" });
|
||||
|
@ -467,13 +467,12 @@ const TabBar = memo(({ workspace }: TabBarProps) => {
|
||||
// Reset dragging state
|
||||
setDraggingTab(null);
|
||||
// Update workspace tab ids
|
||||
fireAndForget(
|
||||
async () =>
|
||||
await WorkspaceService.UpdateTabIds(
|
||||
workspace.oid,
|
||||
tabIds.slice(pinnedTabCount),
|
||||
tabIds.slice(0, pinnedTabCount)
|
||||
)
|
||||
fireAndForget(() =>
|
||||
WorkspaceService.UpdateTabIds(
|
||||
workspace.oid,
|
||||
tabIds.slice(pinnedTabCount),
|
||||
tabIds.slice(0, pinnedTabCount)
|
||||
)
|
||||
);
|
||||
}),
|
||||
[]
|
||||
@ -579,9 +578,7 @@ const TabBar = memo(({ workspace }: TabBarProps) => {
|
||||
const handlePinChange = useCallback(
|
||||
(tabId: string, pinned: boolean) => {
|
||||
console.log("handlePinChange", tabId, pinned);
|
||||
fireAndForget(async () => {
|
||||
await WorkspaceService.ChangeTabPinning(workspace.oid, tabId, pinned);
|
||||
});
|
||||
fireAndForget(() => WorkspaceService.ChangeTabPinning(workspace.oid, tabId, pinned));
|
||||
},
|
||||
[workspace]
|
||||
);
|
||||
|
@ -189,12 +189,10 @@ const WorkspaceSwitcher = () => {
|
||||
}, []);
|
||||
|
||||
const onDeleteWorkspace = useCallback((workspaceId: string) => {
|
||||
fireAndForget(async () => {
|
||||
getApi().deleteWorkspace(workspaceId);
|
||||
setTimeout(() => {
|
||||
fireAndForget(updateWorkspaceList);
|
||||
}, 10);
|
||||
});
|
||||
getApi().deleteWorkspace(workspaceId);
|
||||
setTimeout(() => {
|
||||
fireAndForget(updateWorkspaceList);
|
||||
}, 10);
|
||||
}, []);
|
||||
|
||||
const isActiveWorkspaceSaved = !!(activeWorkspace.name && activeWorkspace.icon);
|
||||
@ -267,12 +265,10 @@ const WorkspaceSwitcherItem = ({
|
||||
const isCurrentWorkspace = activeWorkspace.oid === workspace.oid;
|
||||
|
||||
const setWorkspace = useCallback((newWorkspace: Workspace) => {
|
||||
fireAndForget(async () => {
|
||||
if (newWorkspace.name != "") {
|
||||
setObjectValue({ ...newWorkspace, otype: "workspace" }, undefined, true);
|
||||
}
|
||||
setWorkspaceEntry({ ...workspaceEntry, workspace: newWorkspace });
|
||||
});
|
||||
if (newWorkspace.name != "") {
|
||||
setObjectValue({ ...newWorkspace, otype: "workspace" }, undefined, true);
|
||||
}
|
||||
setWorkspaceEntry({ ...workspaceEntry, workspace: newWorkspace });
|
||||
}, []);
|
||||
|
||||
const isActive = !!workspaceEntry.windowId;
|
||||
|
@ -543,26 +543,26 @@ function TableBody({
|
||||
},
|
||||
{
|
||||
label: "Copy File Name",
|
||||
click: () => navigator.clipboard.writeText(fileName),
|
||||
click: () => fireAndForget(() => navigator.clipboard.writeText(fileName)),
|
||||
},
|
||||
{
|
||||
label: "Copy Full File Name",
|
||||
click: () => navigator.clipboard.writeText(finfo.path),
|
||||
click: () => fireAndForget(() => navigator.clipboard.writeText(finfo.path)),
|
||||
},
|
||||
{
|
||||
label: "Copy File Name (Shell Quoted)",
|
||||
click: () => navigator.clipboard.writeText(shellQuote([fileName])),
|
||||
click: () => fireAndForget(() => navigator.clipboard.writeText(shellQuote([fileName]))),
|
||||
},
|
||||
{
|
||||
label: "Copy Full File Name (Shell Quoted)",
|
||||
click: () => navigator.clipboard.writeText(shellQuote([finfo.path])),
|
||||
click: () => fireAndForget(() => navigator.clipboard.writeText(shellQuote([finfo.path]))),
|
||||
},
|
||||
{
|
||||
type: "separator",
|
||||
},
|
||||
{
|
||||
label: "Download File",
|
||||
click: async () => {
|
||||
click: () => {
|
||||
getApi().downloadFile(normPath);
|
||||
},
|
||||
},
|
||||
@ -572,7 +572,7 @@ function TableBody({
|
||||
// TODO: Only show this option for local files, resolve correct host path if connection is WSL
|
||||
{
|
||||
label: openNativeLabel,
|
||||
click: async () => {
|
||||
click: () => {
|
||||
getApi().openNativePath(normPath);
|
||||
},
|
||||
},
|
||||
@ -581,30 +581,32 @@ function TableBody({
|
||||
},
|
||||
{
|
||||
label: "Open Preview in New Block",
|
||||
click: async () => {
|
||||
const blockDef: BlockDef = {
|
||||
meta: {
|
||||
view: "preview",
|
||||
file: finfo.path,
|
||||
},
|
||||
};
|
||||
await createBlock(blockDef);
|
||||
},
|
||||
click: () =>
|
||||
fireAndForget(async () => {
|
||||
const blockDef: BlockDef = {
|
||||
meta: {
|
||||
view: "preview",
|
||||
file: finfo.path,
|
||||
},
|
||||
};
|
||||
await createBlock(blockDef);
|
||||
}),
|
||||
},
|
||||
];
|
||||
if (finfo.mimetype == "directory") {
|
||||
menu.push({
|
||||
label: "Open Terminal in New Block",
|
||||
click: async () => {
|
||||
const termBlockDef: BlockDef = {
|
||||
meta: {
|
||||
controller: "shell",
|
||||
view: "term",
|
||||
"cmd:cwd": finfo.path,
|
||||
},
|
||||
};
|
||||
await createBlock(termBlockDef);
|
||||
},
|
||||
click: () =>
|
||||
fireAndForget(async () => {
|
||||
const termBlockDef: BlockDef = {
|
||||
meta: {
|
||||
controller: "shell",
|
||||
view: "term",
|
||||
"cmd:cwd": finfo.path,
|
||||
},
|
||||
};
|
||||
await createBlock(termBlockDef);
|
||||
}),
|
||||
});
|
||||
}
|
||||
menu.push(
|
||||
@ -613,9 +615,11 @@ function TableBody({
|
||||
},
|
||||
{
|
||||
label: "Delete",
|
||||
click: async () => {
|
||||
await FileService.DeleteFile(conn, finfo.path).catch((e) => console.log(e));
|
||||
setRefreshVersion((current) => current + 1);
|
||||
click: () => {
|
||||
fireAndForget(async () => {
|
||||
await FileService.DeleteFile(conn, finfo.path).catch((e) => console.log(e));
|
||||
setRefreshVersion((current) => current + 1);
|
||||
});
|
||||
},
|
||||
}
|
||||
);
|
||||
|
@ -24,7 +24,7 @@ import * as WOS from "@/store/wos";
|
||||
import { getWebServerEndpoint } from "@/util/endpoints";
|
||||
import { goHistory, goHistoryBack, goHistoryForward } from "@/util/historyutil";
|
||||
import { adaptFromReactOrNativeKeyEvent, checkKeyPressed, keydownWrapper } from "@/util/keyutil";
|
||||
import { base64ToString, isBlank, jotaiLoadableValue, makeConnRoute, stringToBase64 } from "@/util/util";
|
||||
import { base64ToString, fireAndForget, isBlank, jotaiLoadableValue, makeConnRoute, stringToBase64 } from "@/util/util";
|
||||
import { Monaco } from "@monaco-editor/react";
|
||||
import clsx from "clsx";
|
||||
import { Atom, atom, Getter, PrimitiveAtom, useAtomValue, useSetAtom, WritableAtom } from "jotai";
|
||||
@ -257,7 +257,7 @@ export class PreviewModel implements ViewModel {
|
||||
className: clsx(
|
||||
`${saveClassName} warning border-radius-4 vertical-padding-2 horizontal-padding-10 font-size-11 font-weight-500`
|
||||
),
|
||||
onClick: this.handleFileSave.bind(this),
|
||||
onClick: () => fireAndForget(this.handleFileSave.bind(this)),
|
||||
});
|
||||
if (get(this.canPreview)) {
|
||||
viewTextChildren.push({
|
||||
@ -265,7 +265,7 @@ export class PreviewModel implements ViewModel {
|
||||
text: "Preview",
|
||||
className:
|
||||
"grey border-radius-4 vertical-padding-2 horizontal-padding-10 font-size-11 font-weight-500",
|
||||
onClick: () => this.setEditMode(false),
|
||||
onClick: () => fireAndForget(() => this.setEditMode(false)),
|
||||
});
|
||||
}
|
||||
} else if (get(this.canPreview)) {
|
||||
@ -274,7 +274,7 @@ export class PreviewModel implements ViewModel {
|
||||
text: "Edit",
|
||||
className:
|
||||
"grey border-radius-4 vertical-padding-2 horizontal-padding-10 font-size-11 font-weight-500",
|
||||
onClick: () => this.setEditMode(true),
|
||||
onClick: () => fireAndForget(() => this.setEditMode(true)),
|
||||
});
|
||||
}
|
||||
return [
|
||||
@ -497,7 +497,7 @@ export class PreviewModel implements ViewModel {
|
||||
return;
|
||||
}
|
||||
const blockOref = WOS.makeORef("block", this.blockId);
|
||||
services.ObjectService.UpdateObjectMeta(blockOref, updateMeta);
|
||||
await services.ObjectService.UpdateObjectMeta(blockOref, updateMeta);
|
||||
|
||||
// Clear the saved file buffers
|
||||
globalStore.set(this.fileContentSaved, null);
|
||||
@ -538,7 +538,7 @@ export class PreviewModel implements ViewModel {
|
||||
}
|
||||
console.log(newFileInfo.path);
|
||||
this.updateOpenFileModalAndError(false);
|
||||
this.goHistory(newFileInfo.path);
|
||||
await this.goHistory(newFileInfo.path);
|
||||
refocusNode(this.blockId);
|
||||
} catch (e) {
|
||||
globalStore.set(this.openFileError, e.message);
|
||||
@ -546,7 +546,7 @@ export class PreviewModel implements ViewModel {
|
||||
}
|
||||
}
|
||||
|
||||
goHistoryBack() {
|
||||
async goHistoryBack() {
|
||||
const blockMeta = globalStore.get(this.blockAtom)?.meta;
|
||||
const curPath = globalStore.get(this.metaFilePath);
|
||||
const updateMeta = goHistoryBack("file", curPath, blockMeta, true);
|
||||
@ -555,10 +555,10 @@ export class PreviewModel implements ViewModel {
|
||||
}
|
||||
updateMeta.edit = false;
|
||||
const blockOref = WOS.makeORef("block", this.blockId);
|
||||
services.ObjectService.UpdateObjectMeta(blockOref, updateMeta);
|
||||
await services.ObjectService.UpdateObjectMeta(blockOref, updateMeta);
|
||||
}
|
||||
|
||||
goHistoryForward() {
|
||||
async goHistoryForward() {
|
||||
const blockMeta = globalStore.get(this.blockAtom)?.meta;
|
||||
const curPath = globalStore.get(this.metaFilePath);
|
||||
const updateMeta = goHistoryForward("file", curPath, blockMeta);
|
||||
@ -567,13 +567,13 @@ export class PreviewModel implements ViewModel {
|
||||
}
|
||||
updateMeta.edit = false;
|
||||
const blockOref = WOS.makeORef("block", this.blockId);
|
||||
services.ObjectService.UpdateObjectMeta(blockOref, updateMeta);
|
||||
await services.ObjectService.UpdateObjectMeta(blockOref, updateMeta);
|
||||
}
|
||||
|
||||
setEditMode(edit: boolean) {
|
||||
async setEditMode(edit: boolean) {
|
||||
const blockMeta = globalStore.get(this.blockAtom)?.meta;
|
||||
const blockOref = WOS.makeORef("block", this.blockId);
|
||||
services.ObjectService.UpdateObjectMeta(blockOref, { ...blockMeta, edit });
|
||||
await services.ObjectService.UpdateObjectMeta(blockOref, { ...blockMeta, edit });
|
||||
}
|
||||
|
||||
async handleFileSave() {
|
||||
@ -588,7 +588,7 @@ export class PreviewModel implements ViewModel {
|
||||
}
|
||||
const conn = globalStore.get(this.connection) ?? "";
|
||||
try {
|
||||
services.FileService.SaveFile(conn, filePath, stringToBase64(newFileContent));
|
||||
await services.FileService.SaveFile(conn, filePath, stringToBase64(newFileContent));
|
||||
globalStore.set(this.fileContent, newFileContent);
|
||||
globalStore.set(this.newFileContent, null);
|
||||
console.log("saved file", filePath);
|
||||
@ -630,42 +630,44 @@ export class PreviewModel implements ViewModel {
|
||||
|
||||
getSettingsMenuItems(): ContextMenuItem[] {
|
||||
const menuItems: ContextMenuItem[] = [];
|
||||
const blockData = globalStore.get(this.blockAtom);
|
||||
menuItems.push({
|
||||
label: "Copy Full Path",
|
||||
click: async () => {
|
||||
const filePath = await globalStore.get(this.normFilePath);
|
||||
if (filePath == null) {
|
||||
return;
|
||||
}
|
||||
navigator.clipboard.writeText(filePath);
|
||||
},
|
||||
click: () =>
|
||||
fireAndForget(async () => {
|
||||
const filePath = await globalStore.get(this.normFilePath);
|
||||
if (filePath == null) {
|
||||
return;
|
||||
}
|
||||
await navigator.clipboard.writeText(filePath);
|
||||
}),
|
||||
});
|
||||
menuItems.push({
|
||||
label: "Copy File Name",
|
||||
click: async () => {
|
||||
const fileInfo = await globalStore.get(this.statFile);
|
||||
if (fileInfo == null || fileInfo.name == null) {
|
||||
return;
|
||||
}
|
||||
navigator.clipboard.writeText(fileInfo.name);
|
||||
},
|
||||
click: () =>
|
||||
fireAndForget(async () => {
|
||||
const fileInfo = await globalStore.get(this.statFile);
|
||||
if (fileInfo == null || fileInfo.name == null) {
|
||||
return;
|
||||
}
|
||||
await navigator.clipboard.writeText(fileInfo.name);
|
||||
}),
|
||||
});
|
||||
const mimeType = jotaiLoadableValue(globalStore.get(this.fileMimeTypeLoadable), "");
|
||||
if (mimeType == "directory") {
|
||||
menuItems.push({
|
||||
label: "Open Terminal in New Block",
|
||||
click: async () => {
|
||||
const fileInfo = await globalStore.get(this.statFile);
|
||||
const termBlockDef: BlockDef = {
|
||||
meta: {
|
||||
view: "term",
|
||||
controller: "shell",
|
||||
"cmd:cwd": fileInfo.dir,
|
||||
},
|
||||
};
|
||||
await createBlock(termBlockDef);
|
||||
},
|
||||
click: () =>
|
||||
fireAndForget(async () => {
|
||||
const fileInfo = await globalStore.get(this.statFile);
|
||||
const termBlockDef: BlockDef = {
|
||||
meta: {
|
||||
view: "term",
|
||||
controller: "shell",
|
||||
"cmd:cwd": fileInfo.dir,
|
||||
},
|
||||
};
|
||||
await createBlock(termBlockDef);
|
||||
}),
|
||||
});
|
||||
}
|
||||
const loadableSV = globalStore.get(this.loadableSpecializedView);
|
||||
@ -677,11 +679,11 @@ export class PreviewModel implements ViewModel {
|
||||
menuItems.push({ type: "separator" });
|
||||
menuItems.push({
|
||||
label: "Save File",
|
||||
click: this.handleFileSave.bind(this),
|
||||
click: () => fireAndForget(this.handleFileSave.bind(this)),
|
||||
});
|
||||
menuItems.push({
|
||||
label: "Revert File",
|
||||
click: this.handleFileRevert.bind(this),
|
||||
click: () => fireAndForget(this.handleFileRevert.bind(this)),
|
||||
});
|
||||
}
|
||||
menuItems.push({ type: "separator" });
|
||||
@ -689,12 +691,13 @@ export class PreviewModel implements ViewModel {
|
||||
label: "Word Wrap",
|
||||
type: "checkbox",
|
||||
checked: wordWrap,
|
||||
click: () => {
|
||||
const blockOref = WOS.makeORef("block", this.blockId);
|
||||
services.ObjectService.UpdateObjectMeta(blockOref, {
|
||||
"editor:wordwrap": !wordWrap,
|
||||
});
|
||||
},
|
||||
click: () =>
|
||||
fireAndForget(async () => {
|
||||
const blockOref = WOS.makeORef("block", this.blockId);
|
||||
await services.ObjectService.UpdateObjectMeta(blockOref, {
|
||||
"editor:wordwrap": !wordWrap,
|
||||
});
|
||||
}),
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -716,16 +719,16 @@ export class PreviewModel implements ViewModel {
|
||||
|
||||
keyDownHandler(e: WaveKeyboardEvent): boolean {
|
||||
if (checkKeyPressed(e, "Cmd:ArrowLeft")) {
|
||||
this.goHistoryBack();
|
||||
fireAndForget(this.goHistoryBack.bind(this));
|
||||
return true;
|
||||
}
|
||||
if (checkKeyPressed(e, "Cmd:ArrowRight")) {
|
||||
this.goHistoryForward();
|
||||
fireAndForget(this.goHistoryForward.bind(this));
|
||||
return true;
|
||||
}
|
||||
if (checkKeyPressed(e, "Cmd:ArrowUp")) {
|
||||
// handle up directory
|
||||
this.goParentDirectory({});
|
||||
fireAndForget(() => this.goParentDirectory({}));
|
||||
return true;
|
||||
}
|
||||
const openModalOpen = globalStore.get(this.openFileModal);
|
||||
@ -739,7 +742,7 @@ export class PreviewModel implements ViewModel {
|
||||
if (canPreview) {
|
||||
if (checkKeyPressed(e, "Cmd:e")) {
|
||||
const editMode = globalStore.get(this.editMode);
|
||||
this.setEditMode(!editMode);
|
||||
fireAndForget(() => this.setEditMode(!editMode));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -833,15 +836,15 @@ function CodeEditPreview({ model }: SpecializedViewProps) {
|
||||
|
||||
function codeEditKeyDownHandler(e: WaveKeyboardEvent): boolean {
|
||||
if (checkKeyPressed(e, "Cmd:e")) {
|
||||
model.setEditMode(false);
|
||||
fireAndForget(() => model.setEditMode(false));
|
||||
return true;
|
||||
}
|
||||
if (checkKeyPressed(e, "Cmd:s") || checkKeyPressed(e, "Ctrl:s")) {
|
||||
model.handleFileSave();
|
||||
fireAndForget(model.handleFileSave.bind(model));
|
||||
return true;
|
||||
}
|
||||
if (checkKeyPressed(e, "Cmd:r")) {
|
||||
model.handleFileRevert();
|
||||
fireAndForget(model.handleFileRevert.bind(model));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -990,7 +993,7 @@ const OpenFileModal = memo(
|
||||
|
||||
const handleCommandOperations = async () => {
|
||||
if (checkKeyPressed(waveEvent, "Enter")) {
|
||||
model.handleOpenFile(filePath);
|
||||
await model.handleOpenFile(filePath);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -119,7 +119,11 @@ export class TermWrap {
|
||||
data = data.substring(nextSlashIdx);
|
||||
}
|
||||
setTimeout(() => {
|
||||
services.ObjectService.UpdateObjectMeta(WOS.makeORef("block", this.blockId), { "cmd:cwd": data });
|
||||
fireAndForget(() =>
|
||||
services.ObjectService.UpdateObjectMeta(WOS.makeORef("block", this.blockId), {
|
||||
"cmd:cwd": data,
|
||||
})
|
||||
);
|
||||
}, 0);
|
||||
return true;
|
||||
});
|
||||
@ -284,7 +288,9 @@ export class TermWrap {
|
||||
const serializedOutput = this.serializeAddon.serialize();
|
||||
const termSize: TermSize = { rows: this.terminal.rows, cols: this.terminal.cols };
|
||||
console.log("idle timeout term", this.dataBytesProcessed, serializedOutput.length, termSize);
|
||||
services.BlockService.SaveTerminalState(this.blockId, serializedOutput, "full", this.ptyOffset, termSize);
|
||||
fireAndForget(() =>
|
||||
services.BlockService.SaveTerminalState(this.blockId, serializedOutput, "full", this.ptyOffset, termSize)
|
||||
);
|
||||
this.dataBytesProcessed = 0;
|
||||
}
|
||||
|
||||
|
@ -221,12 +221,12 @@ export class WaveAiModel implements ViewModel {
|
||||
({
|
||||
label: preset[1]["display:name"],
|
||||
onClick: () =>
|
||||
fireAndForget(async () => {
|
||||
await ObjectService.UpdateObjectMeta(WOS.makeORef("block", this.blockId), {
|
||||
fireAndForget(() =>
|
||||
ObjectService.UpdateObjectMeta(WOS.makeORef("block", this.blockId), {
|
||||
...preset[1],
|
||||
"ai:preset": preset[0],
|
||||
});
|
||||
}),
|
||||
})
|
||||
),
|
||||
}) as MenuItem
|
||||
);
|
||||
dropdownItems.push({
|
||||
@ -386,7 +386,7 @@ export class WaveAiModel implements ViewModel {
|
||||
this.setLocked(false);
|
||||
this.cancel = false;
|
||||
};
|
||||
handleAiStreamingResponse();
|
||||
fireAndForget(handleAiStreamingResponse);
|
||||
}
|
||||
|
||||
useWaveAi() {
|
||||
@ -404,14 +404,14 @@ export class WaveAiModel implements ViewModel {
|
||||
|
||||
keyDownHandler(waveEvent: WaveKeyboardEvent): boolean {
|
||||
if (checkKeyPressed(waveEvent, "Cmd:l")) {
|
||||
this.clearMessages();
|
||||
fireAndForget(this.clearMessages.bind(this));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function makeWaveAiViewModel(blockId): WaveAiModel {
|
||||
function makeWaveAiViewModel(blockId: string): WaveAiModel {
|
||||
const waveAiModel = new WaveAiModel(blockId);
|
||||
return waveAiModel;
|
||||
}
|
||||
@ -634,7 +634,7 @@ const WaveAi = ({ model }: { model: WaveAiModel; blockId: string }) => {
|
||||
|
||||
// a weird workaround to initialize ansynchronously
|
||||
useEffect(() => {
|
||||
model.populateMessages();
|
||||
fireAndForget(model.populateMessages.bind(model));
|
||||
}, []);
|
||||
|
||||
const handleTextAreaChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
|
||||
|
@ -293,7 +293,7 @@ export class WebViewModel implements ViewModel {
|
||||
* @param url The URL that has been navigated to.
|
||||
*/
|
||||
handleNavigate(url: string) {
|
||||
ObjectService.UpdateObjectMeta(WOS.makeORef("block", this.blockId), { url });
|
||||
fireAndForget(() => ObjectService.UpdateObjectMeta(WOS.makeORef("block", this.blockId), { url }));
|
||||
globalStore.set(this.url, url);
|
||||
}
|
||||
|
||||
@ -432,22 +432,18 @@ export class WebViewModel implements ViewModel {
|
||||
return [
|
||||
{
|
||||
label: "Set Block Homepage",
|
||||
click: async () => {
|
||||
await this.setHomepageUrl(this.getUrl(), "block");
|
||||
},
|
||||
click: () => fireAndForget(() => this.setHomepageUrl(this.getUrl(), "block")),
|
||||
},
|
||||
{
|
||||
label: "Set Default Homepage",
|
||||
click: async () => {
|
||||
await this.setHomepageUrl(this.getUrl(), "global");
|
||||
},
|
||||
click: () => fireAndForget(() => this.setHomepageUrl(this.getUrl(), "global")),
|
||||
},
|
||||
{
|
||||
type: "separator",
|
||||
},
|
||||
{
|
||||
label: this.webviewRef.current?.isDevToolsOpened() ? "Close DevTools" : "Open DevTools",
|
||||
click: async () => {
|
||||
click: () => {
|
||||
if (this.webviewRef.current) {
|
||||
if (this.webviewRef.current.isDevToolsOpened()) {
|
||||
this.webviewRef.current.closeDevTools();
|
||||
|
@ -58,7 +58,6 @@ function TileLayoutComponent({ tabAtom, contents, getCursorPoint }: TileLayoutPr
|
||||
const setActiveDrag = useSetAtom(layoutModel.activeDrag);
|
||||
const setReady = useSetAtom(layoutModel.ready);
|
||||
const isResizing = useAtomValue(layoutModel.isResizing);
|
||||
const ephemeralNode = useAtomValue(layoutModel.ephemeralNode);
|
||||
|
||||
const { activeDrag, dragClientOffset } = useDragLayer((monitor) => ({
|
||||
activeDrag: monitor.isDragging(),
|
||||
|
@ -2,7 +2,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import { getSettingsKeyAtom } from "@/app/store/global";
|
||||
import { atomWithThrottle, boundNumber } from "@/util/util";
|
||||
import { atomWithThrottle, boundNumber, fireAndForget } from "@/util/util";
|
||||
import { Atom, atom, Getter, PrimitiveAtom, Setter } from "jotai";
|
||||
import { splitAtom } from "jotai/utils";
|
||||
import { createRef, CSSProperties } from "react";
|
||||
@ -852,7 +852,7 @@ export class LayoutModel {
|
||||
animationTimeS: this.animationTimeS,
|
||||
ready: this.ready,
|
||||
disablePointerEvents: this.activeDrag,
|
||||
onClose: async () => await this.closeNode(nodeid),
|
||||
onClose: () => fireAndForget(() => this.closeNode(nodeid)),
|
||||
toggleMagnify: () => this.magnifyNodeToggle(nodeid),
|
||||
focusNode: () => this.focusNode(nodeid),
|
||||
dragHandleRef: createRef(),
|
||||
|
@ -24,7 +24,7 @@ export function getLayoutModelForTab(tabAtom: Atom<Tab>): LayoutModel {
|
||||
}
|
||||
const layoutTreeStateAtom = withLayoutTreeStateAtomFromTab(tabAtom);
|
||||
const layoutModel = new LayoutModel(layoutTreeStateAtom, globalStore.get, globalStore.set);
|
||||
globalStore.sub(layoutTreeStateAtom, () => fireAndForget(async () => layoutModel.onTreeStateAtomUpdated()));
|
||||
globalStore.sub(layoutTreeStateAtom, () => fireAndForget(layoutModel.onTreeStateAtomUpdated.bind(layoutModel)));
|
||||
layoutModelMap.set(tabId, layoutModel);
|
||||
return layoutModel;
|
||||
}
|
||||
@ -56,7 +56,7 @@ export function useTileLayout(tabAtom: Atom<Tab>, tileContent: TileLayoutContent
|
||||
useOnResize(layoutModel?.displayContainerRef, layoutModel?.onContainerResize);
|
||||
|
||||
// Once the TileLayout is mounted, re-run the state update to get all the nodes to flow in the layout.
|
||||
useEffect(() => fireAndForget(async () => layoutModel.onTreeStateAtomUpdated(true)), []);
|
||||
useEffect(() => fireAndForget(() => layoutModel.onTreeStateAtomUpdated(true)), []);
|
||||
|
||||
useEffect(() => layoutModel.registerTileLayout(tileContent), [tileContent]);
|
||||
return layoutModel;
|
||||
|
Loading…
Reference in New Issue
Block a user