@teselagen/ove 0.8.2 → 0.8.4

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 (53) hide show
  1. package/AlignmentView/LabileSitesLayer.d.ts +13 -0
  2. package/AlignmentView/PairwiseAlignmentView.d.ts +1 -9
  3. package/BarPlot/index.d.ts +33 -0
  4. package/LinearView/SequenceName.d.ts +2 -1
  5. package/PropertySidePanel/calculateAminoAcidFrequency.d.ts +46 -0
  6. package/PropertySidePanel/index.d.ts +6 -0
  7. package/RowItem/Caret/index.d.ts +2 -1
  8. package/StatusBar/index.d.ts +2 -1
  9. package/aaprops.svg +2287 -0
  10. package/constants/dnaToColor.d.ts +122 -4
  11. package/index.cjs.js +4214 -7859
  12. package/index.es.js +2166 -5811
  13. package/index.umd.js +3745 -7390
  14. package/ove.css +100 -19
  15. package/package.json +2 -2
  16. package/src/AlignmentView/AlignmentVisibilityTool.js +141 -37
  17. package/src/AlignmentView/LabileSitesLayer.js +33 -0
  18. package/src/AlignmentView/Minimap.js +5 -3
  19. package/src/AlignmentView/PairwiseAlignmentView.js +55 -61
  20. package/src/AlignmentView/index.js +476 -257
  21. package/src/AlignmentView/style.css +27 -0
  22. package/src/BarPlot/index.js +156 -0
  23. package/src/CircularView/Caret.js +8 -2
  24. package/src/CircularView/SelectionLayer.js +4 -2
  25. package/src/CircularView/index.js +5 -1
  26. package/src/Editor/darkmode.css +10 -0
  27. package/src/Editor/index.js +3 -0
  28. package/src/Editor/userDefinedHandlersAndOpts.js +2 -1
  29. package/src/FindBar/index.js +2 -3
  30. package/src/LinearView/SequenceName.js +8 -2
  31. package/src/LinearView/index.js +21 -0
  32. package/src/PropertySidePanel/calculateAminoAcidFrequency.js +77 -0
  33. package/src/PropertySidePanel/index.js +236 -0
  34. package/src/PropertySidePanel/style.css +39 -0
  35. package/src/RowItem/Caret/index.js +8 -2
  36. package/src/RowItem/Labels.js +1 -1
  37. package/src/RowItem/SelectionLayer/index.js +5 -1
  38. package/src/RowItem/Sequence.js +99 -5
  39. package/src/RowItem/Translations/Translation.js +3 -2
  40. package/src/RowItem/Translations/index.js +2 -0
  41. package/src/RowItem/index.js +74 -8
  42. package/src/RowItem/style.css +3 -4
  43. package/src/StatusBar/index.js +11 -4
  44. package/src/constants/dnaToColor.js +151 -0
  45. package/src/helperComponents/PinchHelper/PinchHelper.js +5 -1
  46. package/src/helperComponents/SelectDialog.js +5 -2
  47. package/src/style.css +2 -2
  48. package/src/utils/editorUtils.js +5 -3
  49. package/src/utils/getAlignedAminoAcidSequenceProps.js +379 -0
  50. package/src/withEditorInteractions/createSequenceInputPopup.js +19 -5
  51. package/src/withEditorInteractions/index.js +9 -3
  52. package/utils/editorUtils.d.ts +2 -1
  53. package/utils/getAlignedAminoAcidSequenceProps.d.ts +49 -0
@@ -72,6 +72,9 @@ import { isTargetWithinEl } from "./isTargetWithinEl";
72
72
  import { EditTrackNameDialog } from "./EditTrackNameDialog";
73
73
  import { coerceInitialValue } from "./coerceInitialValue";
74
74
  import { tabHeight } from "../constants";
75
+ import LabileSitesLayer from "./LabileSitesLayer";
76
+ import PropertySidePanel from "../PropertySidePanel";
77
+ import { getAlignedAminoAcidSequenceProps } from "../utils/getAlignedAminoAcidSequenceProps";
75
78
 
76
79
  let charWidthInLinearViewDefault = 12;
77
80
  try {
@@ -173,6 +176,13 @@ export const AlignmentView = props => {
173
176
  })
174
177
  );
175
178
 
179
+ const [propertySidePanel, setPropertySidePanel] = useState({
180
+ isOpen: false,
181
+ selection: null,
182
+ track: null,
183
+ isPairwise: false
184
+ });
185
+
176
186
  const getAllAlignmentsFastaText = useCallback(() => {
177
187
  const selectionLayer =
178
188
  store.getState().VectorEditor.__allEditorsOptions.alignments[id]
@@ -245,6 +255,67 @@ export const AlignmentView = props => {
245
255
  };
246
256
  }, []);
