@@ -41,10 +41,10 @@ export default function DeleteReplays({selectedIds, replays, queryOptions}: Prop
41
41
} ,
42
42
} ) ;
43
43
44
- const hasOneProjectSelected = projectIds . length === 1 ;
45
44
const project = useProjectFromId ( {
46
- project_id : hasOneProjectSelected ? projectIds [ 0 ] : undefined ,
45
+ project_id : projectIds . length === 1 ? projectIds [ 0 ] : undefined ,
47
46
} ) ;
47
+ const hasOneProjectSelected = Boolean ( project ) ;
48
48
49
49
const { bulkDelete, hasAccess, queryOptionsToPayload} = useDeleteReplays ( {
50
50
projectSlug : project ?. slug ?? '' ,
@@ -68,24 +68,21 @@ export default function DeleteReplays({selectedIds, replays, queryOptions}: Prop
68
68
onClick = { ( ) =>
69
69
openConfirmModal ( {
70
70
bypass : selectedIds !== 'all' && selectedIds . length === 1 ,
71
- renderMessage : _props => (
72
- < Fragment >
73
- { selectedIds === 'all' ? (
74
- < ReplayQueryPreview
75
- deletePayload = { deletePayload }
76
- project = { project ! }
77
- />
78
- ) : (
79
- < ErrorBoundary mini >
80
- < ReplayPreviewTable
81
- replays = { replays }
82
- selectedIds = { selectedIds }
83
- project = { project ! }
84
- />
85
- </ ErrorBoundary >
86
- ) }
87
- </ Fragment >
88
- ) ,
71
+ renderMessage : _props =>
72
+ selectedIds === 'all' ? (
73
+ < ReplayQueryPreview deletePayload = { deletePayload } project = { project ! } />
74
+ ) : (
75
+ < ErrorBoundary mini >
76
+ < Title project = { project ! } >
77
+ { tn (
78
+ 'The following %s replay will be deleted' ,
79
+ 'The following %s replays will be deleted' ,
80
+ selectedIds . length
81
+ ) }
82
+ </ Title >
83
+ < ReplayPreviewTable replays = { replays } selectedIds = { selectedIds } />
84
+ </ ErrorBoundary >
85
+ ) ,
89
86
renderConfirmButton : ( { defaultOnClick} ) => (
90
87
< Button onClick = { defaultOnClick } priority = "danger" >
91
88
{ t ( 'Delete' ) }
@@ -148,79 +145,68 @@ function ReplayQueryPreview({
148
145
}
149
146
150
147
function ReplayPreviewTable ( {
151
- project,
152
148
replays,
153
149
selectedIds,
154
150
} : {
155
- project : Project ;
156
151
replays : ReplayListRecord [ ] ;
157
152
selectedIds : string [ ] ;
158
153
} ) {
159
154
return (
160
- < Fragment >
161
- < Title project = { project } >
162
- { tn (
163
- 'The following %s replay will be deleted' ,
164
- 'The following %s replays will be deleted' ,
165
- selectedIds . length
166
- ) }
167
- </ Title >
168
- < SimpleTableWithTwoColumns >
169
- < SimpleTable . Header >
170
- < SimpleTable . HeaderCell > { t ( 'Replay' ) } </ SimpleTable . HeaderCell >
171
- < SimpleTable . HeaderCell > { t ( 'Duration' ) } </ SimpleTable . HeaderCell >
172
- </ SimpleTable . Header >
173
- { selectedIds . map ( id => {
174
- const replay = replays . find ( r => r . id === id ) as ReplayListRecord ;
175
- if ( replay . is_archived ) {
176
- return null ;
177
- }
178
- invariant (
179
- replay . duration && replay . started_at ,
180
- 'For TypeScript: replay.duration and replay.started_at are implied because replay.is_archived is false'
181
- ) ;
155
+ < SimpleTableWithTwoColumns >
156
+ < SimpleTable . Header >
157
+ < SimpleTable . HeaderCell > { t ( 'Replay' ) } </ SimpleTable . HeaderCell >
158
+ < SimpleTable . HeaderCell > { t ( 'Duration' ) } </ SimpleTable . HeaderCell >
159
+ </ SimpleTable . Header >
160
+ { selectedIds . map ( id => {
161
+ const replay = replays . find ( r => r . id === id ) as ReplayListRecord ;
162
+ if ( replay . is_archived ) {
163
+ return null ;
164
+ }
165
+ invariant (
166
+ replay . duration && replay . started_at ,
167
+ 'For TypeScript: replay.duration and replay.started_at are implied because replay.is_archived is false'
168
+ ) ;
182
169
183
- return (
184
- < SimpleTable . Row key = { id } >
185
- < SimpleTable . RowCell >
186
- < Flex key = "session" align = "center" gap = { space ( 1 ) } >
187
- < UserAvatar
188
- user = { {
189
- username : replay . user ?. display_name || '' ,
190
- email : replay . user ?. email || '' ,
191
- id : replay . user ?. id || '' ,
192
- ip_address : replay . user ?. ip || '' ,
193
- name : replay . user ?. username || '' ,
194
- } }
195
- size = { 24 }
196
- />
197
- < SubText >
198
- < Flex gap = { space ( 0.5 ) } align = "flex-start" >
199
- < DisplayName >
200
- { replay . user . display_name || t ( 'Anonymous User' ) }
201
- </ DisplayName >
202
- </ Flex >
170
+ return (
171
+ < SimpleTable . Row key = { id } >
172
+ < SimpleTable . RowCell >
173
+ < Flex key = "session" align = "center" gap = { space ( 1 ) } >
174
+ < UserAvatar
175
+ user = { {
176
+ username : replay . user ?. display_name || '' ,
177
+ email : replay . user ?. email || '' ,
178
+ id : replay . user ?. id || '' ,
179
+ ip_address : replay . user ?. ip || '' ,
180
+ name : replay . user ?. username || '' ,
181
+ } }
182
+ size = { 24 }
183
+ />
184
+ < SubText >
185
+ < Flex gap = { space ( 0.5 ) } align = "flex-start" >
186
+ < DisplayName >
187
+ { replay . user . display_name || t ( 'Anonymous User' ) }
188
+ </ DisplayName >
189
+ </ Flex >
190
+ < Flex gap = { space ( 0.5 ) } >
191
+ { getShortEventId ( replay . id ) }
203
192
< Flex gap = { space ( 0.5 ) } >
204
- { getShortEventId ( replay . id ) }
205
- < Flex gap = { space ( 0.5 ) } >
206
- < IconCalendar color = "gray300" size = "xs" />
207
- < TimeSince date = { replay . started_at } />
208
- </ Flex >
193
+ < IconCalendar color = "gray300" size = "xs" />
194
+ < TimeSince date = { replay . started_at } />
209
195
</ Flex >
210
- </ SubText >
211
- </ Flex >
212
- </ SimpleTable . RowCell >
213
- < SimpleTable . RowCell justify = "flex-end" >
214
- < Duration
215
- duration = { [ replay . duration . asMilliseconds ( ) ?? 0 , 'ms' ] }
216
- precision = "sec"
217
- />
218
- </ SimpleTable . RowCell >
219
- </ SimpleTable . Row >
220
- ) ;
221
- } ) }
222
- </ SimpleTableWithTwoColumns >
223
- </ Fragment >
196
+ </ Flex >
197
+ </ SubText >
198
+ </ Flex >
199
+ </ SimpleTable . RowCell >
200
+ < SimpleTable . RowCell justify = "flex-end" >
201
+ < Duration
202
+ duration = { [ replay . duration . asMilliseconds ( ) ?? 0 , 'ms' ] }
203
+ precision = "sec"
204
+ / >
205
+ </ SimpleTable . RowCell >
206
+ </ SimpleTable . Row >
207
+ ) ;
208
+ } ) }
209
+ </ SimpleTableWithTwoColumns >
224
210
) ;
225
211
}
226
212
@@ -246,6 +232,16 @@ function Title({children, project}: {children: React.ReactNode; project: Project
246
232
247
233
const SimpleTableWithTwoColumns = styled ( SimpleTable ) `
248
234
grid-template-columns: 1fr max-content;
235
+
236
+ max-height: calc(100vh - 315px);
237
+ min-height: 200px;
238
+ overflow-y: auto;
239
+
240
+ & > div:first-child {
241
+ position: sticky;
242
+ top: 0;
243
+ z-index: 1;
244
+ }
249
245
` ;
250
246
251
247
const SubText = styled ( 'div' ) `
0 commit comments