@apollo-annotation/jbrowse-plugin-apollo 0.3.7 → 0.3.9

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 (86) hide show
  1. package/dist/index.esm.js +11212 -10483
  2. package/dist/index.esm.js.map +1 -1
  3. package/dist/jbrowse-plugin-apollo.cjs.development.js +11251 -10509
  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 +7726 -9014
  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 +18 -18
  12. package/src/ApolloInternetAccount/model.ts +123 -70
  13. package/src/ApolloRefNameAliasAdapter/ApolloRefNameAliasAdapter.ts +4 -4
  14. package/src/ApolloSequenceAdapter/ApolloSequenceAdapter.ts +9 -7
  15. package/src/BackendDrivers/CollaborationServerDriver.ts +72 -20
  16. package/src/BackendDrivers/DesktopFileDriver.ts +2 -2
  17. package/src/ChangeManager.ts +36 -14
  18. package/src/FeatureDetailsWidget/ApolloTranscriptDetailsWidget.tsx +64 -5
  19. package/src/FeatureDetailsWidget/BasicInformation.tsx +6 -4
  20. package/src/FeatureDetailsWidget/NumberTextField.tsx +5 -2
  21. package/src/FeatureDetailsWidget/TranscriptSequence.tsx +70 -73
  22. package/src/FeatureDetailsWidget/TranscriptWidgetEditLocation.tsx +72 -234
  23. package/src/LinearApolloDisplay/components/CheckResultWarnings.tsx +92 -0
  24. package/src/LinearApolloDisplay/components/LinearApolloDisplay.tsx +23 -131
  25. package/src/LinearApolloDisplay/glyphs/BoxGlyph.ts +50 -194
  26. package/src/LinearApolloDisplay/glyphs/GeneGlyph.ts +279 -217
  27. package/src/LinearApolloDisplay/glyphs/GenericChildGlyph.ts +53 -34
  28. package/src/LinearApolloDisplay/glyphs/Glyph.ts +7 -9
  29. package/src/LinearApolloDisplay/glyphs/util.ts +19 -0
  30. package/src/LinearApolloDisplay/stateModel/base.ts +34 -43
  31. package/src/LinearApolloDisplay/stateModel/layouts.ts +3 -2
  32. package/src/LinearApolloDisplay/stateModel/mouseEvents.ts +32 -261
  33. package/src/LinearApolloDisplay/stateModel/rendering.ts +43 -343
  34. package/src/LinearApolloReferenceSequenceDisplay/components/LinearApolloReferenceSequenceDisplay.tsx +87 -0
  35. package/src/LinearApolloReferenceSequenceDisplay/components/index.ts +1 -0
  36. package/src/LinearApolloReferenceSequenceDisplay/configSchema.ts +7 -0
  37. package/src/LinearApolloReferenceSequenceDisplay/drawSequenceOverlay.ts +181 -0
  38. package/src/LinearApolloReferenceSequenceDisplay/drawSequenceTrack.ts +218 -0
  39. package/src/LinearApolloReferenceSequenceDisplay/index.ts +3 -0
  40. package/src/LinearApolloReferenceSequenceDisplay/stateModel/base.ts +227 -0
  41. package/src/LinearApolloReferenceSequenceDisplay/stateModel/index.ts +25 -0
  42. package/src/LinearApolloReferenceSequenceDisplay/stateModel/rendering.ts +157 -0
  43. package/src/LinearApolloSixFrameDisplay/components/LinearApolloSixFrameDisplay.tsx +101 -38
  44. package/src/LinearApolloSixFrameDisplay/glyphs/GeneGlyph.ts +334 -262
  45. package/src/LinearApolloSixFrameDisplay/glyphs/Glyph.ts +12 -8
  46. package/src/LinearApolloSixFrameDisplay/stateModel/base.ts +42 -4
  47. package/src/LinearApolloSixFrameDisplay/stateModel/layouts.ts +4 -8
  48. package/src/LinearApolloSixFrameDisplay/stateModel/mouseEvents.ts +73 -97
  49. package/src/LinearApolloSixFrameDisplay/stateModel/rendering.ts +49 -61
  50. package/src/TabularEditor/HybridGrid/Feature.tsx +16 -14
  51. package/src/TabularEditor/HybridGrid/HybridGrid.tsx +7 -5
  52. package/src/components/AddAssembly.tsx +34 -38
  53. package/src/components/AddAssemblyAliases.tsx +1 -1
  54. package/src/components/AddChildFeature.tsx +5 -2
  55. package/src/components/AddFeature.tsx +30 -21
  56. package/src/components/AddRefSeqAliases.tsx +64 -50
  57. package/src/components/CopyFeature.tsx +4 -2
  58. package/src/components/CreateApolloAnnotation.tsx +22 -9
  59. package/src/components/DeleteAssembly.tsx +3 -10
  60. package/src/components/DownloadGFF3.tsx +2 -2
  61. package/src/components/EditZoomThresholdDialog.tsx +69 -0
  62. package/src/components/FilterFeatures.tsx +7 -7
  63. package/src/components/FilterTranscripts.tsx +6 -6
  64. package/src/components/ImportFeatures.tsx +1 -1
  65. package/src/components/ManageChecks.tsx +3 -10
  66. package/src/components/ManageUsers.tsx +23 -22
  67. package/src/components/MergeTranscripts.tsx +12 -15
  68. package/src/components/OntologyTermAutocomplete.tsx +1 -8
  69. package/src/components/OntologyTermMultiSelect.tsx +11 -11
  70. package/src/components/OpenLocalFile.tsx +11 -7
  71. package/src/components/ViewChangeLog.tsx +25 -50
  72. package/src/components/ViewCheckResults.tsx +2 -8
  73. package/src/components/index.ts +1 -0
  74. package/src/config.ts +6 -0
  75. package/src/index.ts +53 -115
  76. package/src/makeDisplayComponent.tsx +9 -14
  77. package/src/menus/index.ts +1 -0
  78. package/src/{ApolloInternetAccount/addMenuItems.ts → menus/topLevelMenu.ts} +56 -47
  79. package/src/menus/topLevelMenuAdmin.ts +154 -0
  80. package/src/session/ClientDataStore.ts +32 -14
  81. package/src/session/session.ts +159 -121
  82. package/src/util/annotationFeatureUtils.ts +15 -21
  83. package/src/util/displayUtils.ts +149 -0
  84. package/src/util/glyphUtils.ts +329 -0
  85. package/src/util/loadAssemblyIntoClient.ts +3 -2
  86. package/src/util/mouseEventsUtils.ts +32 -0
