@apollo-annotation/jbrowse-plugin-apollo 0.3.8 → 0.3.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/dist/index.esm.js +10914 -10799
  2. package/dist/index.esm.js.map +1 -1
  3. package/dist/jbrowse-plugin-apollo.cjs.development.js +10979 -10865
  4. package/dist/jbrowse-plugin-apollo.cjs.development.js.map +1 -1
  5. package/dist/jbrowse-plugin-apollo.cjs.production.min.js +1 -1
  6. package/dist/jbrowse-plugin-apollo.cjs.production.min.js.map +1 -1
  7. package/dist/jbrowse-plugin-apollo.umd.development.js +8799 -11326
  8. package/dist/jbrowse-plugin-apollo.umd.development.js.map +1 -1
  9. package/dist/jbrowse-plugin-apollo.umd.production.min.js +1 -1
  10. package/dist/jbrowse-plugin-apollo.umd.production.min.js.map +1 -1
  11. package/package.json +7 -7
  12. package/src/ApolloInternetAccount/components/AuthTypeSelector.tsx +1 -1
  13. package/src/ApolloInternetAccount/model.ts +87 -65
  14. package/src/ApolloRefNameAliasAdapter/ApolloRefNameAliasAdapter.ts +4 -4
  15. package/src/ApolloSequenceAdapter/ApolloSequenceAdapter.ts +9 -7
  16. package/src/BackendDrivers/CollaborationServerDriver.ts +60 -23
  17. package/src/BackendDrivers/DesktopFileDriver.ts +2 -2
  18. package/src/ChangeManager.ts +22 -5
  19. package/src/FeatureDetailsWidget/BasicInformation.tsx +6 -4
  20. package/src/FeatureDetailsWidget/NumberTextField.tsx +5 -2
  21. package/src/FeatureDetailsWidget/TranscriptWidgetEditLocation.tsx +68 -212
  22. package/src/LinearApolloDisplay/components/CheckResultWarnings.tsx +92 -0
  23. package/src/LinearApolloDisplay/components/LinearApolloDisplay.tsx +6 -102
  24. package/src/LinearApolloDisplay/glyphs/GeneGlyph.ts +33 -232
  25. package/src/LinearApolloDisplay/glyphs/util.ts +36 -0
  26. package/src/LinearApolloReferenceSequenceDisplay/drawSequenceOverlay.ts +174 -0
  27. package/src/LinearApolloReferenceSequenceDisplay/drawSequenceTrack.ts +200 -0
  28. package/src/LinearApolloReferenceSequenceDisplay/stateModel/rendering.ts +62 -386
  29. package/src/LinearApolloSixFrameDisplay/components/LinearApolloSixFrameDisplay.tsx +6 -0
  30. package/src/LinearApolloSixFrameDisplay/glyphs/GeneGlyph.ts +122 -70
  31. package/src/LinearApolloSixFrameDisplay/stateModel/base.ts +33 -2
  32. package/src/LinearApolloSixFrameDisplay/stateModel/rendering.ts +101 -3
  33. package/src/components/AddAssembly.tsx +34 -38
  34. package/src/components/AddFeature.tsx +21 -18
  35. package/src/components/AddRefSeqAliases.tsx +56 -42
  36. package/src/components/CopyFeature.tsx +1 -1
  37. package/src/components/CreateApolloAnnotation.tsx +22 -10
  38. package/src/components/DeleteAssembly.tsx +2 -9
  39. package/src/components/DownloadGFF3.tsx +2 -2
  40. package/src/components/ImportFeatures.tsx +1 -1
  41. package/src/components/ManageChecks.tsx +2 -9
  42. package/src/components/ManageUsers.tsx +23 -22
  43. package/src/components/OntologyTermAutocomplete.tsx +3 -10
  44. package/src/components/OntologyTermMultiSelect.tsx +2 -2
  45. package/src/components/ViewChangeLog.tsx +25 -50
  46. package/src/components/ViewCheckResults.tsx +1 -7
  47. package/src/config.ts +3 -3
  48. package/src/index.ts +17 -16
  49. package/src/makeDisplayComponent.tsx +9 -13
  50. package/src/session/ClientDataStore.ts +33 -15
  51. package/src/session/session.ts +23 -27
  52. package/src/util/displayUtils.ts +28 -0
  53. package/src/util/glyphUtils.ts +196 -1
  54. package/src/util/loadAssemblyIntoClient.ts +3 -2