247
257
 
258
+ const {
259
+ alignmentAnnotationVisibility,
260
+ togglableAlignmentAnnotationSettings
261
+ } = alignmentVisibilityToolOptions;
262
+
263
+ useEffect(() => {
264
+ const dnaAnnotations = [
265
+ "chromatogram",
266
+ "reverseSequence",
267
+ "cdsFeatureTranslations",
268
+ "dnaColors",
269
+ "translations",
270
+ "compactNames"
271
+ ];
272
+
273
+ const aminoAcidAnnotations = [
274
+ "physicalProperties",
275
+ "serineThreonine",
276
+ "labileSites",
277
+ "colorScheme",
278
+ "plot",
279
+ "conservation",
280
+ "properties",
281
+ "hydrophobicity",
282
+ "polar",
283
+ "negative",
284
+ "positive",
285
+ "charged",
286
+ "aliphatic",
287
+ "aromatic",
288
+ "compactNames"
289
+ ];
290
+
291
+ const noNeededAnnotationsForPairwise = ["plot", "labileSites"];
292
+
293
+ if (alignmentTracks[0].sequenceData.isProtein) {
294
+ dnaAnnotations.forEach(key => {
295
+ delete alignmentAnnotationVisibility[key];
296
+ delete togglableAlignmentAnnotationSettings[key];
297
+ });
298
+
299
+ aminoAcidAnnotations.forEach(key => {
300
+ alignmentAnnotationVisibility[key] = false;
301
+ togglableAlignmentAnnotationSettings[key] = false;
302
+ });
303
+
304
+ if (isPairwise) {
305
+ noNeededAnnotationsForPairwise.forEach(key => {
306
+ delete alignmentAnnotationVisibility[key];
307
+ delete togglableAlignmentAnnotationSettings[key];
308
+ });
309
+ }
310
+ } else {
311
+ aminoAcidAnnotations.forEach(key => {
312
+ delete alignmentAnnotationVisibility[key];
313
+ delete togglableAlignmentAnnotationSettings[key];
314
+ });
315
+ }
316
+ // eslint-disable-next-line react-hooks/exhaustive-deps
317
+ }, [alignmentTracks, isPairwise]);
318
+
248
319
  const maxLength = useMemo(() => {
249
320
  const { sequenceData = { sequence: "" }, alignmentData } =
250
321
  alignmentTracks[0];
@@ -393,6 +464,13 @@ export const AlignmentView = props => {
393
464
  )
394
465
  };
395
466
  callback(callbackVals);
467
+
468
+ setPropertySidePanel(prev => {
469
+ return {
470
+ ...prev,
471
+ selection: easyStore.current.selectionLayer
472
+ };
473
+ });
396
474
  },
397
475
  [
398
476
  caretPositionUpdate,
@@ -606,7 +684,12 @@ export const AlignmentView = props => {
606
684
  });
607
685
  };
608
686
 
