@teselagen/ove 0.6.1-beta.1 → 0.7.2
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/DigestTool/DigestTool.d.ts +2 -10
- package/Menlo.ttf +0 -0
- package/Monaco.ttf +0 -0
- package/helperComponents/PropertiesDialog/index.d.ts +2 -7
- package/helperComponents/PropertiesDialog/utils.d.ts +5 -5
- package/html2canvas.esm--JN4fLQL.mjs +7891 -0
- package/html2canvas.esm-B7d7VJmQ.js +7891 -0
- package/html2canvas.esm-GLpiTZLt.cjs +7891 -0
- package/html2canvas.esm-GLpiTZLt.js +7891 -0
- package/html2canvas.esm-nFNn58sx.js +7891 -0
- package/html2canvas.esm-nFNn58sx.mjs +7891 -0
- package/index.cjs.js +78073 -73781
- package/index.es.js +78467 -74175
- package/index.umd.js +81406 -77036
- package/package.json +7 -8
- package/src/AutoAnnotate.js +1 -0
- package/src/CircularView/Labels/index.js +1 -15
- package/src/CircularView/index.js +3 -4
- package/src/CreateAnnotationsPage.js +1 -1
- package/src/CutsiteFilter/index.js +51 -55
- package/src/DigestTool/DigestTool.js +193 -188
- package/src/GlobalDialogUtils.js +1 -0
- package/src/PCRTool/PCRTool.js +8 -2
- package/src/Reflex/reflex-styles.css +10 -10
- package/src/RowItem/CutsiteSelectionLayers.js +1 -1
- package/src/RowItem/SelectionLayer/index.js +2 -2
- package/src/RowItem/Sequence.js +0 -1
- package/src/RowItem/Translations/Translation.js +1 -0
- package/src/RowItem/index.js +0 -1
- package/src/helperComponents/AddOrEditAnnotationDialog/index.js +8 -4
- package/src/helperComponents/AddOrEditFeatureDialog/index.js +9 -7
- package/src/helperComponents/AddOrEditPartDialog/index.js +3 -3
- package/src/helperComponents/AddOrEditPrimerDialog/index.js +3 -7
- package/src/helperComponents/PropertiesDialog/CutsiteProperties.js +126 -135
- package/src/helperComponents/PropertiesDialog/GenericAnnotationProperties.js +52 -50
- package/src/helperComponents/PropertiesDialog/OrfProperties.js +1 -1
- package/src/helperComponents/PropertiesDialog/SingleEnzymeCutsiteInfo.js +59 -51
- package/src/helperComponents/PropertiesDialog/index.js +115 -114
- package/src/helperComponents/PropertiesDialog/utils.js +5 -5
- package/src/helperComponents/RemoveDuplicates/index.js +149 -165
- package/src/utils/useFormValue.js +7 -0
- package/src/withEditorInteractions/index.js +8 -7
- package/style.css +287 -263
- package/utils/useFormValue.d.ts +1 -0
|
@@ -1,194 +1,178 @@
|
|
|
1
|
-
import React from "react";
|
|
1
|
+
import React, { useCallback, useMemo, useState } from "react";
|
|
2
2
|
import { reduxForm } from "redux-form";
|
|
3
|
-
|
|
4
3
|
import {
|
|
5
4
|
wrapDialog,
|
|
6
5
|
DataTable,
|
|
7
|
-
withSelectedEntities,
|
|
8
6
|
SwitchField,
|
|
9
|
-
|
|
7
|
+
useTableEntities
|
|
10
8
|
} from "@teselagen/ui";
|
|
11
9
|
import { compose } from "redux";
|
|
12
10
|
import { Button, Classes, Popover } from "@blueprintjs/core";
|
|
13
11
|
import classNames from "classnames";
|
|
14
|
-
|
|
15
12
|
import withEditorProps from "../../withEditorProps";
|
|
16
13
|
import { forEach, camelCase, startCase } from "lodash-es";
|
|
17
14
|
import { sizeSchema } from "../PropertiesDialog/utils";
|
|
18
15
|
import { getRangeLength } from "@teselagen/range-utils";
|
|
16
|
+
import { useFormValue } from "../../utils/useFormValue";
|
|
19
17
|
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
// }
|
|
35
|
-
// }
|
|
36
|
-
// ]),
|
|
37
|
-
{ path: "name", type: "string" },
|
|
38
|
-
// ...(noType ? [] : [{ path: "type", type: "string" }]),
|
|
39
|
-
sizeSchema,
|
|
40
|
-
{ path: "strand", type: "string" }
|
|
41
|
-
]
|
|
42
|
-
};
|
|
18
|
+
const dialogFormName = "RemoveDuplicatesDialog";
|
|
19
|
+
const dataTableFormName = "duplicatesToRemove";
|
|
20
|
+
const checkboxStyle = { marginTop: 0, marginBottom: 0 };
|
|
21
|
+
|
|
22
|
+
const RemoveDuplicatesDialog = props => {
|
|
23
|
+
const {
|
|
24
|
+
type,
|
|
25
|
+
sequenceData = { sequence: "" },
|
|
26
|
+
sequenceLength,
|
|
27
|
+
isProtein,
|
|
28
|
+
hideModal
|
|
29
|
+
} = props;
|
|
30
|
+
|
|
31
|
+
const { selectedEntities } = useTableEntities(dataTableFormName);
|
|
43
32
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
};
|
|
48
|
-
componentDidMount() {
|
|
49
|
-
this.recomputeDups();
|
|
50
|
-
}
|
|
33
|
+
const ignoreName = useFormValue(dialogFormName, "ignoreName");
|
|
34
|
+
const ignoreStartAndEnd = useFormValue(dialogFormName, "ignoreStartAndEnd");
|
|
35
|
+
const ignoreStrand = useFormValue(dialogFormName, "ignoreStrand");
|
|
51
36
|
|
|
52
|
-
|
|
37
|
+
const recomputeDups = useCallback(
|
|
38
|
+
values => {
|
|
39
|
+
const ignoreName = values?.ignoreName;
|
|
40
|
+
const ignoreStartAndEnd = values?.ignoreStartAndEnd;
|
|
41
|
+
const ignoreStrand = values?.ignoreStrand;
|
|
42
|
+
const annotations = sequenceData[type];
|
|
43
|
+
const newDups = [];
|
|
44
|
+
const seqsHashByStartEndStrandName = {};
|
|
45
|
+
forEach(annotations, a => {
|
|
46
|
+
const hash = `${ignoreStartAndEnd ? "" : a.start}&${
|
|
47
|
+
ignoreStartAndEnd ? "" : a.end
|
|
48
|
+
}&${ignoreStrand ? "" : a.strand}&${ignoreName ? "" : a.name}`;
|
|
49
|
+
if (seqsHashByStartEndStrandName[hash]) {
|
|
50
|
+
newDups.push({ ...a, size: getRangeLength(a, sequenceLength) });
|
|
51
|
+
} else {
|
|
52
|
+
seqsHashByStartEndStrandName[hash] = true;
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
return newDups;
|
|
56
|
+
},
|
|
57
|
+
[sequenceData, sequenceLength, type]
|
|
58
|
+
);
|
|
53
59
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
this.recomputeDups();
|
|
57
|
-
});
|
|
58
|
-
};
|
|
59
|
-
recomputeDups = () => {
|
|
60
|
-
const {
|
|
61
|
-
// hideModal,
|
|
62
|
-
type,
|
|
63
|
-
sequenceData = { sequence: "" },
|
|
64
|
-
// handleSubmit,
|
|
65
|
-
sequenceLength,
|
|
66
|
-
ignoreName,
|
|
67
|
-
ignoreStrand,
|
|
68
|
-
ignoreStartAndEnd
|
|
69
|
-
// circular,
|
|
70
|
-
// upsertFeature
|
|
71
|
-
} = this.props;
|
|
60
|
+
const [dups, setDups] = useState(recomputeDups);
|
|
61
|
+
const selectedIds = useMemo(() => dups.map(d => d.id), [dups]);
|
|
72
62
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
this.setState({ dups });
|
|
87
|
-
};
|
|
88
|
-
render() {
|
|
89
|
-
const { duplicatesToRemoveSelectedEntities, hideModal, type } = this.props;
|
|
63
|
+
const fieldSubmit = useCallback(
|
|
64
|
+
(newVal, field) => {
|
|
65
|
+
const values = {
|
|
66
|
+
ignoreName,
|
|
67
|
+
ignoreStartAndEnd,
|
|
68
|
+
ignoreStrand,
|
|
69
|
+
[field]: newVal
|
|
70
|
+
};
|
|
71
|
+
const newDups = recomputeDups(values);
|
|
72
|
+
setDups(newDups);
|
|
73
|
+
},
|
|
74
|
+
[ignoreName, ignoreStartAndEnd, ignoreStrand, recomputeDups]
|
|
75
|
+
);
|
|
90
76
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
77
|
+
const schema = useMemo(
|
|
78
|
+
() => ({
|
|
79
|
+
fields: [
|
|
80
|
+
{ path: "name", type: "string" },
|
|
81
|
+
// ...(noType ? [] : [{ path: "type", type: "string" }]),
|
|
82
|
+
sizeSchema(isProtein),
|
|
83
|
+
{ path: "strand", type: "string" }
|
|
84
|
+
]
|
|
85
|
+
}),
|
|
86
|
+
[isProtein]
|
|
87
|
+
);
|
|
98
88
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
89
|
+
return (
|
|
90
|
+
<div className={classNames(Classes.DIALOG_BODY, "tg-min-width-dialog")}>
|
|
91
|
+
<DataTable
|
|
92
|
+
noPadding
|
|
93
|
+
withCheckboxes
|
|
94
|
+
noFullscreenButton
|
|
95
|
+
maxHeight={400}
|
|
96
|
+
selectedIds={selectedIds}
|
|
97
|
+
formName={dataTableFormName}
|
|
98
|
+
noRouter
|
|
99
|
+
noRowsFoundMessage="No duplicates found"
|
|
100
|
+
compact
|
|
101
|
+
noHeader
|
|
102
|
+
noFooter
|
|
103
|
+
withSearch={false}
|
|
104
|
+
hideSelectedCount
|
|
105
|
+
isInfinite
|
|
106
|
+
schema={schema}
|
|
107
|
+
entities={dups}
|
|
108
|
+
/>
|
|
109
|
+
<div
|
|
110
|
+
style={{
|
|
111
|
+
marginTop: 10,
|
|
112
|
+
display: "flex",
|
|
113
|
+
justifyContent: "space-between"
|
|
114
|
+
}}
|
|
115
|
+
>
|
|
116
|
+
<Popover
|
|
117
|
+
target={<Button icon="settings" />}
|
|
118
|
+
content={
|
|
119
|
+
<div style={{ padding: 20, maxWidth: 250 }}>
|
|
120
|
+
<div>Ignore These Fields While Finding Duplicates:</div>
|
|
121
|
+
<br />
|
|
122
|
+
<SwitchField
|
|
123
|
+
containerStyle={{ marginBottom: 2 }}
|
|
124
|
+
//delay the call to recompute dups until redux has had time to update
|
|
125
|
+
onFieldSubmit={newVal => fieldSubmit(newVal, "ignoreName")}
|
|
126
|
+
style={checkboxStyle}
|
|
127
|
+
name="ignoreName"
|
|
128
|
+
label="Name"
|
|
129
|
+
/>
|
|
130
|
+
<SwitchField
|
|
131
|
+
containerStyle={{ marginBottom: 2 }}
|
|
132
|
+
//delay the call to recompute dups until redux has had time to update
|
|
133
|
+
onFieldSubmit={newVal => fieldSubmit(newVal, "ignoreStrand")}
|
|
134
|
+
style={checkboxStyle}
|
|
135
|
+
name="ignoreStrand"
|
|
136
|
+
label="Strand"
|
|
137
|
+
/>
|
|
138
|
+
<SwitchField
|
|
139
|
+
containerStyle={{ marginBottom: 2 }}
|
|
140
|
+
//delay the call to recompute dups until redux has had time to update
|
|
141
|
+
onFieldSubmit={newVal =>
|
|
142
|
+
fieldSubmit(newVal, "ignoreStartAndEnd")
|
|
143
|
+
}
|
|
144
|
+
style={checkboxStyle}
|
|
145
|
+
name="ignoreStartAndEnd"
|
|
146
|
+
label="Start and End"
|
|
147
|
+
/>
|
|
148
|
+
</div>
|
|
149
|
+
}
|
|
119
150
|
/>
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
151
|
+
|
|
152
|
+
<Button
|
|
153
|
+
intent="primary"
|
|
154
|
+
onClick={() => {
|
|
155
|
+
props[camelCase(`delete_${type}`).slice(0, -1)](
|
|
156
|
+
Object.keys(selectedEntities || {})
|
|
157
|
+
);
|
|
158
|
+
window.toastr.success(
|
|
159
|
+
`Successfully Deleted ${
|
|
160
|
+
Object.keys(selectedEntities || {}).length
|
|
161
|
+
} ${startCase(type)}`
|
|
162
|
+
);
|
|
163
|
+
hideModal();
|
|
125
164
|
}}
|
|
165
|
+
disabled={!Object.keys(selectedEntities || {}).length}
|
|
126
166
|
>
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
content={
|
|
130
|
-
<div style={{ padding: 20, maxWidth: 250 }}>
|
|
131
|
-
<div>Ignore These Fields While Finding Duplicates:</div>
|
|
132
|
-
<br></br>
|
|
133
|
-
<SwitchField
|
|
134
|
-
containerStyle={{ marginBottom: 2 }}
|
|
135
|
-
//delay the call to recompute dups until redux has had time to update
|
|
136
|
-
onFieldSubmit={this.delayedRecomputeDups}
|
|
137
|
-
style={this.checkboxStyle}
|
|
138
|
-
name="ignoreName"
|
|
139
|
-
label="Name"
|
|
140
|
-
></SwitchField>
|
|
141
|
-
<SwitchField
|
|
142
|
-
containerStyle={{ marginBottom: 2 }}
|
|
143
|
-
//delay the call to recompute dups until redux has had time to update
|
|
144
|
-
onFieldSubmit={this.delayedRecomputeDups}
|
|
145
|
-
style={this.checkboxStyle}
|
|
146
|
-
name="ignoreStrand"
|
|
147
|
-
label="Strand"
|
|
148
|
-
></SwitchField>
|
|
149
|
-
<SwitchField
|
|
150
|
-
containerStyle={{ marginBottom: 2 }}
|
|
151
|
-
//delay the call to recompute dups until redux has had time to update
|
|
152
|
-
onFieldSubmit={this.delayedRecomputeDups}
|
|
153
|
-
style={this.checkboxStyle}
|
|
154
|
-
name="ignoreStartAndEnd"
|
|
155
|
-
label="Start and End"
|
|
156
|
-
></SwitchField>
|
|
157
|
-
</div>
|
|
158
|
-
}
|
|
159
|
-
></Popover>
|
|
160
|
-
|
|
161
|
-
<Button
|
|
162
|
-
intent="primary"
|
|
163
|
-
onClick={() => {
|
|
164
|
-
this.props[camelCase(`delete_${type}`).slice(0, -1)](
|
|
165
|
-
duplicatesToRemoveSelectedEntities.map(d => d.id)
|
|
166
|
-
);
|
|
167
|
-
window.toastr.success(
|
|
168
|
-
`Successfully Deleted ${
|
|
169
|
-
duplicatesToRemoveSelectedEntities.length
|
|
170
|
-
} ${startCase(type)}`
|
|
171
|
-
);
|
|
172
|
-
hideModal();
|
|
173
|
-
}}
|
|
174
|
-
disabled={!(duplicatesToRemoveSelectedEntities || []).length}
|
|
175
|
-
>
|
|
176
|
-
Remove {duplicatesToRemoveSelectedEntities.length} Duplicates
|
|
177
|
-
</Button>
|
|
178
|
-
</div>
|
|
167
|
+
Remove {Object.keys(selectedEntities || {}).length} Duplicates
|
|
168
|
+
</Button>
|
|
179
169
|
</div>
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
}
|
|
170
|
+
</div>
|
|
171
|
+
);
|
|
172
|
+
};
|
|
183
173
|
|
|
184
174
|
export default compose(
|
|
185
175
|
wrapDialog(),
|
|
186
176
|
withEditorProps,
|
|
187
|
-
|
|
188
|
-
withSelectedEntities("duplicatesToRemove"),
|
|
189
|
-
|
|
190
|
-
reduxForm({
|
|
191
|
-
form: "RemoveDuplicatesDialog"
|
|
192
|
-
}),
|
|
193
|
-
tgFormValues("ignoreName", "ignoreStrand", "ignoreStartAndEnd")
|
|
177
|
+
reduxForm({ form: dialogFormName })
|
|
194
178
|
)(RemoveDuplicatesDialog);
|
|
@@ -602,8 +602,13 @@ function VectorInteractionHOC(Component /* options */) {
|
|
|
602
602
|
return new Clipboard(`.${className}`, {
|
|
603
603
|
action: () => action,
|
|
604
604
|
text: () => {
|
|
605
|
-
|
|
606
|
-
|
|
605
|
+
if (action === "copy") {
|
|
606
|
+
document.body.addEventListener("copy", this.handleCopy);
|
|
607
|
+
} else {
|
|
608
|
+
document.body.addEventListener("cut", this.handleCut);
|
|
609
|
+
}
|
|
610
|
+
const { editorName, store } = this.props;
|
|
611
|
+
const { sequenceData, copyOptions, selectionLayer } =
|
|
607
612
|
store.getState().VectorEditor[editorName];
|
|
608
613
|
|
|
609
614
|
const selectedSeqData = getSequenceDataBetweenRange(
|
|
@@ -628,11 +633,7 @@ function VectorInteractionHOC(Component /* options */) {
|
|
|
628
633
|
sequenceData
|
|
629
634
|
);
|
|
630
635
|
this.sequenceDataToCopy = sequenceDataToCopy;
|
|
631
|
-
|
|
632
|
-
document.body.addEventListener("copy", this.handleCopy);
|
|
633
|
-
} else {
|
|
634
|
-
document.body.addEventListener("cut", this.handleCut);
|
|
635
|
-
}
|
|
636
|
+
|
|
636
637
|
if (window.Cypress) {
|
|
637
638
|
window.Cypress.textToCopy = sequenceDataToCopy.textToCopy;
|
|
638
639
|
window.Cypress.seqDataToCopy = sequenceDataToCopy;
|