@@ -55,21 +55,43 @@ export default class ProfileExplorer extends React.PureComponent<Props, State> {
55
55
this . init ( )
56
56
}
57
57
58
+ private updateDebouncer : null | ReturnType < typeof setTimeout > = null
59
+
58
60
private readonly updateFn = ( ) => {
59
- // slice to force a render; TODO we could do a comparison to avoid
60
- // false re-renders if we want to get fancy
61
- this . setState ( ( curState ) => {
62
- const profiles = curState . watcher . profiles . slice ( )
63
- if ( ! curState || ! curState . profiles || curState . profiles . length === 0 ) {
64
- // sort the first time we get a list of profiles; TODO should
65
- // we re-sort if the list changes? what we want to avoid is
66
- // resorting simply because the selection changed
67
- profiles . sort ( ( a , b ) => b . lastUsedTime - a . lastUsedTime )
68
- }
69
- return {
70
- profiles,
71
- }
72
- } )
61
+ if ( this . updateDebouncer ) {
62
+ clearTimeout ( this . updateDebouncer )
63
+ }
64
+
65
+ // hmm, this is imperfect... the watcher seems to give us [A],
66
+ // then [A,B], then [A,B,C] in quick succession. is there any way
67
+ // to know that we are done with the initial batch? for now, we do
68
+ // some debouncing.
69
+ this . updateDebouncer = setTimeout ( ( ) => {
70
+ this . setState ( ( curState ) => {
71
+ if ( JSON . stringify ( curState . watcher . profiles ) === JSON . stringify ( curState . profiles ) ) {
72
+ return null
73
+ }
74
+
75
+ const profiles = curState . watcher . profiles . slice ( )
76
+
77
+ let selectedProfile = curState . selectedProfile
78
+ if ( ! curState || ! curState . profiles || curState . profiles . length === 0 ) {
79
+ // sort the first time we get a list of profiles; TODO should
80
+ // we re-sort if the list changes? what we want to avoid is
81
+ // resorting simply because the selection changed
82
+ profiles . sort ( ( a , b ) => b . lastUsedTime - a . lastUsedTime )
83
+
84
+ // also emit an initial profile selection event
85
+ selectedProfile = profiles [ 0 ] . name
86
+ emitSelectProfile ( selectedProfile )
87
+ }
88
+
89
+ return {
90
+ profiles,
91
+ selectedProfile,
92
+ }
93
+ } )
94
+ } , 100 )
73
95
}
74
96
75
97
private async init ( ) {
@@ -103,6 +125,14 @@ export default class ProfileExplorer extends React.PureComponent<Props, State> {
103
125
}
104
126
}
105
127
128
+ private prettyMillis ( duration : number ) {
129
+ if ( duration < 1000 ) {
130
+ return "just now"
131
+ } else {
132
+ return prettyMillis ( duration , { compact : true } ) + " ago"
133
+ }
134
+ }
135
+
106
136
public render ( ) {
107
137
if ( this . state && this . state . catastrophicError ) {
108
138
return "Internal Error"
@@ -111,16 +141,16 @@ export default class ProfileExplorer extends React.PureComponent<Props, State> {
111
141
} else {
112
142
return (
113
143
< Grid className = "codeflare--gallery-grid flex-fill sans-serif top-pad left-pad right-pad bottom-pad" hasGutter >
114
- { this . state . profiles . map ( ( _ , idx ) => (
144
+ { this . state . profiles . map ( ( _ ) => (
115
145
< GridItem key = { _ . name } >
116
146
< Tile
117
147
className = "codeflare--tile"
118
148
data-profile = { _ . name }
119
149
title = { _ . name }
120
- isSelected = { ! this . state . selectedProfile ? idx === 0 : this . state . selectedProfile === _ . name }
150
+ isSelected = { this . state . selectedProfile === _ . name }
121
151
onClick = { this . onSelect }
122
152
>
123
- { `Last used ${ prettyMillis ( Date . now ( ) - _ . lastUsedTime , { compact : true } ) } ago ` }
153
+ { `Last used ${ this . prettyMillis ( Date . now ( ) - _ . lastUsedTime ) } ` }
124
154
</ Tile >
125
155
</ GridItem >
126
156
) ) }
0 commit comments