@@ -25,7 +25,7 @@ import RemoveIcon from '@mui/icons-material/Remove'
25
25
  import {
26
26
  Accordion,
27
27
  AccordionDetails,
28
- Grid2,
28
+ Grid,
29
29
  Tooltip,
30
30
  Typography,
31
31
  } from '@mui/material'
@@ -149,66 +149,18 @@ export const TranscriptWidgetEditLocation = observer(
149
149
  cdsMax = sortedCDSLocations[sortedCDSLocations.length - 1].max
150
150
  }
151
151
 
152
- function handleCDSLocationChange(
152
+ const updateCDSLocation = (
153
153
  oldLocation: number,
154
154
  newLocation: number,
155
155
  feature: AnnotationFeature,
156
156
  isMin: boolean,
157
- ) {
157
+ onComplete?: () => void,
158
+ ): boolean => {
158
159
  if (!feature.children) {
159
160
  throw new Error('Transcript should have child features')
160
161
  }
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
162
+ if (oldLocation === newLocation) {
163
+ return true
212
164
  }
213
165
 
214
166
  const cdsFeature = getMatchingCDSFeature(
@@ -217,10 +169,14 @@ export const TranscriptWidgetEditLocation = observer(
217
169
  oldLocation,
218
170
  isMin,
219
171
  )
220
-
221
172
  if (!cdsFeature) {
222
173
  notify('No matching CDS feature found', 'error')
223
- return
174
+ return false
175
+ }
176
+
177
+ if (isMin && newLocation >= cdsFeature.max) {
178
+ notify('Start location should be less than CDS end location', 'error')
179
+ return false
224
180
  }
225
181
 
226
182
  if (!isMin && newLocation <= cdsFeature.min) {
@@ -228,145 +184,23 @@ export const TranscriptWidgetEditLocation = observer(
228
184
  'End location should be greater than CDS start location',
229
185
  'error',
230
186
  )
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
187
+ return false
248
188
  }
249
189
 
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
- })
296
- }
297
-
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(
190
+ // overlapping exon of new CDS location
191
+ const overlappingExon = getOverlappingExonForCDS(
362
192
  feature,
363
193
  featureTypeOntology,
364
- oldLocation,
194
+ newLocation,
365
195
  isMin,
366
196
  )
367
- if (!cdsFeature) {
368
- notify('No matching CDS feature found', 'error')
369
- return
197
+
198
+ if (!overlappingExon) {
199
+ notify(
200
+ 'There should be an overlapping exon for the new CDS location',
201
+ 'error',
202
+ )
203
+ return false
370
204
  }
371
205
 
372
206
  const change = isMin
@@ -397,6 +231,7 @@ export const TranscriptWidgetEditLocation = observer(
397
231
  .catch(() => {
398
232
  notify('Error updating feature CDS position', 'error')
399
233
  })
234
+ return true
400
235
  }
401
236
 
402
237
  function handleExonLocationChange(
@@ -404,7 +239,7 @@ export const TranscriptWidgetEditLocation = observer(
404
239
  newLocation: number,
405
240
  feature: AnnotationFeature,
406
241
  isMin: boolean,
407
- ) {
242
+ ): boolean {
408
243
  if (!feature.children) {
409
244
  throw new Error('Transcript should have child features')
410
245
  }
@@ -417,28 +252,28 @@ export const TranscriptWidgetEditLocation = observer(
417
252
 
418
253
  if (!matchingExon) {
419
254
  notify('No matching exon found', 'error')
420
- return
255
+ return false
421
256
  }
422
257
 
423
258
  // Start location should be less than end location
424
259
  if (isMin && newLocation >= matchingExon.max) {
425
260
  notify(`Start location should be less than end location`, 'error')
426
- return
261
+ return false
427
262
  }
428
263
  // End location should be greater than start location
429
264
  if (!isMin && newLocation <= matchingExon.min) {
430
265
  notify(`End location should be greater than start location`, 'error')
431
- return
266
+ return false
432
267
  }
433
268
  // Changed location should be greater than end location of previous exon - give 2bp buffer
434
269
  if (prevExon && prevExon.max + 2 > newLocation) {
435
270
  notify(`Error while changing start location`, 'error')
436
- return
271
+ return false
437
272
  }
438
273
  // Changed location should be less than start location of next exon - give 2bp buffer
439
274
  if (nextExon && nextExon.min - 2 < newLocation) {
440
275
  notify(`Error while changing end location`, 'error')
441
- return
276
+ return false
442
277
  }
443
278
 
444
279
  const exonFeature = getExonFeature(
@@ -449,7 +284,7 @@ export const TranscriptWidgetEditLocation = observer(
449
284
  )
450
285
  if (!exonFeature) {
451
286
  notify('No matching exon feature found', 'error')
452
- return
287
+ return false
453
288
  }
454
289
 
455
290
  const cdsFeature = getFirstCDSFeature(feature, featureTypeOntology)
@@ -577,6 +412,7 @@ export const TranscriptWidgetEditLocation = observer(
577
412
  notify('Error updating feature exon end position', 'error')
578
413
  })
579
414
  }
415
+ return true
580
416
  }
581
417
 
582
418
  const appendEndLocationChange = (
@@ -821,6 +657,7 @@ export const TranscriptWidgetEditLocation = observer(
821
657
  }
822
658
  }
823
659
  }
660
+ spliceSite = spliceSite.toUpperCase()
824
661
  return [
825
662
  {
826
663
  spliceSite,
@@ -846,6 +683,7 @@ export const TranscriptWidgetEditLocation = observer(
846
683
  }
847
684
  }
848
685
  }
686
+ spliceSite = spliceSite.toUpperCase()
849
687
  return [
850
688
  {
851
689
  spliceSite,
@@ -1154,21 +992,21 @@ export const TranscriptWidgetEditLocation = observer(
1154
992
  </div>
1155
993
  </AccordionDetails>
1156
994
  </Accordion>
1157
- <Grid2
995
+ <Grid
1158
996
  container
1159
997
  justifyContent="center"
1160
998
  alignItems="center"
1161
999
  style={{ textAlign: 'center', marginTop: 10 }}
1162
1000
  >
1163
- <Grid2 size={1} />
1001
+ <Grid size={1} />
1164
1002
  {strand === 1 ? (
1165
- <Grid2 size={4}>
1003
+ <Grid size={4}>
1166
1004
  <StyledTextField
1167
1005
  margin="dense"
1168
1006
  variant="outlined"
1169
1007
  value={cdsMin + 1}
1170
1008
  onChangeCommitted={(newLocation: number) => {
1171
- handleCDSLocationChange(
1009
+ return updateCDSLocation(
1172
1010
  cdsMin,
1173
1011
  newLocation - 1,
1174
1012
  feature,
@@ -1177,15 +1015,15 @@ export const TranscriptWidgetEditLocation = observer(
1177
1015
  }}
1178
1016
  style={{ border: '1px solid black', borderRadius: 5 }}
1179
1017
  />
1180
- </Grid2>
1018
+ </Grid>
1181
1019
  ) : (
1182
- <Grid2 size={4}>
1020
+ <Grid size={4}>
1183
1021
  <StyledTextField
1184
1022
  margin="dense"
1185
1023
  variant="outlined"
1186
1024
  value={cdsMax}
1187
1025
  onChangeCommitted={(newLocation: number) => {
1188
- handleCDSLocationChange(
1026
+ return updateCDSLocation(
1189
1027
  cdsMax,
1190
1028
  newLocation,
1191
1029
  feature,
@@ -1194,19 +1032,19 @@ export const TranscriptWidgetEditLocation = observer(
1194
1032
  }}
1195
1033
  style={{ border: '1px solid black', borderRadius: 5 }}
1196
1034
  />
1197
- </Grid2>
1035
+ </Grid>
1198
1036
  )}
1199
- <Grid2 size={2}>
1037
+ <Grid size={2}>
1200
1038
  <Typography component={'span'}>CDS</Typography>
1201
- </Grid2>
1039
+ </Grid>
1202
1040
  {strand === 1 ? (
1203
- <Grid2 size={4}>
1041
+ <Grid size={4}>
1204
1042
  <StyledTextField
1205
1043
  margin="dense"
1206
1044
  variant="outlined"
1207
1045
  value={cdsMax}
1208
1046
  onChangeCommitted={(newLocation: number) => {
1209
- handleCDSLocationChange(
1047
+ return updateCDSLocation(
1210
1048
  cdsMax,
1211
1049
  newLocation,
1212
1050
  feature,
@@ -1215,15 +1053,15 @@ export const TranscriptWidgetEditLocation = observer(
1215
1053
  }}
1216
1054
  style={{ border: '1px solid black', borderRadius: 5 }}
1217
1055
  />
1218
- </Grid2>
1056
+ </Grid>
1219
1057
  ) : (
1220
- <Grid2 size={4}>
1058
+ <Grid size={4}>
1221
1059
  <StyledTextField
1222
1060
  margin="dense"
1223
1061
  variant="outlined"
1224
1062
  value={cdsMin + 1}
1225
1063
  onChangeCommitted={(newLocation: number) => {
1226
- handleCDSLocationChange(
1064
+ return updateCDSLocation(
1227
1065
  cdsMin,
1228
1066
  newLocation - 1,
1229
1067
  feature,
@@ -1232,10 +1070,10 @@ export const TranscriptWidgetEditLocation = observer(
1232
1070
  }}
1233
1071
  style={{ border: '1px solid black', borderRadius: 5 }}
1234
1072
  />
1235
- </Grid2>
1073
+ </Grid>
1236
1074
  )}
1237
- <Grid2 size={1} />
1238
- </Grid2>
1075
+ <Grid size={1} />
1076
+ </Grid>
1239
1077
  </div>
1240
1078
  )}
1241
1079
  <div style={{ marginTop: 5 }}>
@@ -1243,13 +1081,13 @@ export const TranscriptWidgetEditLocation = observer(
1243
1081
  return (
1244
1082
  <div key={index}>
1245
1083
  {loc.type === 'exon' && (
1246
- <Grid2
1084
+ <Grid
1247
1085
  container
1248
1086
  justifyContent="center"
1249
1087
  alignItems="center"
1250
1088
  style={{ textAlign: 'center' }}
1251
1089
  >
1252
- <Grid2 size={1}>
1090
+ <Grid size={1}>
1253
1091
  {index !== 0 &&
1254
1092
  getFivePrimeSpliceSite(loc, index).map((site, idx) => (
1255
1093
  <Typography
@@ -1260,15 +1098,15 @@ export const TranscriptWidgetEditLocation = observer(
1260
1098
  {site.spliceSite}
1261
1099
  </Typography>
1262
1100
  ))}
1263
- </Grid2>
1101
+ </Grid>
1264
1102
  {strand === 1 ? (
1265
- <Grid2 size={4} style={{ padding: 0 }}>
1103
+ <Grid size={4} style={{ padding: 0 }}>
1266
1104
  <StyledTextField
1267
1105
  margin="dense"
1268
1106
  variant="outlined"
1269
1107
  value={loc.min + 1}
1270
1108
  onChangeCommitted={(newLocation: number) => {
1271
- handleExonLocationChange(
1109
+ return handleExonLocationChange(
1272
1110
  loc.min,
1273
1111
  newLocation - 1,
1274
1112
  feature,
@@ -1276,15 +1114,15 @@ export const TranscriptWidgetEditLocation = observer(
1276
1114
  )
1277
1115
  }}
1278
1116
  />
1279
- </Grid2>
1117
+ </Grid>
1280
1118
  ) : (
1281
- <Grid2 size={4} style={{ padding: 0 }}>
1119
+ <Grid size={4} style={{ padding: 0 }}>
1282
1120
  <StyledTextField
1283
1121
  margin="dense"
1284
1122
  variant="outlined"
1285
1123
  value={loc.max}
1286
1124
  onChangeCommitted={(newLocation: number) => {
1287
- handleExonLocationChange(
1125
+ return handleExonLocationChange(
1288
1126
  loc.max,
1289
1127
  newLocation,
1290
1128
  feature,
@@ -1292,19 +1130,19 @@ export const TranscriptWidgetEditLocation = observer(
1292
1130
  )
1293
1131
  }}
1294
1132
  />
1295
- </Grid2>
1133
+ </Grid>
1296
1134
  )}
1297
- <Grid2 size={2}>
1135
+ <Grid size={2}>
1298
1136
  <Strand strand={feature.strand} />
1299
- </Grid2>
1137
+ </Grid>
1300
1138
  {strand === 1 ? (
1301
- <Grid2 size={4} style={{ padding: 0 }}>
1139
+ <Grid size={4} style={{ padding: 0 }}>
1302
1140
  <StyledTextField
1303
1141
  margin="dense"
1304
1142
  variant="outlined"
1305
1143
  value={loc.max}
1306
1144
  onChangeCommitted={(newLocation: number) => {
1307
- handleExonLocationChange(
1145
+ return handleExonLocationChange(
1308
1146
  loc.max,
1309
1147
  newLocation,
1310
1148
  feature,
@@ -1312,15 +1150,15 @@ export const TranscriptWidgetEditLocation = observer(
1312
1150
  )
1313
1151
  }}
1314
1152
  />
1315
- </Grid2>
1153
+ </Grid>
1316
1154
  ) : (
1317
- <Grid2 size={4} style={{ padding: 0 }}>
1155
+ <Grid size={4} style={{ padding: 0 }}>
1318
1156
  <StyledTextField
1319
1157
  margin="dense"
1320
1158
  variant="outlined"
1321
1159
  value={loc.min + 1}
1322
1160
  onChangeCommitted={(newLocation: number) => {
1323
- handleExonLocationChange(
1161
+ return handleExonLocationChange(
1324
1162
  loc.min,
1325
1163
  newLocation - 1,
1326
1164
  feature,
@@ -1328,9 +1166,9 @@ export const TranscriptWidgetEditLocation = observer(
1328
1166
  )
1329
1167
  }}
1330
1168
  />
1331
- </Grid2>
1169
+ </Grid>
1332
1170
  )}
1333
- <Grid2 size={1}>
1171
+ <Grid size={1}>
1334
1172
  {index !== transcriptExonParts.length - 1 &&
1335
1173
  getThreePrimeSpliceSite(loc, index).map((site, idx) => (
1336
1174
  <Typography
@@ -1341,8 +1179,8 @@ export const TranscriptWidgetEditLocation = observer(
1341
1179
  {site.spliceSite}
1342
1180
  </Typography>
1343
1181
  ))}
1344
- </Grid2>
1345
- </Grid2>
1182
+ </Grid>
1183
+ </Grid>
1346
1184
  )}
1347
1185
  </div>
1348
1186
  )
@@ -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
+ })