Skip to content

Commit 7b76eb7

Browse files
committed
fix: remove memoization from DownloadLogsDialog
1 parent f74eda4 commit 7b76eb7

File tree

1 file changed

+33
-49
lines changed

1 file changed

+33
-49
lines changed

site/src/pages/WorkspacePage/WorkspaceActions/DownloadLogsDialog.tsx

Lines changed: 33 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,9 @@ import Skeleton from "@mui/material/Skeleton";
44
import { saveAs } from "file-saver";
55
import JSZip from "jszip";
66
import { type FC, useMemo, useState, useRef, useEffect } from "react";
7-
import { type UseQueryOptions, useQueries, useQuery } from "react-query";
7+
import { useQueries, useQuery } from "react-query";
88
import { agentLogs, buildLogs } from "api/queries/workspaces";
9-
import type {
10-
Workspace,
11-
WorkspaceAgent,
12-
WorkspaceAgentLog,
13-
} from "api/typesGenerated";
9+
import type { Workspace, WorkspaceAgent } from "api/typesGenerated";
1410
import { ErrorAlert } from "components/Alert/ErrorAlert";
1511
import {
1612
ConfirmDialog,
@@ -46,53 +42,31 @@ export const DownloadLogsDialog: FC<DownloadLogsDialogProps> = ({
4642
...buildLogs(workspace),
4743
enabled: open,
4844
});
49-
const buildLogsFile = useMemo<DownloadableFile>(() => {
50-
return {
51-
name: `${workspace.name}-build-logs.txt`,
52-
blob: buildLogsQuery.data
53-
? new Blob([buildLogsQuery.data.map((l) => l.output).join("\n")], {
54-
type: "text/plain",
55-
})
56-
: undefined,
57-
};
58-
}, [workspace.name, buildLogsQuery.data]);
59-
60-
// This is clunky, but we have to memoize in two steps to make sure that we
61-
// don't accidentally break the memo cache every render. We can't tuck
62-
// everything into a single memo call, because we need to set up React Query
63-
// state between processing the agents, but we can't violate rules of hooks by
64-
// putting hooks inside of hooks
65-
type AgentInfo = Readonly<{
66-
agents: readonly WorkspaceAgent[];
67-
logOptionsArray: readonly UseQueryOptions<readonly WorkspaceAgentLog[]>[];
68-
}>;
69-
70-
const { agents, logOptionsArray } = useMemo<AgentInfo>(() => {
45+
46+
const allUniqueAgents = useMemo<readonly WorkspaceAgent[]>(() => {
7147
const allAgents = workspace.latest_build.resources.flatMap(
7248
(resource) => resource.agents ?? [],
7349
);
7450

7551
// Can't use the "new Set()" trick because we're not dealing with primitives
76-
const uniqueAgents = [
77-
...new Map(allAgents.map((agent) => [agent.id, agent])).values(),
78-
];
79-
80-
return {
81-
agents: uniqueAgents,
82-
logOptionsArray: uniqueAgents.map((agent) => {
83-
return {
84-
...agentLogs(workspace.id, agent.id),
85-
enabled: open,
86-
};
87-
}),
88-
};
89-
}, [workspace, open]);
90-
91-
const agentLogQueries = useQueries({ queries: logOptionsArray });
92-
const allFiles = useMemo<readonly DownloadableFile[]>(() => {
93-
const files: DownloadableFile[] = [buildLogsFile];
52+
const uniqueAgents = new Map(allAgents.map((agent) => [agent.id, agent]));
53+
const iterable = [...uniqueAgents.values()];
54+
return iterable;
55+
}, [workspace.latest_build.resources]);
56+
57+
const agentLogQueries = useQueries({
58+
queries: allUniqueAgents.map((agent) => ({
59+
...agentLogs(workspace.id, agent.id),
60+
enabled: open,
61+
})),
62+
});
9463

95-
agents.forEach((a, i) => {
64+
// Note: trying to memoize this via useMemo got really clunky. Removing all
65+
// memoization for now, but if we get to a point where performance matters,
66+
// we should make it so that this state doesn't even begin to mount until the
67+
// user decides to open the Logs dropdown
68+
const allFiles = ((): readonly DownloadableFile[] => {
69+
const files = allUniqueAgents.map<DownloadableFile>((a, i) => {
9670
const name = `${a.name}-logs.txt`;
9771
const txt = agentLogQueries[i]?.data?.map((l) => l.output).join("\n");
9872

@@ -101,11 +75,21 @@ export const DownloadLogsDialog: FC<DownloadLogsDialogProps> = ({
10175
blob = new Blob([txt], { type: "text/plain" });
10276
}
10377

104-
files.push({ name, blob });
78+
return { name, blob };
10579
});
10680

81+
const buildLogFile = {
82+
name: `${workspace.name}-build-logs.txt`,
83+
blob: buildLogsQuery.data
84+
? new Blob([buildLogsQuery.data.map((l) => l.output).join("\n")], {
85+
type: "text/plain",
86+
})
87+
: undefined,
88+
};
89+
90+
files.unshift(buildLogFile);
10791
return files;
108-
}, [agentLogQueries, agents, buildLogsFile]);
92+
})();
10993

11094
const [isDownloading, setIsDownloading] = useState(false);
11195
const isWorkspaceHealthy = workspace.health.healthy;

0 commit comments

Comments
 (0)