@@ -4,13 +4,9 @@ import Skeleton from "@mui/material/Skeleton";
4
4
import { saveAs } from "file-saver" ;
5
5
import JSZip from "jszip" ;
6
6
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" ;
8
8
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" ;
14
10
import { ErrorAlert } from "components/Alert/ErrorAlert" ;
15
11
import {
16
12
ConfirmDialog ,
@@ -46,53 +42,31 @@ export const DownloadLogsDialog: FC<DownloadLogsDialogProps> = ({
46
42
...buildLogs ( workspace ) ,
47
43
enabled : open ,
48
44
} ) ;
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 [ ] > ( ( ) => {
71
47
const allAgents = workspace . latest_build . resources . flatMap (
72
48
( resource ) => resource . agents ?? [ ] ,
73
49
) ;
74
50
75
51
// 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
+ } ) ;
94
63
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 ) => {
96
70
const name = `${ a . name } -logs.txt` ;
97
71
const txt = agentLogQueries [ i ] ?. data ?. map ( ( l ) => l . output ) . join ( "\n" ) ;
98
72
@@ -101,11 +75,21 @@ export const DownloadLogsDialog: FC<DownloadLogsDialogProps> = ({
101
75
blob = new Blob ( [ txt ] , { type : "text/plain" } ) ;
102
76
}
103
77
104
- files . push ( { name, blob } ) ;
78
+ return { name, blob } ;
105
79
} ) ;
106
80
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 ) ;
107
91
return files ;
108
- } , [ agentLogQueries , agents , buildLogsFile ] ) ;
92
+ } ) ( ) ;
109
93
110
94
const [ isDownloading , setIsDownloading ] = useState ( false ) ;
111
95
const isWorkspaceHealthy = workspace . health . healthy ;
0 commit comments