@teselagen/ove 0.3.11 → 0.3.13
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.
- package/index.js +529 -422
- package/index.mjs +530 -423
- package/index.umd.js +532 -402
- package/package.json +2 -2
- package/src/AlignmentView/AlignmentVisibilityTool.js +1 -1
- package/src/AlignmentView/EditTrackNameDialog.js +1 -5
- package/src/AlignmentView/HorizontalPanelDragHandle.js +2 -2
- package/src/AlignmentView/Minimap.js +12 -12
- package/src/AlignmentView/PairwiseAlignmentView.js +1 -1
- package/src/AlignmentView/getGapMap.js +1 -1
- package/src/AlignmentView/getTrackFromEvent.js +1 -1
- package/src/AlignmentView/index.js +32 -37
- package/src/AutoAnnotate.js +48 -48
- package/src/CircularView/Cutsites.js +3 -3
- package/src/CircularView/Labels/index.js +7 -7
- package/src/CircularView/Labels/relaxLabels_DEPRECATED.js +5 -5
- package/src/CircularView/RotateCircularViewSlider.js +1 -1
- package/src/CircularView/SelectionLayer.js +2 -2
- package/src/CircularView/drawAnnotations.js +3 -3
- package/src/CircularView/getAngleForPositionMidpoint.js +1 -1
- package/src/CircularView/index.d.ts +11 -11
- package/src/CircularView/index.js +9 -9
- package/src/CreateAnnotationsPage.js +7 -5
- package/src/CreateCustomEnzyme/index.js +1 -5
- package/src/CutsiteFilter/AdditionalCutsiteInfoDialog.js +11 -11
- package/src/CutsiteFilter/index.js +12 -12
- package/src/DigestTool/AddLaddersDialog.js +1 -1
- package/src/DigestTool/DigestTool.js +3 -3
- package/src/DigestTool/Ladder.js +8 -8
- package/src/DigestTool/ladderDefaults.js +1 -2
- package/src/Editor/CommandHotkeyHandler.js +1 -1
- package/src/Editor/DropHandler.js +2 -2
- package/src/Editor/index.js +15 -15
- package/src/Editor/userDefinedHandlersAndOpts.js +3 -1
- package/src/FindBar/index.js +6 -6
- package/src/GlobalDialogUtils.js +6 -0
- package/src/LinearView/ZoomLinearView.js +1 -1
- package/src/LinearView/index.js +7 -7
- package/src/MenuBar/index.js +1 -1
- package/src/MenuBar/viewSubmenu.js +1 -1
- package/src/PCRTool/PCRTool.js +19 -19
- package/src/Reflex/Browser.js +4 -5
- package/src/Reflex/ReflexContainer.js +3 -3
- package/src/Reflex/ReflexElement.js +2 -2
- package/src/RowItem/Axis.js +1 -1
- package/src/RowItem/Caret/index.js +1 -1
- package/src/RowItem/Chromatograms/Chromatogram.js +3 -3
- package/src/RowItem/CutsiteSelectionLayers.js +1 -1
- package/src/RowItem/Cutsites.js +1 -1
- package/src/RowItem/Labels.js +2 -2
- package/src/RowItem/Orfs.js +2 -2
- package/src/RowItem/Sequence.js +4 -4
- package/src/RowItem/StackedAnnotations/PointedAnnotation.js +3 -3
- package/src/RowItem/StackedAnnotations/getStructuredBases.js +1 -1
- package/src/RowItem/Translations/AASliver.js +71 -75
- package/src/RowItem/Translations/index.js +1 -1
- package/src/RowItem/getCutsiteLabelHeights.js +1 -1
- package/src/RowItem/index.js +14 -8
- package/src/RowView/estimateRowHeight.js +5 -5
- package/src/RowView/index.d.ts +7 -7
- package/src/RowView/index.js +11 -12
- package/src/SimpleCircularOrLinearView.js +6 -6
- package/src/StatusBar/MeltingTemp.js +3 -3
- package/src/StatusBar/index.js +29 -33
- package/src/ToolBar/ToolbarItem.js +2 -2
- package/src/ToolBar/alignmentTool.js +9 -9
- package/src/ToolBar/editTool.js +41 -37
- package/src/ToolBar/findTool.js +2 -2
- package/src/ToolBar/importTool.js +1 -1
- package/src/ToolBar/index.js +2 -2
- package/src/ToolBar/oligoTool.js +1 -1
- package/src/ToolBar/orfTool.js +1 -6
- package/src/ToolBar/printTool.js +2 -2
- package/src/ToolBar/visibilityTool.js +1 -1
- package/src/VersionHistoryView/index.js +2 -2
- package/src/commands/index.js +237 -230
- package/src/createVectorEditor/index.js +4 -4
- package/src/fileUtils.js +18 -18
- package/src/helperComponents/AddOrEditAnnotationDialog/index.js +22 -15
- package/src/helperComponents/AddOrEditFeatureDialog/index.js +2 -2
- package/src/helperComponents/AddOrEditPartDialog/index.js +2 -2
- package/src/helperComponents/AddOrEditPrimerDialog/index.js +5 -5
- package/src/helperComponents/EnzymesDialog/index.js +17 -22
- package/src/helperComponents/GoToDialog.js +5 -1
- package/src/helperComponents/MergeFeaturesDialog/index.js +3 -3
- package/src/helperComponents/PinchHelper/PinchHelper.js +1 -1
- package/src/helperComponents/PrintDialog/index.js +4 -4
- package/src/helperComponents/PropertiesDialog/CutsiteProperties.js +3 -3
- package/src/helperComponents/PropertiesDialog/GenbankView.js +1 -1
- package/src/helperComponents/PropertiesDialog/GeneralProperties.js +10 -8
- package/src/helperComponents/PropertiesDialog/GenericAnnotationProperties.js +136 -138
- package/src/helperComponents/PropertiesDialog/OrfProperties.js +3 -3
- package/src/helperComponents/PropertiesDialog/PrimerProperties.js +1 -1
- package/src/helperComponents/PropertiesDialog/TranslationProperties.js +2 -2
- package/src/helperComponents/PropertiesDialog/index.js +3 -3
- package/src/helperComponents/RemoveDuplicates/index.js +3 -3
- package/src/helperComponents/SelectDialog.js +3 -3
- package/src/helperComponents/UncontrolledSliderWithPlusMinusBtns.js +5 -5
- package/src/helperComponents/createSimpleDialog.js +1 -1
- package/src/helperComponents/partTagSearch.js +2 -5
- package/src/helperComponents/withHover.js +3 -3
- package/src/redux/alignments.js +6 -6
- package/src/redux/annotationVisibility.js +4 -4
- package/src/redux/featureLengthsToHide.js +1 -1
- package/src/redux/frameTranslations.js +3 -3
- package/src/redux/middleware.js +2 -2
- package/src/redux/panelsShown.js +19 -19
- package/src/redux/partLengthsToHide.js +1 -1
- package/src/redux/primerLengthsToHide.js +1 -1
- package/src/redux/readOnly.js +1 -4
- package/src/redux/selectionLayer.js +1 -1
- package/src/redux/sequenceData/features.js +1 -1
- package/src/redux/sequenceData/upsertDeleteActionGenerator.js +1 -1
- package/src/redux/sequenceDataHistory.js +5 -5
- package/src/redux/toolBar.js +2 -4
- package/src/redux/utils/createMetaAction.js +2 -2
- package/src/redux/versionHistory.js +1 -2
- package/src/selectors/annotationSearchSelector.js +4 -4
- package/src/selectors/circularSelector.js +1 -1
- package/src/selectors/cutsiteLabelColorSelector.js +1 -1
- package/src/selectors/filteredCutsitesSelector.js +6 -6
- package/src/selectors/filteredFeaturesSelector.js +4 -4
- package/src/selectors/filteredPartsSelector.js +5 -5
- package/src/selectors/filteredPrimersSelector.js +3 -3
- package/src/selectors/isEnzymeFilterAndSelector.js +1 -1
- package/src/selectors/orfsSelector.js +1 -1
- package/src/selectors/restrictionEnzymesSelector.js +2 -2
- package/src/selectors/searchLayersSelector.js +7 -7
- package/src/selectors/sequenceLengthSelector.js +1 -1
- package/src/selectors/sequenceSelector.js +1 -1
- package/src/selectors/tagsToBoldSelector.js +1 -1
- package/src/selectors/translationsSelector.js +7 -7
- package/src/updateEditor.js +1 -1
- package/src/utils/PassThrough.js +1 -1
- package/src/utils/addWrappedAddons.js +1 -1
- package/src/utils/annotationTypes.js +2 -2
- package/src/utils/combineReducersDontIgnoreKeys.js +1 -1
- package/src/utils/editorUtils.js +2 -2
- package/src/utils/massageTickSpacing.js +1 -1
- package/src/utils/onlyUpdateForKeysDeep.js +1 -1
- package/src/utils/pureNoFunc.js +1 -1
- package/src/utils/shouldRerender.js +1 -1
- package/src/utils/showFileDialog.js +6 -7
- package/src/utils/updateLabelsForInViewFeatures.js +1 -1
- package/src/utils/useAnnotationLimits.js +1 -1
- package/src/withEditorInteractions/Keyboard.js +2 -3
- package/src/withEditorInteractions/createSequenceInputPopup.js +4 -4
- package/src/withEditorInteractions/index.js +93 -55
- package/src/withEditorProps/index.js +39 -37
- package/style.css +138 -138
package/src/AutoAnnotate.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
/* eslint-disable no-throw-literal */
|
|
4
4
|
import { unparse } from "papaparse";
|
|
5
5
|
import pluralize from "pluralize";
|
|
6
|
-
import
|
|
6
|
+
import { SubmissionError, reduxForm } from "redux-form";
|
|
7
7
|
import shortid from "shortid";
|
|
8
8
|
import CreateAnnotationsPage from "./CreateAnnotationsPage";
|
|
9
9
|
import { formName } from "./constants";
|
|
@@ -11,7 +11,7 @@ import { AutoAnnotateBpMatchingDialog } from "./AutoAnnotateBpMatchingDialog";
|
|
|
11
11
|
import {
|
|
12
12
|
parseCsvFile,
|
|
13
13
|
validateCSVRequiredHeaders,
|
|
14
|
-
validateCSVRow
|
|
14
|
+
validateCSVRow
|
|
15
15
|
} from "./fileUtils";
|
|
16
16
|
import downloadjs from "downloadjs";
|
|
17
17
|
import {
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
convertApELikeRegexToRegex,
|
|
20
20
|
convertProteinSeqToDNAIupac,
|
|
21
21
|
getFeatureToColorMap,
|
|
22
|
-
getFeatureTypes
|
|
22
|
+
getFeatureTypes
|
|
23
23
|
} from "@teselagen/sequence-utils";
|
|
24
24
|
import { hideDialog, showDialog } from "./GlobalDialogUtils";
|
|
25
25
|
import { compose } from "redux";
|
|
@@ -29,7 +29,7 @@ import {
|
|
|
29
29
|
FileUploadField,
|
|
30
30
|
InfoHelper,
|
|
31
31
|
showConfirmationDialog,
|
|
32
|
-
wrapDialog
|
|
32
|
+
wrapDialog
|
|
33
33
|
} from "@teselagen/ui";
|
|
34
34
|
import { startCase } from "lodash";
|
|
35
35
|
import withEditorProps from "./withEditorProps";
|
|
@@ -41,41 +41,41 @@ export function autoAnnotateFeatures() {
|
|
|
41
41
|
showDialog({
|
|
42
42
|
ModalComponent: AutoAnnotateModal, //we want to use a ModalComponent here so our addon does not
|
|
43
43
|
props: {
|
|
44
|
-
annotationType: "feature"
|
|
45
|
-
}
|
|
44
|
+
annotationType: "feature"
|
|
45
|
+
}
|
|
46
46
|
});
|
|
47
47
|
}
|
|
48
48
|
export function autoAnnotateParts() {
|
|
49
49
|
showDialog({
|
|
50
50
|
ModalComponent: AutoAnnotateModal, //we want to use a ModalComponent here so our addon does not
|
|
51
51
|
props: {
|
|
52
|
-
annotationType: "part"
|
|
53
|
-
}
|
|
52
|
+
annotationType: "part"
|
|
53
|
+
}
|
|
54
54
|
});
|
|
55
55
|
}
|
|
56
56
|
export function autoAnnotatePrimers() {
|
|
57
57
|
showDialog({
|
|
58
58
|
ModalComponent: AutoAnnotateModal, //we want to use a ModalComponent here so our addon does not
|
|
59
59
|
props: {
|
|
60
|
-
annotationType: "primer"
|
|
61
|
-
}
|
|
60
|
+
annotationType: "primer"
|
|
61
|
+
}
|
|
62
62
|
});
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
export const AutoAnnotateModal = compose(
|
|
66
|
-
wrapDialog(
|
|
66
|
+
wrapDialog(p => ({
|
|
67
67
|
canEscapeKeyClose: false,
|
|
68
|
-
title: `Auto Annotate ${startCase(pluralize(p.annotationType))}
|
|
68
|
+
title: `Auto Annotate ${startCase(pluralize(p.annotationType))}`
|
|
69
69
|
})),
|
|
70
70
|
withEditorProps,
|
|
71
71
|
reduxForm({ form: formName })
|
|
72
|
-
)(
|
|
72
|
+
)(props => {
|
|
73
73
|
const {
|
|
74
74
|
sequenceData,
|
|
75
75
|
handleSubmit,
|
|
76
76
|
annotationType = "feature",
|
|
77
77
|
error,
|
|
78
|
-
getCustomAutoAnnotateList
|
|
78
|
+
getCustomAutoAnnotateList
|
|
79
79
|
} = props;
|
|
80
80
|
const [fileType, setSelectedImportType] = useState("csvFile");
|
|
81
81
|
const [newAnnotations, setNewAnns] = useState(false);
|
|
@@ -126,31 +126,31 @@ export const AutoAnnotateModal = compose(
|
|
|
126
126
|
description: "I'm a description",
|
|
127
127
|
sequence: `gatNNtacaggttt`,
|
|
128
128
|
...(annotationType === "feature" && {
|
|
129
|
-
type: `cds
|
|
129
|
+
type: `cds`
|
|
130
130
|
}),
|
|
131
131
|
isRegex: false,
|
|
132
|
-
matchType: "dna"
|
|
132
|
+
matchType: "dna"
|
|
133
133
|
},
|
|
134
134
|
{
|
|
135
135
|
name: `Example Protein ${startCase(annotationType)}`,
|
|
136
136
|
description: "I'm a description",
|
|
137
137
|
sequence: `APGSGTGGGSGSAPG`,
|
|
138
138
|
...(annotationType === "feature" && {
|
|
139
|
-
type: `cds
|
|
139
|
+
type: `cds`
|
|
140
140
|
}),
|
|
141
141
|
isRegex: false,
|
|
142
|
-
matchType: "protein"
|
|
142
|
+
matchType: "protein"
|
|
143
143
|
},
|
|
144
144
|
{
|
|
145
145
|
name: `Example ${startCase(annotationType)} 2`,
|
|
146
146
|
description: "I'm another description",
|
|
147
147
|
sequence: `gat.*tacccc.*aggttt`,
|
|
148
148
|
...(annotationType === "feature" && {
|
|
149
|
-
type: `cds
|
|
149
|
+
type: `cds`
|
|
150
150
|
}),
|
|
151
151
|
isRegex: true,
|
|
152
|
-
matchType: "dna"
|
|
153
|
-
}
|
|
152
|
+
matchType: "dna"
|
|
153
|
+
}
|
|
154
154
|
];
|
|
155
155
|
const csv = unparse(rows);
|
|
156
156
|
// const blob = new Blob([convert(sequenceData)], { type: "text/plain" });
|
|
@@ -172,11 +172,11 @@ export const AutoAnnotateModal = compose(
|
|
|
172
172
|
<span style={{ display: "flex" }}>
|
|
173
173
|
isRegex
|
|
174
174
|
<InfoHelper
|
|
175
|
-
onClick={
|
|
175
|
+
onClick={e => {
|
|
176
176
|
e.stopPropagation();
|
|
177
177
|
e.preventDefault();
|
|
178
178
|
showDialog({
|
|
179
|
-
ModalComponent: AutoAnnotateBpMatchingDialog
|
|
179
|
+
ModalComponent: AutoAnnotateBpMatchingDialog
|
|
180
180
|
});
|
|
181
181
|
}}
|
|
182
182
|
content={
|
|
@@ -293,17 +293,17 @@ FRT GAAGTTCCTATTCTCTAGAAAGTATAGGAACTTC misc_recomb orchid pink 0 0`,
|
|
|
293
293
|
|
|
294
294
|
if (annotationType === "feature") {
|
|
295
295
|
const cleanedType = getFeatureTypes().find(
|
|
296
|
-
|
|
296
|
+
t => t.toLowerCase() === type.toLowerCase()
|
|
297
297
|
);
|
|
298
298
|
if (!cleanedType) {
|
|
299
299
|
if (!convertNonStandardTypes) {
|
|
300
300
|
convertNonStandardTypes = await showConfirmationDialog({
|
|
301
301
|
cancelButtonText: "Stop Auto-Annotate",
|
|
302
|
-
text: `Detected that ${rowName} has a non-standard type of ${type}. We will assign it and all subsequent non-standard types to use the misc_feature type instead
|
|
302
|
+
text: `Detected that ${rowName} has a non-standard type of ${type}. We will assign it and all subsequent non-standard types to use the misc_feature type instead`
|
|
303
303
|
});
|
|
304
304
|
if (!convertNonStandardTypes) {
|
|
305
305
|
throw {
|
|
306
|
-
validationError: `${rowName} specifies the feature type ${type} which is not valid
|
|
306
|
+
validationError: `${rowName} specifies the feature type ${type} which is not valid`
|
|
307
307
|
};
|
|
308
308
|
}
|
|
309
309
|
}
|
|
@@ -314,7 +314,7 @@ FRT GAAGTTCCTATTCTCTAGAAAGTATAGGAACTTC misc_recomb orchid pink 0 0`,
|
|
|
314
314
|
}
|
|
315
315
|
if (!sequence) {
|
|
316
316
|
throw {
|
|
317
|
-
validationError: `${rowName} did not have a sequence
|
|
317
|
+
validationError: `${rowName} did not have a sequence`
|
|
318
318
|
};
|
|
319
319
|
}
|
|
320
320
|
if (row.isRegex && row.isRegex.toUpperCase() === "TRUE") {
|
|
@@ -322,7 +322,7 @@ FRT GAAGTTCCTATTCTCTAGAAAGTATAGGAACTTC misc_recomb orchid pink 0 0`,
|
|
|
322
322
|
new RegExp(regexConvertedSeq); //just trying out whether the regexConvertedSeq will work as a valid regex
|
|
323
323
|
} catch (error) {
|
|
324
324
|
throw {
|
|
325
|
-
validationError: `${rowName} has an invalid sequence/regex. Please fix it manually
|
|
325
|
+
validationError: `${rowName} has an invalid sequence/regex. Please fix it manually.`
|
|
326
326
|
};
|
|
327
327
|
}
|
|
328
328
|
row.isRegex = true;
|
|
@@ -336,7 +336,7 @@ FRT GAAGTTCCTATTCTCTAGAAAGTATAGGAACTTC misc_recomb orchid pink 0 0`,
|
|
|
336
336
|
// eslint-disable-next-line no-unused-vars
|
|
337
337
|
i,
|
|
338
338
|
// eslint-disable-next-line no-unused-vars
|
|
339
|
-
{ name, sequence, matchType, type, isRegex }
|
|
339
|
+
{ name, sequence, matchType, type, isRegex }
|
|
340
340
|
] of customAnnResponse.list.entries()) {
|
|
341
341
|
await validateRow(
|
|
342
342
|
{
|
|
@@ -344,7 +344,7 @@ FRT GAAGTTCCTATTCTCTAGAAAGTATAGGAACTTC misc_recomb orchid pink 0 0`,
|
|
|
344
344
|
sequence,
|
|
345
345
|
matchType,
|
|
346
346
|
type,
|
|
347
|
-
isRegex: isRegex ? "TRUE" : "FALSE"
|
|
347
|
+
isRegex: isRegex ? "TRUE" : "FALSE"
|
|
348
348
|
},
|
|
349
349
|
`Row ${i + 1} (${name})`
|
|
350
350
|
);
|
|
@@ -357,12 +357,12 @@ FRT GAAGTTCCTATTCTCTAGAAAGTATAGGAACTTC misc_recomb orchid pink 0 0`,
|
|
|
357
357
|
csvHeaders.push("isRegex");
|
|
358
358
|
const {
|
|
359
359
|
data,
|
|
360
|
-
meta: { fields }
|
|
360
|
+
meta: { fields }
|
|
361
361
|
} = await parseCsvFile(csvFile[0]);
|
|
362
362
|
const error = validateCSVRequiredHeaders(fields, csvHeaders);
|
|
363
363
|
if (error) {
|
|
364
364
|
throw {
|
|
365
|
-
validationError: error
|
|
365
|
+
validationError: error
|
|
366
366
|
};
|
|
367
367
|
}
|
|
368
368
|
|
|
@@ -371,14 +371,14 @@ FRT GAAGTTCCTATTCTCTAGAAAGTATAGGAACTTC misc_recomb orchid pink 0 0`,
|
|
|
371
371
|
const error = validateCSVRow(row, csvHeaders, index);
|
|
372
372
|
if (error) {
|
|
373
373
|
throw {
|
|
374
|
-
validationError: error
|
|
374
|
+
validationError: error
|
|
375
375
|
};
|
|
376
376
|
}
|
|
377
377
|
await validateRow(row, `Row ${index + 1} (${row.name})`);
|
|
378
378
|
}
|
|
379
379
|
} else if (fileType === "apeFile") {
|
|
380
380
|
const { data } = await parseCsvFile(apeFile[0], {
|
|
381
|
-
header: false
|
|
381
|
+
header: false
|
|
382
382
|
});
|
|
383
383
|
// eslint-disable-next-line no-unused-vars
|
|
384
384
|
for (const [i, [name, sequence, type]] of data.entries()) {
|
|
@@ -398,7 +398,7 @@ FRT GAAGTTCCTATTCTCTAGAAAGTATAGGAACTTC misc_recomb orchid pink 0 0`,
|
|
|
398
398
|
);
|
|
399
399
|
}
|
|
400
400
|
const annotationsToCheckById = {};
|
|
401
|
-
annsToCheck.forEach(
|
|
401
|
+
annsToCheck.forEach(ann => {
|
|
402
402
|
if (ann.matchType === "protein") {
|
|
403
403
|
ann.sequence = convertProteinSeqToDNAIupac(ann.sequence);
|
|
404
404
|
}
|
|
@@ -408,26 +408,26 @@ FRT GAAGTTCCTATTCTCTAGAAAGTATAGGAACTTC misc_recomb orchid pink 0 0`,
|
|
|
408
408
|
sequence: ann.isRegex
|
|
409
409
|
? ann.sequence
|
|
410
410
|
: convertApELikeRegexToRegex(ann.sequence),
|
|
411
|
-
id
|
|
411
|
+
id
|
|
412
412
|
};
|
|
413
413
|
});
|
|
414
414
|
|
|
415
415
|
const seqId = "placeholderId";
|
|
416
416
|
const { [seqId]: newAnns } = autoAnnotate({
|
|
417
417
|
seqsToAnnotateById: {
|
|
418
|
-
[seqId]: { ...sequenceData, id: seqId }
|
|
418
|
+
[seqId]: { ...sequenceData, id: seqId }
|
|
419
419
|
},
|
|
420
|
-
annotationsToCheckById
|
|
420
|
+
annotationsToCheckById
|
|
421
421
|
});
|
|
422
422
|
|
|
423
423
|
if (newAnns && newAnns.length) {
|
|
424
424
|
setNewAnns(
|
|
425
|
-
newAnns.map(
|
|
425
|
+
newAnns.map(a => {
|
|
426
426
|
const toRet = {
|
|
427
427
|
...annotationsToCheckById[a.id],
|
|
428
428
|
...a,
|
|
429
429
|
forward: a.strand !== -1,
|
|
430
|
-
id: shortid()
|
|
430
|
+
id: shortid()
|
|
431
431
|
};
|
|
432
432
|
toRet.color =
|
|
433
433
|
toRet.color || getFeatureToColorMap()[toRet.type];
|
|
@@ -469,32 +469,32 @@ const validateAgainstSchema = {
|
|
|
469
469
|
{
|
|
470
470
|
path: "name",
|
|
471
471
|
type: "string",
|
|
472
|
-
isRequired: true
|
|
472
|
+
isRequired: true
|
|
473
473
|
},
|
|
474
474
|
{
|
|
475
475
|
path: "description",
|
|
476
|
-
type: "string"
|
|
476
|
+
type: "string"
|
|
477
477
|
},
|
|
478
478
|
{
|
|
479
479
|
path: "sequence",
|
|
480
480
|
type: "string",
|
|
481
|
-
isRequired: true
|
|
481
|
+
isRequired: true
|
|
482
482
|
},
|
|
483
483
|
{
|
|
484
484
|
path: "type",
|
|
485
485
|
type: "dropdown",
|
|
486
486
|
values: getFeatureTypes(),
|
|
487
|
-
defaultValue: "misc_feature"
|
|
487
|
+
defaultValue: "misc_feature"
|
|
488
488
|
},
|
|
489
489
|
{
|
|
490
490
|
path: "isRegex",
|
|
491
|
-
type: "boolean"
|
|
491
|
+
type: "boolean"
|
|
492
492
|
},
|
|
493
493
|
{
|
|
494
494
|
path: "matchType",
|
|
495
495
|
type: "dropdown",
|
|
496
496
|
defaultValue: "dna",
|
|
497
|
-
values: ["dna", "protein"]
|
|
498
|
-
}
|
|
499
|
-
]
|
|
497
|
+
values: ["dna", "protein"]
|
|
498
|
+
}
|
|
499
|
+
]
|
|
500
500
|
};
|
|
@@ -43,15 +43,15 @@ function Cutsites({
|
|
|
43
43
|
color: annotation.restrictionEnzyme.color,
|
|
44
44
|
className: " veCutsiteLabel",
|
|
45
45
|
id: annotation.id,
|
|
46
|
-
onClick:
|
|
46
|
+
onClick: event => {
|
|
47
47
|
cutsiteClicked({ event, annotation });
|
|
48
48
|
event.stopPropagation();
|
|
49
49
|
},
|
|
50
|
-
onDoubleClick:
|
|
50
|
+
onDoubleClick: event => {
|
|
51
51
|
cutsiteDoubleClicked({ event, annotation });
|
|
52
52
|
event.stopPropagation();
|
|
53
53
|
},
|
|
54
|
-
onContextMenu:
|
|
54
|
+
onContextMenu: event => {
|
|
55
55
|
cutsiteRightClicked({ event, annotation });
|
|
56
56
|
event.stopPropagation();
|
|
57
57
|
}
|
|
@@ -7,12 +7,12 @@ import { cloneDeep, clamp, noop } from "lodash";
|
|
|
7
7
|
|
|
8
8
|
const fontWidthToFontSize = 1.75;
|
|
9
9
|
|
|
10
|
-
const getTextLength =
|
|
10
|
+
const getTextLength = text => {
|
|
11
11
|
let len = (text || "Unlabeled").length;
|
|
12
12
|
// eslint-disable-next-line no-control-regex
|
|
13
13
|
const nonEnInputReg = /[^\x00-\xff]+/g;
|
|
14
14
|
const nonEnStrings = (text || "Unlabeled").match(nonEnInputReg) || [];
|
|
15
|
-
nonEnStrings.forEach(
|
|
15
|
+
nonEnStrings.forEach(str => (len += str.length * 0.5));
|
|
16
16
|
return len;
|
|
17
17
|
};
|
|
18
18
|
|
|
@@ -93,8 +93,8 @@ function Labels({
|
|
|
93
93
|
|
|
94
94
|
let maxRadius = 1;
|
|
95
95
|
const groupedLabels = relaxLabelAngles(labelPoints, fontHeight, outerRadius)
|
|
96
|
-
.filter(
|
|
97
|
-
.map(
|
|
96
|
+
.filter(l => !!l)
|
|
97
|
+
.map(originalLabel => {
|
|
98
98
|
if (smartCircViewLabelRender) {
|
|
99
99
|
const newR = Math.sqrt(
|
|
100
100
|
Math.pow(
|
|
@@ -114,7 +114,7 @@ function Labels({
|
|
|
114
114
|
}
|
|
115
115
|
|
|
116
116
|
const _highPrioritySublabel = originalLabel.labelAndSublabels.find(
|
|
117
|
-
|
|
117
|
+
l => l.highPriorityLabel
|
|
118
118
|
);
|
|
119
119
|
if (_highPrioritySublabel) {
|
|
120
120
|
const highPrioritySublabel = cloneDeep(_highPrioritySublabel);
|
|
@@ -133,7 +133,7 @@ function Labels({
|
|
|
133
133
|
"truncatedInnerPoint",
|
|
134
134
|
"x",
|
|
135
135
|
"y"
|
|
136
|
-
].forEach(
|
|
136
|
+
].forEach(k => {
|
|
137
137
|
highPrioritySublabel[k] = originalLabel[k];
|
|
138
138
|
});
|
|
139
139
|
|
|
@@ -449,7 +449,7 @@ const DrawGroupInnerLabel = withHover(
|
|
|
449
449
|
textLength={getTextLength(label.text) * fontWidth}
|
|
450
450
|
lengthAdjust="spacing"
|
|
451
451
|
onClick={label.onClick}
|
|
452
|
-
onDoubleClick={
|
|
452
|
+
onDoubleClick={e => {
|
|
453
453
|
e.stopPropagation();
|
|
454
454
|
label.onDoubleClick && label.onDoubleClick(e);
|
|
455
455
|
}}
|
|
@@ -9,7 +9,7 @@ let alpha = 1.5; //the larger the alpha, the fewer loops through relax necessary
|
|
|
9
9
|
let spacing = 12;
|
|
10
10
|
let relaxCounter = 0;
|
|
11
11
|
export default function relaxLabels(labelPoints) {
|
|
12
|
-
let mutableLabelPoints = labelPoints.map(function(point) {
|
|
12
|
+
let mutableLabelPoints = labelPoints.map(function (point) {
|
|
13
13
|
return {
|
|
14
14
|
...point
|
|
15
15
|
};
|
|
@@ -18,14 +18,14 @@ export default function relaxLabels(labelPoints) {
|
|
|
18
18
|
function relax() {
|
|
19
19
|
let again = false;
|
|
20
20
|
relaxCounter++;
|
|
21
|
-
mutableLabelPoints.forEach(function(point1, index1) {
|
|
21
|
+
mutableLabelPoints.forEach(function (point1, index1) {
|
|
22
22
|
// var xOverlaps = xRanges.search(point1.x, point1.x + point1.width)
|
|
23
23
|
// var yOverlaps = yRanges.search(point1.y, point1.y + point1.height)
|
|
24
24
|
// xOverlaps
|
|
25
25
|
// xRanges.add(point1.x, point1.x + point1.width, undefined, point1)
|
|
26
26
|
// yRanges.add(point1.y, point1.y + point1.height, undefined, point1)
|
|
27
27
|
|
|
28
|
-
mutableLabelPoints.forEach(function(point2, index2) {
|
|
28
|
+
mutableLabelPoints.forEach(function (point2, index2) {
|
|
29
29
|
// a & b are the same element and don't collide.
|
|
30
30
|
if (index1 === index2) return;
|
|
31
31
|
|
|
@@ -69,9 +69,9 @@ export default function relaxLabels(labelPoints) {
|
|
|
69
69
|
|
|
70
70
|
//group colliding labels
|
|
71
71
|
let stableLabels = [];
|
|
72
|
-
mutableLabelPoints.forEach(function(point1) {
|
|
72
|
+
mutableLabelPoints.forEach(function (point1) {
|
|
73
73
|
let collision = false;
|
|
74
|
-
stableLabels.some(function(point2) {
|
|
74
|
+
stableLabels.some(function (point2) {
|
|
75
75
|
// a & b are on opposite sides of the chart and
|
|
76
76
|
// don't collide
|
|
77
77
|
if ((point1.x > 0 && point2.x <= 0) || (point1.x < 0 && point2.x >= 0)) {
|
|
@@ -44,7 +44,7 @@ export function RotateCircularViewSlider({
|
|
|
44
44
|
>
|
|
45
45
|
<UncontrolledSliderWithPlusMinusBtns
|
|
46
46
|
bindOutsideChangeHelper={bindOutsideChangeHelper}
|
|
47
|
-
onChange={
|
|
47
|
+
onChange={_val => {
|
|
48
48
|
const val = 360 - _val;
|
|
49
49
|
const el = target.current
|
|
50
50
|
.closest(`.veCircularView`)
|
|
@@ -63,7 +63,7 @@ function SelectionLayer({
|
|
|
63
63
|
});
|
|
64
64
|
return (
|
|
65
65
|
<g
|
|
66
|
-
onContextMenu={
|
|
66
|
+
onContextMenu={event => {
|
|
67
67
|
onRightClicked &&
|
|
68
68
|
onRightClicked({
|
|
69
69
|
annotation: selectionLayer,
|
|
@@ -72,7 +72,7 @@ function SelectionLayer({
|
|
|
72
72
|
}}
|
|
73
73
|
onClick={
|
|
74
74
|
onClick
|
|
75
|
-
?
|
|
75
|
+
? event => {
|
|
76
76
|
onClick({
|
|
77
77
|
annotation: selectionLayer,
|
|
78
78
|
event
|
|
@@ -53,10 +53,10 @@ function drawAnnotations(props) {
|
|
|
53
53
|
const labels = {};
|
|
54
54
|
|
|
55
55
|
if (!Object.keys(annotations).length) return null;
|
|
56
|
-
sortBy(annotations,
|
|
56
|
+
sortBy(annotations, a => {
|
|
57
57
|
return -getRangeLength(a, sequenceLength);
|
|
58
58
|
})
|
|
59
|
-
.map(
|
|
59
|
+
.map(annotation => {
|
|
60
60
|
const { startAngle, endAngle, totalAngle, centerAngle, locationAngles } =
|
|
61
61
|
getRangeAngles(
|
|
62
62
|
positionBy ? positionBy(annotation) : annotation,
|
|
@@ -196,7 +196,7 @@ function drawAnnotations(props) {
|
|
|
196
196
|
return ellipsizedName;
|
|
197
197
|
}
|
|
198
198
|
if (locationAngles) {
|
|
199
|
-
annotation.locationAngles = locationAngles.map(
|
|
199
|
+
annotation.locationAngles = locationAngles.map(l => {
|
|
200
200
|
const en = getEllipsizedName(l.totalAngle);
|
|
201
201
|
if (en?.length > (ellipsizedName?.length || 0)) {
|
|
202
202
|
ellipsizedName = en;
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
export interface CircularViewProps {
|
|
3
|
-
editorName: string
|
|
4
|
-
maxAnnotationsToDisplay
|
|
5
|
-
circularAndLinearTickSpacing: number
|
|
6
|
-
spaceBetweenAnnotations: number
|
|
7
|
-
annotationHeight: number
|
|
8
|
-
hideName: boolean
|
|
3
|
+
editorName: string; //the name of the editor instance (this should match what you've set up in your redux store)
|
|
4
|
+
maxAnnotationsToDisplay;
|
|
5
|
+
circularAndLinearTickSpacing: number;
|
|
6
|
+
spaceBetweenAnnotations: number; // default = 2,
|
|
7
|
+
annotationHeight: number; // default = 15,
|
|
8
|
+
hideName: boolean;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
export interface maxAnnotationsToDisplay {
|
|
12
|
-
features: number
|
|
13
|
-
primers: number
|
|
12
|
+
features: number;
|
|
13
|
+
primers: number;
|
|
14
14
|
// translations: number,
|
|
15
15
|
// parts: number,
|
|
16
|
-
orfs: number
|
|
17
|
-
cutsites: number
|
|
16
|
+
orfs: number;
|
|
17
|
+
cutsites: number;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
export default class CircularView extends React.Component
|
|
20
|
+
export default class CircularView extends React.Component<CircularViewProps> {}
|
|
@@ -279,7 +279,7 @@ export function CircularView(props) {
|
|
|
279
279
|
: Math.ceil(rangeToShowLength / 100) * 10,
|
|
280
280
|
sequenceLength,
|
|
281
281
|
isProtein
|
|
282
|
-
}).map(
|
|
282
|
+
}).map(pos => {
|
|
283
283
|
return {
|
|
284
284
|
name: "Tick Mark",
|
|
285
285
|
tickPosition: pos,
|
|
@@ -446,7 +446,7 @@ export function CircularView(props) {
|
|
|
446
446
|
];
|
|
447
447
|
const paredDownMessages = [];
|
|
448
448
|
const output = layersToDraw
|
|
449
|
-
.map(
|
|
449
|
+
.map(layer => {
|
|
450
450
|
const {
|
|
451
451
|
layerName,
|
|
452
452
|
maxToDisplay,
|
|
@@ -501,7 +501,7 @@ export function CircularView(props) {
|
|
|
501
501
|
sequenceData["filtered" + nameUpper] ||
|
|
502
502
|
sequenceData[layerName] ||
|
|
503
503
|
[],
|
|
504
|
-
|
|
504
|
+
range => {
|
|
505
505
|
const overlapOfRanges = getOverlapsOfPotentiallyCircularRanges(
|
|
506
506
|
range,
|
|
507
507
|
rangeToShow,
|
|
@@ -620,7 +620,7 @@ export function CircularView(props) {
|
|
|
620
620
|
return null;
|
|
621
621
|
}
|
|
622
622
|
})
|
|
623
|
-
.filter(
|
|
623
|
+
.filter(el => {
|
|
624
624
|
return !!el;
|
|
625
625
|
});
|
|
626
626
|
}
|
|
@@ -727,7 +727,7 @@ export function CircularView(props) {
|
|
|
727
727
|
}}
|
|
728
728
|
onWheel={
|
|
729
729
|
withZoomCircularView && hasRotateableLength
|
|
730
|
-
?
|
|
730
|
+
? e => {
|
|
731
731
|
let delta = e.deltaY;
|
|
732
732
|
if (Math.abs(e.deltaY) < Math.abs(e.deltaX)) {
|
|
733
733
|
delta = e.deltaX;
|
|
@@ -805,10 +805,10 @@ export function CircularView(props) {
|
|
|
805
805
|
<Draggable
|
|
806
806
|
// enableUserSelectHack={false} //needed to prevent the input bubble from losing focus post user drag
|
|
807
807
|
bounds={{ top: 0, left: 0, right: 0, bottom: 0 }}
|
|
808
|
-
onDrag={
|
|
808
|
+
onDrag={event => {
|
|
809
809
|
getNearestCursorPositionToMouseEvent(event, toPass, editorDragged);
|
|
810
810
|
}}
|
|
811
|
-
onStart={
|
|
811
|
+
onStart={event => {
|
|
812
812
|
getNearestCursorPositionToMouseEvent(
|
|
813
813
|
event,
|
|
814
814
|
toPass,
|
|
@@ -822,7 +822,7 @@ export function CircularView(props) {
|
|
|
822
822
|
>
|
|
823
823
|
<svg
|
|
824
824
|
key="circViewSvg"
|
|
825
|
-
onClick={
|
|
825
|
+
onClick={event => {
|
|
826
826
|
instantiated &&
|
|
827
827
|
getNearestCursorPositionToMouseEvent(
|
|
828
828
|
event,
|
|
@@ -830,7 +830,7 @@ export function CircularView(props) {
|
|
|
830
830
|
editorClicked
|
|
831
831
|
);
|
|
832
832
|
}}
|
|
833
|
-
onContextMenu={
|
|
833
|
+
onContextMenu={e => {
|
|
834
834
|
getNearestCursorPositionToMouseEvent(
|
|
835
835
|
e,
|
|
836
836
|
toPass,
|
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
import { compose } from "redux";
|
|
2
2
|
import pluralize from "pluralize";
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
4
|
import { formName } from "./constants";
|
|
7
5
|
import { typeField } from "./helperComponents/PropertiesDialog/typeField";
|
|
8
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
DataTable,
|
|
8
|
+
DialogFooter,
|
|
9
|
+
withSelectTableRecords,
|
|
10
|
+
withSelectedEntities
|
|
11
|
+
} from "@teselagen/ui";
|
|
9
12
|
import { useEffect } from "react";
|
|
10
13
|
import { hideDialog } from "./GlobalDialogUtils";
|
|
11
14
|
import { startCase } from "lodash";
|
|
12
15
|
import { tidyUpAnnotation } from "@teselagen/sequence-utils";
|
|
13
16
|
|
|
14
|
-
|
|
15
17
|
const schemaFeatures = ["name", typeField, "start", "end", "strand"];
|
|
16
18
|
const schemaOther = ["name", "start", "end", "strand"];
|
|
17
19
|
export default compose(
|
|
@@ -39,7 +41,7 @@ export default compose(
|
|
|
39
41
|
<DataTable
|
|
40
42
|
isInfinite
|
|
41
43
|
formName={formName}
|
|
42
|
-
entities={newAnnotations.map(
|
|
44
|
+
entities={newAnnotations.map(e => ({
|
|
43
45
|
...e,
|
|
44
46
|
start: e.start + 1,
|
|
45
47
|
end: e.end + 1
|
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
import { connect } from "react-redux";
|
|
2
2
|
// import {reduxForm, Field, formValueSelector} from 'redux-form'
|
|
3
3
|
import React from "react";
|
|
4
|
-
import {
|
|
5
|
-
DialogFooter,
|
|
6
|
-
InfoHelper,
|
|
7
|
-
wrapDialog
|
|
8
|
-
} from "@teselagen/ui";
|
|
4
|
+
import { DialogFooter, InfoHelper, wrapDialog } from "@teselagen/ui";
|
|
9
5
|
|
|
10
6
|
// import './style.css';
|
|
11
7
|
import { cutSequenceByRestrictionEnzyme } from "@teselagen/sequence-utils";
|