@teselagen/ove 0.7.28 → 0.7.30-beta.1

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 (301) hide show
  1. package/CreateAnnotationsPage.d.ts +4 -3
  2. package/README.md +1 -1
  3. package/fileUtils.d.ts +12 -0
  4. package/html2canvas.esm--JN4fLQL.js +7891 -0
  5. package/html2canvas.esm-B7d7VJmQ.cjs +7891 -0
  6. package/index.cjs.js +1305 -1121
  7. package/index.es.js +1305 -1121
  8. package/index.umd.js +189161 -0
  9. package/ove.css +17 -4
  10. package/package.json +5 -9
  11. package/redux/findTool.d.ts +1 -0
  12. package/selectors/searchLayersSelector.d.ts +1 -1
  13. package/src/AutoAnnotate.js +1 -1
  14. package/src/CreateAnnotationsPage.js +1 -2
  15. package/src/Editor/style.css +8 -3
  16. package/src/FindBar/index.js +32 -1
  17. package/src/RowItem/SelectionLayer/index.js +42 -4
  18. package/src/RowItem/SelectionLayer/style.css +8 -0
  19. package/src/fileUtils.js +103 -0
  20. package/src/helperComponents/PropertiesDialog/TranslationProperties.js +1 -1
  21. package/src/redux/findTool.js +9 -0
  22. package/src/selectors/searchLayersSelector.js +40 -2
  23. package/style.css +12098 -1
  24. package/AASliver.js +0 -187
  25. package/AddLaddersDialog.js +0 -82
  26. package/AdditionalCutsiteInfoDialog.js +0 -599
  27. package/AlignmentVisibilityTool.js +0 -105
  28. package/AnnotationContainerHolder.js +0 -20
  29. package/AnnotationPositioner.js +0 -27
  30. package/AutoAnnotate.js +0 -501
  31. package/AutoAnnotateBpMatchingDialog.js +0 -208
  32. package/Axis.js +0 -151
  33. package/AxisNumbers.js +0 -35
  34. package/Browser.js +0 -106
  35. package/Caret.js +0 -63
  36. package/Chromatogram.js +0 -293
  37. package/CircularDnaSequence.js +0 -73
  38. package/CircularZoomMinimap.js +0 -16
  39. package/ColorPicker.js +0 -30
  40. package/CommandHotkeyHandler.js +0 -44
  41. package/CreateAnnotationsPage.js +0 -98
  42. package/Cutsite.js +0 -18
  43. package/CutsiteProperties.js +0 -176
  44. package/CutsiteSelectionLayers.js +0 -47
  45. package/Cutsites.js +0 -271
  46. package/DeletionLayer.js +0 -28
  47. package/DropHandler.css +0 -21
  48. package/DropHandler.js +0 -64
  49. package/EditCaretPosition.js +0 -234
  50. package/EditTrackNameDialog.js +0 -30
  51. package/Feature.js +0 -83
  52. package/FeatureProperties.js +0 -6
  53. package/FillWindow.js +0 -47
  54. package/GenbankView.js +0 -74
  55. package/GeneralProperties.js +0 -117
  56. package/GenericAnnotationProperties.js +0 -406
  57. package/GlobalDialog.js +0 -73
  58. package/GlobalDialogUtils.js +0 -110
  59. package/GoToDialog.js +0 -25
  60. package/HorizontalPanelDragHandle.js +0 -35
  61. package/Keyboard.js +0 -85
  62. package/Labels.js +0 -327
  63. package/Ladder.css +0 -20
  64. package/Ladder.js +0 -303
  65. package/MeltingTemp.js +0 -85
  66. package/Menlo.ttf +0 -0
  67. package/Minimap.js +0 -515
  68. package/Mismatches.js +0 -134
  69. package/Monaco.ttf +0 -0
  70. package/MultipleSeqsDetectedOnImportDialog.js +0 -74
  71. package/Orf.js +0 -109
  72. package/OrfProperties.js +0 -117
  73. package/Orfs.js +0 -35
  74. package/PCRTool.js +0 -179
  75. package/PairwiseAlignmentView.js +0 -68
  76. package/Part.js +0 -34
  77. package/PartProperties.js +0 -9
  78. package/PassThrough.js +0 -3
  79. package/PerformantSelectionLayer.js +0 -32
  80. package/PinchHelper.js +0 -24
  81. package/PointedAnnotation.js +0 -347
  82. package/PositionAnnotationOnCircle.js +0 -26
  83. package/Primer.js +0 -41
  84. package/PrimerProperties.js +0 -19
  85. package/ReflexContainer.js +0 -802
  86. package/ReflexElement.js +0 -160
  87. package/ReflexEvents.js +0 -77
  88. package/ReflexSplitter.js +0 -205
  89. package/RenameSequenceDialog.js +0 -7
  90. package/RotateCircularViewSlider.js +0 -93
  91. package/SelectDialog.js +0 -150
  92. package/SequenceName.js +0 -15
  93. package/SimpleCircularOrLinearView.js +0 -381
  94. package/SimpleOligoPreview.js +0 -39
  95. package/SingleEnzymeCutsiteInfo.js +0 -139
  96. package/ToolbarItem.js +0 -192
  97. package/Translation.js +0 -198
  98. package/TranslationProperties.js +0 -149
  99. package/UncontrolledSliderWithPlusMinusBtns.css +0 -5
  100. package/UncontrolledSliderWithPlusMinusBtns.js +0 -134
  101. package/VeTopRightContainer.js +0 -12
  102. package/ZoomCircularViewSlider.js +0 -62
  103. package/ZoomLinearView.js +0 -47
  104. package/addAlignment.js +0 -6
  105. package/addMetaToActionCreators.js +0 -12
  106. package/addWrappedAddons.js +0 -20
  107. package/alignmentTool.js +0 -503
  108. package/alignments.js +0 -379
  109. package/annotationLabelVisibility.js +0 -2
  110. package/annotationSearchSelector.js +0 -24
  111. package/annotationTypes.js +0 -35
  112. package/annotationVisibility.js +0 -196
  113. package/annotationsToSupport.js +0 -104
  114. package/arrayToObjWithIds.js +0 -17
  115. package/arrayUtils.js +0 -19
  116. package/array_move.js +0 -10
  117. package/calculateTickMarkPositionsForGivenRange.js +0 -47
  118. package/caretPosition.js +0 -27
  119. package/cdsFeaturesSelector.js +0 -9
  120. package/charWidth.js +0 -22
  121. package/circular.js +0 -19
  122. package/circularSelector.js +0 -4
  123. package/clickAndDragUtils.js +0 -576
  124. package/coerceInitialValue.js +0 -7
  125. package/combineReducersDontIgnoreKeys.js +0 -12
  126. package/commandUtils.js +0 -20
  127. package/constants.js +0 -2
  128. package/copyOptions.js +0 -34
  129. package/createFragmentLines.js +0 -120
  130. package/createMergedDefaultStateReducer.js +0 -30
  131. package/createMetaAction.js +0 -12
  132. package/createSequenceInputPopup.js +0 -290
  133. package/createSequenceInputPopupStyle.css +0 -87
  134. package/createSimpleDialog.js +0 -89
  135. package/createYourOwnEnzyme.js +0 -39
  136. package/cutsiteLabelColorSelector.js +0 -6
  137. package/cutsiteTool.js +0 -88
  138. package/cutsitesByRangeSelector.js +0 -5
  139. package/cutsitesSelector.js +0 -61
  140. package/darkmode.css +0 -98
  141. package/defaultConfig.js +0 -150
  142. package/deletionLayers.js +0 -36
  143. package/description.js +0 -21
  144. package/digestTool.js +0 -34
  145. package/dnaToColor.js +0 -17
  146. package/downloadTool.js +0 -39
  147. package/draggableClassnames.js +0 -5
  148. package/drawAnnotations.js +0 -440
  149. package/drawDirectedPiePiece.js +0 -142
  150. package/editTool.js +0 -49
  151. package/editorSelector.js +0 -2
  152. package/editorUtils.js +0 -205
  153. package/estimateRowHeight.js +0 -184
  154. package/featureLengthsToHide.js +0 -27
  155. package/featureTool.js +0 -34
  156. package/features.js +0 -19
  157. package/featuresSelector.js +0 -8
  158. package/filteredCutsitesSelector.js +0 -136
  159. package/filteredFeaturesSelector.js +0 -32
  160. package/filteredPartsSelector.js +0 -57
  161. package/filteredPrimersSelector.js +0 -27
  162. package/filteredRestrictionEnzymesSelector.js +0 -1
  163. package/find.png +0 -0
  164. package/findTool.js +0 -79
  165. package/findToolConstants.js +0 -1
  166. package/frameTranslations.js +0 -52
  167. package/fullscreen.png +0 -0
  168. package/getAdditionalEnzymesSelector.js +0 -46
  169. package/getAngleForPositionMidpoint.js +0 -3
  170. package/getAnnotationClassnames.js +0 -12
  171. package/getAnnotationNameAndStartStopString.js +0 -61
  172. package/getBpsPerRow.js +0 -19
  173. package/getCutsiteLabelHeights.js +0 -56
  174. package/getGapMap.js +0 -12
  175. package/getGaps.js +0 -27
  176. package/getInternalLabel.js +0 -40
  177. package/getOveHotkeyDefs.js +0 -12
  178. package/getPairwiseOverviewLinearViewOptions.js +0 -38
  179. package/getRangeAnglesSpecial.js +0 -12
  180. package/getStructuredBases.js +0 -97
  181. package/getTrackFromEvent.js +0 -25
  182. package/getVisibleStartEnd.js +0 -7
  183. package/getXStartAndWidthFromNonCircularRange.js +0 -12
  184. package/getXStartAndWidthOfRangeWrtRow.js +0 -27
  185. package/getXStartAndWidthOfRowAnnotation.js +0 -19
  186. package/getYOffset.js +0 -15
  187. package/hoveredAnnotation.js +0 -24
  188. package/importTool.js +0 -27
  189. package/index.js +0 -71
  190. package/inlineFindTool.js +0 -38
  191. package/isElementInViewport.js +0 -29
  192. package/isEnzymeFilterAndSelector.js +0 -1
  193. package/isTargetWithinEl.js +0 -6
  194. package/labelLineIntensity.js +0 -25
  195. package/labelSize.js +0 -23
  196. package/ladderDefaults.js +0 -25
  197. package/lastSavedId.js +0 -20
  198. package/lineageLines.js +0 -11
  199. package/linear.png +0 -0
  200. package/makeStore.js +0 -34
  201. package/massageTickSpacing.js +0 -19
  202. package/materiallyAvailable.js +0 -19
  203. package/middleware.js +0 -112
  204. package/minimumOrfSize.js +0 -24
  205. package/minimumOrfSizeSelector.js +0 -2
  206. package/modalActions.js +0 -3
  207. package/moveCaret.js +0 -58
  208. package/name.js +0 -19
  209. package/normalizeAngle.js +0 -3
  210. package/normalizeAngleRange.js +0 -9
  211. package/oligoTool.js +0 -30
  212. package/onlyUpdateForKeysDeep.js +0 -31
  213. package/orfFrameToColorMap.js +0 -10
  214. package/orfTool.js +0 -136
  215. package/orfsSelector.js +0 -15
  216. package/panelsShown.js +0 -294
  217. package/partLengthsToHide.js +0 -23
  218. package/partOverhangs.js +0 -6
  219. package/partTagSearch.js +0 -69
  220. package/partTool.js +0 -45
  221. package/parts.js +0 -19
  222. package/partsSelector.js +0 -8
  223. package/pie.png +0 -0
  224. package/polarToSpecialCartesian.js +0 -7
  225. package/positionCutsites.js +0 -6
  226. package/prepareRowData.js +0 -64
  227. package/primerBases.js +0 -221
  228. package/primerLengthsToHide.js +0 -27
  229. package/primers.js +0 -19
  230. package/primersSelector.js +0 -8
  231. package/print.png +0 -0
  232. package/printTool.js +0 -31
  233. package/propertiesTool.js +0 -40
  234. package/proteinUtils.js +0 -3
  235. package/pureNoFunc.js +0 -18
  236. package/readOnly.js +0 -25
  237. package/redoTool.js +0 -30
  238. package/reflex-styles.css +0 -128
  239. package/reflex-styles.css.map +0 -9
  240. package/relaxLabelAngles.js +0 -157
  241. package/relaxLabels_DEPRECATED.js +0 -105
  242. package/replacementLayers.js +0 -36
  243. package/restrictionEnzymes.js +0 -52
  244. package/restrictionEnzymesSelector.js +0 -34
  245. package/rowviewContants.js +0 -3
  246. package/ruler.css +0 -89
  247. package/save.png +0 -0
  248. package/saveTool.js +0 -44
  249. package/searchLayersSelector.js +0 -71
  250. package/selectedAnnotations.js +0 -89
  251. package/selectedAnnotationsSelector.js +0 -1
  252. package/selectedCutsitesSelector.js +0 -21
  253. package/selectedPartTags.js +0 -21
  254. package/selectionLayer.js +0 -25
  255. package/sequence.js +0 -12
  256. package/sequenceDataHistory.js +0 -43
  257. package/sequenceDataSelector.js +0 -2
  258. package/sequenceLengthSelector.js +0 -5
  259. package/sequenceSelector.js +0 -4
  260. package/sharedActionCreators.js +0 -0
  261. package/shouldFlipText.js +0 -4
  262. package/shouldRerender.js +0 -27
  263. package/showFileDialog.js +0 -25
  264. package/showGCContent.js +0 -23
  265. package/show_cut_sites.png +0 -0
  266. package/show_features.png +0 -0
  267. package/show_orfs.png +0 -0
  268. package/show_primers.png +0 -0
  269. package/simpleDialog.css +0 -13
  270. package/specialCutsiteFilterOptions.js +0 -22
  271. package/tagsToBoldSelector.js +0 -2
  272. package/toggle_views.svg +0 -1
  273. package/toolBar.js +0 -23
  274. package/translationSearchMatchesSelector.js +0 -14
  275. package/translations.js +0 -20
  276. package/translationsRawSelector.js +0 -8
  277. package/translationsSelector.js +0 -137
  278. package/typeField.js +0 -24
  279. package/undoTool.js +0 -30
  280. package/updateEditor.js +0 -200
  281. package/updateLabelsForInViewFeatures.js +0 -55
  282. package/updateLabelsForInViewFeaturesCircView.js +0 -41
  283. package/updateTrackHelper.js +0 -58
  284. package/uppercaseSequenceMapFont.js +0 -25
  285. package/upsertDeleteActionGenerator.js +0 -31
  286. package/useAAColorType.js +0 -8
  287. package/useAdditionalOrfStartCodons.js +0 -24
  288. package/useAnnotationLimits.js +0 -42
  289. package/useChromatogramPrefs.js +0 -31
  290. package/useFormValue.js +0 -7
  291. package/useLadders.js +0 -6
  292. package/useMeltingTemp.js +0 -7
  293. package/useTmType.js +0 -10
  294. package/userDefinedHandlersAndOpts.js +0 -61
  295. package/utils.js +0 -37
  296. package/versionHistory.js +0 -26
  297. package/versionHistoryTool.js +0 -21
  298. package/viewSubmenu.js +0 -479
  299. package/visibilityTool.js +0 -39
  300. package/withHover.js +0 -113
  301. package/withRestrictionEnzymes.js +0 -15