609
- const renderItem = (_i, key, isTemplate, cloneProps) => {
687
+ const aminoAcidAlignmentProperties = useMemo(() => {
688
+ if (isPairwise || !alignmentTracks[0].sequenceData.isProtein) return;
689
+ return getAlignedAminoAcidSequenceProps(alignmentTracks);
690
+ }, [alignmentTracks, isPairwise]);
691
+
692
+ const renderItem = (_i, _key, isTemplate, cloneProps) => {
610
693
  const isDragDisabled = !allowTrackRearrange || isPairwise;
611
694
  let i;
612
695
  if (isTemplate) {
@@ -653,12 +736,36 @@ export const AlignmentView = props => {
653
736
  className: "tg-trimmed-region",
654
737
  color: "gray"
655
738
  }));
739
+
740
+ const trackIdentifier = track?.sequenceData.id ? "id" : "hash";
741
+ const selectedTrack = propertySidePanel?.track;
742
+ const isTrackSelected =
743
+ selectedTrack?.sequenceData[trackIdentifier] ===
744
+ track?.sequenceData[trackIdentifier];
745
+
746
+ let aaIdentity;
747
+ let aaIdenticalPosition;
748
+ if (sequenceData.isProtein && !isPairwise) {
749
+ aaIdentity = aminoAcidAlignmentProperties?.matrix?.[0]?.[i]?.toFixed(1);
750
+ aaIdenticalPosition =
751
+ aminoAcidAlignmentProperties?.identicalPositions?.[i - 1]
752
+ ?.identicalPositions;
753
+
754
+ if (sequenceData.name === "Consensus") {
755
+ sequenceData.aminoAcidProperties =
756
+ isPairwise || !sequenceData.isProtein
757
+ ? null
758
+ : aminoAcidAlignmentProperties;
759
+ }
760
+ }
761
+
656
762
  const innerRenderItem = (provided = {}, snapshot) => (
657
763
  <div
658
764
  ref={provided?.innerRef}
659
765
  {...provided?.draggableProps}
660
766
  className={classNames("alignmentViewTrackContainer", {
661
- isDragDisabled
767
+ isDragDisabled,
768
+ isTrackSelected
662
769
  })}
663
770
  data-alignment-track-index={i}
664
771
  style={{
@@ -670,6 +777,16 @@ export const AlignmentView = props => {
670
777
  ...(snapshot?.isDragging && { left: unset })
671
778
  }}
672
779
  key={i}
780
+ onClick={() => {
781
+ setPropertySidePanel(prev => {
782
+ return {
783
+ ...prev,
784
+ selection: easyStore.current.selectionLayer,
785
+ track,
786
+ isPairwise
787
+ };
788
+ });
789
+ }}
673
790
  >
674
791
  <div
675
792
  className="alignmentTrackName"
@@ -792,7 +909,21 @@ export const AlignmentView = props => {
792
909
  TRIMMED
793
910
  </span>
794
911
  )}
795
- {sequenceData.sequence.length} bps
912
+ {sequenceData.isProtein ? (
913
+ <>
914
+ <span>{sequenceData.proteinSequence.length} AAs</span>
915
+ {!compactNames && i > 0 && !isPairwise && (
916
+ <>
917
+ <br />
918
+ <span>Identical Positions: {aaIdenticalPosition}</span>
919
+ <br />
920
+ <span>Identity: {aaIdentity}%</span>
921
+ </>
922
+ )}
923
+ </>
924
+ ) : (
925
+ <span>{sequenceData.sequence.length} bps</span>
926
+ )}
796
927
  </div>
797
928
  </div>
798
929
  <HorizontalPanelDragHandle
@@ -801,7 +932,6 @@ export const AlignmentView = props => {
801
932
  }}
802
933
  />
803
934
  </div>
804
-
805
935
  {handleSelectTrack && !isTemplate && (
806
936
  <div
807
937
  onClick={() => {
@@ -1111,7 +1241,16 @@ export const AlignmentView = props => {
1111
1241
  return "corrupted data!";
1112
1242
  }
1113
1243
 
1114
- const getTrackVis = (alignmentTracks, isTemplate, allTracks) => {
1244
+ const getTrackVis = (
1245
+ alignmentTracks,
1246
+ isTemplate,
1247
+ allTracks,
1248
+ aminoAcidAlignmentProperties,
1249
+ labileSites
1250
+ ) => {
1251
+ const labilePositions =
1252
+ aminoAcidAlignmentProperties?.labileSites.sites.map(ls => ls.position) ||
1253
+ [];
1115
1254
  const rowData = {};
1116
1255
  const innerTrackVis = (drop_provided, drop_snapshot) => {
1117
1256
  return (
@@ -1324,6 +1463,13 @@ export const AlignmentView = props => {
1324
1463
  row={{ start: 0, end: maxLength - 1 }}
1325
1464
  easyStore={easyStore.current}
1326
1465
  />
1466
+ {labileSites && labilePositions.length > 0 && (
1467
+ <LabileSitesLayer
1468
+ leftMargin={nameDivWidth}
1469
+ charWidth={charWidth}
1470
+ positionsToMark={labilePositions}
1471
+ />
1472
+ )}
1327
1473
  {isTemplate ? (
1328
1474
  renderItem(0, 0, isTemplate)
1329
1475
  ) : (
@@ -1409,279 +1555,338 @@ export const AlignmentView = props => {
1409
1555
  updateLabelsForInViewFeatures();
1410
1556
  }
1411
1557
  };
1558
+
1559
+ const { labileSites } =
1560
+ alignmentVisibilityToolOptions.alignmentAnnotationVisibility;
1561
+
1412
1562
  return (
1413
1563
  <PinchHelper {...pinchHandler}>
1414
- <ResizeSensor onResize={handleResize}>
1415
- <div
1416
- style={{
1417
- height: height || (isPairwise ? "auto" : viewportHeight * 0.88),
1418
- display: "flex",
1419
- flexDirection: "column",
1420
- justifyContent: "space-between",
1421
- position: "relative",
1422
- overflowY: "auto",
1423
- ...style
1424
- // borderTop: "1px solid black"
1425
- }}
1426
- className="alignmentView"
1427
- >
1428
- <DragDropContext
1429
- onDragStart={onTrackDragStart}
1430
- onDragEnd={onTrackDragEnd}
1564
+ <div
1565
+ style={{
1566
+ display: "flex",
1567
+ flexDirection: "row"
1568
+ }}
1569
+ >
1570
+ <ResizeSensor onResize={handleResize}>
1571
+ <div
1572
+ style={{
1573
+ height: height || (isPairwise ? "auto" : viewportHeight * 0.88),
1574
+ width: "100%",
1575
+ display: "flex",
1576
+ flexDirection: "column",
1577
+ justifyContent: "space-between",
1578
+ position: "relative",
1579
+ overflowY: "auto",
1580
+ ...style
1581
+ // borderTop: "1px solid black"
1582
+ }}
1583
+ className="alignmentView"
1431
1584
  >
1432
- <div
1433
- style={{
1434
- display: "flex",
1435
- flexDirection: "column",
1436
- position: "relative",
1437
- overflowY: "auto"
1438
- }}
1439
- className="alignmentView-top-container"
1585
+ <DragDropContext
1586
+ onDragStart={onTrackDragStart}
1587
+ onDragEnd={onTrackDragEnd}
1440
1588
  >
1441
1589
  <div
1442
1590
  style={{
1443
- paddingTop: "3px",
1444
- paddingBottom: "5px",
1445
- borderBottom: "1px solid",
1446
1591
  display: "flex",
1447
- minHeight: "32px",
1592
+ flexDirection: "column",
1593
+ position: "relative",
1448
1594
  width: "100%",
1449
- flexWrap: "nowrap",
1450
- flexDirection: "row",
1451
- flex: "0 0 auto"
1595
+ overflowY: "auto"
1452
1596
  }}
1453
- className="ve-alignment-top-bar"
1597
+ className="alignmentView-top-container"
1454
1598
  >
1455
- {additionalTopLeftEl}
1456
- {handleBackButtonClicked && (
1457
- <Tooltip content="Back to Pairwise Alignment Overview">
1458
- <Button
1459
- icon="arrow-left"
1460
- onClick={() => {
1461
- handleBackButtonClicked();
1462
- caretPositionUpdate(-1);
1599
+ <div
1600
+ style={{
1601
+ paddingTop: "3px",
1602
+ paddingBottom: "5px",
1603
+ borderBottom: "1px solid",
1604
+ display: "flex",
1605
+ minHeight: "32px",
1606
+ width: "100%",
1607
+ flexWrap: "nowrap",
1608
+ flexDirection: "row",
1609
+ flex: "0 0 auto"
1610
+ }}
1611
+ className="ve-alignment-top-bar"
1612
+ >
1613
+ {additionalTopLeftEl}
1614
+ {handleBackButtonClicked && (
1615
+ <Tooltip content="Back to Pairwise Alignment Overview">
1616
+ <Button
1617
+ icon="arrow-left"
1618
+ onClick={() => {
1619
+ handleBackButtonClicked();
1620
+ caretPositionUpdate(-1);
1621
+ }}
1622
+ small
1623
+ intent={Intent.PRIMARY}
1624
+ minimal
1625
+ style={{ marginRight: 10 }}
1626
+ className="alignmentViewBackButton"
1627
+ />
1628
+ </Tooltip>
1629
+ )}
1630
+
1631
+ <div style={{ display: "flex" }}>
1632
+ <EditableText
1633
+ disabled={!handleAlignmentRename}
1634
+ onChange={v => {
1635
+ setAlignmentName(v);
1463
1636
  }}
1464
- small
1465
- intent={Intent.PRIMARY}
1466
- minimal
1467
- style={{ marginRight: 10 }}
1468
- className="alignmentViewBackButton"
1637
+ maxLength={399} //stop the name from being tooo long
1638
+ value={alignmentName}
1639
+ onConfirm={async v => {
1640
+ if (!v) {
1641
+ setAlignmentName(_alignmentName);
1642
+ return;
1643
+ }
1644
+ if (v === _alignmentName) {
1645
+ return; //already saved this name
1646
+ }
1647
+ setSaveMessage("Alignment Renaming..");
1648
+ setSaveMessageLoading(true);
1649
+ await handleAlignmentRename(v, props);
1650
+ setSaveMessage("Rename Successful");
1651
+ setSaveMessageLoading(false);
1652
+ setTimeout(() => {
1653
+ setSaveMessage(undefined);
1654
+ setSaveMessageLoading(false);
1655
+ }, 5000);
1656
+ }}
1657
+ selectAllOnFocus={true}
1658
+ className="veAlignmentName"
1469
1659
  />
1470
- </Tooltip>
1471
- )}
1660
+ &nbsp;&nbsp;&nbsp;
1661
+ <div
1662
+ className="veAlignmentType"
1663
+ style={{
1664
+ paddingTop: "3px",
1665
+ fontSize: "14px",
1666
+ color: "grey",
1667
+ maxWidth: "300px",
1668
+ overflow: "hidden",
1669
+ textOverflow: "ellipsis",
1670
+ whiteSpace: "nowrap"
1671
+ }}
1672
+ data-title={alignmentType || "Unknown Alignment Type"}
1673
+ >
1674
+ {alignmentType || "Unknown Alignment Type"}
1675
+ </div>
1676
+ </div>
1472
1677
 
1473
- <div style={{ display: "flex" }}>
1474
- <EditableText
1475
- disabled={!handleAlignmentRename}
1476
- onChange={v => {
1477
- setAlignmentName(v);
1478
- }}
1479
- maxLength={399} //stop the name from being tooo long
1480
- value={alignmentName}
1481
- onConfirm={async v => {
1482
- if (!v) {
1483
- setAlignmentName(_alignmentName);
1484
- return;
1678
+ {unmappedSeqs && (
1679
+ <InfoHelper
1680
+ size={20}
1681
+ content={
1682
+ <div>
1683
+ This alignment had sequences that did not map to the
1684
+ template sequence:
1685
+ {unmappedSeqs.map(({ sequenceData }, i) => (
1686
+ <div key={i}>{sequenceData.name}</div>
1687
+ ))}
1688
+ </div>
1485
1689
  }
1486
- if (v === _alignmentName) {
1487
- return; //already saved this name
1690
+ intent="warning"
1691
+ icon="warning-sign"
1692
+ />
1693
+ )}
1694
+ {!isInPairwiseOverviewView && (
1695
+ <UncontrolledSliderWithPlusMinusBtns
1696
+ noWraparound
1697
+ bindOutsideChangeHelper={bindOutsideChangeHelper.current}
1698
+ onClick={() => {
1699
+ setTimeout(scrollToCaret, 0);
1700
+ }}
1701
+ minCharWidth={getMinCharWidth()}
1702
+ onChange={async zoomLvl => {
1703
+ isZooming.current = true;
1704
+ setTimeout(() => {
1705
+ isZooming.current = false;
1706
+ }, 10);
1707
+ // zoomLvl is in the range of 0 to 10
1708
+ const minCharWidth = getMinCharWidth();
1709
+ const scaleFactor = Math.pow(12 / minCharWidth, 1 / 10);
1710
+ const newCharWidth =
1711
+ minCharWidth * Math.pow(scaleFactor, zoomLvl);
1712
+ await setCharWidthInLinearView({
1713
+ charWidthInLinearView: newCharWidth
1714
+ });
1715
+ await scrollToCaret();
1716
+ await updateLabelsForInViewFeatures({
1717
+ rectElement: ".alignmentHolder"
1718
+ });
1719
+ }}
1720
+ coerceInitialValue={coerceInitialValue}
1721
+ title="Adjust Zoom Level"
1722
+ style={{ paddingTop: "4px", width: 100 }}
1723
+ className="veZoomAlignmentSlider ove-slider"
1724
+ labelRenderer={false}
1725
+ initialValue={charWidth}
1726
+ stepSize={0.05} //was 0.01
1727
+ max={10}
1728
+ min={0}
1729
+ clickStepSize={0.5}
1730
+ />
1731
+ )}
1732
+ {!noVisibilityOptions && !isInPairwiseOverviewView && (
1733
+ <AlignmentVisibilityTool
1734
+ currentPairwiseAlignmentIndex={
1735
+ currentPairwiseAlignmentIndex
1488
1736
  }
1489
- setSaveMessage("Alignment Renaming..");
1490
- setSaveMessageLoading(true);
1491
- await handleAlignmentRename(v, props);
1492
- setSaveMessage("Rename Successful");
1493
- setSaveMessageLoading(false);
1494
- setTimeout(() => {
1495
- setSaveMessage(undefined);
1496
- setSaveMessageLoading(false);
1497
- }, 5000);
1498
- }}
1499
- selectAllOnFocus={true}
1500
- className="veAlignmentName"
1501
- />
1502
- &nbsp;&nbsp;&nbsp;
1503
- <div
1504
- className="veAlignmentType"
1505
- style={{
1506
- paddingTop: "3px",
1507
- fontSize: "14px",
1508
- color: "grey",
1509
- maxWidth: "300px",
1510
- overflow: "hidden",
1511
- textOverflow: "ellipsis",
1512
- whiteSpace: "nowrap"
1513
- }}
1514
- data-title={alignmentType || "Unknown Alignment Type"}
1515
- >
1516
- {alignmentType || "Unknown Alignment Type"}
1517
- </div>
1518
- </div>
1519
-
1520
- {unmappedSeqs && (
1521
- <InfoHelper
1522
- size={20}
1523
- content={
1524
- <div>
1525
- This alignment had sequences that did not map to the
1526
- template sequence:
1527
- {unmappedSeqs.map(({ sequenceData }, i) => (
1528
- <div key={i}>{sequenceData.name}</div>
1529
- ))}
1530
- </div>
1531
- }
1532
- intent="warning"
1533
- icon="warning-sign"
1534
- />
1535
- )}
1536
- {!isInPairwiseOverviewView && (
1537
- <UncontrolledSliderWithPlusMinusBtns
1538
- noWraparound
1539
- bindOutsideChangeHelper={bindOutsideChangeHelper.current}
1540
- onClick={() => {
1541
- setTimeout(scrollToCaret, 0);
1542
- }}
1543
- minCharWidth={getMinCharWidth()}
1544
- onChange={async zoomLvl => {
1545
- isZooming.current = true;
1546
- setTimeout(() => {
1547
- isZooming.current = false;
1548
- }, 10);
1549
- // zoomLvl is in the range of 0 to 10
1550
- const minCharWidth = getMinCharWidth();
1551
- const scaleFactor = Math.pow(12 / minCharWidth, 1 / 10);
1552
- const newCharWidth =
1553
- minCharWidth * Math.pow(scaleFactor, zoomLvl);
1554
- await setCharWidthInLinearView({
1555
- charWidthInLinearView: newCharWidth
1556
- });
1557
- await scrollToCaret();
1558
- await updateLabelsForInViewFeatures({
1559
- rectElement: ".alignmentHolder"
1560
- });
1561
- }}
1562
- coerceInitialValue={coerceInitialValue}
1563
- title="Adjust Zoom Level"
1564
- style={{ paddingTop: "4px", width: 100 }}
1565
- className="veZoomAlignmentSlider ove-slider"
1566
- labelRenderer={false}
1567
- initialValue={charWidth}
1568
- stepSize={0.05} //was 0.01
1569
- max={10}
1570
- min={0}
1571
- clickStepSize={0.5}
1572
- />
1573
- )}
1574
- {!noVisibilityOptions && !isInPairwiseOverviewView && (
1575
- <AlignmentVisibilityTool
1576
- currentPairwiseAlignmentIndex={
1577
- currentPairwiseAlignmentIndex
1578
- }
1579
- {...alignmentVisibilityToolOptions}
1580
- />
1581
- )}
1582
- {additionalTopEl}
1583
- {saveMessage && (
1584
- <div
1585
- className="ove-menu-toast"
1586
- style={{
1587
- display: "flex",
1588
- alignItems: "center",
1589
- marginLeft: "auto",
1590
- marginRight: 10
1591
- }}
1592
- >
1593
- {saveMessageLoading ? (
1594
- <div>
1595
- <Spinner size={15}></Spinner>
1596
- </div>
1597
- ) : (
1598
- <Icon icon="tick-circle" intent="success"></Icon>
1599
- )}{" "}
1600
- &nbsp;
1601
- {saveMessage}
1602
- </div>
1603
- )}
1604
- </div>
1605
- {hasTemplate ? (
1606
- <>
1607
- <div className="alignmentTrackFixedToTop">
1608
- {getTrackVis([firstTrack], true, alignmentTracks)}
1609
- </div>
1610
- {getTrackVis(otherTracks, false, alignmentTracks)}
1611
- </>
1612
- ) : (
1613
- getTrackVis(alignmentTracks, false, alignmentTracks)
1614
- )}
1615
- </div>
1616
- </DragDropContext>
1617
- {!isInPairwiseOverviewView && (
1618
- <div
1619
- className="alignmentViewBottomBar"
1620
- style={{
1621
- // flexGrow: 1,
1622
- // minHeight: "-webkit-min-content", //https://stackoverflow.com/questions/28029736/how-to-prevent-a-flex-item-from-shrinking-smaller-than-its-content
1623
- maxHeight: 210,
1624
- marginTop: 4,
1625
- paddingTop: 4,
1626
- borderTop: "1px solid lightgrey",
1627
- display: "flex"
1628
- }}
1629
- >
1630
- <Minimap
1631
- selectionLayerComp={
1632
- <>
1633
- <PerformantSelectionLayer
1634
- is
1635
- hideCarets
1636
- className="veAlignmentSelectionLayer veMinimapSelectionLayer"
1637
- easyStore={easyStore.current}
1638
- sequenceLength={maxLength}
1639
- charWidth={getMinCharWidth(true)}
1640
- row={{ start: 0, end: maxLength - 1 }}
1737
+ {...alignmentVisibilityToolOptions}
1641
1738
  />
1642
- <PerformantCaret
1739
+ )}
1740
+ {additionalTopEl}
1741
+ {saveMessage && (
1742
+ <div
1743
+ className="ove-menu-toast"
1643
1744
  style={{
1644
- opacity: 0.2
1745
+ display: "flex",
1746
+ alignItems: "center",
1747
+ marginLeft: "auto",
1748
+ marginRight: 10
1645
1749
  }}
1646
- className="veAlignmentSelectionLayer veMinimapSelectionLayer"
1647
- sequenceLength={maxLength}
1648
- charWidth={getMinCharWidth(true)}
1649
- row={{ start: 0, end: maxLength - 1 }}
1650
- easyStore={easyStore.current}
1651
- />
1750
+ >
1751
+ {saveMessageLoading ? (
1752
+ <div>
1753
+ <Spinner size={15}></Spinner>
1754
+ </div>
1755
+ ) : (
1756
+ <Icon icon="tick-circle" intent="success"></Icon>
1757
+ )}{" "}
1758
+ &nbsp;
1759
+ {saveMessage}
1760
+ </div>
1761
+ )}
1762
+ {!propertySidePanel.isOpen && (
1763
+ <Button
1764
+ small
1765
+ minimal
1766
+ className={"showTrackPropertiesBtn"}
1767
+ icon={"menu-closed"}
1768
+ intent="primary"
1769
+ style={{ marginLeft: "auto" }}
1770
+ onClick={() => {
1771
+ setPropertySidePanel(prev => {
1772
+ return {
1773
+ ...prev,
1774
+ isOpen: true
1775
+ };
1776
+ });
1777
+ }}
1778
+ data-tip={"Show Track Properties"}
1779
+ ></Button>
1780
+ )}
1781
+ </div>
1782
+ {hasTemplate ? (
1783
+ <>
1784
+ <div className="alignmentTrackFixedToTop">
1785
+ {getTrackVis(
1786
+ [firstTrack],
1787
+ true,
1788
+ alignmentTracks,
1789
+ aminoAcidAlignmentProperties,
1790
+ labileSites
1791
+ )}
1792
+ </div>
1793
+ {getTrackVis(
1794
+ otherTracks,
1795
+ false,
1796
+ alignmentTracks,
1797
+ aminoAcidAlignmentProperties,
1798
+ labileSites
1799
+ )}
1652
1800
  </>
1653
- }
1654
- alignmentTracks={alignmentTracks}
1655
- dimensions={{
1656
- width: Math.max(width, 10) || 10
1801
+ ) : (
1802
+ getTrackVis(
1803
+ alignmentTracks,
1804
+ false,
1805
+ alignmentTracks,
1806
+ aminoAcidAlignmentProperties,
1807
+ labileSites
1808
+ )
1809
+ )}
1810
+ </div>
1811
+ </DragDropContext>
1812
+ {!isInPairwiseOverviewView && (
1813
+ <div
1814
+ className="alignmentViewBottomBar"
1815
+ style={{
1816
+ // flexGrow: 1,
1817
+ // minHeight: "-webkit-min-content", //https://stackoverflow.com/questions/28029736/how-to-prevent-a-flex-item-from-shrinking-smaller-than-its-content
1818
+ maxHeight: 210,
1819
+ marginTop: 4,
1820
+ paddingTop: 4,
1821
+ borderTop: "1px solid lightgrey",
1822
+ display: "flex"
1657
1823
  }}
1658
- nameDivOffsetPercent={0}
1659
- scrollYToTrack={scrollYToTrack}
1660
- onSizeAdjust={onMinimapSizeAdjust}
1661
- minSliderSize={minSliderSize}
1662
- laneHeight={
1663
- minimapLaneHeight || (alignmentTracks.length > 5 ? 10 : 17)
1664
- }
1665
- laneSpacing={
1666
- minimapLaneSpacing || (alignmentTracks.length > 5 ? 2 : 1)
1667
- }
1668
- easyStore={easyStore.current}
1669
- numBpsShownInLinearView={getNumBpsShownInLinearView()}
1670
- scrollAlignmentView={false}
1671
- onMinimapScrollX={scrollAlignmentToPercent}
1672
- />
1673
- </div>
1674
- )}
1675
- <GlobalDialog
1676
- // {...pickedUserDefinedHandlersAndOpts}
1677
- // dialogOverrides={pick(this.props, [
1678
- // "AddOrEditFeatureDialogOverride",
1679
- // "AddOrEditPartDialogOverride",
1680
- // "AddOrEditPrimerDialogOverride"
1681
- // ])}
1824
+ >
1825
+ <Minimap
1826
+ selectionLayerComp={
1827
+ <>
1828
+ <PerformantSelectionLayer
1829
+ is
1830
+ hideCarets
1831
+ className="veAlignmentSelectionLayer veMinimapSelectionLayer"
1832
+ easyStore={easyStore.current}
1833
+ sequenceLength={maxLength}
1834
+ charWidth={getMinCharWidth(true)}
1835
+ row={{ start: 0, end: maxLength - 1 }}
1836
+ />
1837
+ <PerformantCaret
1838
+ style={{
1839
+ opacity: 0.2
1840
+ }}
1841
+ className="veAlignmentSelectionLayer veMinimapSelectionLayer"
1842
+ sequenceLength={maxLength}
1843
+ charWidth={getMinCharWidth(true)}
1844
+ row={{ start: 0, end: maxLength - 1 }}
1845
+ easyStore={easyStore.current}
1846
+ />
1847
+ </>
1848
+ }
1849
+ alignmentTracks={alignmentTracks}
1850
+ dimensions={{
1851
+ width: Math.max(width, 10) || 10
1852
+ }}
1853
+ nameDivOffsetPercent={0}
1854
+ scrollYToTrack={scrollYToTrack}
1855
+ onSizeAdjust={onMinimapSizeAdjust}
1856
+ minSliderSize={minSliderSize}
1857
+ laneHeight={
1858
+ minimapLaneHeight || (alignmentTracks.length > 5 ? 10 : 17)
1859
+ }
1860
+ laneSpacing={
1861
+ minimapLaneSpacing || (alignmentTracks.length > 5 ? 2 : 1)
1862
+ }
1863
+ easyStore={easyStore.current}
1864
+ numBpsShownInLinearView={getNumBpsShownInLinearView()}
1865
+ scrollAlignmentView={false}
1866
+ onMinimapScrollX={scrollAlignmentToPercent}
1867
+ />
1868
+ </div>
1869
+ )}
1870
+ <GlobalDialog
1871
+ // {...pickedUserDefinedHandlersAndOpts}
1872
+ // dialogOverrides={pick(this.props, [
1873
+ // "AddOrEditFeatureDialogOverride",
1874
+ // "AddOrEditPartDialogOverride",
1875
+ // "AddOrEditPrimerDialogOverride"
1876
+ // ])}
1877
+ />
1878
+ </div>
1879
+ </ResizeSensor>
1880
+ {propertySidePanel.isOpen && (
1881
+ <PropertySidePanel
1882
+ properties={propertySidePanel}
1883
+ setProperties={setPropertySidePanel}
1884
+ style={{
1885
+ height: viewportHeight * 0.88
1886
+ }}
1682
1887
  />
1683
- </div>
1684
- </ResizeSensor>
1888
+ )}
1889
+ </div>
1685
1890
  </PinchHelper>
1686
1891
  );
1687
1892
  };
@@ -1737,6 +1942,20 @@ export default compose(
1737
1942
  "cdsFeatureTranslations",
1738
1943
  "chromatogram",
1739
1944
  "dnaColors",
1945
+ "physicalProperties",
1946
+ "serineThreonine",
1947
+ "labileSites",
1948
+ "colorScheme",
1949
+ "plot",
1950
+ "conservation",
1951
+ "properties",
1952
+ "hydrophobicity",
1953
+ "polar",
1954
+ "negative",
1955
+ "positive",
1956
+ "charged",
1957
+ "aliphatic",
1958
+ "aromatic",
1740
1959
  "compactNames"
1741
1960
  ];
1742
1961
  const togglableAlignmentAnnotationSettings = {};