@teselagen/ove 0.8.39 → 0.8.41
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/AlignmentView/AlignmentSearchBar.d.ts +2 -0
- package/AlignmentView/Mismatches.d.ts +2 -20
- package/AlignmentView/findAlignmentDifferences.d.ts +53 -0
- package/AlignmentView/utils.d.ts +31 -0
- package/index.cjs.js +1063 -164
- package/index.es.js +1063 -164
- package/index.umd.js +1063 -164
- package/ove.css +138 -54
- package/package.json +1 -1
- package/src/AlignmentView/AlignmentSearchBar.js +810 -0
- package/src/AlignmentView/AlignmentVisibilityTool.js +9 -11
- package/src/AlignmentView/Minimap.js +21 -3
- package/src/AlignmentView/Mismatches.js +201 -123
- package/src/AlignmentView/findAlignmentDifferences.js +116 -0
- package/src/AlignmentView/findAlignmentDifferences.test.js +208 -0
- package/src/AlignmentView/index.js +30 -2
- package/src/AlignmentView/style.css +84 -0
- package/src/AlignmentView/utils.js +30 -0
- package/src/PropertySidePanel/index.js +89 -28
- package/src/redux/alignments.js +58 -20
package/index.cjs.js
CHANGED
|
@@ -95510,14 +95510,34 @@ function addHighlightedDifferences(alignmentTracks) {
|
|
|
95510
95510
|
track.alignmentData.sequence
|
|
95511
95511
|
);
|
|
95512
95512
|
const mismatches = matchHighlightRanges.filter(({ isMatch }) => !isMatch);
|
|
95513
|
+
const alignedSeq = track.alignmentData.sequence;
|
|
95514
|
+
const seqLen = alignedSeq.length;
|
|
95515
|
+
const startIndex = seqLen - alignedSeq.replace(/^-+/, "").length;
|
|
95516
|
+
const endIndex = alignedSeq.replace(/-+$/, "").length;
|
|
95517
|
+
const gapRanges = [
|
|
95518
|
+
startIndex > 0 && {
|
|
95519
|
+
start: 0,
|
|
95520
|
+
end: startIndex - 1,
|
|
95521
|
+
differenceType: "gap"
|
|
95522
|
+
},
|
|
95523
|
+
endIndex < seqLen && {
|
|
95524
|
+
start: endIndex,
|
|
95525
|
+
end: seqLen - 1,
|
|
95526
|
+
differenceType: "gap"
|
|
95527
|
+
}
|
|
95528
|
+
].filter(Boolean);
|
|
95513
95529
|
return __spreadProps(__spreadValues({}, track), {
|
|
95514
95530
|
sequenceData: sequenceData2,
|
|
95515
95531
|
matchHighlightRanges,
|
|
95516
|
-
additionalSelectionLayers:
|
|
95517
|
-
|
|
95532
|
+
additionalSelectionLayers: [
|
|
95533
|
+
...matchHighlightRanges.filter(({ isMatch }) => !isMatch).map((range2) => __spreadProps(__spreadValues(__spreadValues({}, range2), highlightRangeProps), {
|
|
95518
95534
|
className: "veAlignmentMismatch"
|
|
95519
|
-
})
|
|
95520
|
-
|
|
95535
|
+
})),
|
|
95536
|
+
...gapRanges.map((range2) => __spreadProps(__spreadValues(__spreadValues({}, range2), highlightRangeProps), {
|
|
95537
|
+
className: "veAlignmentMismatch"
|
|
95538
|
+
}))
|
|
95539
|
+
],
|
|
95540
|
+
gapRanges,
|
|
95521
95541
|
mismatches
|
|
95522
95542
|
});
|
|
95523
95543
|
});
|
|
@@ -95651,23 +95671,30 @@ function getRangeMatchesBetweenTemplateAndNonTemplate(tempSeq, nonTempSeq) {
|
|
|
95651
95671
|
const startIndex = seqLength - nonTempSeqWithoutLeadingDashes.length;
|
|
95652
95672
|
const endIndex = seqLength - (seqLength - nonTempSeqWithoutTrailingDashes.length);
|
|
95653
95673
|
for (let index2 = startIndex; index2 < endIndex; index2++) {
|
|
95654
|
-
const
|
|
95655
|
-
const
|
|
95656
|
-
|
|
95657
|
-
|
|
95658
|
-
|
|
95674
|
+
const tempBase = tempSeq[index2].toLowerCase();
|
|
95675
|
+
const nonTempBase = nonTempSeq[index2].toLowerCase();
|
|
95676
|
+
const isMatch = tempBase === nonTempBase;
|
|
95677
|
+
let differenceType = null;
|
|
95678
|
+
if (!isMatch) {
|
|
95679
|
+
if (tempBase === "-") {
|
|
95680
|
+
differenceType = "insertion";
|
|
95681
|
+
} else if (nonTempBase === "-") {
|
|
95682
|
+
differenceType = "deletion";
|
|
95659
95683
|
} else {
|
|
95660
|
-
|
|
95661
|
-
start: index2,
|
|
95662
|
-
end: index2,
|
|
95663
|
-
isMatch
|
|
95664
|
-
});
|
|
95684
|
+
differenceType = "mismatch";
|
|
95665
95685
|
}
|
|
95686
|
+
}
|
|
95687
|
+
const previousRange = ranges[ranges.length - 1];
|
|
95688
|
+
if (previousRange && previousRange.isMatch === isMatch && previousRange.differenceType === differenceType) {
|
|
95689
|
+
previousRange.end++;
|
|
95690
|
+
} else if (previousRange) {
|
|
95691
|
+
ranges.push({ start: index2, end: index2, isMatch, differenceType });
|
|
95666
95692
|
} else {
|
|
95667
95693
|
ranges.push({
|
|
95668
95694
|
start: startIndex,
|
|
95669
95695
|
end: startIndex,
|
|
95670
|
-
isMatch
|
|
95696
|
+
isMatch,
|
|
95697
|
+
differenceType
|
|
95671
95698
|
});
|
|
95672
95699
|
}
|
|
95673
95700
|
}
|
|
@@ -117245,7 +117272,7 @@ function showFileDialog({ multiple = false, onSelect }) {
|
|
|
117245
117272
|
input.click();
|
|
117246
117273
|
}
|
|
117247
117274
|
__name(showFileDialog, "showFileDialog");
|
|
117248
|
-
const version = "0.8.
|
|
117275
|
+
const version = "0.8.41";
|
|
117249
117276
|
const packageJson = {
|
|
117250
117277
|
version
|
|
117251
117278
|
};
|
|
@@ -125114,11 +125141,13 @@ const _Minimap = class _Minimap extends React.Component {
|
|
|
125114
125141
|
dimensions: { width = 200 },
|
|
125115
125142
|
laneHeight,
|
|
125116
125143
|
laneSpacing = 1,
|
|
125117
|
-
isTrackSelected = []
|
|
125144
|
+
isTrackSelected = [],
|
|
125145
|
+
activeFilterType = "all"
|
|
125118
125146
|
} = this.props;
|
|
125119
125147
|
const charWidth2 = this.getCharWidth();
|
|
125120
125148
|
const {
|
|
125121
125149
|
matchHighlightRanges: _matchHighlightRanges,
|
|
125150
|
+
gapRanges = [],
|
|
125122
125151
|
alignmentData: { trimmedRange } = {}
|
|
125123
125152
|
} = alignmentTracks[i];
|
|
125124
125153
|
const matchHighlightRanges = !trimmedRange ? _matchHighlightRanges : flatMap(_matchHighlightRanges, (r2) => {
|
|
@@ -125145,10 +125174,19 @@ const _Minimap = class _Minimap extends React.Component {
|
|
|
125145
125174
|
charWidth2
|
|
125146
125175
|
);
|
|
125147
125176
|
const toAdd = `M${xStart},${y2} L${xStart + width2},${y2} L${xStart + width2},${y2 + height} L${xStart},${y2 + height}`;
|
|
125148
|
-
if (!range2.isMatch) {
|
|
125177
|
+
if (!range2.isMatch && (activeFilterType === "all" || range2.differenceType === activeFilterType)) {
|
|
125149
125178
|
redPath += toAdd;
|
|
125150
125179
|
}
|
|
125151
125180
|
});
|
|
125181
|
+
if (activeFilterType === "gap") {
|
|
125182
|
+
gapRanges.forEach((range2) => {
|
|
125183
|
+
const { xStart, width: width2 } = getXStartAndWidthFromNonCircularRange(
|
|
125184
|
+
range2,
|
|
125185
|
+
charWidth2
|
|
125186
|
+
);
|
|
125187
|
+
redPath += `M${xStart},${y2} L${xStart + width2},${y2} L${xStart + width2},${y2 + height} L${xStart},${y2 + height}`;
|
|
125188
|
+
});
|
|
125189
|
+
}
|
|
125152
125190
|
return /* @__PURE__ */ React.createElement(
|
|
125153
125191
|
"div",
|
|
125154
125192
|
{
|
|
@@ -125178,7 +125216,8 @@ const _Minimap = class _Minimap extends React.Component {
|
|
|
125178
125216
|
"scrollAlignmentView",
|
|
125179
125217
|
"laneHeight",
|
|
125180
125218
|
"laneSpacing",
|
|
125181
|
-
"isTrackSelected"
|
|
125219
|
+
"isTrackSelected",
|
|
125220
|
+
"activeFilterType"
|
|
125182
125221
|
].some((key) => props[key] !== newProps[key]))
|
|
125183
125222
|
return true;
|
|
125184
125223
|
return false;
|
|
@@ -125456,6 +125495,899 @@ function getTrimmedRangesToDisplay({ trimmedRange, seqLen }) {
|
|
|
125456
125495
|
return splitRangeIntoTwoPartsIfItIsCircular(inverted, seqLen);
|
|
125457
125496
|
}
|
|
125458
125497
|
__name(getTrimmedRangesToDisplay, "getTrimmedRangesToDisplay");
|
|
125498
|
+
function groupConsecutiveDifferences(differences) {
|
|
125499
|
+
const grouped = [];
|
|
125500
|
+
for (const diff of differences) {
|
|
125501
|
+
if (diff.type === "mismatch") {
|
|
125502
|
+
grouped.push(__spreadProps(__spreadValues({}, diff), { start: diff.position, end: diff.position }));
|
|
125503
|
+
continue;
|
|
125504
|
+
}
|
|
125505
|
+
const last2 = grouped[grouped.length - 1];
|
|
125506
|
+
if (last2 && last2.type === diff.type && last2.end === diff.position - 1) {
|
|
125507
|
+
grouped[grouped.length - 1] = __spreadProps(__spreadValues({}, last2), { end: diff.position });
|
|
125508
|
+
} else {
|
|
125509
|
+
grouped.push(__spreadProps(__spreadValues({}, diff), { start: diff.position, end: diff.position }));
|
|
125510
|
+
}
|
|
125511
|
+
}
|
|
125512
|
+
return grouped;
|
|
125513
|
+
}
|
|
125514
|
+
__name(groupConsecutiveDifferences, "groupConsecutiveDifferences");
|
|
125515
|
+
function findAlignmentDifferences(alignedSeqs) {
|
|
125516
|
+
var _a2;
|
|
125517
|
+
if (alignedSeqs.length < 2 || !((_a2 = alignedSeqs[0]) == null ? void 0 : _a2.length)) return [];
|
|
125518
|
+
const template = alignedSeqs[0].toLowerCase();
|
|
125519
|
+
const nonTemplates = alignedSeqs.slice(1).map((s2) => s2.toLowerCase());
|
|
125520
|
+
const trackBounds = nonTemplates.map((seq) => {
|
|
125521
|
+
const withoutLeading = seq.replace(/^-+/, "");
|
|
125522
|
+
const withoutTrailing = seq.replace(/-+$/, "");
|
|
125523
|
+
const start2 = seq.length - withoutLeading.length;
|
|
125524
|
+
const end2 = seq.length - (seq.length - withoutTrailing.length);
|
|
125525
|
+
return { start: start2, end: end2 };
|
|
125526
|
+
});
|
|
125527
|
+
const differences = [];
|
|
125528
|
+
for (let i = 0; i < template.length; i++) {
|
|
125529
|
+
const templateBase = template[i];
|
|
125530
|
+
const allNonTemplateBases = nonTemplates.map((seq) => seq[i]);
|
|
125531
|
+
const bases = [templateBase, ...allNonTemplateBases];
|
|
125532
|
+
const alignedIndices = trackBounds.reduce((acc, { start: start2, end: end2 }, idx) => {
|
|
125533
|
+
if (i >= start2 && i < end2) acc.push(idx);
|
|
125534
|
+
return acc;
|
|
125535
|
+
}, []);
|
|
125536
|
+
if (alignedIndices.length === 0) {
|
|
125537
|
+
differences.push({ position: i, type: "gap", bases });
|
|
125538
|
+
continue;
|
|
125539
|
+
}
|
|
125540
|
+
const alignedBases = alignedIndices.map((idx) => allNonTemplateBases[idx]);
|
|
125541
|
+
const templateIsGap = templateBase === "-";
|
|
125542
|
+
const nonTemplateHasBase = alignedBases.some((b3) => b3 !== "-");
|
|
125543
|
+
const nonTemplateHasGap = alignedBases.some((b3) => b3 === "-");
|
|
125544
|
+
if (templateIsGap && nonTemplateHasBase) {
|
|
125545
|
+
differences.push({ position: i, type: "insertion", bases });
|
|
125546
|
+
} else if (!templateIsGap && nonTemplateHasGap) {
|
|
125547
|
+
differences.push({ position: i, type: "deletion", bases });
|
|
125548
|
+
} else if (!templateIsGap) {
|
|
125549
|
+
const uniqueBases = /* @__PURE__ */ new Set([templateBase, ...alignedBases]);
|
|
125550
|
+
if (uniqueBases.size > 1) {
|
|
125551
|
+
differences.push({ position: i, type: "mismatch", bases });
|
|
125552
|
+
}
|
|
125553
|
+
}
|
|
125554
|
+
}
|
|
125555
|
+
return differences;
|
|
125556
|
+
}
|
|
125557
|
+
__name(findAlignmentDifferences, "findAlignmentDifferences");
|
|
125558
|
+
function scrollToAlignmentSelection() {
|
|
125559
|
+
const el = document.querySelector(".veCaret");
|
|
125560
|
+
if (el) {
|
|
125561
|
+
el.scrollIntoView({ inline: "center", block: "nearest" });
|
|
125562
|
+
}
|
|
125563
|
+
}
|
|
125564
|
+
__name(scrollToAlignmentSelection, "scrollToAlignmentSelection");
|
|
125565
|
+
function updateCaretPosition({ start: start2, end: end2 }) {
|
|
125566
|
+
if (window.updateAlignmentSelection) {
|
|
125567
|
+
window.updateAlignmentSelection({ start: start2, end: end2 });
|
|
125568
|
+
}
|
|
125569
|
+
}
|
|
125570
|
+
__name(updateCaretPosition, "updateCaretPosition");
|
|
125571
|
+
const FILTER_OPTIONS = [
|
|
125572
|
+
{ value: "all", label: "All" },
|
|
125573
|
+
{ value: "mismatch", label: "Mismatches" },
|
|
125574
|
+
{ value: "insertion", label: "Insertions" },
|
|
125575
|
+
{ value: "deletion", label: "Deletions" },
|
|
125576
|
+
{ value: "gap", label: "Gaps" }
|
|
125577
|
+
];
|
|
125578
|
+
function FindMismatches(props) {
|
|
125579
|
+
var _a2;
|
|
125580
|
+
const { alignmentJson, id: id2, onFilterChange } = props;
|
|
125581
|
+
const alignedSeqs = React.useMemo(
|
|
125582
|
+
() => alignmentJson.map((t2) => {
|
|
125583
|
+
var _a3;
|
|
125584
|
+
return ((_a3 = t2.alignmentData) == null ? void 0 : _a3.sequence) || "";
|
|
125585
|
+
}),
|
|
125586
|
+
[alignmentJson]
|
|
125587
|
+
);
|
|
125588
|
+
const [activeFilter, setActiveFilter] = React.useState("all");
|
|
125589
|
+
const allDifferences = React.useMemo(
|
|
125590
|
+
() => groupConsecutiveDifferences(findAlignmentDifferences(alignedSeqs)),
|
|
125591
|
+
[alignedSeqs]
|
|
125592
|
+
);
|
|
125593
|
+
const countsByType = React.useMemo(() => {
|
|
125594
|
+
const counts = { all: 0, mismatch: 0, insertion: 0, deletion: 0, gap: 0 };
|
|
125595
|
+
allDifferences.forEach((d2) => {
|
|
125596
|
+
counts[d2.type] = (counts[d2.type] || 0) + 1;
|
|
125597
|
+
counts.all++;
|
|
125598
|
+
});
|
|
125599
|
+
return counts;
|
|
125600
|
+
}, [allDifferences]);
|
|
125601
|
+
const differences = React.useMemo(() => {
|
|
125602
|
+
const filtered = activeFilter === "all" ? allDifferences : allDifferences.filter((d2) => d2.type === activeFilter);
|
|
125603
|
+
return [{ position: -1, start: -1, end: -1, bases: [""] }, ...filtered];
|
|
125604
|
+
}, [allDifferences, activeFilter]);
|
|
125605
|
+
const currentCaretPosition = reactRedux.useSelector(
|
|
125606
|
+
(state2) => {
|
|
125607
|
+
var _a3;
|
|
125608
|
+
return (_a3 = state2.VectorEditor.__allEditorsOptions.alignments[id2]) == null ? void 0 : _a3.caretPosition;
|
|
125609
|
+
}
|
|
125610
|
+
);
|
|
125611
|
+
const [currentIdx, setCurrentIdx] = React.useState(0);
|
|
125612
|
+
const currentDiff = differences[currentIdx];
|
|
125613
|
+
const disablePrev = currentIdx <= 1;
|
|
125614
|
+
const disableNext = currentIdx >= differences.length - 1;
|
|
125615
|
+
React.useEffect(() => {
|
|
125616
|
+
setCurrentIdx(0);
|
|
125617
|
+
}, [activeFilter]);
|
|
125618
|
+
React.useEffect(() => {
|
|
125619
|
+
onFilterChange == null ? void 0 : onFilterChange({ activeFilter });
|
|
125620
|
+
}, [activeFilter, onFilterChange]);
|
|
125621
|
+
React.useEffect(() => {
|
|
125622
|
+
if (currentCaretPosition !== -1) {
|
|
125623
|
+
const diffIdx = differences.findIndex(
|
|
125624
|
+
(d2, i) => i > 0 && currentCaretPosition >= d2.start && currentCaretPosition <= d2.end + 1
|
|
125625
|
+
);
|
|
125626
|
+
if (diffIdx !== -1 && diffIdx !== currentIdx) {
|
|
125627
|
+
setCurrentIdx(diffIdx);
|
|
125628
|
+
}
|
|
125629
|
+
}
|
|
125630
|
+
}, [currentCaretPosition, differences, currentIdx]);
|
|
125631
|
+
const updateView = /* @__PURE__ */ __name((diff) => {
|
|
125632
|
+
const idx = differences.indexOf(diff);
|
|
125633
|
+
const { start: start2, end: end2 } = diff;
|
|
125634
|
+
setCurrentIdx(idx);
|
|
125635
|
+
updateCaretPosition({ start: start2, end: end2 });
|
|
125636
|
+
setTimeout(() => {
|
|
125637
|
+
scrollToAlignmentSelection();
|
|
125638
|
+
}, 0);
|
|
125639
|
+
}, "updateView");
|
|
125640
|
+
const prevDifference = /* @__PURE__ */ __name(() => {
|
|
125641
|
+
var _a3, _b2;
|
|
125642
|
+
const pivot = currentCaretPosition >= 0 ? currentCaretPosition : (_b2 = (_a3 = differences[currentIdx]) == null ? void 0 : _a3.start) != null ? _b2 : 0;
|
|
125643
|
+
const prev = [...differences].reverse().find((d2) => d2.start >= 0 && d2.start < pivot);
|
|
125644
|
+
if (prev) updateView(prev);
|
|
125645
|
+
}, "prevDifference");
|
|
125646
|
+
const nextDifference = /* @__PURE__ */ __name(() => {
|
|
125647
|
+
var _a3, _b2;
|
|
125648
|
+
const pivot = currentCaretPosition >= 0 ? currentCaretPosition : (_b2 = (_a3 = differences[currentIdx]) == null ? void 0 : _a3.start) != null ? _b2 : -1;
|
|
125649
|
+
const next = differences.find((d2) => d2.start > pivot && d2.start >= 0);
|
|
125650
|
+
if (next) updateView(next);
|
|
125651
|
+
}, "nextDifference");
|
|
125652
|
+
const noDifferences = differences.length <= 1;
|
|
125653
|
+
const activeOption = FILTER_OPTIONS.find((o2) => o2.value === activeFilter);
|
|
125654
|
+
const activeLabel = (_a2 = activeOption == null ? void 0 : activeOption.label) != null ? _a2 : "Differences";
|
|
125655
|
+
const filterMenu = /* @__PURE__ */ React.createElement(core.Menu, null, FILTER_OPTIONS.map(({ value, label }) => {
|
|
125656
|
+
var _a3;
|
|
125657
|
+
const count2 = (_a3 = countsByType[value]) != null ? _a3 : 0;
|
|
125658
|
+
const isActive2 = activeFilter === value;
|
|
125659
|
+
return /* @__PURE__ */ React.createElement(
|
|
125660
|
+
core.MenuItem,
|
|
125661
|
+
{
|
|
125662
|
+
key: value,
|
|
125663
|
+
active: isActive2,
|
|
125664
|
+
onClick: /* @__PURE__ */ __name(() => setActiveFilter(value), "onClick"),
|
|
125665
|
+
text: /* @__PURE__ */ React.createElement("span", { className: "veDiffMenuItem-inner" }, label, /* @__PURE__ */ React.createElement(core.Tag, { round: true, minimal: true, style: { marginLeft: 6 } }, count2))
|
|
125666
|
+
}
|
|
125667
|
+
);
|
|
125668
|
+
}));
|
|
125669
|
+
return /* @__PURE__ */ React.createElement("div", { className: "veDiffNavigator" }, /* @__PURE__ */ React.createElement(
|
|
125670
|
+
core.Popover,
|
|
125671
|
+
{
|
|
125672
|
+
minimal: true,
|
|
125673
|
+
position: core.Position.BOTTOM_LEFT,
|
|
125674
|
+
content: filterMenu,
|
|
125675
|
+
target: /* @__PURE__ */ React.createElement(
|
|
125676
|
+
core.Button,
|
|
125677
|
+
{
|
|
125678
|
+
minimal: true,
|
|
125679
|
+
"data-tip": "Filter Difference Type",
|
|
125680
|
+
small: true,
|
|
125681
|
+
rightIcon: "caret-down",
|
|
125682
|
+
className: "veDiffFilter-trigger"
|
|
125683
|
+
},
|
|
125684
|
+
activeLabel
|
|
125685
|
+
)
|
|
125686
|
+
}
|
|
125687
|
+
), noDifferences ? /* @__PURE__ */ React.createElement("span", { className: "veDiffNav-empty" }, "no", " ", activeFilter === "all" ? "differences" : activeLabel.toLowerCase()) : /* @__PURE__ */ React.createElement("div", { className: "veDiffNav" }, /* @__PURE__ */ React.createElement(
|
|
125688
|
+
core.Button,
|
|
125689
|
+
{
|
|
125690
|
+
minimal: true,
|
|
125691
|
+
small: true,
|
|
125692
|
+
"data-tip": "Previous Difference",
|
|
125693
|
+
icon: "arrow-left",
|
|
125694
|
+
intent: core.Intent.PRIMARY,
|
|
125695
|
+
onClick: prevDifference,
|
|
125696
|
+
disabled: disablePrev
|
|
125697
|
+
}
|
|
125698
|
+
), /* @__PURE__ */ React.createElement("div", { className: "veDiffNav-center" }, /* @__PURE__ */ React.createElement("span", { className: "veDiffNav-fraction" }, currentIdx, /* @__PURE__ */ React.createElement("span", { className: "veDiffNav-sep" }, "/"), differences.length - 1), (currentDiff == null ? void 0 : currentDiff.start) > -1 && /* @__PURE__ */ React.createElement("span", { className: "veDiffNav-pos" }, ":", currentDiff.start + 1)), /* @__PURE__ */ React.createElement(
|
|
125699
|
+
core.Button,
|
|
125700
|
+
{
|
|
125701
|
+
minimal: true,
|
|
125702
|
+
small: true,
|
|
125703
|
+
"data-tip": "Next Difference",
|
|
125704
|
+
icon: "arrow-right",
|
|
125705
|
+
intent: core.Intent.PRIMARY,
|
|
125706
|
+
onClick: nextDifference,
|
|
125707
|
+
disabled: disableNext
|
|
125708
|
+
}
|
|
125709
|
+
)));
|
|
125710
|
+
}
|
|
125711
|
+
__name(FindMismatches, "FindMismatches");
|
|
125712
|
+
function getGapMap(sequence2) {
|
|
125713
|
+
const gapMap = [0];
|
|
125714
|
+
sequence2.split("").forEach((char) => {
|
|
125715
|
+
if (char === "-") {
|
|
125716
|
+
gapMap[Math.max(0, gapMap.length - 1)] = (gapMap[Math.max(0, gapMap.length - 1)] || 0) + 1;
|
|
125717
|
+
} else {
|
|
125718
|
+
gapMap.push(gapMap[gapMap.length - 1] || 0);
|
|
125719
|
+
}
|
|
125720
|
+
});
|
|
125721
|
+
return gapMap;
|
|
125722
|
+
}
|
|
125723
|
+
__name(getGapMap, "getGapMap");
|
|
125724
|
+
const MATCH_COLOR = "gold";
|
|
125725
|
+
const CURRENT_MATCH_COLOR = "green";
|
|
125726
|
+
const MISMATCH_COLOR = "red";
|
|
125727
|
+
const ANNOTATION_TYPES = ["features", "parts", "primers"];
|
|
125728
|
+
const initialSearchState = {
|
|
125729
|
+
searchText: "",
|
|
125730
|
+
matches: [],
|
|
125731
|
+
currentMatchIndex: 0,
|
|
125732
|
+
searched: false,
|
|
125733
|
+
featureMatches: [],
|
|
125734
|
+
dnaOrAA: "DNA",
|
|
125735
|
+
ambiguousOrLiteral: "LITERAL",
|
|
125736
|
+
mismatchesAllowed: 0
|
|
125737
|
+
};
|
|
125738
|
+
function searchReducer(state2, action2) {
|
|
125739
|
+
switch (action2.type) {
|
|
125740
|
+
case "SET_SEARCH_TEXT":
|
|
125741
|
+
return __spreadProps(__spreadValues({}, state2), { searchText: action2.payload });
|
|
125742
|
+
case "SET_MATCHES":
|
|
125743
|
+
return __spreadProps(__spreadValues({}, state2), {
|
|
125744
|
+
matches: action2.payload.matches,
|
|
125745
|
+
currentMatchIndex: action2.payload.currentMatchIndex
|
|
125746
|
+
});
|
|
125747
|
+
case "SET_CURRENT_MATCH_INDEX":
|
|
125748
|
+
return __spreadProps(__spreadValues({}, state2), { currentMatchIndex: action2.payload });
|
|
125749
|
+
case "SET_SEARCHED":
|
|
125750
|
+
return __spreadProps(__spreadValues({}, state2), { searched: action2.payload });
|
|
125751
|
+
case "SEARCH_COMPLETE":
|
|
125752
|
+
return __spreadProps(__spreadValues({}, state2), {
|
|
125753
|
+
matches: action2.payload.matches,
|
|
125754
|
+
currentMatchIndex: action2.payload.currentMatchIndex,
|
|
125755
|
+
searched: action2.payload.searched
|
|
125756
|
+
});
|
|
125757
|
+
case "SET_FEATURE_MATCHES":
|
|
125758
|
+
return __spreadProps(__spreadValues({}, state2), { featureMatches: action2.payload });
|
|
125759
|
+
case "SET_DNA_OR_AA":
|
|
125760
|
+
return __spreadProps(__spreadValues({}, state2), { dnaOrAA: action2.payload });
|
|
125761
|
+
case "SET_AMBIGUOUS_OR_LITERAL":
|
|
125762
|
+
return __spreadProps(__spreadValues({}, state2), { ambiguousOrLiteral: action2.payload });
|
|
125763
|
+
case "SET_MISMATCHES_ALLOWED":
|
|
125764
|
+
return __spreadProps(__spreadValues({}, state2), { mismatchesAllowed: Math.max(0, action2.payload) });
|
|
125765
|
+
case "RESET":
|
|
125766
|
+
return __spreadValues({}, initialSearchState);
|
|
125767
|
+
default:
|
|
125768
|
+
return state2;
|
|
125769
|
+
}
|
|
125770
|
+
}
|
|
125771
|
+
__name(searchReducer, "searchReducer");
|
|
125772
|
+
function AlignmentSearchBar(props) {
|
|
125773
|
+
const { alignmentTracks = [], setSearchMatchLayers } = props;
|
|
125774
|
+
const [searchState, dispatch] = React.useReducer(searchReducer, initialSearchState);
|
|
125775
|
+
const {
|
|
125776
|
+
searchText,
|
|
125777
|
+
matches,
|
|
125778
|
+
currentMatchIndex,
|
|
125779
|
+
searched,
|
|
125780
|
+
featureMatches,
|
|
125781
|
+
dnaOrAA,
|
|
125782
|
+
ambiguousOrLiteral,
|
|
125783
|
+
mismatchesAllowed
|
|
125784
|
+
} = searchState;
|
|
125785
|
+
const debouncedSearch = React.useRef(
|
|
125786
|
+
debounce$1((text2, search2, featureSearch) => {
|
|
125787
|
+
search2(text2);
|
|
125788
|
+
featureSearch(text2);
|
|
125789
|
+
}, 50)
|
|
125790
|
+
).current;
|
|
125791
|
+
React.useEffect(() => {
|
|
125792
|
+
return () => {
|
|
125793
|
+
debouncedSearch.cancel();
|
|
125794
|
+
};
|
|
125795
|
+
}, [debouncedSearch]);
|
|
125796
|
+
const [highlightAll, setHighlightAll] = React.useState(false);
|
|
125797
|
+
const [isExpanded, setIsExpanded] = React.useState(false);
|
|
125798
|
+
const [isOpen, setIsOpen] = React.useState(false);
|
|
125799
|
+
const [isPopoverOpen, setIsPopoverOpen] = React.useState(false);
|
|
125800
|
+
const handleToggleExpanded = React.useCallback(() => {
|
|
125801
|
+
setIsExpanded((prev) => {
|
|
125802
|
+
const next = !prev;
|
|
125803
|
+
if (!next) setIsPopoverOpen(true);
|
|
125804
|
+
return next;
|
|
125805
|
+
});
|
|
125806
|
+
}, [setIsPopoverOpen]);
|
|
125807
|
+
React.useEffect(() => {
|
|
125808
|
+
dispatch({ type: "RESET" });
|
|
125809
|
+
if (setSearchMatchLayers) setSearchMatchLayers([]);
|
|
125810
|
+
}, [setSearchMatchLayers]);
|
|
125811
|
+
const buildMatchLayers = React.useCallback(
|
|
125812
|
+
(allMatches, activeIndex) => {
|
|
125813
|
+
if (!setSearchMatchLayers) return;
|
|
125814
|
+
if (!allMatches.length) {
|
|
125815
|
+
setSearchMatchLayers([]);
|
|
125816
|
+
return;
|
|
125817
|
+
}
|
|
125818
|
+
const makeMismatchLayers = /* @__PURE__ */ __name((match) => (match.mismatchAlignmentPositions || []).map((pos) => ({
|
|
125819
|
+
start: pos,
|
|
125820
|
+
end: pos,
|
|
125821
|
+
color: MISMATCH_COLOR,
|
|
125822
|
+
className: "veSearchMismatch",
|
|
125823
|
+
ignoreGaps: true,
|
|
125824
|
+
hideCarets: true
|
|
125825
|
+
})), "makeMismatchLayers");
|
|
125826
|
+
const layers = highlightAll ? allMatches.flatMap((match, i) => [
|
|
125827
|
+
{
|
|
125828
|
+
start: match.alignmentStart,
|
|
125829
|
+
end: match.alignmentEnd,
|
|
125830
|
+
color: i === activeIndex ? CURRENT_MATCH_COLOR : MATCH_COLOR,
|
|
125831
|
+
className: i === activeIndex ? "veSearchLayerActive" : "veSearchLayer",
|
|
125832
|
+
ignoreGaps: true
|
|
125833
|
+
},
|
|
125834
|
+
...makeMismatchLayers(match)
|
|
125835
|
+
]) : [
|
|
125836
|
+
{
|
|
125837
|
+
start: allMatches[activeIndex].alignmentStart,
|
|
125838
|
+
end: allMatches[activeIndex].alignmentEnd,
|
|
125839
|
+
color: CURRENT_MATCH_COLOR,
|
|
125840
|
+
className: "veSearchLayerActive",
|
|
125841
|
+
ignoreGaps: true
|
|
125842
|
+
},
|
|
125843
|
+
...makeMismatchLayers(allMatches[activeIndex])
|
|
125844
|
+
];
|
|
125845
|
+
setSearchMatchLayers(layers);
|
|
125846
|
+
},
|
|
125847
|
+
[setSearchMatchLayers, highlightAll]
|
|
125848
|
+
);
|
|
125849
|
+
const navigateTo = React.useCallback(
|
|
125850
|
+
(allMatches, index2) => {
|
|
125851
|
+
const match = allMatches[index2];
|
|
125852
|
+
if (!match) return;
|
|
125853
|
+
updateCaretPosition({
|
|
125854
|
+
start: match.alignmentStart,
|
|
125855
|
+
end: match.alignmentEnd
|
|
125856
|
+
});
|
|
125857
|
+
setTimeout(() => {
|
|
125858
|
+
scrollToAlignmentSelection();
|
|
125859
|
+
}, 0);
|
|
125860
|
+
buildMatchLayers(allMatches, index2);
|
|
125861
|
+
},
|
|
125862
|
+
[buildMatchLayers]
|
|
125863
|
+
);
|
|
125864
|
+
const runSearch = React.useCallback(
|
|
125865
|
+
(text2) => {
|
|
125866
|
+
const query = text2.trim();
|
|
125867
|
+
if (!query) {
|
|
125868
|
+
dispatch({
|
|
125869
|
+
type: "SEARCH_COMPLETE",
|
|
125870
|
+
payload: { matches: [], currentMatchIndex: 0, searched: false }
|
|
125871
|
+
});
|
|
125872
|
+
if (setSearchMatchLayers) setSearchMatchLayers([]);
|
|
125873
|
+
return;
|
|
125874
|
+
}
|
|
125875
|
+
const allMatches = [];
|
|
125876
|
+
alignmentTracks.slice(0, 1).forEach((track, trackIndex) => {
|
|
125877
|
+
var _a2, _b2;
|
|
125878
|
+
const rawSeq = ((_a2 = track.sequenceData) == null ? void 0 : _a2.sequence) || "";
|
|
125879
|
+
const alignedSeq = ((_b2 = track.alignmentData) == null ? void 0 : _b2.sequence) || "";
|
|
125880
|
+
const gapMap = getGapMap(alignedSeq);
|
|
125881
|
+
const gapOffset = /* @__PURE__ */ __name((n2) => {
|
|
125882
|
+
var _a3, _b3;
|
|
125883
|
+
return (_b3 = (_a3 = gapMap[n2]) != null ? _a3 : gapMap[gapMap.length - 1]) != null ? _b3 : 0;
|
|
125884
|
+
}, "gapOffset");
|
|
125885
|
+
let seqMatches = [];
|
|
125886
|
+
if (dnaOrAA === "DNA" && ambiguousOrLiteral === "LITERAL" && mismatchesAllowed > 0) {
|
|
125887
|
+
const approxMatches = findApproxMatches(
|
|
125888
|
+
query.toLowerCase(),
|
|
125889
|
+
rawSeq.toLowerCase(),
|
|
125890
|
+
mismatchesAllowed,
|
|
125891
|
+
false
|
|
125892
|
+
);
|
|
125893
|
+
seqMatches = approxMatches.map((m2) => ({
|
|
125894
|
+
start: m2.index,
|
|
125895
|
+
end: m2.index + m2.match.length - 1,
|
|
125896
|
+
mismatchPositions: m2.mismatchPositions
|
|
125897
|
+
}));
|
|
125898
|
+
} else {
|
|
125899
|
+
seqMatches = findSequenceMatches(rawSeq, query, {
|
|
125900
|
+
isCircular: false,
|
|
125901
|
+
isAmbiguous: ambiguousOrLiteral === "AMBIGUOUS",
|
|
125902
|
+
isProteinSearch: dnaOrAA !== "DNA",
|
|
125903
|
+
searchReverseStrand: dnaOrAA === "DNA"
|
|
125904
|
+
});
|
|
125905
|
+
}
|
|
125906
|
+
const hitsToProcess = query.length < 2 ? seqMatches.slice(0, 1) : seqMatches;
|
|
125907
|
+
hitsToProcess.forEach(({ start: start2, end: end2, mismatchPositions }) => {
|
|
125908
|
+
const alignmentStart = start2 + gapOffset(start2);
|
|
125909
|
+
const alignmentEnd = end2 + gapOffset(end2);
|
|
125910
|
+
const mismatchAlignmentPositions = (mismatchPositions || []).map(
|
|
125911
|
+
(p2) => {
|
|
125912
|
+
const absPos = start2 + p2;
|
|
125913
|
+
return absPos + gapOffset(absPos);
|
|
125914
|
+
}
|
|
125915
|
+
);
|
|
125916
|
+
allMatches.push({
|
|
125917
|
+
trackIndex,
|
|
125918
|
+
alignmentStart,
|
|
125919
|
+
alignmentEnd,
|
|
125920
|
+
mismatchAlignmentPositions
|
|
125921
|
+
});
|
|
125922
|
+
});
|
|
125923
|
+
});
|
|
125924
|
+
const results = query.length < 2 ? allMatches.slice(0, 1) : allMatches;
|
|
125925
|
+
dispatch({
|
|
125926
|
+
type: "SEARCH_COMPLETE",
|
|
125927
|
+
payload: { matches: results, currentMatchIndex: 0, searched: true }
|
|
125928
|
+
});
|
|
125929
|
+
if (results.length) {
|
|
125930
|
+
navigateTo(results, 0);
|
|
125931
|
+
} else {
|
|
125932
|
+
if (setSearchMatchLayers) setSearchMatchLayers([]);
|
|
125933
|
+
}
|
|
125934
|
+
},
|
|
125935
|
+
[
|
|
125936
|
+
alignmentTracks,
|
|
125937
|
+
navigateTo,
|
|
125938
|
+
dnaOrAA,
|
|
125939
|
+
ambiguousOrLiteral,
|
|
125940
|
+
mismatchesAllowed,
|
|
125941
|
+
setSearchMatchLayers
|
|
125942
|
+
]
|
|
125943
|
+
);
|
|
125944
|
+
const runFeatureSearch = React.useCallback(
|
|
125945
|
+
(text2) => {
|
|
125946
|
+
const query = text2.trim().toLowerCase();
|
|
125947
|
+
if (!query) {
|
|
125948
|
+
dispatch({ type: "SET_FEATURE_MATCHES", payload: [] });
|
|
125949
|
+
return;
|
|
125950
|
+
}
|
|
125951
|
+
const allMatches = [];
|
|
125952
|
+
alignmentTracks.slice(0, 1).forEach((track, trackIndex) => {
|
|
125953
|
+
const { sequenceData: sequenceData2, alignmentData } = track;
|
|
125954
|
+
const alignedSeq = (alignmentData == null ? void 0 : alignmentData.sequence) || "";
|
|
125955
|
+
const gapMap = getGapMap(alignedSeq);
|
|
125956
|
+
const gapOffset = /* @__PURE__ */ __name((n2) => {
|
|
125957
|
+
var _a2, _b2;
|
|
125958
|
+
return (_b2 = (_a2 = gapMap[n2]) != null ? _a2 : gapMap[gapMap.length - 1]) != null ? _b2 : 0;
|
|
125959
|
+
}, "gapOffset");
|
|
125960
|
+
const trackName = (alignmentData == null ? void 0 : alignmentData.name) || (sequenceData2 == null ? void 0 : sequenceData2.name) || (sequenceData2 == null ? void 0 : sequenceData2.id) || "";
|
|
125961
|
+
ANNOTATION_TYPES.forEach((type2) => {
|
|
125962
|
+
const anns = sequenceData2 == null ? void 0 : sequenceData2[type2];
|
|
125963
|
+
if (!anns) return;
|
|
125964
|
+
const annsArray = Array.isArray(anns) ? anns : Object.values(anns);
|
|
125965
|
+
annsArray.forEach((ann) => {
|
|
125966
|
+
if (!ann.name) return;
|
|
125967
|
+
if (ann.name.toLowerCase().includes(query)) {
|
|
125968
|
+
const alignmentStart = ann.start + gapOffset(ann.start);
|
|
125969
|
+
const alignmentEnd = ann.end + gapOffset(ann.end);
|
|
125970
|
+
allMatches.push({
|
|
125971
|
+
trackIndex,
|
|
125972
|
+
trackName,
|
|
125973
|
+
type: type2,
|
|
125974
|
+
annotation: ann,
|
|
125975
|
+
alignmentStart,
|
|
125976
|
+
alignmentEnd
|
|
125977
|
+
});
|
|
125978
|
+
}
|
|
125979
|
+
});
|
|
125980
|
+
});
|
|
125981
|
+
});
|
|
125982
|
+
dispatch({ type: "SET_FEATURE_MATCHES", payload: allMatches });
|
|
125983
|
+
},
|
|
125984
|
+
[alignmentTracks]
|
|
125985
|
+
);
|
|
125986
|
+
const goToPrev = React.useCallback(() => {
|
|
125987
|
+
if (!matches.length) return;
|
|
125988
|
+
const newIndex = currentMatchIndex === 0 ? matches.length - 1 : currentMatchIndex - 1;
|
|
125989
|
+
dispatch({ type: "SET_CURRENT_MATCH_INDEX", payload: newIndex });
|
|
125990
|
+
navigateTo(matches, newIndex);
|
|
125991
|
+
}, [matches, currentMatchIndex, navigateTo]);
|
|
125992
|
+
const goToNext = React.useCallback(() => {
|
|
125993
|
+
if (!matches.length) return;
|
|
125994
|
+
const newIndex = currentMatchIndex === matches.length - 1 ? 0 : currentMatchIndex + 1;
|
|
125995
|
+
dispatch({ type: "SET_CURRENT_MATCH_INDEX", payload: newIndex });
|
|
125996
|
+
navigateTo(matches, newIndex);
|
|
125997
|
+
}, [matches, currentMatchIndex, navigateTo]);
|
|
125998
|
+
const handleKeyDown = React.useCallback(
|
|
125999
|
+
(e) => {
|
|
126000
|
+
if (e.key === "Escape") {
|
|
126001
|
+
setIsOpen(false);
|
|
126002
|
+
}
|
|
126003
|
+
if (e.key === "Enter") {
|
|
126004
|
+
if (e.shiftKey) {
|
|
126005
|
+
goToPrev();
|
|
126006
|
+
} else {
|
|
126007
|
+
goToNext();
|
|
126008
|
+
}
|
|
126009
|
+
e.preventDefault();
|
|
126010
|
+
e.stopPropagation();
|
|
126011
|
+
}
|
|
126012
|
+
},
|
|
126013
|
+
[goToPrev, goToNext]
|
|
126014
|
+
);
|
|
126015
|
+
React.useEffect(() => {
|
|
126016
|
+
if (!searched || !searchText.trim()) return;
|
|
126017
|
+
runSearch(searchText);
|
|
126018
|
+
runFeatureSearch(searchText);
|
|
126019
|
+
}, [
|
|
126020
|
+
dnaOrAA,
|
|
126021
|
+
ambiguousOrLiteral,
|
|
126022
|
+
mismatchesAllowed,
|
|
126023
|
+
runSearch,
|
|
126024
|
+
runFeatureSearch,
|
|
126025
|
+
searched,
|
|
126026
|
+
searchText
|
|
126027
|
+
]);
|
|
126028
|
+
React.useEffect(() => {
|
|
126029
|
+
if (searchText.trim().length < 1) setHighlightAll(false);
|
|
126030
|
+
}, [searchText]);
|
|
126031
|
+
const prevHighlightAll = React.useRef(highlightAll);
|
|
126032
|
+
React.useEffect(() => {
|
|
126033
|
+
if (prevHighlightAll.current !== highlightAll) {
|
|
126034
|
+
prevHighlightAll.current = highlightAll;
|
|
126035
|
+
if (matches.length) buildMatchLayers(matches, currentMatchIndex);
|
|
126036
|
+
}
|
|
126037
|
+
}, [highlightAll, matches, currentMatchIndex, buildMatchLayers]);
|
|
126038
|
+
const hasMatches = matches.length > 0;
|
|
126039
|
+
const handleChange = React.useCallback(
|
|
126040
|
+
(e) => {
|
|
126041
|
+
const value = e.target.value;
|
|
126042
|
+
dispatch({ type: "SET_SEARCH_TEXT", payload: value });
|
|
126043
|
+
debouncedSearch(value, runSearch, runFeatureSearch);
|
|
126044
|
+
},
|
|
126045
|
+
[debouncedSearch, runSearch, runFeatureSearch]
|
|
126046
|
+
);
|
|
126047
|
+
const handleFeatureClick = React.useCallback((featureMatch) => {
|
|
126048
|
+
updateCaretPosition({
|
|
126049
|
+
start: featureMatch.alignmentStart,
|
|
126050
|
+
end: featureMatch.alignmentEnd
|
|
126051
|
+
});
|
|
126052
|
+
setTimeout(() => {
|
|
126053
|
+
scrollToAlignmentSelection();
|
|
126054
|
+
}, 0);
|
|
126055
|
+
}, []);
|
|
126056
|
+
const matchCounter = /* @__PURE__ */ React.createElement(
|
|
126057
|
+
"span",
|
|
126058
|
+
{
|
|
126059
|
+
style: {
|
|
126060
|
+
marginRight: 3,
|
|
126061
|
+
color: "lightgrey",
|
|
126062
|
+
fontSize: "0.9em",
|
|
126063
|
+
whiteSpace: "nowrap"
|
|
126064
|
+
}
|
|
126065
|
+
},
|
|
126066
|
+
hasMatches ? currentMatchIndex + 1 : 0,
|
|
126067
|
+
"/",
|
|
126068
|
+
matches.length
|
|
126069
|
+
);
|
|
126070
|
+
const inlineNavEl = /* @__PURE__ */ React.createElement("span", { style: { display: "flex", alignItems: "center" } }, !isExpanded && /* @__PURE__ */ React.createElement(
|
|
126071
|
+
core.Popover,
|
|
126072
|
+
{
|
|
126073
|
+
autoFocus: false,
|
|
126074
|
+
enforceFocus: false,
|
|
126075
|
+
isOpen: isPopoverOpen,
|
|
126076
|
+
onInteraction: setIsPopoverOpen,
|
|
126077
|
+
position: core.Position.TOP,
|
|
126078
|
+
content: /* @__PURE__ */ React.createElement(
|
|
126079
|
+
"div",
|
|
126080
|
+
{
|
|
126081
|
+
className: "ve-find-options-popover",
|
|
126082
|
+
style: {
|
|
126083
|
+
display: "flex",
|
|
126084
|
+
flexDirection: "column",
|
|
126085
|
+
paddingLeft: 20,
|
|
126086
|
+
paddingBottom: 10,
|
|
126087
|
+
paddingTop: 10,
|
|
126088
|
+
paddingRight: 20,
|
|
126089
|
+
gap: 6
|
|
126090
|
+
}
|
|
126091
|
+
},
|
|
126092
|
+
/* @__PURE__ */ React.createElement(
|
|
126093
|
+
FindOptionsPanel,
|
|
126094
|
+
{
|
|
126095
|
+
dnaOrAA,
|
|
126096
|
+
ambiguousOrLiteral,
|
|
126097
|
+
mismatchesAllowed,
|
|
126098
|
+
searchText,
|
|
126099
|
+
matches,
|
|
126100
|
+
dispatch,
|
|
126101
|
+
highlightAll,
|
|
126102
|
+
setHighlightAll,
|
|
126103
|
+
isExpanded,
|
|
126104
|
+
onToggleExpanded: handleToggleExpanded
|
|
126105
|
+
}
|
|
126106
|
+
)
|
|
126107
|
+
),
|
|
126108
|
+
target: /* @__PURE__ */ React.createElement(core.Button, { minimal: true, icon: "wrench", "data-tip": "Options" })
|
|
126109
|
+
}
|
|
126110
|
+
), matchCounter, /* @__PURE__ */ React.createElement(
|
|
126111
|
+
core.Button,
|
|
126112
|
+
{
|
|
126113
|
+
minimal: true,
|
|
126114
|
+
small: true,
|
|
126115
|
+
icon: "caret-left",
|
|
126116
|
+
"data-tip": "Previous",
|
|
126117
|
+
disabled: !hasMatches,
|
|
126118
|
+
onClick: goToPrev
|
|
126119
|
+
}
|
|
126120
|
+
), /* @__PURE__ */ React.createElement(
|
|
126121
|
+
core.Button,
|
|
126122
|
+
{
|
|
126123
|
+
minimal: true,
|
|
126124
|
+
small: true,
|
|
126125
|
+
icon: "caret-right",
|
|
126126
|
+
"data-tip": "Next",
|
|
126127
|
+
disabled: !hasMatches,
|
|
126128
|
+
onClick: goToNext
|
|
126129
|
+
}
|
|
126130
|
+
), /* @__PURE__ */ React.createElement(
|
|
126131
|
+
core.Button,
|
|
126132
|
+
{
|
|
126133
|
+
minimal: true,
|
|
126134
|
+
small: true,
|
|
126135
|
+
"data-tip": "Close (Esc)",
|
|
126136
|
+
icon: "small-cross",
|
|
126137
|
+
onClick: /* @__PURE__ */ __name(() => setIsOpen(false), "onClick")
|
|
126138
|
+
}
|
|
126139
|
+
));
|
|
126140
|
+
const expandedNavEl = /* @__PURE__ */ React.createElement("span", { style: { display: "flex", alignItems: "center" } }, matchCounter, /* @__PURE__ */ React.createElement(
|
|
126141
|
+
core.Button,
|
|
126142
|
+
{
|
|
126143
|
+
minimal: true,
|
|
126144
|
+
small: true,
|
|
126145
|
+
icon: "caret-up",
|
|
126146
|
+
disabled: !hasMatches,
|
|
126147
|
+
onClick: goToPrev
|
|
126148
|
+
}
|
|
126149
|
+
), /* @__PURE__ */ React.createElement(
|
|
126150
|
+
core.Button,
|
|
126151
|
+
{
|
|
126152
|
+
minimal: true,
|
|
126153
|
+
small: true,
|
|
126154
|
+
icon: "caret-down",
|
|
126155
|
+
disabled: !hasMatches,
|
|
126156
|
+
onClick: goToNext
|
|
126157
|
+
}
|
|
126158
|
+
));
|
|
126159
|
+
if (!isOpen) {
|
|
126160
|
+
return /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(
|
|
126161
|
+
core.Button,
|
|
126162
|
+
{
|
|
126163
|
+
minimal: true,
|
|
126164
|
+
small: true,
|
|
126165
|
+
intent: "primary",
|
|
126166
|
+
icon: "search",
|
|
126167
|
+
rightIcon: "caret-right",
|
|
126168
|
+
"data-tip": "Search",
|
|
126169
|
+
onClick: /* @__PURE__ */ __name(() => setIsOpen(true), "onClick")
|
|
126170
|
+
}
|
|
126171
|
+
));
|
|
126172
|
+
}
|
|
126173
|
+
const annotationPopoverOpen = searched && featureMatches.length > 0;
|
|
126174
|
+
const inputEl = /* @__PURE__ */ React.createElement(
|
|
126175
|
+
core.InputGroup,
|
|
126176
|
+
{
|
|
126177
|
+
className: "tg-find-tool-input alignment-search-bar",
|
|
126178
|
+
leftIcon: "search",
|
|
126179
|
+
placeholder: "Search...",
|
|
126180
|
+
autoFocus: true,
|
|
126181
|
+
value: searchText,
|
|
126182
|
+
onChange: handleChange,
|
|
126183
|
+
onKeyDown: handleKeyDown,
|
|
126184
|
+
rightElement: inlineNavEl
|
|
126185
|
+
}
|
|
126186
|
+
);
|
|
126187
|
+
return /* @__PURE__ */ React.createElement("div", { style: { position: "relative" } }, !isExpanded && /* @__PURE__ */ React.createElement(
|
|
126188
|
+
core.Popover,
|
|
126189
|
+
{
|
|
126190
|
+
autoFocus: false,
|
|
126191
|
+
enforceFocus: false,
|
|
126192
|
+
modifiers: {
|
|
126193
|
+
arrow: false
|
|
126194
|
+
},
|
|
126195
|
+
position: core.Position.BOTTOM,
|
|
126196
|
+
isOpen: annotationPopoverOpen,
|
|
126197
|
+
content: /* @__PURE__ */ React.createElement(
|
|
126198
|
+
AnnotationResultsComp,
|
|
126199
|
+
{
|
|
126200
|
+
featureMatches,
|
|
126201
|
+
onClickMatch: handleFeatureClick
|
|
126202
|
+
}
|
|
126203
|
+
),
|
|
126204
|
+
target: inputEl
|
|
126205
|
+
}
|
|
126206
|
+
), isExpanded && /* @__PURE__ */ React.createElement(
|
|
126207
|
+
"div",
|
|
126208
|
+
{
|
|
126209
|
+
style: {
|
|
126210
|
+
position: "absolute",
|
|
126211
|
+
top: 0,
|
|
126212
|
+
left: 0,
|
|
126213
|
+
padding: 10,
|
|
126214
|
+
paddingBottom: 25,
|
|
126215
|
+
display: "flex",
|
|
126216
|
+
alignItems: "flex-start",
|
|
126217
|
+
gap: 10,
|
|
126218
|
+
zIndex: 5e4,
|
|
126219
|
+
background: "white",
|
|
126220
|
+
boxShadow: "0 2px 8px rgba(0,0,0,0.2)",
|
|
126221
|
+
borderRadius: 3
|
|
126222
|
+
}
|
|
126223
|
+
},
|
|
126224
|
+
/* @__PURE__ */ React.createElement("div", { style: { display: "flex", flexDirection: "column", gap: 6 } }, /* @__PURE__ */ React.createElement(
|
|
126225
|
+
core.TextArea,
|
|
126226
|
+
{
|
|
126227
|
+
autoFocus: true,
|
|
126228
|
+
placeholder: "Search sequences and annotations...",
|
|
126229
|
+
value: searchText,
|
|
126230
|
+
onChange: handleChange,
|
|
126231
|
+
onKeyDown: handleKeyDown,
|
|
126232
|
+
style: { resize: "vertical", width: 350, height: 190 }
|
|
126233
|
+
}
|
|
126234
|
+
), annotationPopoverOpen && /* @__PURE__ */ React.createElement(
|
|
126235
|
+
AnnotationResultsComp,
|
|
126236
|
+
{
|
|
126237
|
+
featureMatches,
|
|
126238
|
+
onClickMatch: handleFeatureClick
|
|
126239
|
+
}
|
|
126240
|
+
)),
|
|
126241
|
+
/* @__PURE__ */ React.createElement("div", { style: { display: "flex", flexDirection: "column", gap: 5 } }, expandedNavEl, /* @__PURE__ */ React.createElement(
|
|
126242
|
+
FindOptionsPanel,
|
|
126243
|
+
{
|
|
126244
|
+
dnaOrAA,
|
|
126245
|
+
ambiguousOrLiteral,
|
|
126246
|
+
mismatchesAllowed,
|
|
126247
|
+
searchText,
|
|
126248
|
+
matches,
|
|
126249
|
+
dispatch,
|
|
126250
|
+
highlightAll,
|
|
126251
|
+
setHighlightAll,
|
|
126252
|
+
isExpanded,
|
|
126253
|
+
onToggleExpanded: handleToggleExpanded
|
|
126254
|
+
}
|
|
126255
|
+
)),
|
|
126256
|
+
/* @__PURE__ */ React.createElement(
|
|
126257
|
+
core.Button,
|
|
126258
|
+
{
|
|
126259
|
+
minimal: true,
|
|
126260
|
+
style: { position: "absolute", bottom: 0, right: 0 },
|
|
126261
|
+
onClick: /* @__PURE__ */ __name(() => setIsOpen(false), "onClick"),
|
|
126262
|
+
icon: "cross"
|
|
126263
|
+
}
|
|
126264
|
+
)
|
|
126265
|
+
));
|
|
126266
|
+
}
|
|
126267
|
+
__name(AlignmentSearchBar, "AlignmentSearchBar");
|
|
126268
|
+
function AnnotationResultsComp({ featureMatches, onClickMatch }) {
|
|
126269
|
+
const byType = {};
|
|
126270
|
+
ANNOTATION_TYPES.forEach((type2) => {
|
|
126271
|
+
byType[type2] = [];
|
|
126272
|
+
});
|
|
126273
|
+
featureMatches.forEach((match) => {
|
|
126274
|
+
if (byType[match.type]) {
|
|
126275
|
+
byType[match.type].push(match);
|
|
126276
|
+
}
|
|
126277
|
+
});
|
|
126278
|
+
const featureColorMap = getFeatureToColorMap({ includeHidden: true });
|
|
126279
|
+
return /* @__PURE__ */ React.createElement("div", { className: "veAnnotationFindMatches" }, ANNOTATION_TYPES.map((type2) => {
|
|
126280
|
+
const anns = byType[type2];
|
|
126281
|
+
if (!anns.length) return null;
|
|
126282
|
+
const showing = anns.slice(0, 10);
|
|
126283
|
+
return /* @__PURE__ */ React.createElement("div", { key: type2 }, /* @__PURE__ */ React.createElement("div", { className: "veAnnotationFoundType" }, anns.length, " ", getSingular(type2), " match", anns.length > 1 ? "es" : null, anns.length > 10 ? ` (only showing 10)` : null, ":"), /* @__PURE__ */ React.createElement("div", null, showing.map((match, i) => {
|
|
126284
|
+
const { annotation } = match;
|
|
126285
|
+
const annotationColor = type2 === "parts" ? "#ac68cc" : annotation.color || featureColorMap[annotation.type];
|
|
126286
|
+
return /* @__PURE__ */ React.createElement(
|
|
126287
|
+
"div",
|
|
126288
|
+
{
|
|
126289
|
+
key: i,
|
|
126290
|
+
onClick: /* @__PURE__ */ __name(() => onClickMatch(match), "onClick"),
|
|
126291
|
+
className: "veAnnotationFoundResult"
|
|
126292
|
+
},
|
|
126293
|
+
/* @__PURE__ */ React.createElement("div", { style: { display: "flex", alignItems: "center" } }, /* @__PURE__ */ React.createElement(
|
|
126294
|
+
"div",
|
|
126295
|
+
{
|
|
126296
|
+
style: {
|
|
126297
|
+
background: annotationColor,
|
|
126298
|
+
height: 15,
|
|
126299
|
+
width: 15,
|
|
126300
|
+
marginRight: 3
|
|
126301
|
+
}
|
|
126302
|
+
}
|
|
126303
|
+
), annotation.name),
|
|
126304
|
+
/* @__PURE__ */ React.createElement("div", { className: "veAnnotationFoundResultRange" }, annotation.start + 1, "-", annotation.end + 1)
|
|
126305
|
+
);
|
|
126306
|
+
})));
|
|
126307
|
+
}));
|
|
126308
|
+
}
|
|
126309
|
+
__name(AnnotationResultsComp, "AnnotationResultsComp");
|
|
126310
|
+
function FindOptionsPanel({
|
|
126311
|
+
dnaOrAA,
|
|
126312
|
+
ambiguousOrLiteral,
|
|
126313
|
+
mismatchesAllowed,
|
|
126314
|
+
searchText,
|
|
126315
|
+
matches,
|
|
126316
|
+
dispatch,
|
|
126317
|
+
highlightAll,
|
|
126318
|
+
setHighlightAll,
|
|
126319
|
+
isExpanded,
|
|
126320
|
+
onToggleExpanded
|
|
126321
|
+
}) {
|
|
126322
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(
|
|
126323
|
+
TgHTMLSelect,
|
|
126324
|
+
{
|
|
126325
|
+
options: [
|
|
126326
|
+
{ label: "DNA", value: "DNA" },
|
|
126327
|
+
{ label: "Amino Acids", value: "AA" }
|
|
126328
|
+
],
|
|
126329
|
+
value: dnaOrAA,
|
|
126330
|
+
onChange: /* @__PURE__ */ __name((e) => dispatch({ type: "SET_DNA_OR_AA", payload: e.target.value }), "onChange")
|
|
126331
|
+
}
|
|
126332
|
+
), /* @__PURE__ */ React.createElement("div", { style: { display: "flex" } }, /* @__PURE__ */ React.createElement(
|
|
126333
|
+
TgHTMLSelect,
|
|
126334
|
+
{
|
|
126335
|
+
options: [
|
|
126336
|
+
{ label: "Literal", value: "LITERAL" },
|
|
126337
|
+
{ label: "Ambiguous", value: "AMBIGUOUS" }
|
|
126338
|
+
],
|
|
126339
|
+
value: ambiguousOrLiteral,
|
|
126340
|
+
onChange: /* @__PURE__ */ __name((e) => dispatch({
|
|
126341
|
+
type: "SET_AMBIGUOUS_OR_LITERAL",
|
|
126342
|
+
payload: e.target.value
|
|
126343
|
+
}), "onChange")
|
|
126344
|
+
}
|
|
126345
|
+
), /* @__PURE__ */ React.createElement(InfoHelper, { style: { marginLeft: 10 } }, /* @__PURE__ */ React.createElement("div", null, "Ambiguous substitutions:", /* @__PURE__ */ React.createElement("div", { style: { display: "flex", fontSize: 12 } }, /* @__PURE__ */ React.createElement("div", { style: { marginRight: 20 } }, /* @__PURE__ */ React.createElement("div", { style: { fontSize: 14, marginBottom: 4, marginTop: 5 } }, "DNA:"), /* @__PURE__ */ React.createElement("div", null, "M: AC"), /* @__PURE__ */ React.createElement("div", null, "R: AG"), /* @__PURE__ */ React.createElement("div", null, "W: AT"), /* @__PURE__ */ React.createElement("div", null, "S: CG"), /* @__PURE__ */ React.createElement("div", null, "Y: CT"), /* @__PURE__ */ React.createElement("div", null, "K: GT"), /* @__PURE__ */ React.createElement("div", null, "V: ACG"), /* @__PURE__ */ React.createElement("div", null, "H: ACT"), /* @__PURE__ */ React.createElement("div", null, "D: AGT"), /* @__PURE__ */ React.createElement("div", null, "B: CGT"), /* @__PURE__ */ React.createElement("div", null, "X: GATC"), /* @__PURE__ */ React.createElement("div", null, "N: GATC"), /* @__PURE__ */ React.createElement("div", null, "*: any")), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("div", { style: { fontSize: 14, marginBottom: 4, marginTop: 5 } }, "AA:"), /* @__PURE__ */ React.createElement("div", null, "B: ND"), /* @__PURE__ */ React.createElement("div", null, "J: IL"), /* @__PURE__ */ React.createElement("div", null, "X: ACDEFGHIKLMNPQRSTVWY"), /* @__PURE__ */ React.createElement("div", null, "Z: QE"), /* @__PURE__ */ React.createElement("div", null, "*: any")))))), /* @__PURE__ */ React.createElement(
|
|
126346
|
+
"div",
|
|
126347
|
+
{
|
|
126348
|
+
style: {
|
|
126349
|
+
marginTop: "8px",
|
|
126350
|
+
display: "flex",
|
|
126351
|
+
flexDirection: "row",
|
|
126352
|
+
gap: "3px",
|
|
126353
|
+
alignItems: "center"
|
|
126354
|
+
}
|
|
126355
|
+
},
|
|
126356
|
+
/* @__PURE__ */ React.createElement("label", null, "Mismatches Allowed:"),
|
|
126357
|
+
/* @__PURE__ */ React.createElement(
|
|
126358
|
+
core.NumericInput,
|
|
126359
|
+
{
|
|
126360
|
+
min: 0,
|
|
126361
|
+
max: 10,
|
|
126362
|
+
className: "tg-mismatches-allowed-input",
|
|
126363
|
+
style: { width: "60px" },
|
|
126364
|
+
value: mismatchesAllowed,
|
|
126365
|
+
disabled: dnaOrAA !== "DNA" || ambiguousOrLiteral !== "LITERAL",
|
|
126366
|
+
onValueChange: /* @__PURE__ */ __name((value) => dispatch({
|
|
126367
|
+
type: "SET_MISMATCHES_ALLOWED",
|
|
126368
|
+
payload: Number.parseInt(value, 10) || 0
|
|
126369
|
+
}), "onValueChange")
|
|
126370
|
+
}
|
|
126371
|
+
),
|
|
126372
|
+
/* @__PURE__ */ React.createElement(InfoHelper, { style: { marginLeft: 10 } }, /* @__PURE__ */ React.createElement("div", null, "Number of mismatches allowed when searching DNA sequences with literal matching.", /* @__PURE__ */ React.createElement("br", null), /* @__PURE__ */ React.createElement("br", null), "Higher values may slow down search performance."))
|
|
126373
|
+
), /* @__PURE__ */ React.createElement(
|
|
126374
|
+
core.Switch,
|
|
126375
|
+
{
|
|
126376
|
+
checked: highlightAll,
|
|
126377
|
+
onChange: /* @__PURE__ */ __name(() => setHighlightAll((v2) => !v2), "onChange"),
|
|
126378
|
+
disabled: searchText.trim().length < 2 || matches.length > MAX_MATCHES_DISPLAYED
|
|
126379
|
+
},
|
|
126380
|
+
/* @__PURE__ */ React.createElement(
|
|
126381
|
+
core.Tooltip,
|
|
126382
|
+
{
|
|
126383
|
+
disabled: matches.length <= MAX_MATCHES_DISPLAYED,
|
|
126384
|
+
content: `Disabled because there are >${MAX_MATCHES_DISPLAYED} matches`
|
|
126385
|
+
},
|
|
126386
|
+
"Highlight All"
|
|
126387
|
+
)
|
|
126388
|
+
), /* @__PURE__ */ React.createElement(core.Switch, { checked: isExpanded, onChange: onToggleExpanded }, "Expanded"));
|
|
126389
|
+
}
|
|
126390
|
+
__name(FindOptionsPanel, "FindOptionsPanel");
|
|
125459
126391
|
const AlignmentVisibilityTool = pure(/* @__PURE__ */ __name(function AlignmentVisibilityTool2(props) {
|
|
125460
126392
|
return /* @__PURE__ */ React.createElement(
|
|
125461
126393
|
core.Popover,
|
|
@@ -125463,17 +126395,18 @@ const AlignmentVisibilityTool = pure(/* @__PURE__ */ __name(function AlignmentVi
|
|
|
125463
126395
|
minimal: true,
|
|
125464
126396
|
position: "bottom",
|
|
125465
126397
|
content: /* @__PURE__ */ React.createElement(VisibilityOptions$2, __spreadValues({}, props)),
|
|
125466
|
-
target: /* @__PURE__ */ React.createElement(
|
|
126398
|
+
target: /* @__PURE__ */ React.createElement(
|
|
125467
126399
|
core.Button,
|
|
125468
126400
|
{
|
|
125469
126401
|
className: "tg-alignment-visibility-toggle",
|
|
125470
126402
|
small: true,
|
|
126403
|
+
"data-tip": "Visibility Options",
|
|
125471
126404
|
rightIcon: "caret-down",
|
|
125472
126405
|
intent: core.Intent.PRIMARY,
|
|
125473
126406
|
minimal: true,
|
|
125474
126407
|
icon: "eye-open"
|
|
125475
126408
|
}
|
|
125476
|
-
)
|
|
126409
|
+
)
|
|
125477
126410
|
}
|
|
125478
126411
|
);
|
|
125479
126412
|
}, "AlignmentVisibilityTool"));
|
|
@@ -138639,7 +139572,6 @@ const aminoAcidShortNames = {
|
|
|
138639
139572
|
const PropertySidePanel = /* @__PURE__ */ __name(({ properties: properties2, setProperties, style: style2 }) => {
|
|
138640
139573
|
const sidebarRef = React.useRef(null);
|
|
138641
139574
|
const [mismatchesCount, setMismatchesCount] = React.useState(0);
|
|
138642
|
-
const [mismatchesInRange, setMismatchesInRange] = React.useState(0);
|
|
138643
139575
|
const { track, isOpen, selection, isPairwise } = properties2;
|
|
138644
139576
|
const getSequenceInRegion = React.useCallback(() => {
|
|
138645
139577
|
var _a2, _b2;
|
|
@@ -138658,6 +139590,30 @@ const PropertySidePanel = /* @__PURE__ */ __name(({ properties: properties2, set
|
|
|
138658
139590
|
if (!Array.isArray(tr)) return [];
|
|
138659
139591
|
return isPairwise ? tr.filter((m2) => (m2 == null ? void 0 : m2.color) === "red") : tr;
|
|
138660
139592
|
}, [track, mismatchKey, isPairwise]);
|
|
139593
|
+
const mismatchSchema = React.useMemo(
|
|
139594
|
+
() => ({
|
|
139595
|
+
fields: [
|
|
139596
|
+
{
|
|
139597
|
+
path: "start",
|
|
139598
|
+
type: "number",
|
|
139599
|
+
displayName: "Start",
|
|
139600
|
+
render: /* @__PURE__ */ __name((val2) => val2 + 1, "render")
|
|
139601
|
+
},
|
|
139602
|
+
{
|
|
139603
|
+
path: "end",
|
|
139604
|
+
type: "number",
|
|
139605
|
+
displayName: "End",
|
|
139606
|
+
render: /* @__PURE__ */ __name((val2) => val2 + 1, "render")
|
|
139607
|
+
}
|
|
139608
|
+
]
|
|
139609
|
+
}),
|
|
139610
|
+
[]
|
|
139611
|
+
);
|
|
139612
|
+
const mismatchEntities = React.useMemo(() => {
|
|
139613
|
+
return (trackMismatches || []).map((m2, i) => __spreadProps(__spreadValues({}, m2), {
|
|
139614
|
+
id: i.toString()
|
|
139615
|
+
}));
|
|
139616
|
+
}, [trackMismatches]);
|
|
138661
139617
|
React.useEffect(() => {
|
|
138662
139618
|
if (!isOpen || sidebarRef.current === null || !track) {
|
|
138663
139619
|
return;
|
|
@@ -138675,21 +139631,6 @@ const PropertySidePanel = /* @__PURE__ */ __name(({ properties: properties2, set
|
|
|
138675
139631
|
}
|
|
138676
139632
|
});
|
|
138677
139633
|
setMismatchesCount(mismatchCount);
|
|
138678
|
-
setMismatchesInRange(mismatchCount);
|
|
138679
|
-
if (selection && selection.start > -1 && selection.end > -1) {
|
|
138680
|
-
let count2 = 0;
|
|
138681
|
-
trackMismatches == null ? void 0 : trackMismatches.forEach((tm) => {
|
|
138682
|
-
if (tm === null || tm.start === null || tm.end === null) {
|
|
138683
|
-
return;
|
|
138684
|
-
}
|
|
138685
|
-
const overlapStart = Math.max(tm.start, selection.start);
|
|
138686
|
-
const overlapEnd = Math.min(tm.end, selection.end);
|
|
138687
|
-
if (overlapEnd >= overlapStart) {
|
|
138688
|
-
count2 += overlapEnd - overlapStart + 1;
|
|
138689
|
-
}
|
|
138690
|
-
});
|
|
138691
|
-
setMismatchesInRange(count2);
|
|
138692
|
-
}
|
|
138693
139634
|
}, [isOpen, track, selection, trackMismatches]);
|
|
138694
139635
|
const aminoFreq = React.useMemo(() => {
|
|
138695
139636
|
var _a2, _b2;
|
|
@@ -138725,7 +139666,7 @@ const PropertySidePanel = /* @__PURE__ */ __name(({ properties: properties2, set
|
|
|
138725
139666
|
width: "100%"
|
|
138726
139667
|
}
|
|
138727
139668
|
}
|
|
138728
|
-
), /* @__PURE__ */ React.createElement(
|
|
139669
|
+
), /* @__PURE__ */ React.createElement(HeaderItem, { title: "Track Properties" }), /* @__PURE__ */ React.createElement("div", { className: "bp3-tab-panel" }, /* @__PURE__ */ React.createElement(RowItem, { item: name2, title: "Name" }), /* @__PURE__ */ React.createElement(RowItem, { item: isProtein2 ? proteinSize : size, title: "Length" }), /* @__PURE__ */ React.createElement(
|
|
138729
139670
|
RowItem,
|
|
138730
139671
|
{
|
|
138731
139672
|
item: molecularWeight == null ? void 0 : molecularWeight.toFixed(2),
|
|
@@ -138739,18 +139680,45 @@ const PropertySidePanel = /* @__PURE__ */ __name(({ properties: properties2, set
|
|
|
138739
139680
|
title: "Extinction Coefficient"
|
|
138740
139681
|
}
|
|
138741
139682
|
)), /* @__PURE__ */ React.createElement(
|
|
138742
|
-
RowItem,
|
|
138743
|
-
{
|
|
138744
|
-
item: `${mismatchesInRange}/${mismatchesCount}`,
|
|
138745
|
-
title: "Mismatches"
|
|
138746
|
-
}
|
|
138747
|
-
), /* @__PURE__ */ React.createElement(
|
|
138748
139683
|
RowItem,
|
|
138749
139684
|
{
|
|
138750
139685
|
item: selection && selection.start > -1 ? /* @__PURE__ */ React.createElement("span", null, selection.start + 1, " - ", selection.end + 1) : /* @__PURE__ */ React.createElement("span", null, "1 - ", isProtein2 ? proteinSize : size),
|
|
138751
139686
|
title: "Region"
|
|
138752
139687
|
}
|
|
138753
|
-
)
|
|
139688
|
+
), /* @__PURE__ */ React.createElement(HeaderItem, { title: `Mismatches (${mismatchesCount})` }), trackMismatches && trackMismatches.length > 0 && /* @__PURE__ */ React.createElement(
|
|
139689
|
+
"div",
|
|
139690
|
+
{
|
|
139691
|
+
style: {
|
|
139692
|
+
margin: "0px 10px"
|
|
139693
|
+
}
|
|
139694
|
+
},
|
|
139695
|
+
/* @__PURE__ */ React.createElement(
|
|
139696
|
+
WrappedDT,
|
|
139697
|
+
{
|
|
139698
|
+
formName: "mismatchesTable",
|
|
139699
|
+
isSimple: true,
|
|
139700
|
+
noHeader: true,
|
|
139701
|
+
noFooter: true,
|
|
139702
|
+
withSearch: false,
|
|
139703
|
+
noPadding: true,
|
|
139704
|
+
compact: true,
|
|
139705
|
+
maxHeight: 150,
|
|
139706
|
+
entities: mismatchEntities,
|
|
139707
|
+
schema: mismatchSchema,
|
|
139708
|
+
onRowClick: /* @__PURE__ */ __name((e, row) => {
|
|
139709
|
+
updateCaretPosition({ start: row.start, end: row.end });
|
|
139710
|
+
setTimeout(() => {
|
|
139711
|
+
scrollToAlignmentSelection();
|
|
139712
|
+
}, 0);
|
|
139713
|
+
}, "onRowClick")
|
|
139714
|
+
}
|
|
139715
|
+
)
|
|
139716
|
+
)), /* @__PURE__ */ React.createElement(
|
|
139717
|
+
HeaderItem,
|
|
139718
|
+
{
|
|
139719
|
+
title: `${isProtein2 ? "Amino Acid" : "Base Pair"} Frequencies`
|
|
139720
|
+
}
|
|
139721
|
+
), /* @__PURE__ */ React.createElement("div", { className: "sidebar-table" }, /* @__PURE__ */ React.createElement("div", { className: "sidebar-row" }, /* @__PURE__ */ React.createElement("div", { className: "sidebar-cell" }, isProtein2 ? "Amino Acid" : "Base"), /* @__PURE__ */ React.createElement("div", { className: "sidebar-cell" }, "Count"), /* @__PURE__ */ React.createElement("div", { className: "sidebar-cell" }, "Percentage")), frequencyEntries.map(([aa, data], idx) => {
|
|
138754
139722
|
return /* @__PURE__ */ React.createElement("div", { className: `sidebar-row property-amino-acid-${idx}` }, /* @__PURE__ */ React.createElement("div", { className: "sidebar-cell" }, aa, " ", isProtein2 ? `(${aminoAcidShortNames[aa]})` : ""), /* @__PURE__ */ React.createElement("div", { className: "sidebar-cell" }, data.count), /* @__PURE__ */ React.createElement("div", { className: "sidebar-cell" }, data.percentage.toFixed(1), "%"));
|
|
138755
139723
|
})));
|
|
138756
139724
|
} else {
|
|
@@ -138807,11 +139775,29 @@ const PropertySidePanel = /* @__PURE__ */ __name(({ properties: properties2, set
|
|
|
138807
139775
|
);
|
|
138808
139776
|
}, "PropertySidePanel");
|
|
138809
139777
|
function RowItem({ item, title, units }) {
|
|
138810
|
-
if (
|
|
139778
|
+
if (item == null) {
|
|
139779
|
+
return null;
|
|
139780
|
+
}
|
|
138811
139781
|
const propertyClass = title.split(" ").join("-").toLowerCase();
|
|
138812
|
-
return /* @__PURE__ */ React.createElement("div", { className: `ve-flex-row property-${propertyClass}` }, /* @__PURE__ */ React.createElement("div", { className: "ve-column-left" }, title), /* @__PURE__ */ React.createElement("div", { className: "ve-column-right" }, item, " ", units != null ? units : ""));
|
|
139782
|
+
return /* @__PURE__ */ React.createElement("div", { className: `ve-flex-row property-${propertyClass}` }, /* @__PURE__ */ React.createElement("div", { style: { fontWeight: "bold" }, className: "ve-column-left" }, title), /* @__PURE__ */ React.createElement("div", { className: "ve-column-right" }, item, " ", units != null ? units : ""));
|
|
138813
139783
|
}
|
|
138814
139784
|
__name(RowItem, "RowItem");
|
|
139785
|
+
const HeaderItem = /* @__PURE__ */ __name(({ title }) => {
|
|
139786
|
+
return /* @__PURE__ */ React.createElement(
|
|
139787
|
+
"h5",
|
|
139788
|
+
{
|
|
139789
|
+
style: {
|
|
139790
|
+
margin: 0,
|
|
139791
|
+
fontSize: 15,
|
|
139792
|
+
fontWeight: "bold",
|
|
139793
|
+
textAlign: "center",
|
|
139794
|
+
padding: "5px 0",
|
|
139795
|
+
borderBottom: "1px solid #f1f1f1"
|
|
139796
|
+
}
|
|
139797
|
+
},
|
|
139798
|
+
title
|
|
139799
|
+
);
|
|
139800
|
+
}, "HeaderItem");
|
|
138815
139801
|
function calculatePairwiseIdentity(seq1, seq2, excludeGaps = true) {
|
|
138816
139802
|
if (seq1.length !== seq2.length) {
|
|
138817
139803
|
throw new Error("Sequences must be aligned (same length)");
|
|
@@ -139207,6 +140193,11 @@ const AlignmentView = /* @__PURE__ */ __name((props) => {
|
|
|
139207
140193
|
const [tempTrimBefore, setTempTrimBefore] = React.useState({});
|
|
139208
140194
|
const [tempTrimAfter, setTempTrimAfter] = React.useState({});
|
|
139209
140195
|
const [tempTrimmingCaret, setTempTrimmingCaret] = React.useState({});
|
|
140196
|
+
const [searchMatchLayers, setSearchMatchLayers] = React.useState([]);
|
|
140197
|
+
const [activeFilterType, setActiveFilterType] = React.useState("all");
|
|
140198
|
+
const handleFilterChange = React.useCallback(({ activeFilter }) => {
|
|
140199
|
+
setActiveFilterType(activeFilter);
|
|
140200
|
+
}, []);
|
|
139210
140201
|
const bindOutsideChangeHelper = React.useRef({});
|
|
139211
140202
|
const alignmentHolder = React.useRef(null);
|
|
139212
140203
|
const alignmentHolderTop = React.useRef(null);
|
|
@@ -139931,7 +140922,12 @@ ${seqDataToCopy}\r
|
|
|
139931
140922
|
alignmentData,
|
|
139932
140923
|
chromatogramData
|
|
139933
140924
|
}) : linearViewOptions)), {
|
|
139934
|
-
additionalSelectionLayers
|
|
140925
|
+
additionalSelectionLayers: [
|
|
140926
|
+
...i !== 0 ? (additionalSelectionLayers || []).filter(
|
|
140927
|
+
(layer) => activeFilterType === "all" ? layer.differenceType !== "gap" : layer.differenceType === activeFilterType
|
|
140928
|
+
) : additionalSelectionLayers || [],
|
|
140929
|
+
...searchMatchLayers || []
|
|
140930
|
+
],
|
|
139935
140931
|
dimensions: {
|
|
139936
140932
|
width: linearViewWidth
|
|
139937
140933
|
},
|
|
@@ -140459,7 +141455,7 @@ ${seqDataToCopy}\r
|
|
|
140459
141455
|
display: "flex",
|
|
140460
141456
|
minHeight: "32px",
|
|
140461
141457
|
width: "100%",
|
|
140462
|
-
flexWrap: "
|
|
141458
|
+
flexWrap: "wrap",
|
|
140463
141459
|
flexDirection: "row",
|
|
140464
141460
|
flex: "0 0 auto"
|
|
140465
141461
|
},
|
|
@@ -140580,6 +141576,22 @@ ${seqDataToCopy}\r
|
|
|
140580
141576
|
currentPairwiseAlignmentIndex
|
|
140581
141577
|
}, alignmentVisibilityToolOptions)
|
|
140582
141578
|
),
|
|
141579
|
+
/* @__PURE__ */ React.createElement(
|
|
141580
|
+
AlignmentSearchBar,
|
|
141581
|
+
{
|
|
141582
|
+
alignmentTracks,
|
|
141583
|
+
id: id2,
|
|
141584
|
+
setSearchMatchLayers
|
|
141585
|
+
}
|
|
141586
|
+
),
|
|
141587
|
+
/* @__PURE__ */ React.createElement(
|
|
141588
|
+
FindMismatches,
|
|
141589
|
+
{
|
|
141590
|
+
alignmentJson: alignmentTracks,
|
|
141591
|
+
id: id2,
|
|
141592
|
+
onFilterChange: handleFilterChange
|
|
141593
|
+
}
|
|
141594
|
+
),
|
|
140583
141595
|
additionalTopEl,
|
|
140584
141596
|
saveMessage && /* @__PURE__ */ React.createElement(
|
|
140585
141597
|
"div",
|
|
@@ -140680,6 +141692,7 @@ ${seqDataToCopy}\r
|
|
|
140680
141692
|
}
|
|
140681
141693
|
)),
|
|
140682
141694
|
alignmentTracks,
|
|
141695
|
+
activeFilterType,
|
|
140683
141696
|
dimensions: {
|
|
140684
141697
|
width: Math.max(width, 10) || 10
|
|
140685
141698
|
},
|
|
@@ -145869,108 +146882,6 @@ const schema = {
|
|
|
145869
146882
|
]
|
|
145870
146883
|
};
|
|
145871
146884
|
const DigestTool$1 = withEditorInteractions(DigestTool);
|
|
145872
|
-
const _Mismatches = class _Mismatches extends React.Component {
|
|
145873
|
-
constructor() {
|
|
145874
|
-
super(...arguments);
|
|
145875
|
-
__publicField(this, "getGapMap", /* @__PURE__ */ __name((sequence2) => {
|
|
145876
|
-
const gapMap = [0];
|
|
145877
|
-
sequence2.split("").forEach((char) => {
|
|
145878
|
-
if (char === "-") {
|
|
145879
|
-
gapMap[Math.max(0, gapMap.length - 1)] = (gapMap[Math.max(0, gapMap.length - 1)] || 0) + 1;
|
|
145880
|
-
} else {
|
|
145881
|
-
gapMap.push(gapMap[gapMap.length - 1] || 0);
|
|
145882
|
-
}
|
|
145883
|
-
});
|
|
145884
|
-
return gapMap;
|
|
145885
|
-
}, "getGapMap"));
|
|
145886
|
-
__publicField(this, "getMismatchList", /* @__PURE__ */ __name((alignmentData, mismatches) => {
|
|
145887
|
-
const mismatchList = [];
|
|
145888
|
-
let getGaps = /* @__PURE__ */ __name(() => ({
|
|
145889
|
-
gapsBefore: 0,
|
|
145890
|
-
gapsInside: 0
|
|
145891
|
-
}), "getGaps");
|
|
145892
|
-
const gapMap = this.getGapMap(alignmentData.sequence);
|
|
145893
|
-
getGaps = /* @__PURE__ */ __name((rangeOrCaretPosition) => {
|
|
145894
|
-
if (typeof rangeOrCaretPosition !== "object") {
|
|
145895
|
-
return {
|
|
145896
|
-
gapsBefore: gapMap[Math.min(rangeOrCaretPosition, gapMap.length - 1)]
|
|
145897
|
-
};
|
|
145898
|
-
}
|
|
145899
|
-
const { start: start2, end: end2 } = rangeOrCaretPosition;
|
|
145900
|
-
const toReturn = {
|
|
145901
|
-
gapsBefore: gapMap[start2],
|
|
145902
|
-
gapsInside: gapMap[Math.min(end2, gapMap.length - 1)] - gapMap[Math.min(start2, gapMap.length - 1)]
|
|
145903
|
-
};
|
|
145904
|
-
return toReturn;
|
|
145905
|
-
}, "getGaps");
|
|
145906
|
-
const gapsBeforeSequence = getGaps(0).gapsBefore;
|
|
145907
|
-
for (let mismatchI = 0; mismatchI < mismatches.length; mismatchI++) {
|
|
145908
|
-
const mismatchEnd = mismatches[mismatchI].end;
|
|
145909
|
-
const mismatchStart = mismatches[mismatchI].start;
|
|
145910
|
-
const mismatchDifference = mismatchEnd - mismatchStart;
|
|
145911
|
-
if (mismatchDifference === 0) {
|
|
145912
|
-
mismatchList.push({
|
|
145913
|
-
mismatches: mismatchStart + 1 - gapsBeforeSequence,
|
|
145914
|
-
start: mismatchStart - gapsBeforeSequence,
|
|
145915
|
-
end: mismatchStart - gapsBeforeSequence
|
|
145916
|
-
});
|
|
145917
|
-
} else {
|
|
145918
|
-
for (let innerI = 0; innerI <= mismatchDifference; innerI++) {
|
|
145919
|
-
mismatchList.push({
|
|
145920
|
-
mismatches: mismatchStart + innerI + 1 - gapsBeforeSequence,
|
|
145921
|
-
start: mismatchStart + innerI - gapsBeforeSequence,
|
|
145922
|
-
end: mismatchStart + innerI - gapsBeforeSequence
|
|
145923
|
-
});
|
|
145924
|
-
}
|
|
145925
|
-
}
|
|
145926
|
-
}
|
|
145927
|
-
return mismatchList;
|
|
145928
|
-
}, "getMismatchList"));
|
|
145929
|
-
}
|
|
145930
|
-
UNSAFE_componentWillMount() {
|
|
145931
|
-
const { alignmentData, mismatches } = this.props;
|
|
145932
|
-
const mismatchList = this.getMismatchList(alignmentData, mismatches);
|
|
145933
|
-
const schema2 = {
|
|
145934
|
-
fields: [{ path: "mismatches", type: "number" }]
|
|
145935
|
-
};
|
|
145936
|
-
this.setState({ mismatchList, schema: schema2 });
|
|
145937
|
-
}
|
|
145938
|
-
render() {
|
|
145939
|
-
const { mismatchList, schema: schema2 } = this.state;
|
|
145940
|
-
let tableOfMismatches;
|
|
145941
|
-
if (mismatchList.length === 0) {
|
|
145942
|
-
tableOfMismatches = null;
|
|
145943
|
-
} else {
|
|
145944
|
-
tableOfMismatches = /* @__PURE__ */ React.createElement(
|
|
145945
|
-
WrappedDT,
|
|
145946
|
-
{
|
|
145947
|
-
maxHeight: 168,
|
|
145948
|
-
formName: "mismatchesTable",
|
|
145949
|
-
isSimple: true,
|
|
145950
|
-
compact: true,
|
|
145951
|
-
noRouter: true,
|
|
145952
|
-
schema: schema2,
|
|
145953
|
-
entities: mismatchList
|
|
145954
|
-
}
|
|
145955
|
-
);
|
|
145956
|
-
}
|
|
145957
|
-
return /* @__PURE__ */ React.createElement("div", { style: { maxHeight: 180.8, overflowY: "scroll" } }, /* @__PURE__ */ React.createElement(
|
|
145958
|
-
"div",
|
|
145959
|
-
{
|
|
145960
|
-
style: {
|
|
145961
|
-
// margin: 10,
|
|
145962
|
-
display: "flex",
|
|
145963
|
-
flexDirection: "column",
|
|
145964
|
-
alignItems: "center"
|
|
145965
|
-
}
|
|
145966
|
-
},
|
|
145967
|
-
/* @__PURE__ */ React.createElement("div", { style: { width: 100, margin: 4 } }, tableOfMismatches)
|
|
145968
|
-
));
|
|
145969
|
-
}
|
|
145970
|
-
};
|
|
145971
|
-
__name(_Mismatches, "Mismatches");
|
|
145972
|
-
let Mismatches = _Mismatches;
|
|
145973
|
-
const Mismatches$1 = withSelectedEntities("mismatchesTable")(Mismatches);
|
|
145974
146885
|
function PCRTool(props) {
|
|
145975
146886
|
const {
|
|
145976
146887
|
sequenceData: sequenceData2,
|
|
@@ -146142,7 +147053,7 @@ const _panelMap = {
|
|
|
146142
147053
|
comp: PropertiesDialog$1,
|
|
146143
147054
|
panelSpecificProps: ["PropertiesProps"]
|
|
146144
147055
|
},
|
|
146145
|
-
mismatches:
|
|
147056
|
+
mismatches: FindMismatches
|
|
146146
147057
|
};
|
|
146147
147058
|
const reorder = /* @__PURE__ */ __name((list2, startIndex, endIndex) => {
|
|
146148
147059
|
const result = Array.from(list2);
|
|
@@ -148972,18 +149883,6 @@ __name(createAlignmentView, "createAlignmentView");
|
|
|
148972
149883
|
window.createVectorEditor = createVectorEditor;
|
|
148973
149884
|
window.createAlignmentView = createAlignmentView;
|
|
148974
149885
|
window.createVersionHistoryView = createVersionHistoryView;
|
|
148975
|
-
function getGapMap(sequence2) {
|
|
148976
|
-
const gapMap = [0];
|
|
148977
|
-
sequence2.split("").forEach((char) => {
|
|
148978
|
-
if (char === "-") {
|
|
148979
|
-
gapMap[Math.max(0, gapMap.length - 1)] = (gapMap[Math.max(0, gapMap.length - 1)] || 0) + 1;
|
|
148980
|
-
} else {
|
|
148981
|
-
gapMap.push(gapMap[gapMap.length - 1] || 0);
|
|
148982
|
-
}
|
|
148983
|
-
});
|
|
148984
|
-
return gapMap;
|
|
148985
|
-
}
|
|
148986
|
-
__name(getGapMap, "getGapMap");
|
|
148987
149886
|
exports.getGaps = () => ({
|
|
148988
149887
|
gapsBefore: 0,
|
|
148989
149888
|
gapsInside: 0
|