package/ove.css CHANGED
@@ -9676,7 +9676,7 @@ body:not(.drag-active)
9676
9676
  display: flex;
9677
9677
  flex-wrap: wrap;
9678
9678
  align-items: center;
9679
- margin-top: 20px;
9679
+ margin-top: 10px;
9680
9680
  }
9681
9681
 
9682
9682
  .ReactTable {
@@ -10689,6 +10689,14 @@ li.bp3-menu-divider:last-child {
10689
10689
  top: -2px;
10690
10690
  position: absolute;
10691
10691
  z-index: 10;
10692
+ display: flex;
10693
+ align-items: center;
10694
+ justify-content: center;
10695
+ font-family: monospace;
10696
+ }
10697
+
10698
+ .veMismatchLayer {
10699
+ z-index: 11; /* Ensure mismatch layers appear on top of normal selection layer */
10692
10700
  }
10693
10701
 
10694
10702
  .veCaret {
@@ -11847,9 +11855,14 @@ path.partWithSelectedTag {
11847
11855
  border-right-color: yellow !important;
11848
11856
  }
11849
11857
  .veSearchLayerActive {
11850
- stroke: red !important;
11851
- fill: red !important;
11852
- background: red !important;
11858
+ stroke: green !important;
11859
+ fill: green !important;
11860
+ background: green !important;
11861
+ }
11862
+ .veMismatchedBase {
11863
+ color: red !important;
11864
+ font-weight: bold;
11865
+ background-color: rgba(255, 0, 0, 0.3);
11853
11866
  }
11854
11867
  .notCaret.veSearchLayerBottomStrand:after {
11855
11868
  content: "";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@teselagen/ove",
3
- "version": "0.7.28",
3
+ "version": "0.7.30-beta.1",
4
4
  "main": "./src/index.js",
5
5
  "type": "module",
6
6
  "exports": {
@@ -11,11 +11,11 @@
11
11
  "./*": "./*"
12
12
  },
13
13
  "dependencies": {
14
- "@teselagen/sequence-utils": "0.3.31",
15
- "@teselagen/range-utils": "0.3.13",
16
- "@teselagen/ui": "0.8.6",
14
+ "@teselagen/sequence-utils": "0.3.32-beta.1",
15
+ "@teselagen/range-utils": "0.3.14-beta.1",
16
+ "@teselagen/ui": "0.8.6-beta.24",
17
17
  "@teselagen/file-utils": "0.3.20",
18
- "@teselagen/bio-parsers": "0.4.28",
18
+ "@teselagen/bio-parsers": "0.4.29-beta.1",
19
19
  "@blueprintjs/core": "3.54.0",
20
20
  "@hello-pangea/dnd": "16.2.0",
21
21
  "@risingstack/react-easy-state": "^6.3.0",
@@ -62,10 +62,6 @@
62
62
  "biomsa": "^0.2.4",
63
63
  "shortid": "2.2.16",
64
64
  "@use-gesture/react": "10.3.0",
65
- "vite": "^5.2.11",
66
- "@vitejs/plugin-react": "^4.3.0",
67
- "vite-plugin-libcss": "^1.1.1",
68
- "vite-tsconfig-paths": "^4.3.2",
69
65
  "@playwright/test": "^1.44.1"
70
66
  },
71
67
  "license": "MIT"
@@ -4,6 +4,7 @@ export const toggleIsInline: import('redux-act').ComplexActionCreator1<any, any,
4
4
  export const updateSearchText: import('redux-act').ComplexActionCreator1<any, any, any>;
5
5
  export const updateAmbiguousOrLiteral: import('redux-act').ComplexActionCreator1<any, any, any>;
6
6
  export const updateDnaOrAA: import('redux-act').ComplexActionCreator1<any, any, any>;
7
+ export const updateMismatchesAllowed: import('redux-act').ComplexActionCreator1<any, any, any>;
7
8
  export const updateMatchNumber: import('redux-act').ComplexActionCreator1<any, any, any>;
8
9
  declare const _default: {
9
10
  (newState: {} | undefined, action: any): any;
@@ -1,4 +1,4 @@
1
- declare const _default: ((state: any) => any[]) & import('reselect').OutputSelectorFields<(args_0: any, args_1: any, args_2: any, args_3: any, args_4: any, args_5: any, args_6: any, args_7: any) => any[], {
1
+ declare const _default: ((state: any) => any[]) & import('reselect').OutputSelectorFields<(args_0: any, args_1: any, args_2: any, args_3: any, args_4: any, args_5: any, args_6: any, args_7: any, args_8: any) => any[], {
2
2
  clearCache: () => void;
3
3
  }> & {
4
4
  clearCache: () => void;
@@ -33,7 +33,7 @@ import {
33
33
  } from "@teselagen/ui";
34
34
  import { startCase } from "lodash-es";
35
35
  import withEditorProps from "./withEditorProps";
36
- import { useEffect, useState } from "react";
36
+ import React, { useEffect, useState } from "react";
37
37
  import { Colors, Tab, Tabs } from "@blueprintjs/core";
38
38
  import { typeField } from "./helperComponents/PropertiesDialog/typeField";
39
39
 
@@ -1,6 +1,5 @@
1
1
  import { compose } from "redux";
2
2
  import pluralize from "pluralize";
3
-
4
3
  import { formName } from "./constants";
5
4
  import { typeField } from "./helperComponents/PropertiesDialog/typeField";
6
5
  import {
@@ -9,7 +8,7 @@ import {
9
8
  withSelectTableRecords,
10
9
  withSelectedEntities
11
10
  } from "@teselagen/ui";
12
- import { useEffect } from "react";
11
+ import React, { useEffect } from "react";
13
12
  import { hideDialog } from "./GlobalDialogUtils";
14
13
  import { startCase } from "lodash-es";
15
14
  import { tidyUpAnnotation } from "@teselagen/sequence-utils";
@@ -89,9 +89,14 @@
89
89
  border-right-color: yellow !important;
90
90
  }
91
91
  .veSearchLayerActive {
92
- stroke: red !important;
93
- fill: red !important;
94
- background: red !important;
92
+ stroke: green !important;
93
+ fill: green !important;
94
+ background: green !important;
95
+ }
96
+ .veMismatchedBase {
97
+ color: red !important;
98
+ font-weight: bold;
99
+ background-color: rgba(255, 0, 0, 0.3);
95
100
  }
96
101
  .notCaret.veSearchLayerBottomStrand:after {
97
102
  content: "";
@@ -6,7 +6,8 @@ import {
6
6
  Popover,
7
7
  Position,
8
8
  TextArea,
9
- Tooltip
9
+ Tooltip,
10
+ NumericInput
10
11
  } from "@blueprintjs/core";
11
12
  import withEditorProps from "../withEditorProps";
12
13
  import { MAX_MATCHES_DISPLAYED } from "../constants/findToolConstants";
@@ -50,6 +51,7 @@ export class FindBar extends React.Component {
50
51
  annotationVisibilityShow,
51
52
  updateAmbiguousOrLiteral,
52
53
  updateDnaOrAA,
54
+ updateMismatchesAllowed,
53
55
  updateMatchNumber: _updateMatchNumber,
54
56
  selectionLayerUpdate,
55
57
  annotationSearchMatches,
@@ -63,6 +65,7 @@ export class FindBar extends React.Component {
63
65
  ambiguousOrLiteral,
64
66
  matchesTotal = 0,
65
67
  matchNumber = 0,
68
+ mismatchesAllowed = 0,
66
69
  isInline
67
70
  } = findTool;
68
71
  const updateMatchNumber = (...args) => {
@@ -139,6 +142,33 @@ export class FindBar extends React.Component {
139
142
  </div>
140
143
  </InfoHelper>
141
144
  </div>,
145
+ <div
146
+ key="mismatchesAllowed"
147
+ style={{ marginTop: "8px", display: "flex", alignItems: "center" }}
148
+ >
149
+ <label style={{ marginRight: "8px" }}>Mismatches Allowed:</label>
150
+ <NumericInput
151
+ min={0}
152
+ max={10}
153
+ className={"tg-mismatches-allowed-input"}
154
+ style={{ width: "60px" }}
155
+ value={mismatchesAllowed}
156
+ disabled={dnaOrAA !== "DNA" || ambiguousOrLiteral !== "LITERAL"}
157
+ onValueChange={value => {
158
+ const newValue = Math.max(0, parseInt(value, 10) || 0);
159
+ updateMismatchesAllowed(newValue);
160
+ }}
161
+ />
162
+ <InfoHelper style={{ marginLeft: 10 }}>
163
+ <div>
164
+ Number of mismatches allowed when searching DNA sequences with
165
+ literal matching.
166
+ <br />
167
+ <br />
168
+ Higher values may slow down search performance.
169
+ </div>
170
+ </InfoHelper>
171
+ </div>,
142
172
  <Switch
143
173
  key="highlightall"
144
174
  checked={highlightAll}
@@ -152,6 +182,7 @@ export class FindBar extends React.Component {
152
182
  Highlight All
153
183
  </Tooltip>
154
184
  </Switch>,
185
+
155
186
  ...(isMobile()
156
187
  ? []
157
188
  : [
@@ -149,7 +149,8 @@ function SelectionLayer(props) {
149
149
  )
150
150
  ];
151
151
  }
152
- return [
152
+ // Create base selection layer element
153
+ const selectionElement = (
153
154
  <div
154
155
  onClick={_onClick}
155
156
  title={selectionMessage}
@@ -168,9 +169,46 @@ function SelectionLayer(props) {
168
169
  background: color || topLevelColor,
169
170
  height
170
171
  }}
171
- />,
172
- ...caretSvgs
173
- ];
172
+ ></div>
173
+ );
174
+
175
+ // Generate mismatch sub-regions if mismatchPositions exist
176
+ let mismatchElements = [];
177
+ if (
178
+ selectionLayer.mismatchPositions &&
179
+ selectionLayer.mismatchPositions.length > 0
180
+ ) {
181
+ // Calculate relative mismatch positions within this overlap
182
+ const relativeToOverlap = selectionLayer.mismatchPositions
183
+ .filter(pos => {
184
+ // Adjust position based on overlap's relation to the original selection layer
185
+ const absPos = pos + selectionLayer.start;
186
+ return absPos >= overlap.start && absPos <= overlap.end;
187
+ })
188
+ .map(pos => {
189
+ // Convert to position relative to this overlap segment
190
+ return pos - (overlap.start - selectionLayer.start);
191
+ });
192
+
193
+ // Create a red highlight for each mismatch position
194
+ mismatchElements = relativeToOverlap.map((pos, i) => (
195
+ <div
196
+ key={`${key}-mismatch-${i}`}
197
+ className="veSelectionLayer veMismatchLayer notCaret"
198
+ style={{
199
+ width: charWidth,
200
+ left: leftMargin + xStart + pos * charWidth,
201
+ top: 0,
202
+ height: height || "100%",
203
+ background: "red",
204
+ position: "absolute",
205
+ opacity: 0.5
206
+ }}
207
+ ></div>
208
+ ));
209
+ }
210
+
211
+ return [selectionElement, ...mismatchElements, ...caretSvgs];
174
212
  });
175
213
  } else {
176
214
  return null;
@@ -6,6 +6,14 @@
6
6
  top: -2px;
7
7
  position: absolute;
8
8
  z-index: 10;
9
+ display: flex;
10
+ align-items: center;
11
+ justify-content: center;
12
+ font-family: monospace;
13
+ }
14
+
15
+ .veMismatchLayer {
16
+ z-index: 11; /* Ensure mismatch layers appear on top of normal selection layer */
9
17
  }
10
18
 
11
19
  .veCaret {
@@ -0,0 +1,103 @@
1
+ /* Copyright (C) 2018 TeselaGen Biotechnology, Inc. */
2
+ import { parse } from "papaparse";
3
+
4
+ export const allowedCsvFileTypes = [".csv", ".txt", ".xlsx"];
5
+
6
+ export const isZipFile = file => {
7
+ const type = file.mimetype || file.type;
8
+ return type === "application/zip" || type === "application/x-zip-compressed";
9
+ };
10
+
11
+ export const getExt = file => file.name.split(".").pop();
12
+ export const isExcelFile = file => getExt(file) === "xlsx";
13
+ export const isCsvFile = file => getExt(file) === "csv";
14
+ export const isTextFile = file => ["text", "txt"].includes(getExt(file));
15
+
16
+ const defaultCsvParserOptions = {
17
+ header: true,
18
+ skipEmptyLines: "greedy",
19
+ trimHeaders: true
20
+ // delimiter: ","
21
+ };
22
+
23
+ export const parseCsvFile = (csvFile, parserOptions = {}) => {
24
+ return new Promise((resolve, reject) => {
25
+ parse(csvFile.originFileObj, {
26
+ ...defaultCsvParserOptions,
27
+ complete: results => {
28
+ if (results && results.errors && results.errors.length) {
29
+ return reject("Error in csv: " + JSON.stringify(results.errors));
30
+ }
31
+ resolve(results);
32
+ },
33
+ error: error => {
34
+ reject(error);
35
+ },
36
+ ...parserOptions
37
+ });
38
+ });
39
+ };
40
+
41
+ export const parseCsvString = (csvString, parserOptions = {}) => {
42
+ return parse(csvString, { ...defaultCsvParserOptions, ...parserOptions });
43
+ };
44
+
45
+ export const cleanCommaSeparatedCell = cellData =>
46
+ (cellData || "")
47
+ .split(",")
48
+ .map(n => n.trim())
49
+ .filter(n => n);
50
+
51
+ /**
52
+ * Because the csv rows might not have the same header keys in some cases (extended properties)
53
+ * this function will make sure that each row will have all headers so that the export
54
+ * does not drop fields
55
+ * @param {*} rows
56
+ */
57
+ export const cleanCsvExport = rows => {
58
+ const allHeaders = [];
59
+ rows.forEach(row => {
60
+ Object.keys(row).forEach(header => {
61
+ if (!allHeaders.includes(header)) {
62
+ allHeaders.push(header);
63
+ }
64
+ });
65
+ });
66
+ rows.forEach(row => {
67
+ allHeaders.forEach(header => {
68
+ row[header] = row[header] || "";
69
+ });
70
+ });
71
+ return rows;
72
+ };
73
+
74
+ export const validateCSVRequiredHeaders = (
75
+ fields,
76
+ requiredHeaders,
77
+ filename
78
+ ) => {
79
+ const missingRequiredHeaders = requiredHeaders.filter(field => {
80
+ return !fields.includes(field);
81
+ });
82
+ if (missingRequiredHeaders.length) {
83
+ const name = filename ? `The file ${filename}` : "CSV file";
84
+ return `${name} is missing required headers. (${missingRequiredHeaders.join(
85
+ ", "
86
+ )})`;
87
+ }
88
+ };
89
+
90
+ export const validateCSVRow = (row, requiredHeaders, index) => {
91
+ const missingRequiredFields = requiredHeaders.filter(field => !row[field]);
92
+ if (missingRequiredFields.length) {
93
+ if (missingRequiredFields.length === 1) {
94
+ return `Row ${index + 1} is missing the required field "${
95
+ missingRequiredFields[0]
96
+ }"`;
97
+ } else {
98
+ return `Row ${
99
+ index + 1
100
+ } is missing these required fields: ${missingRequiredFields.join(", ")}`;
101
+ }
102
+ }
103
+ };
@@ -45,7 +45,7 @@ class TranslationProperties extends React.Component {
45
45
  let aaString = "";
46
46
  for (let i = 0; i < translation.aminoAcids.length; i++) {
47
47
  // sometimes the `translation.aminoAcids[i].aminoAcid` is null
48
- aaString += translation.aminoAcids[i].aminoAcid?.value || '';
48
+ aaString += translation.aminoAcids[i].aminoAcid?.value || "";
49
49
  }
50
50
  return {
51
51
  ...translation,
@@ -13,6 +13,7 @@ export const updateAmbiguousOrLiteral = createAction(
13
13
  "updateAmbiguousOrLiteral"
14
14
  );
15
15
  export const updateDnaOrAA = createAction("updateDnaOrAA");
16
+ export const updateMismatchesAllowed = createAction("updateMismatchesAllowed");
16
17
  export const updateMatchNumber = createAction("updateMatchNumber");
17
18
 
18
19
  // ------------------------------------
@@ -53,6 +54,13 @@ export default createMergedDefaultStateReducer(
53
54
  dnaOrAA: payload
54
55
  };
55
56
  },
57
+ [updateMismatchesAllowed]: (state, payload) => {
58
+ return {
59
+ ...state,
60
+ matchNumber: 0,
61
+ mismatchesAllowed: payload
62
+ };
63
+ },
56
64
  [updateSearchText]: (state, payload) => {
57
65
  return {
58
66
  ...state,
@@ -74,6 +82,7 @@ export default createMergedDefaultStateReducer(
74
82
  dnaOrAA: "DNA",
75
83
  ambiguousOrLiteral: "LITERAL",
76
84
  highlightAll: false,
85
+ mismatchesAllowed: 0,
77
86
  matchNumber: 0
78
87
  }
79
88
  );
@@ -1,4 +1,7 @@
1
- import { findSequenceMatches } from "@teselagen/sequence-utils";
1
+ import {
2
+ findSequenceMatches,
3
+ findApproxMatches
4
+ } from "@teselagen/sequence-utils";
2
5
  import sequenceSelector from "./sequenceSelector";
3
6
  import { createSelector } from "reselect";
4
7
  import circularSelector from "./circularSelector";
@@ -11,7 +14,8 @@ function searchLayersSelector(
11
14
  ambiguousOrLiteral,
12
15
  dnaOrAA,
13
16
  isProtein,
14
- proteinSequence
17
+ proteinSequence,
18
+ mismatchesAllowed
15
19
  ) {
16
20
  if (!searchString || !isOpen) {
17
21
  return [];
@@ -40,6 +44,39 @@ function searchLayersSelector(
40
44
  end: end * 3 + 2
41
45
  }));
42
46
  }
47
+
48
+ // Use findApproxMatches when literal matching DNA with mismatches allowed
49
+ if (
50
+ dnaOrAA === "DNA" &&
51
+ ambiguousOrLiteral === "LITERAL" &&
52
+ mismatchesAllowed > 0
53
+ ) {
54
+ const approxMatches = findApproxMatches(
55
+ searchString,
56
+ sequence,
57
+ mismatchesAllowed,
58
+ isCircular
59
+ );
60
+ // Convert approximate matches to the format expected by the application
61
+ const matches = approxMatches
62
+ .map(match => ({
63
+ start: match.index,
64
+ end: match.index + match.match.length - 1,
65
+ matchedString: match.match,
66
+ mismatchPositions: match.mismatchPositions,
67
+ numMismatches: match.numMismatches,
68
+ isSearchLayer: true,
69
+ forward: true
70
+ }))
71
+ .sort((a, b) => a.start - b.start);
72
+
73
+ return matches.map(match => ({
74
+ ...match,
75
+ className: "veSearchLayer"
76
+ }));
77
+ }
78
+
79
+ // Use regular findSequenceMatches for all other cases
43
80
  const matches = findSequenceMatches(sequence, searchString, {
44
81
  isCircular,
45
82
  isAmbiguous: ambiguousOrLiteral === "AMBIGUOUS",
@@ -67,5 +104,6 @@ export default createSelector(
67
104
  state => state.findTool && state.findTool.dnaOrAA,
68
105
  state => state.sequenceData.isProtein,
69
106
  state => state.sequenceData.proteinSequence,
107
+ state => state.findTool && state.findTool.mismatchesAllowed,
70
108
  searchLayersSelector
71
109
  );