@@ -113,6 +113,7 @@ export const TranscriptWidgetEditLocation = observer(
113
113
  const refData = currentAssembly?.getByRefName(refName)
114
114
  const { changeManager } = session.apolloDataStore
115
115
  const seqRef = useRef<HTMLDivElement>(null)
116
+ const { changeInProgress } = session
116
117
 
117
118
  if (!refData) {
118
119
  return null
@@ -149,66 +150,18 @@ export const TranscriptWidgetEditLocation = observer(
149
150
  cdsMax = sortedCDSLocations[sortedCDSLocations.length - 1].max
150
151
  }
151
152
 
152
- function handleCDSLocationChange(
153
+ const updateCDSLocation = (
153
154
  oldLocation: number,
154
155
  newLocation: number,
155
156
  feature: AnnotationFeature,
156
157
  isMin: boolean,
157
- ) {
158
+ onComplete?: () => void,
159
+ ): boolean => {
158
160
  if (!feature.children) {
159
161
  throw new Error('Transcript should have child features')
160
162
  }
161
-
162
- const overlappingExon = getOverlappingExonForCDS(
163
- feature,
164
- featureTypeOntology,
165
- oldLocation,
166
- isMin,
167
- )
168
- if (!overlappingExon) {
169
- notify('No matching exon found', 'error')
170
- return
171
- }
172
- const oldExonLocation = isMin ? overlappingExon.min : overlappingExon.max
173
- const { prevExon, nextExon } = getNeighboringExonParts(
174
- feature,
175
- featureTypeOntology,
176
- oldExonLocation,
177
- isMin,
178
- )
179
-
180
- // Start location should be less than end location
181
- if (isMin && newLocation >= overlappingExon.max) {
182
- notify(
183
- 'Start location should be less than overlapping exon end location',
184
- 'error',
185
- )
186
- return
187
- }
188
-
189
- // End location should be greater than start location
190
- if (!isMin && newLocation <= overlappingExon.min) {
191
- notify(
192
- 'End location should be greater than overlapping exon start location',
193
- 'error',
194
- )
195
- return
196
- }
197
- // Changed location should be greater than end location of previous exon - give 2bp buffer
198
- if (prevExon && prevExon.max + 2 > newLocation) {
199
- notify(
200
- 'Start location should be greater than previous exon end location',
201
- 'error',
202
- )
203
- return
204
- }
205
- // Changed location should be less than start location of next exon
206
- if (nextExon && nextExon.min - 2 < newLocation) {
207
- notify(
208
- 'End location should be less than next exon start location',
209
- 'error',
210
- )
211
- return
163
+ if (oldLocation === newLocation) {
164
+ return true
212
165
  }
213
166
 
214
167
  const cdsFeature = getMatchingCDSFeature(
@@ -217,10 +170,14 @@ export const TranscriptWidgetEditLocation = observer(
217
170
  oldLocation,
218
171
  isMin,
219
172
  )
220
-
221
173
  if (!cdsFeature) {
222
174
  notify('No matching CDS feature found', 'error')
223
- return
175
+ return false
176
+ }
177
+
178
+ if (isMin && newLocation >= cdsFeature.max) {
179
+ notify('Start location should be less than CDS end location', 'error')
180
+ return false
224
181
  }
225
182
 
226
183
  if (!isMin && newLocation <= cdsFeature.min) {
@@ -228,145 +185,23 @@ export const TranscriptWidgetEditLocation = observer(
228
185
  'End location should be greater than CDS start location',
229
186
  'error',
230
187
  )
231
- return
232
- }
233
- if (isMin && newLocation >= cdsFeature.max) {
234
- notify('Start location should be less than CDS end location', 'error')
235
- return
236
- }
237
-
238
- const overlappingExonFeature = getExonFeature(
239
- feature,
240
- overlappingExon.min,
241
- overlappingExon.max,
242
- featureTypeOntology,
243
- )
244
-
245
- if (!overlappingExonFeature) {
246
- notify('No matching exon feature found', 'error')
247
- return
248
- }
249
-
250
- if (isMin && newLocation !== cdsFeature.min) {
251
- const startChange: LocationStartChange = new LocationStartChange({
252
- typeName: 'LocationStartChange',
253
- changedIds: [],
254
- changes: [],
255
- assembly,
256
- })
257
-
258
- if (newLocation < overlappingExon.min) {
259
- if (prevExon) {
260
- // update exon start location
261
- appendStartLocationChange(
262
- overlappingExonFeature,
263
- startChange,
264
- newLocation,
265
- )
266
- // update CDS start location
267
- appendStartLocationChange(cdsFeature, startChange, newLocation)
268
- } else {
269
- const transcriptStart = feature.min
270
- const gene = feature.parent
271
- if (newLocation < transcriptStart) {
272
- if (gene && newLocation < gene.min) {
273
- // update gene start location
274
- appendStartLocationChange(gene, startChange, newLocation)
275
- }
276
- // update transcript start location
277
- appendStartLocationChange(feature, startChange, newLocation)
278
- // update exon start location
279
- appendStartLocationChange(
280
- overlappingExonFeature,
281
- startChange,
282
- newLocation,
283
- )
284
- // update CDS start location
285
- appendStartLocationChange(cdsFeature, startChange, newLocation)
286
- }
287
- }
288
- } else {
289
- // update CDS start location
290
- appendStartLocationChange(cdsFeature, startChange, newLocation)
291
- }
292
-
293
- void changeManager.submit(startChange).catch(() => {
294
- notify('Error updating feature CDS start position', 'error')
295
- })
188
+ return false
296
189
  }
297
190
 
298
- if (!isMin && newLocation !== cdsFeature.max) {
299
- const endChange: LocationEndChange = new LocationEndChange({
300
- typeName: 'LocationEndChange',
301
- changedIds: [],
302
- changes: [],
303
- assembly,
304
- })
305
-
306
- if (newLocation > overlappingExon.max) {
307
- if (nextExon) {
308
- // update exon end location
309
- appendEndLocationChange(
310
- overlappingExonFeature,
311
- endChange,
312
- newLocation,
313
- )
314
- // update CDS end location
315
- appendEndLocationChange(cdsFeature, endChange, newLocation)
316
- } else {
317
- const transcriptEnd = feature.max
318
- const gene = feature.parent
319
- if (newLocation > transcriptEnd) {
320
- if (gene && newLocation > gene.max) {
321
- // update gene end location
322
- appendEndLocationChange(gene, endChange, newLocation)
323
- }
324
- // update transcript end location
325
- appendEndLocationChange(feature, endChange, newLocation)
326
- // update exon end location
327
- appendEndLocationChange(
328
- overlappingExonFeature,
329
- endChange,
330
- newLocation,
331
- )
332
- // update CDS end location
333
- appendEndLocationChange(cdsFeature, endChange, newLocation)
334
- }
335
- }
336
- } else {
337
- // update CDS end location
338
- appendEndLocationChange(cdsFeature, endChange, newLocation)
339
- }
340
-
341
- void changeManager.submit(endChange).catch(() => {
342
- notify('Error updating feature CDS end position', 'error')
343
- })
344
- }
345
- }
346
-
347
- const updateCDSLocation = (
348
- oldLocation: number,
349
- newLocation: number,
350
- feature: AnnotationFeature,
351
- isMin: boolean,
352
- onComplete?: () => void,
353
- ) => {
354
- if (!feature.children) {
355
- throw new Error('Transcript should have child features')
356
- }
357
- if (oldLocation === newLocation) {
358
- return
359
- }
360
-
361
- const cdsFeature = getMatchingCDSFeature(
191
+ // overlapping exon of new CDS location
192
+ const overlappingExon = getOverlappingExonForCDS(
362
193
  feature,
363
194
  featureTypeOntology,
364
- oldLocation,
195
+ newLocation,
365
196
  isMin,
366
197
  )
367
- if (!cdsFeature) {
368
- notify('No matching CDS feature found', 'error')
369
- return
198
+
199
+ if (!overlappingExon) {
200
+ notify(
201
+ 'There should be an overlapping exon for the new CDS location',
202
+ 'error',
203
+ )
204
+ return false
370
205
  }
371
206
 
372
207
  const change = isMin
@@ -397,6 +232,7 @@ export const TranscriptWidgetEditLocation = observer(
397
232
  .catch(() => {
398
233
  notify('Error updating feature CDS position', 'error')
399
234
  })
235
+ return true
400
236
  }
401
237
 
402
238
  function handleExonLocationChange(
@@ -404,7 +240,7 @@ export const TranscriptWidgetEditLocation = observer(
404
240
  newLocation: number,
405
241
  feature: AnnotationFeature,
406
242
  isMin: boolean,
407
- ) {
243
+ ): boolean {
408
244
  if (!feature.children) {
409
245
  throw new Error('Transcript should have child features')
410
246
  }
@@ -417,28 +253,28 @@ export const TranscriptWidgetEditLocation = observer(
417
253
 
418
254
  if (!matchingExon) {
419
255
  notify('No matching exon found', 'error')
420
- return
256
+ return false
421
257
  }
422
258
 
423
259
  // Start location should be less than end location
424
260
  if (isMin && newLocation >= matchingExon.max) {
425
261
  notify(`Start location should be less than end location`, 'error')
426
- return
262
+ return false
427
263
  }
428
264
  // End location should be greater than start location
429
265
  if (!isMin && newLocation <= matchingExon.min) {
430
266
  notify(`End location should be greater than start location`, 'error')
431
- return
267
+ return false
432
268
  }
433
269
  // Changed location should be greater than end location of previous exon - give 2bp buffer
434
270
  if (prevExon && prevExon.max + 2 > newLocation) {
435
271
  notify(`Error while changing start location`, 'error')
436
- return
272
+ return false
437
273
  }
438
274
  // Changed location should be less than start location of next exon - give 2bp buffer
439
275
  if (nextExon && nextExon.min - 2 < newLocation) {
440
276
  notify(`Error while changing end location`, 'error')
441
- return
277
+ return false
442
278
  }
443
279
 
444
280
  const exonFeature = getExonFeature(
@@ -449,7 +285,7 @@ export const TranscriptWidgetEditLocation = observer(
449
285
  )
450
286
  if (!exonFeature) {
451
287
  notify('No matching exon feature found', 'error')
452
- return
288
+ return false
453
289
  }
454
290
 
455
291
  const cdsFeature = getFirstCDSFeature(feature, featureTypeOntology)
@@ -577,6 +413,7 @@ export const TranscriptWidgetEditLocation = observer(
577
413
  notify('Error updating feature exon end position', 'error')
578
414
  })
579
415
  }
416
+ return true
580
417
  }
581
418
 
582
419
  const appendEndLocationChange = (
@@ -888,12 +725,15 @@ export const TranscriptWidgetEditLocation = observer(
888
725
  <Typography
889
726
  component={'span'}
890
727
  style={{
891
- backgroundColor: 'yellow',
728
+ backgroundColor: changeInProgress ? 'lightgray' : 'yellow',
892
729
  cursor: 'pointer',
893
730
  border: '1px solid black',
894
731
  }}
895
732
  key={codonGenomicPos}
896
733
  onClick={() => {
734
+ if (changeInProgress) {
735
+ return
736
+ }
897
737
  // NOTE: codonGenomicPos is important here for calculating the genomic location
898
738
  // of the start codon. We are using the codonGenomicPos as the key in the typography
899
739
  // elements to maintain the genomic postion of the codon start
@@ -1012,7 +852,7 @@ export const TranscriptWidgetEditLocation = observer(
1012
852
 
1013
853
  // Trim any sequence before first start codon and after stop codon
1014
854
  const startCodonIndex = translationSequence.indexOf('M')
1015
- const stopCodonIndex = translationSequence.indexOf('*') + 1
855
+ const stopCodonIndex = translationSequence.indexOf('*')
1016
856
 
1017
857
  const startCodonPos =
1018
858
  translSeqCodonStartGenomicPosArr[startCodonIndex].codonGenomicPos
@@ -1025,7 +865,7 @@ export const TranscriptWidgetEditLocation = observer(
1025
865
  const startCodonGenomicLoc = getCodonGenomicLocation(
1026
866
  startCodonPos as unknown as number,
1027
867
  )
1028
- const stopCodonGenomicLoc = getCodonGenomicLocation(
868
+ let stopCodonGenomicLoc = getCodonGenomicLocation(
1029
869
  stopCodonPos as unknown as number,
1030
870
  )
1031
871
 
@@ -1038,6 +878,7 @@ export const TranscriptWidgetEditLocation = observer(
1038
878
  return
1039
879
  }
1040
880
  let promise
881
+ stopCodonGenomicLoc += 3 // move to end of stop codon
1041
882
  if (startCodonGenomicLoc !== cdsMin) {
1042
883
  promise = new Promise((resolve) => {
1043
884
  updateCDSLocation(
@@ -1073,6 +914,7 @@ export const TranscriptWidgetEditLocation = observer(
1073
914
  return
1074
915
  }
1075
916
  let promise
917
+ stopCodonGenomicLoc -= 3 // move to end of stop codon
1076
918
  if (startCodonGenomicLoc !== cdsMax) {
1077
919
  promise = new Promise((resolve) => {
1078
920
  updateCDSLocation(
@@ -1142,16 +984,22 @@ export const TranscriptWidgetEditLocation = observer(
1142
984
  }}
1143
985
  >
1144
986
  <Tooltip title="Copy">
1145
- <ContentCopyIcon
1146
- style={{ fontSize: 15, cursor: 'pointer' }}
987
+ <button
1147
988
  onClick={onCopyClick}
1148
- />
989
+ style={{ border: 'none', background: 'none', padding: 0 }}
990
+ disabled={changeInProgress}
991
+ >
992
+ <ContentCopyIcon style={{ fontSize: 15 }} />
993
+ </button>
1149
994
  </Tooltip>
1150
995
  <Tooltip title="Trim">
1151
- <ContentCutIcon
1152
- style={{ fontSize: 15, cursor: 'pointer' }}
996
+ <button
1153
997
  onClick={trimTranslationSequence}
1154
- />
998
+ style={{ border: 'none', background: 'none', padding: 0 }}
999
+ disabled={changeInProgress}
1000
+ >
1001
+ <ContentCutIcon style={{ fontSize: 15 }} />
1002
+ </button>
1155
1003
  </Tooltip>
1156
1004
  </div>
1157
1005
  </AccordionDetails>
@@ -1170,7 +1018,7 @@ export const TranscriptWidgetEditLocation = observer(
1170
1018
  variant="outlined"
1171
1019
  value={cdsMin + 1}
1172
1020
  onChangeCommitted={(newLocation: number) => {
1173
- handleCDSLocationChange(
1021
+ return updateCDSLocation(
1174
1022
  cdsMin,
1175
1023
  newLocation - 1,
1176
1024
  feature,
@@ -1178,6 +1026,7 @@ export const TranscriptWidgetEditLocation = observer(
1178
1026
  )
1179
1027
  }}
1180
1028
  style={{ border: '1px solid black', borderRadius: 5 }}
1029
+ disabled={changeInProgress}
1181
1030
  />
1182
1031
  </Grid>
1183
1032
  ) : (
@@ -1187,7 +1036,7 @@ export const TranscriptWidgetEditLocation = observer(
1187
1036
  variant="outlined"
1188
1037
  value={cdsMax}
1189
1038
  onChangeCommitted={(newLocation: number) => {
1190
- handleCDSLocationChange(
1039
+ return updateCDSLocation(
1191
1040
  cdsMax,
1192
1041
  newLocation,
1193
1042
  feature,
@@ -1195,6 +1044,7 @@ export const TranscriptWidgetEditLocation = observer(
1195
1044
  )
1196
1045
  }}
1197
1046
  style={{ border: '1px solid black', borderRadius: 5 }}
1047
+ disabled={changeInProgress}
1198
1048
  />
1199
1049
  </Grid>
1200
1050
  )}
@@ -1208,7 +1058,7 @@ export const TranscriptWidgetEditLocation = observer(
1208
1058
  variant="outlined"
1209
1059
  value={cdsMax}
1210
1060
  onChangeCommitted={(newLocation: number) => {
1211
- handleCDSLocationChange(
1061
+ return updateCDSLocation(
1212
1062
  cdsMax,
1213
1063
  newLocation,
1214
1064
  feature,
@@ -1216,6 +1066,7 @@ export const TranscriptWidgetEditLocation = observer(
1216
1066
  )
1217
1067
  }}
1218
1068
  style={{ border: '1px solid black', borderRadius: 5 }}
1069
+ disabled={changeInProgress}
1219
1070
  />
1220
1071
  </Grid>
1221
1072
  ) : (
@@ -1225,7 +1076,7 @@ export const TranscriptWidgetEditLocation = observer(
1225
1076
  variant="outlined"
1226
1077
  value={cdsMin + 1}
1227
1078
  onChangeCommitted={(newLocation: number) => {
1228
- handleCDSLocationChange(
1079
+ return updateCDSLocation(
1229
1080
  cdsMin,
1230
1081
  newLocation - 1,
1231
1082
  feature,
@@ -1233,6 +1084,7 @@ export const TranscriptWidgetEditLocation = observer(
1233
1084
  )
1234
1085
  }}
1235
1086
  style={{ border: '1px solid black', borderRadius: 5 }}
1087
+ disabled={changeInProgress}
1236
1088
  />
1237
1089
  </Grid>
1238
1090
  )}
@@ -1270,13 +1122,14 @@ export const TranscriptWidgetEditLocation = observer(
1270
1122
  variant="outlined"
1271
1123
  value={loc.min + 1}
1272
1124
  onChangeCommitted={(newLocation: number) => {
1273
- handleExonLocationChange(
1125
+ return handleExonLocationChange(
1274
1126
  loc.min,
1275
1127
  newLocation - 1,
1276
1128
  feature,
1277
1129
  true,
1278
1130
  )
1279
1131
  }}
1132
+ disabled={changeInProgress}
1280
1133
  />
1281
1134
  </Grid>
1282
1135
  ) : (
@@ -1286,13 +1139,14 @@ export const TranscriptWidgetEditLocation = observer(
1286
1139
  variant="outlined"
1287
1140
  value={loc.max}
1288
1141
  onChangeCommitted={(newLocation: number) => {
1289
- handleExonLocationChange(
1142
+ return handleExonLocationChange(
1290
1143
  loc.max,
1291
1144
  newLocation,
1292
1145
  feature,
1293
1146
  false,
1294
1147
  )
1295
1148
  }}
1149
+ disabled={changeInProgress}
1296
1150
  />
1297
1151
  </Grid>
1298
1152
  )}
@@ -1306,13 +1160,14 @@ export const TranscriptWidgetEditLocation = observer(
1306
1160
  variant="outlined"
1307
1161
  value={loc.max}
1308
1162
  onChangeCommitted={(newLocation: number) => {
1309
- handleExonLocationChange(
1163
+ return handleExonLocationChange(
1310
1164
  loc.max,
1311
1165
  newLocation,
1312
1166
  feature,
1313
1167
  false,
1314
1168
  )
1315
1169
  }}
1170
+ disabled={changeInProgress}
1316
1171
  />
1317
1172
  </Grid>
1318
1173
  ) : (
@@ -1322,13 +1177,14 @@ export const TranscriptWidgetEditLocation = observer(
1322
1177
  variant="outlined"
1323
1178
  value={loc.min + 1}
1324
1179
  onChangeCommitted={(newLocation: number) => {
1325
- handleExonLocationChange(
1180
+ return handleExonLocationChange(
1326
1181
  loc.min,
1327
1182
  newLocation - 1,
1328
1183
  feature,
1329
1184
  true,
1330
1185
  )
1331
1186
  }}
1187
+ disabled={changeInProgress}
1332
1188
  />
1333
1189
  </Grid>
1334
1190
  )}
@@ -0,0 +1,92 @@
1
+ import { type CheckResultI } from '@apollo-annotation/mst'
2
+ import { type AbstractSessionModel, doesIntersect2 } from '@jbrowse/core/util'
3
+ import ErrorIcon from '@mui/icons-material/Error'
4
+ import { Avatar, Badge, Box, Tooltip } from '@mui/material'
5
+ import { observer } from 'mobx-react'
6
+ import React from 'react'
7
+
8
+ import { clusterResultByMessage, useStyles } from '../../util/displayUtils'
9
+ import { getLeftPx } from '../glyphs/util'
10
+ import { type LinearApolloDisplay as LinearApolloDisplayI } from '../stateModel'
11
+
12
+ export const CheckResultWarnings = observer(function CheckResultWarnings({
13
+ display,
14
+ }: {
15
+ display: LinearApolloDisplayI
16
+ }) {
17
+ const { classes } = useStyles()
18
+ const { apolloDragging, apolloRowHeight, lgv, session, showCheckResults } =
19
+ display
20
+ const { assemblyManager } = session as unknown as AbstractSessionModel
21
+ if (!showCheckResults) {
22
+ return null
23
+ }
24
+ return lgv.dynamicBlocks.contentBlocks.map((block) => {
25
+ const widthBp = lgv.bpPerPx * apolloRowHeight
26
+ const assembly = assemblyManager.get(block.assemblyName)
27
+ if (!assembly) {
28
+ return null
29
+ }
30
+ const filteredCheckResults = [
31
+ ...session.apolloDataStore.checkResults.values(),
32
+ ].filter(
33
+ (checkResult) =>
34
+ assembly.isValidRefName(checkResult.refSeq) &&
35
+ assembly.getCanonicalRefName(checkResult.refSeq) === block.refName &&
36
+ doesIntersect2(
37
+ block.start,
38
+ block.end,
39
+ checkResult.start,
40
+ checkResult.end,
41
+ ),
42
+ )
43
+ const checkResults = clusterResultByMessage<CheckResultI>(
44
+ filteredCheckResults,
45
+ widthBp,
46
+ true,
47
+ )
48
+ return checkResults.map((checkResult) => {
49
+ const left = Math.round(getLeftPx(display, checkResult.range, block))
50
+
51
+ const [feature] = checkResult.featureIds
52
+ if (!feature) {
53
+ return null
54
+ }
55
+ let row = 0
56
+ const featureLayout = display.getFeatureLayoutPosition(feature)
57
+ if (featureLayout) {
58
+ row = featureLayout.layoutRow + featureLayout.featureRow
59
+ }
60
+ const top = row * apolloRowHeight
61
+ const height = apolloRowHeight
62
+ return (
63
+ <Tooltip key={checkResult._id} title={checkResult.message}>
64
+ <Box
65
+ className={classes.box}
66
+ style={{
67
+ top,
68
+ left,
69
+ height,
70
+ width: height,
71
+ pointerEvents: apolloDragging ? 'none' : 'auto',
72
+ }}
73
+ >
74
+ <Badge
75
+ className={classes.badge}
76
+ badgeContent={checkResult.count}
77
+ color="primary"
78
+ overlap="circular"
79
+ anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}
80
+ invisible={checkResult.count <= 1}
81
+ >
82
+ <Avatar className={classes.avatar}>
83
+ <ErrorIcon data-testid={`ErrorIcon-${checkResult.start}`} />
84
+ </Avatar>
85
+ </Badge>
86
+ </Box>
87
+ </Tooltip>
88
+ )
89
+ })
90
+ return null
91
+ })
92
+ })