mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-08-23 11:54:01 +02:00
Fix UI freezes with large workspaces (#536)
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import type { Extension } from "@codemirror/state";
|
||||
import { Compartment } from "@codemirror/state";
|
||||
import { getCurrentWebviewWindow } from "@tauri-apps/api/webviewWindow";
|
||||
import { debounce } from "@yaakapp-internal/lib";
|
||||
import { gitMutations } from "@yaakapp-internal/git";
|
||||
import type { GitStatus } from "@yaakapp-internal/git";
|
||||
@@ -131,11 +132,17 @@ function Sidebar({ className }: { className?: string }) {
|
||||
if (!didFocus) filterRef.current?.focus();
|
||||
}, []);
|
||||
|
||||
// Focus any new sidebar models when created
|
||||
useListenToTauriEvent<ModelPayload>("model_write", ({ payload }) => {
|
||||
if (!isSidebarLeafModel(payload.model)) return;
|
||||
if (!(payload.change.type === "upsert" && payload.change.created)) return;
|
||||
treeRef.current?.selectItem(payload.model.id, true);
|
||||
// Focus new sidebar models created by the user in this window. Writes from other
|
||||
// sources (import, sync, CLI) can carry thousands of models and shouldn't move
|
||||
// the selection.
|
||||
useListenToTauriEvent<ModelPayload[]>("model_writes", ({ payload: payloads }) => {
|
||||
for (const payload of payloads) {
|
||||
if (payload.updateSource.type !== "window") continue;
|
||||
if (payload.updateSource.label !== getCurrentWebviewWindow().label) continue;
|
||||
if (!isSidebarLeafModel(payload.model)) continue;
|
||||
if (!(payload.change.type === "upsert" && payload.change.created)) continue;
|
||||
treeRef.current?.selectItem(payload.model.id, true);
|
||||
}
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -16,6 +16,7 @@ import { useCreateWorkspace } from "../hooks/useCreateWorkspace";
|
||||
import { useDeleteSendHistory } from "../hooks/useDeleteSendHistory";
|
||||
import { useWorkspaceActions } from "../hooks/useWorkspaceActions";
|
||||
import { showDialog } from "../lib/dialog";
|
||||
import { importData } from "../lib/importData";
|
||||
import { jotaiStore } from "../lib/jotai";
|
||||
import { revealInFinderText } from "../lib/reveal";
|
||||
import { CloneGitRepositoryDialog } from "./CloneGitRepositoryDialog";
|
||||
@@ -90,6 +91,11 @@ export const WorkspaceActionsDropdown = memo(function WorkspaceActionsDropdown({
|
||||
leftSlot: <Icon icon="hard_drive_download" />,
|
||||
onSelect: openCloneGitRepositoryDialog,
|
||||
},
|
||||
{
|
||||
label: "Import Data",
|
||||
leftSlot: <Icon icon="folder_input" />,
|
||||
onSelect: () => importData.mutate(),
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
@@ -8,10 +8,12 @@ function setFontSizeOnDocument(fontSize: number) {
|
||||
document.documentElement.style.fontSize = `${fontSize}px`;
|
||||
}
|
||||
|
||||
listen<ModelPayload>("model_write", async (event) => {
|
||||
if (event.payload.change.type !== "upsert") return;
|
||||
if (event.payload.model.model !== "settings") return;
|
||||
setFontSizeOnDocument(event.payload.model.interfaceFontSize);
|
||||
listen<ModelPayload[]>("model_writes", async (event) => {
|
||||
for (const payload of event.payload) {
|
||||
if (payload.change.type !== "upsert") continue;
|
||||
if (payload.model.model !== "settings") continue;
|
||||
setFontSizeOnDocument(payload.model.interfaceFontSize);
|
||||
}
|
||||
}).catch(console.error);
|
||||
|
||||
fireAndForget(getSettings().then((settings) => setFontSizeOnDocument(settings.interfaceFontSize)));
|
||||
|
||||
@@ -12,10 +12,12 @@ function setFonts(settings: Settings) {
|
||||
);
|
||||
}
|
||||
|
||||
listen<ModelPayload>("model_write", async (event) => {
|
||||
if (event.payload.change.type !== "upsert") return;
|
||||
if (event.payload.model.model !== "settings") return;
|
||||
setFonts(event.payload.model);
|
||||
listen<ModelPayload[]>("model_writes", async (event) => {
|
||||
for (const payload of event.payload) {
|
||||
if (payload.change.type !== "upsert") continue;
|
||||
if (payload.model.model !== "settings") continue;
|
||||
setFonts(payload.model);
|
||||
}
|
||||
}).catch(console.error);
|
||||
|
||||
fireAndForget(getSettings().then((settings) => setFonts(settings)));
|
||||
|
||||
@@ -7,24 +7,33 @@ import { jotaiStore } from "../lib/jotai";
|
||||
const requestUpdateKeyAtom = atom<Record<string, string>>({});
|
||||
|
||||
getCurrentWebviewWindow()
|
||||
.listen<ModelPayload>("model_write", ({ payload }) => {
|
||||
if (payload.change.type !== "upsert") return;
|
||||
.listen<ModelPayload[]>("model_writes", ({ payload: payloads }) => {
|
||||
const changedIds: string[] = [];
|
||||
for (const payload of payloads) {
|
||||
if (payload.change.type !== "upsert") continue;
|
||||
|
||||
if (
|
||||
(payload.model.model === "http_request" ||
|
||||
payload.model.model === "grpc_request" ||
|
||||
payload.model.model === "websocket_request") &&
|
||||
((payload.updateSource.type === "window" &&
|
||||
payload.updateSource.label !== getCurrentWebviewWindow().label) ||
|
||||
payload.updateSource.type !== "window")
|
||||
) {
|
||||
wasUpdatedExternally(payload.model.id);
|
||||
if (
|
||||
(payload.model.model === "http_request" ||
|
||||
payload.model.model === "grpc_request" ||
|
||||
payload.model.model === "websocket_request") &&
|
||||
((payload.updateSource.type === "window" &&
|
||||
payload.updateSource.label !== getCurrentWebviewWindow().label) ||
|
||||
payload.updateSource.type !== "window")
|
||||
) {
|
||||
changedIds.push(payload.model.id);
|
||||
}
|
||||
}
|
||||
if (changedIds.length > 0) wasUpdatedExternally(changedIds);
|
||||
})
|
||||
.catch(console.error);
|
||||
|
||||
export function wasUpdatedExternally(changedRequestId: string) {
|
||||
jotaiStore.set(requestUpdateKeyAtom, (m) => ({ ...m, [changedRequestId]: generateId() }));
|
||||
export function wasUpdatedExternally(changedRequestIds: string | string[]) {
|
||||
const ids = Array.isArray(changedRequestIds) ? changedRequestIds : [changedRequestIds];
|
||||
jotaiStore.set(requestUpdateKeyAtom, (m) => {
|
||||
const next = { ...m };
|
||||
for (const id of ids) next[id] = generateId();
|
||||
return next;
|
||||
});
|
||||
}
|
||||
|
||||
export function useRequestUpdateKey(requestId: string | null) {
|
||||
|
||||
@@ -33,8 +33,8 @@ const syncAfterModelWrite = eagerDebounceAsync(sync, 1000);
|
||||
* simply add long-lived subscribers for the lifetime of the app.
|
||||
*/
|
||||
function initModelListeners() {
|
||||
listenToTauriEvent<ModelPayload>("model_write", (p) => {
|
||||
if (isModelRelevant(p.payload.model)) syncAfterModelWrite();
|
||||
listenToTauriEvent<ModelPayload[]>("model_writes", (p) => {
|
||||
if (p.payload.some((payload) => isModelRelevant(payload.model))) syncAfterModelWrite();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -46,11 +46,13 @@ async function configureThemeAndShow() {
|
||||
}
|
||||
|
||||
// Listen for settings changes, the re-compute theme
|
||||
listen<ModelPayload>("model_write", async (event) => {
|
||||
if (event.payload.change.type !== "upsert") return;
|
||||
|
||||
const model = event.payload.model.model;
|
||||
if (model !== "settings" && model !== "plugin") return;
|
||||
listen<ModelPayload[]>("model_writes", async (event) => {
|
||||
const relevant = event.payload.some(
|
||||
(p) =>
|
||||
p.change.type === "upsert" &&
|
||||
(p.model.model === "settings" || p.model.model === "plugin"),
|
||||
);
|
||||
if (!relevant) return;
|
||||
await configureThemeAndShow();
|
||||
}).catch(console.error);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user