jbrowse-plugin-msaview 5.4.0 → 5.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dist/MsaViewPanel/afterCreateAutoruns.d.ts +1 -0
  2. package/dist/MsaViewPanel/afterCreateAutoruns.js +8 -0
  3. package/dist/MsaViewPanel/connectedDomains.d.ts +58 -0
  4. package/dist/MsaViewPanel/connectedDomains.js +101 -0
  5. package/dist/MsaViewPanel/connectedDomains.test.d.ts +1 -0
  6. package/dist/MsaViewPanel/connectedDomains.test.js +147 -0
  7. package/dist/MsaViewPanel/domainTrack.d.ts +84 -0
  8. package/dist/MsaViewPanel/domainTrack.js +51 -0
  9. package/dist/MsaViewPanel/domainTrack.test.d.ts +1 -0
  10. package/dist/MsaViewPanel/domainTrack.test.js +69 -0
  11. package/dist/MsaViewPanel/loadProteinDomains.js +2 -1
  12. package/dist/MsaViewPanel/loadProteinDomains.test.js +2 -0
  13. package/dist/MsaViewPanel/model.d.ts +22 -2
  14. package/dist/MsaViewPanel/model.js +71 -2
  15. package/dist/MsaViewPanel/model.test.js +94 -0
  16. package/dist/MsaViewPanel/msaCoordToGenomeCoord.d.ts +11 -3
  17. package/dist/MsaViewPanel/msaCoordToGenomeCoord.js +21 -14
  18. package/dist/chunks/{LaunchMsaViewDialog-HGL6P4E4.js → LaunchMsaViewDialog-BG4MX2BW.js} +2 -2
  19. package/dist/chunks/{chunk-2XCUSA22.js → chunk-4TEPHD3L.js} +2 -2
  20. package/dist/chunks/{chunk-2XCUSA22.js.map → chunk-4TEPHD3L.js.map} +2 -2
  21. package/dist/chunks/model-SEEQQSQO.js +12 -0
  22. package/dist/chunks/model-SEEQQSQO.js.map +7 -0
  23. package/dist/jbrowse-plugin-msaview.esm.js +2 -2
  24. package/dist/jbrowse-plugin-msaview.esm.js.map +2 -2
  25. package/dist/utils/domainCache.js +24 -2
  26. package/dist/utils/ncbiDomains.d.ts +4 -1
  27. package/dist/utils/ncbiDomains.js +16 -25
  28. package/dist/version.d.ts +1 -1
  29. package/dist/version.js +1 -1
  30. package/package.json +1 -1
  31. package/src/LaunchMsaViewExtensionPoint/index.ts +5 -0
  32. package/src/MsaViewPanel/afterCreateAutoruns.ts +11 -0
  33. package/src/MsaViewPanel/connectedDomains.test.ts +196 -0
  34. package/src/MsaViewPanel/connectedDomains.ts +151 -0
  35. package/src/MsaViewPanel/domainTrack.test.ts +75 -0
  36. package/src/MsaViewPanel/domainTrack.ts +66 -0
  37. package/src/MsaViewPanel/loadProteinDomains.test.ts +2 -0
  38. package/src/MsaViewPanel/loadProteinDomains.ts +13 -11
  39. package/src/MsaViewPanel/model.test.ts +100 -0
  40. package/src/MsaViewPanel/model.ts +82 -1
  41. package/src/MsaViewPanel/msaCoordToGenomeCoord.ts +37 -25
  42. package/src/utils/domainCache.ts +27 -2
  43. package/src/utils/ncbiDomains.ts +20 -27
  44. package/src/version.ts +1 -1
  45. package/dist/chunks/model-36HCIOZJ.js +0 -12
  46. package/dist/chunks/model-36HCIOZJ.js.map +0 -7
  47. /package/dist/chunks/{LaunchMsaViewDialog-HGL6P4E4.js.map → LaunchMsaViewDialog-BG4MX2BW.js.map} +0 -0
@@ -1,9 +1,11 @@
1
1
  import { BaseViewModel } from '@jbrowse/core/pluggableElementTypes';
2
- import { getSession } from '@jbrowse/core/util';
2
+ import { getSession, isSessionWithAddSessionTrack, isSessionWithDeleteTrackConf, isSessionWithSessionTracks, } from '@jbrowse/core/util';
3
3
  import { addDisposer, getSnapshot, types } from '@jbrowse/mobx-state-tree';
4
4
  import { autorun } from 'mobx';
5
5
  import { MSAModelF } from 'react-msaview';
6
- import { autoLoadProteinDomains, launchBlastIfNeeded, launchOrthologsIfNeeded, loadStoredData, observeProteinHighlights, processInit, runCleanup, storeDataToIndexedDB, syncGenomeHoverToMsaColumn, } from './afterCreateAutoruns';
6
+ import { autoLoadProteinDomains, launchBlastIfNeeded, launchOrthologsIfNeeded, loadStoredData, observeProteinHighlights, processInit, runCleanup, storeDataToIndexedDB, showDomainsOnGenomeIfAsked, syncGenomeHoverToMsaColumn, } from './afterCreateAutoruns';
7
+ import { connectedDomains } from './connectedDomains';
8
+ import { domainTrackConf } from './domainTrack';
7
9
  import { msaCoordToGenomeCoord, msaCoordToGenomeRegions, } from './msaCoordToGenomeCoord';
8
10
  import { resolveConnectedTranscriptIfNeeded } from './resolveConnectedTranscript';
9
11
  import { transcriptMap } from './transcriptMap';
@@ -106,6 +108,13 @@ export default function stateModelFactory() {
106
108
  * it false for the labeled toolbar.
107
109
  */
108
110
  embeddedMode: true,
111
+ /**
112
+ * #property
113
+ * a launch asking for the domains on the genome: once the connected
114
+ * view and the query row's domains are both there, the view adds the
115
+ * domain track and clears this
116
+ */
117
+ domainsOnGenome: types.stripDefault(types.boolean, false),
109
118
  }))
110
119
  .volatile(() => ({
111
120
  /**
@@ -205,6 +214,15 @@ export default function stateModelFactory() {
205
214
  ...this.connectedClickHighlights,
206
215
  ];
207
216
  },
217
+ /**
218
+ * #getter
219
+ * cross-plugin contract: the query row's domains on the genome, with
220
+ * the color object every surface paints them through.
221
+ * jbrowse-plugin-protein3d reads it to draw them on the structure
222
+ */
223
+ get connectedDomains() {
224
+ return connectedDomains(self);
225
+ },
208
226
  }))
209
227
  .views(self => ({
210
228
  /**
@@ -396,6 +414,46 @@ export default function stateModelFactory() {
396
414
  setDomainsRequested(arg) {
397
415
  self.domainsRequested = arg;
398
416
  },
417
+ /**
418
+ * #action
419
+ */
420
+ setDomainsOnGenome(arg) {
421
+ self.domainsOnGenome = arg;
422
+ },
423
+ /**
424
+ * #action
425
+ * Add the query row's domains to the connected genome view as a session
426
+ * track, replacing the one an earlier call added.
427
+ */
428
+ showDomainsOnGenome() {
429
+ const session = getSession(self);
430
+ const { connectedView, connectedDomains, connectedFeature } = self;
431
+ const assemblyName = connectedView?.assemblyNames[0];
432
+ if (!connectedView ||
433
+ !assemblyName ||
434
+ connectedDomains.features.length === 0 ||
435
+ !isSessionWithAddSessionTrack(session)) {
436
+ return;
437
+ }
438
+ const feature = connectedFeature;
439
+ const label = [feature?.gene_name, feature?.gene, feature?.name].find((v) => typeof v === 'string' && v !== '');
440
+ const conf = domainTrackConf({
441
+ viewId: self.id,
442
+ assemblyName,
443
+ name: `${label ?? self.querySeqName} domains (from the alignment)`,
444
+ strand: self.mafRegion ? undefined : self.transcriptToMsaMap?.strand,
445
+ domains: connectedDomains,
446
+ });
447
+ const existing = isSessionWithSessionTracks(session)
448
+ ? session.sessionTracks.find(t => t.trackId === conf.trackId)
449
+ : undefined;
450
+ if (existing && isSessionWithDeleteTrackConf(session)) {
451
+ session.deleteTrackConf(existing);
452
+ }
453
+ if (session.addSessionTrackConf(conf)) {
454
+ void connectedView.launchTrack(conf.trackId);
455
+ }
456
+ },
399
457
  /**
400
458
  * #action
401
459
  */
@@ -477,6 +535,16 @@ export default function stateModelFactory() {
477
535
  self.setZoomToBaseLevel(!self.zoomToBaseLevel);
478
536
  },
479
537
  },
538
+ ...(self.connectedView && self.connectedDomains.features.length > 0
539
+ ? [
540
+ {
541
+ label: 'Show domains on the genome',
542
+ onClick: () => {
543
+ self.showDomainsOnGenome();
544
+ },
545
+ },
546
+ ]
547
+ : []),
480
548
  ];
481
549
  },
482
550
  };
@@ -498,6 +566,7 @@ export default function stateModelFactory() {
498
566
  launchOrthologsIfNeeded,
499
567
  processInit,
500
568
  autoLoadProteinDomains,
569
+ showDomainsOnGenomeIfAsked,
501
570
  ]) {
502
571
  addDisposer(self, autorun(() => {
503
572
  fn(self);
@@ -166,3 +166,97 @@ describe('returning to the import form', () => {
166
166
  test('the view asks react-msaview for its icon toolbar', () => {
167
167
  expect(view().embeddedMode).toBe(true);
168
168
  });
169
+ // two CDS on the reverse strand, so residue 3's codon straddles the intron
170
+ const reverseTranscript = {
171
+ refName: 'chr1',
172
+ strand: -1,
173
+ start: 100,
174
+ end: 208,
175
+ subfeatures: [
176
+ { type: 'CDS', start: 100, end: 107, phase: 0 },
177
+ { type: 'CDS', start: 200, end: 208, phase: 0 },
178
+ ],
179
+ };
180
+ describe('connectedDomains', () => {
181
+ function domainView() {
182
+ const model = stateModelFactory().create({
183
+ type: 'MsaView',
184
+ id: 'msaview1',
185
+ data: { msa: '>QUERY\nMKV-LA\n>Mouse\nMKVQLA' },
186
+ connectedFeature: reverseTranscript,
187
+ });
188
+ model.setAnnotations([
189
+ {
190
+ id: 'QUERY',
191
+ accession: 'cd1',
192
+ name: 'Hb beta-like',
193
+ description: '',
194
+ start: 1,
195
+ end: 5,
196
+ },
197
+ {
198
+ id: 'QUERY',
199
+ accession: 'cd2',
200
+ name: 'heme binding site',
201
+ description: '',
202
+ featureType: 'Site',
203
+ start: 2,
204
+ end: 4,
205
+ },
206
+ {
207
+ id: 'Mouse',
208
+ accession: 'cd1',
209
+ name: 'Hb beta-like',
210
+ description: '',
211
+ start: 1,
212
+ end: 6,
213
+ },
214
+ ]);
215
+ return model;
216
+ }
217
+ test('carries the query row domains in the colors the alignment draws', () => {
218
+ const model = domainView();
219
+ const fills = new Map([...model.featureColors].map(([a, c]) => [
220
+ `${a.id}:${a.accession}`,
221
+ c.fill,
222
+ ]));
223
+ expect(model.connectedDomains).toEqual({
224
+ features: [
225
+ {
226
+ name: 'Hb beta-like',
227
+ accession: 'cd1',
228
+ kind: 'domain',
229
+ regions: [
230
+ { refName: 'chr1', start: 100, end: 107 },
231
+ { refName: 'chr1', start: 200, end: 208 },
232
+ ],
233
+ },
234
+ {
235
+ name: 'heme binding site',
236
+ accession: 'cd2',
237
+ kind: 'site',
238
+ regions: [
239
+ { refName: 'chr1', start: 103, end: 107 },
240
+ { refName: 'chr1', start: 200, end: 205 },
241
+ ],
242
+ },
243
+ ],
244
+ color: {
245
+ field: 'accession',
246
+ domain: ['cd1', 'cd2'],
247
+ range: [fills.get('QUERY:cd1'), fills.get('QUERY:cd2')],
248
+ labels: ['Hb beta-like', 'heme binding site'],
249
+ },
250
+ });
251
+ });
252
+ test('follows the overlay and the legend filter', () => {
253
+ const model = domainView();
254
+ model.setFilter('cd2', false);
255
+ expect(model.connectedDomains.color.domain).toEqual(['cd1']);
256
+ model.setShowDomains(false);
257
+ expect(model.connectedDomains).toEqual({
258
+ features: [],
259
+ color: { field: 'accession', domain: [], range: [], labels: [] },
260
+ });
261
+ });
262
+ });
@@ -1,11 +1,10 @@
1
1
  import type { MafRegion } from './types';
2
- interface GenomeRegion {
2
+ export interface GenomeRegion {
3
3
  refName: string;
4
4
  start: number;
5
5
  end: number;
6
6
  }
7
- interface CoordModel {
8
- querySeqName: string;
7
+ export interface SeqPosModel {
9
8
  transcriptToMsaMap: {
10
9
  refName: string;
11
10
  p2gCodon: Record<number, number[]>;
@@ -13,6 +12,9 @@ interface CoordModel {
13
12
  mafRegion?: MafRegion;
14
13
  /** transcript residues before the query row's first residue */
15
14
  querySeqOffset?: number;
15
+ }
16
+ interface CoordModel extends SeqPosModel {
17
+ querySeqName: string;
16
18
  /**
17
19
  * react-msaview's converter, which is the only thing that knows which columns
18
20
  * are on screen. `rows` carries the whole gapped alignment, so counting
@@ -22,6 +24,12 @@ interface CoordModel {
22
24
  */
23
25
  visibleColToSeqPos: (rowName: string, visibleCol: number) => number | undefined;
24
26
  }
27
+ /**
28
+ * The genome regions under residue `ungappedPos` (0-based) of the query row,
29
+ * 0-based half-open: the codon, one region per contiguous piece, or one base
30
+ * in a MAF alignment.
31
+ */
32
+ export declare function seqPosToGenomeRegions(model: SeqPosModel, ungappedPos: number): GenomeRegion[];
25
33
  /**
26
34
  * The genome regions covered by MSA column `coord` of the query row, in 0-based
27
35
  * half-open coordinates (what bpToPx and navTo take).
@@ -1,20 +1,11 @@
1
1
  import { getCodonRanges } from 'g2p_mapper';
2
2
  /**
3
- * The genome regions covered by MSA column `coord` of the query row, in 0-based
4
- * half-open coordinates (what bpToPx and navTo take).
5
- *
6
- * `coord` is a VISIBLE column -- what mouseCol and mouseClickCol carry.
7
- *
8
- * Usually one region -- one codon, or one base in a MAF alignment -- but a
9
- * codon split across an exon boundary yields one region per contiguous piece,
10
- * which is why this returns a list.
3
+ * The genome regions under residue `ungappedPos` (0-based) of the query row,
4
+ * 0-based half-open: the codon, one region per contiguous piece, or one base
5
+ * in a MAF alignment.
11
6
  */
12
- export function msaCoordToGenomeRegions({ model, coord: mouseCol, }) {
13
- const { querySeqName, transcriptToMsaMap, mafRegion } = model;
14
- const ungappedPos = model.visibleColToSeqPos(querySeqName, mouseCol);
15
- if (ungappedPos === undefined) {
16
- return [];
17
- }
7
+ export function seqPosToGenomeRegions(model, ungappedPos) {
8
+ const { transcriptToMsaMap, mafRegion } = model;
18
9
  if (mafRegion) {
19
10
  const genomePos = mafRegion.start + ungappedPos;
20
11
  return genomePos < mafRegion.end
@@ -40,6 +31,22 @@ export function msaCoordToGenomeRegions({ model, coord: mouseCol, }) {
40
31
  }
41
32
  return [];
42
33
  }
34
+ /**
35
+ * The genome regions covered by MSA column `coord` of the query row, in 0-based
36
+ * half-open coordinates (what bpToPx and navTo take).
37
+ *
38
+ * `coord` is a VISIBLE column -- what mouseCol and mouseClickCol carry.
39
+ *
40
+ * Usually one region -- one codon, or one base in a MAF alignment -- but a
41
+ * codon split across an exon boundary yields one region per contiguous piece,
42
+ * which is why this returns a list.
43
+ */
44
+ export function msaCoordToGenomeRegions({ model, coord: mouseCol, }) {
45
+ const ungappedPos = model.visibleColToSeqPos(model.querySeqName, mouseCol);
46
+ return ungappedPos === undefined
47
+ ? []
48
+ : seqPosToGenomeRegions(model, ungappedPos);
49
+ }
43
50
  /**
44
51
  * A single region spanning the codon at MSA column `coord`, for navigation. For
45
52
  * a codon split across an exon boundary this spans the intervening intron.
@@ -1,5 +1,5 @@
1
- import{D as Et,a as G,c as bt,d as pe,e as se,f as fe,g as te,h as vt,i as Be,j as qe,k as Ee,l as rr,m as Mt,q as kt,r as ot,s as _e,v as Ve,x as qt}from"./chunk-2XCUSA22.js";import{a as Ft}from"./chunk-NLAW2OYS.js";import{g as de,h as St,i as Ne,k as tt,l as De,m as At,n as Oe,o as Ct,p as Lt,r as je,s as $e,t as Nt}from"./chunk-F726IWCW.js";import{a as yt,b as Bt,c as nr}from"./chunk-AQ2THRTR.js";import{e as Pt,f as It}from"./chunk-XXCNVFGP.js";import{a as wt,b as ke,c as xt,d as Tt}from"./chunk-DECSTFAT.js";import{a as V}from"./chunk-NSASZ5FM.js";import{a as be,c as Ie,d as gt}from"./chunk-KSCGTF4R.js";import{a as or}from"./chunk-2IWD4OO4.js";import"./chunk-73KAPCJ2.js";import{a as ve}from"./chunk-CVLB4VFP.js";import{a as we}from"./chunk-DNFD5II2.js";import{a as L}from"./chunk-BX4Z274Q.js";import{a as f}from"./chunk-J6KYLXRD.js";import{a as tr,b as s}from"./chunk-FY3BTKY4.js";var Qo=tr((us,Go)=>{Go.exports=JBrowseExports["@jbrowse/core/data_adapters/dataAdapterCache"]});var A=s(f()),Zo=s(we()),Ro=s(be()),ye=s(L());var K=s(f());var Dt=s(gt(),1),Ot=(0,Ie.createSvgIcon)((0,Dt.jsx)("path",{d:"M19.14 12.94c.04-.3.06-.61.06-.94 0-.32-.02-.64-.07-.94l2.03-1.58c.18-.14.23-.41.12-.61l-1.92-3.32c-.12-.22-.37-.29-.59-.22l-2.39.96c-.5-.38-1.03-.7-1.62-.94l-.36-2.54c-.04-.24-.24-.41-.48-.41h-3.84c-.24 0-.43.17-.47.41l-.36 2.54c-.59.24-1.13.57-1.62.94l-2.39-.96c-.22-.08-.47 0-.59.22L2.74 8.87c-.12.21-.08.47.12.61l2.03 1.58c-.05.3-.09.63-.09.94s.02.64.07.94l-2.03 1.58c-.18.14-.23.41-.12.61l1.92 3.32c.12.22.37.29.59.22l2.39-.96c.5.38 1.03.7 1.62.94l.36 2.54c.05.24.24.41.48.41h3.84c.24 0 .44-.17.47-.41l.36-2.54c.59-.24 1.13-.56 1.62-.94l2.39.96c.22.08.47 0 .59-.22l1.92-3.32c.12-.22.07-.47-.12-.61zM12 15.6c-1.98 0-3.6-1.62-3.6-3.6s1.62-3.6 3.6-3.6 3.6 1.62 3.6 3.6-1.62 3.6-3.6 3.6"}),"Settings");var Ke=s(L()),Lo=s(V());var w=s(f());var U=s(L()),ho=s(ve()),go=s(V());var rt=s(f()),jt=s(L());function ar({children:e,...t}){return rt.default.createElement("div",null,rt.default.createElement(jt.TextField,{...t},e))}var g=ar;var nt=s(f()),$t=s(we()),_t=s(L()),Vt=s(V()),sr=(0,Vt.makeStyles)()({dialogContent:{width:"80em"}});function Y({error:e,children:t}){let{classes:o}=sr();return nt.default.createElement(_t.DialogContent,{className:o.dialogContent},e?nt.default.createElement($t.ErrorMessage,{error:e}):null,t)}var at=s(f()),Gt=s(we()),Qt=s(L());function ie({status:e}){return e==="loading"?at.default.createElement(Gt.LoadingEllipses,{message:"Translating transcript"}):e==="missing"?at.default.createElement(Qt.Typography,{color:"textSecondary",variant:"body2"},"no coding sequence to align"):null}var ce=s(f()),Ut=s(be()),me=s(L());var le=s(f());var Ht=(0,le.createContext)(void 0);function Wt({children:e}){let t=(0,le.useState)(()=>ke()==="splitRight");return le.default.createElement(Ht.Provider,{value:t},e)}function Ge(){let e=(0,le.useContext)(Ht),t=(0,le.useState)(()=>ke()==="splitRight");return e??t}function ir({checked:e,onChange:t}){return ce.default.createElement(me.FormControlLabel,{label:"Open beside the genome view",control:ce.default.createElement(me.Checkbox,{checked:e,onChange:o=>{t(o.target.checked)}})})}function X({onSubmit:e,onCancel:t,submitDisabled:o,hint:r,submitLabel:n="Submit",model:a}){let[i,u]=Ge(),c=!!a&&wt((0,Ut.getSession)(a));return ce.default.createElement(me.DialogActions,{sx:{flexWrap:"wrap",rowGap:1}},c?ce.default.createElement(ir,{checked:i,onChange:u}):null,ce.default.createElement("div",{style:{display:"flex",alignItems:"center",gap:8,marginLeft:"auto"}},r,ce.default.createElement(me.Button,{sx:{flexShrink:0},color:"primary",variant:"contained",disabled:o,onClick:()=>{if(c){let l=i?"splitRight":"stack";xt(l),e(l)}else e(ke())}},n),ce.default.createElement(me.Button,{sx:{flexShrink:0},color:"secondary",variant:"contained",onClick:()=>{t()}},"Cancel")))}var Z=s(f()),xe=s(L()),Jt=s(V());var zt=s(f()),Kt=s(V());var lr=(0,Kt.makeStyles)()({textAreaFont:{fontFamily:"Courier New"}});function st({value:e}){let{classes:t}=lr();return zt.default.createElement(g,{variant:"outlined",multiline:!0,minRows:5,maxRows:10,fullWidth:!0,value:e,slotProps:{input:{readOnly:!0,classes:{input:t.textAreaFont}}}})}var mr=(0,Jt.makeStyles)()({flex:{display:"flex"},minWidth:{minWidth:300},centered:{alignContent:"center",marginLeft:20}});function R({feature:e,options:t,selectedId:o,selectedTranscript:r,setSelectedId:n,proteinSequence:a,sequenceStatus:i="ready",validIds:u}){let{classes:c}=mr(),[l,p]=(0,Z.useState)(!1);return Z.default.createElement(Z.default.Fragment,null,Z.default.createElement("div",{className:c.flex},Z.default.createElement(xe.TextField,{variant:"outlined",label:`Choose isoform of ${te(e)}`,helperText:"the query row, so the alignment stays linked to the genome view",select:!0,className:c.minWidth,value:o,onChange:d=>{n(d.target.value)}},t.map(d=>{let m=u?u.some(v=>se(d,v)):!0,{len:b,mod:S}=bt(d);return Z.default.createElement(xe.MenuItem,{value:pe(d),key:d.id(),disabled:!m},fe(d)," (",b," aa)"," ",S?" (possible fragment)":"",u?m?" (has data)":" (no data)":"")})),Z.default.createElement("div",{className:c.centered},Z.default.createElement(xe.Button,{variant:"contained",color:"primary",onClick:()=>{p(!l)}},l?"Hide sequence":"Show sequence"))),l?Z.default.createElement(st,{value:a?`>${fe(r)}
1
+ import{E as Et,a as G,c as bt,d as pe,e as se,f as fe,g as te,h as vt,i as Be,j as qe,k as Ee,l as rr,m as Mt,r as kt,s as ot,t as _e,w as Ve,y as qt}from"./chunk-4TEPHD3L.js";import{a as Ft}from"./chunk-NLAW2OYS.js";import{g as de,h as St,i as Ne,k as tt,l as De,m as At,n as Oe,o as Ct,p as Lt,r as je,s as $e,t as Nt}from"./chunk-F726IWCW.js";import{a as yt,b as Bt,c as nr}from"./chunk-AQ2THRTR.js";import{e as Pt,f as It}from"./chunk-XXCNVFGP.js";import{a as wt,b as ke,c as xt,d as Tt}from"./chunk-DECSTFAT.js";import{a as V}from"./chunk-NSASZ5FM.js";import{a as be,c as Ie,d as gt}from"./chunk-KSCGTF4R.js";import{a as or}from"./chunk-2IWD4OO4.js";import"./chunk-73KAPCJ2.js";import{a as ve}from"./chunk-CVLB4VFP.js";import{a as we}from"./chunk-DNFD5II2.js";import{a as L}from"./chunk-BX4Z274Q.js";import{a as f}from"./chunk-J6KYLXRD.js";import{a as tr,b as s}from"./chunk-FY3BTKY4.js";var Qo=tr((us,Go)=>{Go.exports=JBrowseExports["@jbrowse/core/data_adapters/dataAdapterCache"]});var A=s(f()),Zo=s(we()),Ro=s(be()),ye=s(L());var K=s(f());var Dt=s(gt(),1),Ot=(0,Ie.createSvgIcon)((0,Dt.jsx)("path",{d:"M19.14 12.94c.04-.3.06-.61.06-.94 0-.32-.02-.64-.07-.94l2.03-1.58c.18-.14.23-.41.12-.61l-1.92-3.32c-.12-.22-.37-.29-.59-.22l-2.39.96c-.5-.38-1.03-.7-1.62-.94l-.36-2.54c-.04-.24-.24-.41-.48-.41h-3.84c-.24 0-.43.17-.47.41l-.36 2.54c-.59.24-1.13.57-1.62.94l-2.39-.96c-.22-.08-.47 0-.59.22L2.74 8.87c-.12.21-.08.47.12.61l2.03 1.58c-.05.3-.09.63-.09.94s.02.64.07.94l-2.03 1.58c-.18.14-.23.41-.12.61l1.92 3.32c.12.22.37.29.59.22l2.39-.96c.5.38 1.03.7 1.62.94l.36 2.54c.05.24.24.41.48.41h3.84c.24 0 .44-.17.47-.41l.36-2.54c.59-.24 1.13-.56 1.62-.94l2.39.96c.22.08.47 0 .59-.22l1.92-3.32c.12-.22.07-.47-.12-.61zM12 15.6c-1.98 0-3.6-1.62-3.6-3.6s1.62-3.6 3.6-3.6 3.6 1.62 3.6 3.6-1.62 3.6-3.6 3.6"}),"Settings");var Ke=s(L()),Lo=s(V());var w=s(f());var U=s(L()),ho=s(ve()),go=s(V());var rt=s(f()),jt=s(L());function ar({children:e,...t}){return rt.default.createElement("div",null,rt.default.createElement(jt.TextField,{...t},e))}var g=ar;var nt=s(f()),$t=s(we()),_t=s(L()),Vt=s(V()),sr=(0,Vt.makeStyles)()({dialogContent:{width:"80em"}});function Y({error:e,children:t}){let{classes:o}=sr();return nt.default.createElement(_t.DialogContent,{className:o.dialogContent},e?nt.default.createElement($t.ErrorMessage,{error:e}):null,t)}var at=s(f()),Gt=s(we()),Qt=s(L());function ie({status:e}){return e==="loading"?at.default.createElement(Gt.LoadingEllipses,{message:"Translating transcript"}):e==="missing"?at.default.createElement(Qt.Typography,{color:"textSecondary",variant:"body2"},"no coding sequence to align"):null}var ce=s(f()),Ut=s(be()),me=s(L());var le=s(f());var Ht=(0,le.createContext)(void 0);function Wt({children:e}){let t=(0,le.useState)(()=>ke()==="splitRight");return le.default.createElement(Ht.Provider,{value:t},e)}function Ge(){let e=(0,le.useContext)(Ht),t=(0,le.useState)(()=>ke()==="splitRight");return e??t}function ir({checked:e,onChange:t}){return ce.default.createElement(me.FormControlLabel,{label:"Open beside the genome view",control:ce.default.createElement(me.Checkbox,{checked:e,onChange:o=>{t(o.target.checked)}})})}function X({onSubmit:e,onCancel:t,submitDisabled:o,hint:r,submitLabel:n="Submit",model:a}){let[i,u]=Ge(),c=!!a&&wt((0,Ut.getSession)(a));return ce.default.createElement(me.DialogActions,{sx:{flexWrap:"wrap",rowGap:1}},c?ce.default.createElement(ir,{checked:i,onChange:u}):null,ce.default.createElement("div",{style:{display:"flex",alignItems:"center",gap:8,marginLeft:"auto"}},r,ce.default.createElement(me.Button,{sx:{flexShrink:0},color:"primary",variant:"contained",disabled:o,onClick:()=>{if(c){let l=i?"splitRight":"stack";xt(l),e(l)}else e(ke())}},n),ce.default.createElement(me.Button,{sx:{flexShrink:0},color:"secondary",variant:"contained",onClick:()=>{t()}},"Cancel")))}var Z=s(f()),xe=s(L()),Jt=s(V());var zt=s(f()),Kt=s(V());var lr=(0,Kt.makeStyles)()({textAreaFont:{fontFamily:"Courier New"}});function st({value:e}){let{classes:t}=lr();return zt.default.createElement(g,{variant:"outlined",multiline:!0,minRows:5,maxRows:10,fullWidth:!0,value:e,slotProps:{input:{readOnly:!0,classes:{input:t.textAreaFont}}}})}var mr=(0,Jt.makeStyles)()({flex:{display:"flex"},minWidth:{minWidth:300},centered:{alignContent:"center",marginLeft:20}});function R({feature:e,options:t,selectedId:o,selectedTranscript:r,setSelectedId:n,proteinSequence:a,sequenceStatus:i="ready",validIds:u}){let{classes:c}=mr(),[l,p]=(0,Z.useState)(!1);return Z.default.createElement(Z.default.Fragment,null,Z.default.createElement("div",{className:c.flex},Z.default.createElement(xe.TextField,{variant:"outlined",label:`Choose isoform of ${te(e)}`,helperText:"the query row, so the alignment stays linked to the genome view",select:!0,className:c.minWidth,value:o,onChange:d=>{n(d.target.value)}},t.map(d=>{let m=u?u.some(v=>se(d,v)):!0,{len:b,mod:S}=bt(d);return Z.default.createElement(xe.MenuItem,{value:pe(d),key:d.id(),disabled:!m},fe(d)," (",b," aa)"," ",S?" (possible fragment)":"",u?m?" (has data)":" (no data)":"")})),Z.default.createElement("div",{className:c.centered},Z.default.createElement(xe.Button,{variant:"contained",color:"primary",onClick:()=>{p(!l)}},l?"Hide sequence":"Show sequence"))),l?Z.default.createElement(st,{value:a?`>${fe(r)}
2
2
  ${a}`:i==="missing"?"This transcript has no coding sequence, so there is nothing to translate.":i==="error"?"The sequence could not be fetched.":"Loading..."}):null)}var Qe=s(f()),Yt=s(be());var Te={drawNodeBubbles:!0,colWidth:10,rowHeight:12};function Q({view:e,feature:t,placement:o,...r}){return Tt((0,Yt.getSession)(e),{placement:o,connectedViewId:e.id,connectedFeature:t?.toJSON(),...r})}function oe(e){let[t,o]=(0,Qe.useState)(),r=(0,Qe.useRef)(!1);return{launchError:t,submit:n=>{r.current||(r.current=!0,o(void 0),n().then(e,a=>{r.current=!1,console.error(a),o(a)}))}}}var We=s(f());var Zt=s(f()),Rt=s(be()),eo=s(rr());var H=s(f()),Xt=e=>e==null||e===!1;function ur(e){return Xt(e)||Array.isArray(e)&&e.some(Xt)?null:JSON.stringify(e)}function W(e,t,{onSuccess:o}={}){let r=ur(e),[n,a]=(0,H.useState)(0),[i,u]=(0,H.useState)(),c=r===null?null:`${n}\0${r}`,l=i?.attempt===c,p=i?.question===r,d=(0,H.useRef)({fetcher:t,onSuccess:o});return(0,H.useEffect)(()=>{d.current={fetcher:t,onSuccess:o}}),(0,H.useEffect)(()=>{if(c===null||r===null)return;let m=new AbortController;return d.current.fetcher(m.signal).then(b=>{m.signal.aborted||(u({attempt:c,question:r,data:b}),d.current.onSuccess?.(b))}).catch(b=>{m.signal.aborted||u({attempt:c,question:r,error:b})}),()=>{m.abort()}},[c,r]),{data:p?i.data:void 0,error:l?i.error:void 0,isLoading:c!==null&&!l,mutate:(0,H.useCallback)(()=>{a(m=>m+1)},[])}}function He(e,t){let[o,r]=(0,H.useState)(e);return(0,H.useEffect)(()=>{let n=setTimeout(()=>{r(e)},t);return()=>{clearTimeout(n)}},[e,t]),o}function to({view:e,feature:t}){let o=e?.assemblyNames?.[0],{data:r,error:n,isLoading:a}=W(t&&o?[t.id(),o,"feature-sequence"]:null,async()=>{let{start:u,end:c,refName:l}=t.toJSON();return Mt({start:u,end:c,refName:l,assemblyName:o,session:(0,Rt.getSession)(e)})});return{proteinSequence:(0,Zt.useMemo)(()=>r&&t?(0,eo.translateTranscript)({transcript:t,...r})?.protein??"":"",[r,t]),sequence:r,error:n,isLoading:a}}function cr(e,t,o){if(!o?.length)return e;let r=i=>o.some(u=>se(i,u)),n=t.find(i=>pe(i)===e);if(n&&r(n))return e;let a=t.find(r);return a?pe(a):e}function dr({error:e,isLoading:t,proteinSequence:o}){return e?"error":t?"loading":o?"ready":"missing"}function re({feature:e,view:t,validIds:o,preferredTranscriptId:r}){let n=(0,We.useMemo)(()=>Be(e),[e]),[a,i]=(0,We.useState)(()=>pe(n.find(m=>se(m,r??""))??n[0])),u=cr(a,n,o),c=n.find(m=>pe(m)===u),{proteinSequence:l,error:p,isLoading:d}=to({view:t,feature:c});return{options:n,selectedId:u,setSelectedId:i,selectedTranscript:c,proteinSequence:l,error:p,isLoading:d,sequenceStatus:dr({error:p,isLoading:d,proteinSequence:l}),validIds:o}}var q=s(f()),ao=s(we());var oo=s(gt(),1),ro=(0,Ie.createSvgIcon)((0,oo.jsx)("path",{d:"M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6zM19 4h-3.5l-1-1h-5l-1 1H5v2h14z"}),"Delete");var E=s(L()),so=s(ve()),io=s(V());var pr=(0,io.makeStyles)()({header:{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:8},resultList:{maxHeight:300,overflow:"auto"}});function no(e){let t=[e.geneName,e.transcriptName!==e.geneName?e.transcriptName:void 0].filter(o=>!!o);return t.length>0?t.join(" - "):e.geneId??e.transcriptId??"Unknown"}function fr(e){return[e.blastDatabase,e.searchProgram??e.blastProgram??"blastp",e.msaAlgorithm].filter(Boolean).join(" / ")}var hr=(0,so.observer)(function({model:e,handleClose:t,feature:o,cached:{results:r,handleDelete:n,handleClearAll:a}}){let{classes:i}=pr(),u=G(e),[c,l]=(0,q.useState)(),[p]=Ge(),d=m=>{let{transcriptId:b,msa:S,tree:v,treeMetadata:j}=m;Q({view:u,feature:b?Be(o).find(M=>se(M,b)):void 0,placement:p?"splitRight":"stack",displayName:`BLAST - ${no(m)}`,...Te,data:{msa:S,tree:v,treeMetadata:j}}).then(t,M=>{console.error(M),l(M)})};return q.default.createElement("div",null,c?q.default.createElement(ao.ErrorMessage,{error:c}):null,q.default.createElement("div",{className:i.header},q.default.createElement(E.Typography,{variant:"subtitle1"},"Cached BLAST Results (",r.length,")"),q.default.createElement(E.Button,{size:"small",color:"error",onClick:async()=>{try{l(void 0),await a()}catch(m){l(m)}}},"Clear results for this gene")),q.default.createElement(E.List,{dense:!0,className:i.resultList},r.map(m=>q.default.createElement(E.ListItem,{key:m.id,disablePadding:!0,secondaryAction:q.default.createElement(E.IconButton,{edge:"end",size:"small",onClick:async b=>{b.stopPropagation();try{l(void 0),await n(m.id)}catch(S){l(S)}}},q.default.createElement(ro,{fontSize:"small"}))},q.default.createElement(E.ListItemButton,{onClick:()=>{d(m)}},q.default.createElement(E.ListItemText,{primary:`${no(m)} - ${fr(m)}`,secondary:`${new Date(m.timestamp).toLocaleString()} - Seq: ${m.proteinSequence.slice(0,30)}...`}))))))}),lo=hr;var it=s(f()),mo=s(L());function Fe({value:e,onChange:t,className:o}){return it.default.createElement(g,{variant:"outlined",label:"MSA Algorithm",className:o,select:!0,value:e,helperText:e==="browser"?"no EBI job; rows aligned to the query":void 0,onChange:r=>{t(r.target.value)}},De.map(r=>it.default.createElement(mo.MenuItem,{value:r,key:r},At[r])))}var gr="msaView-blastSearch",Sr="msaView-msaAlgorithm",uo=je("blastp"),co="clustalo";function yr(e){let{program:t,database:o}=e??{},r=Oe.find(n=>n===t);return r&&$e(r).some(n=>n===o)?{program:r,database:o}:uo}function br(e){return De.find(t=>t===e)??co}function po(){let[e,t]=de(gr,uo);return[yr(e),o=>{t(o)}]}function Ue(){let[e,t]=de(Sr,co);return[br(e),o=>{t(o)}]}function fo(e){let{data:t,error:o,isLoading:r,mutate:n}=W(`cached-blast-${e.join(",")}`,async()=>(await kt()).filter(i=>i.geneId&&e.includes(i.geneId)));return{results:t??[],error:o,isLoading:r,handleDelete:async a=>{await ot(a),n()},handleClearAll:async()=>{await Promise.all((t??[]).map(a=>ot(a.id))),n()}}}var vr=(0,go.makeStyles)()({selectField:{width:150},databaseField:{width:260},cachedResultsAccordion:{marginTop:20},infoText:{marginTop:20}}),wr=(0,ho.observer)(function({handleClose:e,feature:t,model:o,children:r,preferredTranscriptId:n}){let{classes:a}=vr(),i=G(o),{launchError:u,submit:c}=oe(e),[l,p]=po(),[d,m]=Ue(),[b,S]=(0,w.useState)(String(Lt)),v=Number(b),j=Number.isInteger(v)&&v>=1,M=l.program==="phmmer",P=(0,w.useMemo)(()=>Ee(t),[t]),C=fo(P),I=re({feature:t,view:i,preferredTranscriptId:n}),{selectedTranscript:k,proteinSequence:F,sequenceStatus:$}=I,_=I.error??u??C.error;return w.default.createElement(w.default.Fragment,null,w.default.createElement(Y,{error:_},r,w.default.createElement(g,{variant:"outlined",label:"Search program",className:a.selectField,select:!0,value:l.program,onChange:x=>{p(je(x.target.value))}},Oe.map(x=>w.default.createElement(U.MenuItem,{value:x,key:x},Ct[x]))),w.default.createElement(g,{variant:"outlined",label:"Database",className:a.databaseField,select:!0,value:l.database,onChange:x=>{p({program:l.program,database:x.target.value})}},$e(l.program).map(x=>w.default.createElement(U.MenuItem,{value:x,key:x},Nt(x)))),M?null:w.default.createElement(Fe,{className:a.selectField,value:d,onChange:m}),w.default.createElement(g,{variant:"outlined",label:"Hits",className:a.selectField,type:"number",value:b,onChange:x=>{S(x.target.value)},error:!j,helperText:"best-scoring sequences to keep"}),w.default.createElement(R,{feature:t,...I}),w.default.createElement(U.Typography,{variant:"body2",className:a.infoText},M?"phmmer aligns the hits as it finds them, so nothing is realigned afterwards.":"The hits come back from EBI and are then run through the chosen aligner."," ","The EBI queue is the wait, and it runs from seconds to many minutes."),C.results.length>0?w.default.createElement(U.Accordion,{className:a.cachedResultsAccordion},w.default.createElement(U.AccordionSummary,{expandIcon:w.default.createElement(yt,null)},w.default.createElement(U.Typography,null,"Previous BLAST Results")),w.default.createElement(U.AccordionDetails,null,w.default.createElement(lo,{model:o,handleClose:e,feature:t,cached:C}))):null),w.default.createElement(X,{model:o,hint:w.default.createElement(ie,{status:$}),submitDisabled:!F||!j,onSubmit:x=>{if(k){let ue=l.program==="phmmer"?{searchProgram:"phmmer",blastDatabase:l.database,maxHits:v,selectedTranscript:k.toJSON(),proteinSequence:F}:{searchProgram:"blastp",blastDatabase:l.database,msaAlgorithm:d,maxHits:v,selectedTranscript:k.toJSON(),proteinSequence:F};c(()=>Q({view:i,feature:k,placement:x,displayName:vt(t,k),...Te,blastParams:ue}))}},onCancel:e}))}),So=wr;var y=s(f()),xo=s(be()),ge=s(L()),To=s(ve()),Mo=s(V());var ze=s(f());function yo(e){return qe(e).toUpperCase()}function xr(e,t){let o=Math.min(e.length,t.length);if(o===0)return 0;let r=0;for(let n=0;n<o;n++)e[n]===t[n]&&r++;return r/o}var Tr=.9,Mr=.5;function bo(e,t){if(!e.trim())return{names:[]};let o;try{o=Pt(e)}catch{return{names:[]}}let r=o.getNames(),n=yo(t);return{names:r,match:n?Ar(o,r,n):void 0}}function Ar(e,t,o){let r=[];for(let a of t){let i=yo(It(e.getRow(a)));if(!i)continue;if(i===o)return{name:a,quality:"exact",identity:1,offset:0};let u=o.indexOf(i),c=i.indexOf(o);if(u!==-1||c!==-1){let p=Math.min(i.length,o.length)/Math.max(i.length,o.length);p>=Mr&&r.push({name:a,quality:"partial",identity:p,offset:u===-1?-c:u});continue}let l=xr(i,o);l>=Tr&&r.push({name:a,quality:"similar",identity:l,offset:0})}let n=["partial","similar"];return r.sort((a,i)=>n.indexOf(a.quality)-n.indexOf(i.quality)||i.identity-a.identity)[0]}function vo(e,t){return e.querySeqName||(e.names.includes(t)?t:"")}function Me(e,t){let[o,r]=(0,ze.useState)(),{names:n,match:a}=(0,ze.useMemo)(()=>bo(e,t),[e,t]),i=o!==void 0&&(n.length===0||n.includes(o))?o:void 0,u=i??a?.name??"";return{detected:a,names:n,querySeqName:u,querySeqOffset:u===a?.name?a.offset:0,setQuerySeqName:r,isAutoDetected:i===void 0&&!!a}}var ee=s(f()),Ae=s(L()),wo=s(V());var Cr=(0,wo.makeStyles)()({field:{marginTop:20},alert:{marginTop:10}});function Lr({identity:e,offset:t}){let o=`, covering ${Math.round(e*100)}% of it`;return t>0?`${o} from residue ${t+1}`:t<0?`${o} and running ${-t} residues past its start`:o}function he({names:e,detected:t,querySeqName:o,setQuerySeqName:r,isAutoDetected:n}){let{classes:a}=Cr();return ee.default.createElement(ee.default.Fragment,null,e.length>0?ee.default.createElement(g,{variant:"outlined",label:"MSA row matching the selected transcript",select:!0,fullWidth:!0,className:a.field,value:e.includes(o)?o:"",onChange:i=>{r(i.target.value)}},e.map(i=>ee.default.createElement(Ae.MenuItem,{value:i,key:i},i,t?.name===i?" \u2014 matches your protein":""))):ee.default.createElement(g,{variant:"outlined",label:"MSA row matching the selected transcript",fullWidth:!0,className:a.field,helperText:"Paste an alignment above and this fills in on its own",value:o,onChange:i=>{r(i.target.value)}}),n&&t?t.quality==="similar"?ee.default.createElement(Ae.Alert,{severity:"warning",className:a.alert},ee.default.createElement("strong",null,t.name)," is"," ",Math.round(t.identity*100),"% identical to your protein but is not the same sequence. Clicking the alignment navigates the genome view, approximately: wherever the two differ by an insertion or a deletion, every residue after it lands one codon off."):ee.default.createElement(Ae.Alert,{severity:"success",className:a.alert},"Matched ",ee.default.createElement("strong",null,t.name)," to your protein sequence",t.quality==="exact"?"":Lr(t),". Clicking the alignment will navigate the genome view."):e.length>0&&!o?ee.default.createElement(Ae.Alert,{severity:"warning",className:a.alert},"No row matched your protein sequence \u2014 pick the one for your gene above. Without it the alignment still renders, but clicking it will not navigate the genome view."):null)}var Nr=(0,Mo.makeStyles)()({ncbiLink:{wordBreak:"break-all"},textAreaFont:{fontFamily:"Courier New"},msaInput:{marginBottom:20},step:{marginTop:20},stepBody:{marginLeft:20,marginTop:8}}),kr=(0,To.observer)(function({handleClose:e,feature:t,model:o,children:r,preferredTranscriptId:n}){let{classes:a}=Nr(),i=G(o),{launchError:u,submit:c}=oe(e),[l,p]=(0,y.useState)(""),[d,m]=(0,y.useState)(""),b=re({feature:t,view:i,preferredTranscriptId:n}),{proteinSequence:S,selectedTranscript:v,error:j}=b,M=Me(l,S),P=qe(S),C=`${tt}?PAGE_TYPE=BlastSearch&PAGE=Proteins&PROGRAM=blastp&QUERY=${P}`,I=`${tt}?PAGE_TYPE=BlastSearch&PAGE=Proteins&PROGRAM=blastp&QUERY=${(0,xo.shorten2)(P,10)}`;return y.default.createElement(y.default.Fragment,null,y.default.createElement(Y,{error:u??j},r,y.default.createElement(R,{feature:t,...b}),y.default.createElement("div",{className:a.step},y.default.createElement(ge.Typography,{variant:"subtitle2"},"1. Run the search at NCBI"),y.default.createElement("div",{className:a.stepBody},S?y.default.createElement("div",{className:a.ncbiLink},y.default.createElement(Ft,{href:C},I)):y.default.createElement(ge.Alert,{severity:"info"},"Pick a transcript above to get a link carrying its protein sequence."))),y.default.createElement("div",{className:a.step},y.default.createElement(ge.Typography,{variant:"subtitle2"},"2. Align the hits"),y.default.createElement("div",{className:a.stepBody},y.default.createElement(ge.Typography,null,`On the results page click "Multiple Alignment" to run COBALT, NCBI's aligner. Download the alignment (.aln) and, if you want the tree drawn, the Newick tree (.nh).`))),y.default.createElement("div",{className:a.step},y.default.createElement(ge.Typography,{variant:"subtitle2"},"3. Paste the results back here"),y.default.createElement("div",{className:a.stepBody},y.default.createElement(g,{variant:"outlined",label:"Alignment",multiline:!0,minRows:5,maxRows:10,fullWidth:!0,className:a.msaInput,slotProps:{input:{className:a.textAreaFont}},placeholder:"Paste the .aln contents here",value:l,onChange:k=>{p(k.target.value)}}),y.default.createElement(g,{variant:"outlined",label:"Tree (optional)",multiline:!0,minRows:3,maxRows:10,fullWidth:!0,slotProps:{input:{className:a.textAreaFont}},placeholder:"Paste the .nh Newick tree here",value:d,onChange:k=>{m(k.target.value)}}),y.default.createElement(he,{...M})))),y.default.createElement(X,{model:o,submitDisabled:!v||!l.trim(),onSubmit:k=>{v&&c(()=>Q({view:i,feature:v,placement:k,displayName:te(v),querySeqName:M.querySeqName,querySeqOffset:M.querySeqOffset,data:{msa:l,tree:d}}))},onCancel:e}))}),Ao=kr;var Se=s(f()),ne=s(L());function lt({lookupMethod:e,setLookupMethod:t}){return Se.default.createElement(ne.FormControl,{component:"fieldset"},Se.default.createElement(ne.RadioGroup,{row:!0,value:e,onChange:o=>{t(o.target.value)}},Se.default.createElement(ne.FormControlLabel,{value:"automatic",control:Se.default.createElement(ne.Radio,null),label:"Automatic"}),Se.default.createElement(ne.FormControlLabel,{value:"manual",control:Se.default.createElement(ne.Radio,null),label:"Manual"})))}var z=s(f()),D=s(L()),Co=s(V());var Fr=(0,Co.makeStyles)()({field:{minWidth:300},help:{marginBottom:8}});function mt({handleClose:e,ebiEmail:t}){let{classes:o}=Fr(),[r,n]=(0,z.useState)(t);return z.default.createElement(D.Dialog,{open:!0,maxWidth:"lg",onClose:()=>{e()}},z.default.createElement(D.DialogTitle,null,"EBI settings"),z.default.createElement(D.DialogContent,null,z.default.createElement(D.Typography,{variant:"subtitle2",className:o.help},"Every search this tab runs is submitted to EBI with this address, which is how they reach whoever is generating the load. If your site sends real volume, use your own."),z.default.createElement(g,{autoFocus:!0,margin:"dense",label:"EBI contact email",fullWidth:!0,variant:"outlined",value:r,className:o.field,onChange:a=>{n(a.target.value)}}),z.default.createElement(D.Button,{variant:"contained",onClick:()=>{n(Ne)}},"Reset")),z.default.createElement(D.DialogActions,null,z.default.createElement(D.Button,{variant:"contained",color:"secondary",onClick:()=>{e()}},"Cancel"),z.default.createElement(D.Button,{color:"primary",variant:"contained",onClick:()=>{e({ebiEmail:r})}},"Save")))}var Pr=(0,Lo.makeStyles)()({settingsButton:{float:"right"}}),Ir={automatic:So,manual:Ao};function ut({handleClose:e,model:t,feature:o,preferredTranscriptId:r}){let[n,a]=(0,K.useState)("automatic"),[i,u]=de(St,Ne),[c,l]=(0,K.useState)(!1),{classes:p}=Pr(),d=Ir[n];return K.default.createElement(K.default.Fragment,null,K.default.createElement(Ke.Tooltip,{title:`EBI settings \u2014 jobs are submitted with ${i.trim()||Ne}`},K.default.createElement(Ke.IconButton,{className:p.settingsButton,"aria-label":"EBI settings",size:"small",onClick:()=>{l(!0)}},K.default.createElement(Ot,null))),K.default.createElement(d,{model:t,feature:o,handleClose:e,preferredTranscriptId:r},K.default.createElement(lt,{lookupMethod:n,setLookupMethod:a})),c?K.default.createElement(mt,{ebiEmail:i,handleClose:m=>{m&&u(m.ebiEmail),l(!1)}}):null)}var O=s(f());var Je=s(L()),Br=(0,O.lazy)(()=>import("./HelpDialog-DF4Y536X.js"));function ct(){let[e,t]=(0,O.useState)(!1);return O.default.createElement(O.default.Fragment,null,O.default.createElement(Je.Tooltip,{title:"What each tab does"},O.default.createElement(Je.IconButton,{"aria-label":"Help",onClick:()=>{t(!0)}},O.default.createElement(Bt,null))),e?O.default.createElement(O.Suspense,{fallback:null},O.default.createElement(Br,{handleClose:()=>{t(!1)}})):null)}var h=s(f()),dt=s(we()),No=s(nr()),ae=s(L()),ko=s(ve()),Fo=s(V());function qr(e){let t=He(e,500),{data:o,error:r,isLoading:n}=W(t?[JSON.stringify(t),"msa-file-text"]:null,()=>(0,No.openLocation)(t).readFile("utf8"));return{text:o??"",error:r,isLoading:n||t!==e}}var Er=(0,Fo.makeStyles)()({inputContainer:{marginBottom:30},fileContainer:{maxWidth:500},msaInput:{marginBottom:20}}),Dr=(0,ko.observer)(function({model:t,feature:o,handleClose:r,preferredTranscriptId:n}){let a=G(t),{classes:i}=Er(),{launchError:u,submit:c}=oe(r),[l,p]=(0,h.useState)("file"),[d,m]=(0,h.useState)(""),[b,S]=(0,h.useState)(""),[v,j]=(0,h.useState)(),[M,P]=(0,h.useState)(),C=re({feature:o,view:a,preferredTranscriptId:n}),{selectedTranscript:I,proteinSequence:k,error:F,sequenceStatus:$}=C,_=qr(l==="file"?v:void 0),x=Me(l==="file"?_.text:d,k),ue=u??F??_.error;return h.default.createElement(h.default.Fragment,null,h.default.createElement(Y,{error:ue},h.default.createElement(ae.FormControl,{component:"fieldset"},h.default.createElement(ae.RadioGroup,{row:!0,value:l,onChange:J=>{p(J.target.value)}},h.default.createElement(ae.FormControlLabel,{value:"file",control:h.default.createElement(ae.Radio,null),label:"Open files"}),h.default.createElement(ae.FormControlLabel,{value:"text",control:h.default.createElement(ae.Radio,null),label:"Paste text"}))),h.default.createElement("div",{className:i.inputContainer},l==="file"?h.default.createElement("div",{className:i.fileContainer},h.default.createElement(dt.FileSelector,{name:"MSA File .aln (Clustal), .fa/.mfa (aligned FASTA), .stock (Stockholm), etc)",inline:!0,location:v,setLocation:j}),h.default.createElement(dt.FileSelector,{name:"Tree file .nh (Newick) or .asn (NCBI COBALT ASN.1)",inline:!0,location:M,setLocation:P})):h.default.createElement(h.default.Fragment,null,h.default.createElement(g,{variant:"outlined",name:"MSA",multiline:!0,minRows:5,className:i.msaInput,maxRows:10,fullWidth:!0,placeholder:"Paste MSA here",value:d,onChange:J=>{m(J.target.value)}}),h.default.createElement(g,{variant:"outlined",name:"Tree",multiline:!0,minRows:5,maxRows:10,fullWidth:!0,placeholder:"Paste newick tree (optional)",value:b,onChange:J=>{S(J.target.value)}}))),h.default.createElement(R,{feature:o,...C}),h.default.createElement(he,{...x})),h.default.createElement(X,{model:t,hint:h.default.createElement(ie,{status:$}),submitDisabled:!I||l==="file"&&(!v||_.isLoading)||l==="text"&&!d.trim(),onSubmit:J=>{I&&c(()=>Q({view:a,feature:I,placement:J,displayName:te(I),querySeqName:x.querySeqName,querySeqOffset:x.querySeqOffset,...l==="file"?{msaFilehandle:v,treeFilehandle:M}:{data:{msa:d,tree:b}}}))},onCancel:r}))}),Po=Dr;var N=s(f()),jo=s(L()),$o=s(ve()),_o=s(V());var pt=s(f()),Io=s(L());var Or="msaview-ortholog-source",Bo={ncbi:"NCBI orthologs",panther:"PANTHER",uniref:"UniRef cluster"},qo=Object.keys(Bo);function jr(e){return qo.find(t=>t===e)??"ncbi"}function Eo(){let[e,t]=de(Or,"ncbi");return[jr(e),o=>{t(o)}]}var $r={ncbi:"vertebrates and insects",panther:"also yeast, worm, fly and plants",uniref:"all of UniProtKB within 50% identity"};function ft({value:e,onChange:t,className:o}){return pt.default.createElement(g,{variant:"outlined",label:"Source",className:o,select:!0,value:e,helperText:$r[e],onChange:r=>{t(r.target.value)}},qo.map(r=>pt.default.createElement(Io.MenuItem,{value:r,key:r},Bo[r])))}var Ye=s(f());async function Do(e,t){let o=e.trim();if(!o)return;if(/^\d+$/.test(o))return Number(o);let n=(await Ve(_e("esearch",{db:"taxonomy",term:o,retmax:"1",retmode:"json"}),{signal:t})).esearchresult?.idlist?.[0];return n?Number(n):void 0}async function Oo(e,t){let o=e.trim();if(!o)return;let n=(await Ve(_e("esearch",{db:"assembly",term:o,retmax:"1",retmode:"json"}),{signal:t})).esearchresult?.idlist?.[0];if(!n)return;let i=(await Ve(_e("esummary",{db:"assembly",id:n,retmode:"json"}),{signal:t})).result?.[n],u=Number(i?.speciestaxid);return i?.speciesname&&u?{taxId:u,speciesName:i.speciesname}:void 0}async function _r(e,t){let o=await Do(e,t);if(!o)throw new Error(`No NCBI taxon matches "${e}"`);let r=[],n=(await Et([o],t,i=>{r.push(i)})).get(o);if(!n&&r.length>0)throw new Error(`NCBI did not answer for the name of taxon ${o}`,{cause:r[0]});let a=[n?.sciname,n?.commonName&&`(${n.commonName})`].filter(Boolean).join(" ");return{taxId:o,label:a||`taxon ${o}`}}function ht({value:e,assemblyName:t,onChange:o,className:r}){let[n,a]=(0,Ye.useState)(),i=He(n,400),{data:u}=W(t&&n===void 0?[t,"assembly-species"]:null,m=>Oo(t,m),{onSuccess:m=>{m&&o(m.taxId)}}),{data:c,error:l}=W(i?.trim()?[i.trim(),"taxon"]:null,m=>_r(i,m),{onSuccess:({taxId:m})=>{o(m)}}),p=n??u?.speciesName??"human",d=n===void 0?u?.speciesName:c?.label;return Ye.default.createElement(g,{variant:"outlined",label:"Query species",className:r,value:p,onChange:m=>{a(m.target.value)},error:!!l,helperText:l?`${l}`:d??`the species this gene is from (taxon ${e})`})}var Vr=(0,_o.makeStyles)()({selectField:{width:180}}),Gr={ncbi:e=>`the ${e} closest species NCBI has`,panther:e=>`the ${e} closest species PANTHER has`,uniref:e=>`${e} rows, one per species, reviewed entries first`},Qr=(0,$o.observer)(function({handleClose:e,feature:t,model:o,preferredTranscriptId:r}){let{classes:n}=Vr(),a=G(o),{launchError:i,submit:u}=oe(e),[c,l]=(0,N.useState)(9606),[p,d]=Eo(),[m,b]=Ue(),[S,v]=(0,N.useState)(String(qt)),j=(0,N.useMemo)(()=>Ee(t),[t]),M=re({feature:t,view:a,preferredTranscriptId:r}),{selectedTranscript:P,proteinSequence:C,sequenceStatus:I}=M,k=M.error??i,F=Number(S),$=Number.isInteger(F)&&F>=2;return N.default.createElement(N.default.Fragment,null,N.default.createElement(Y,{error:k},N.default.createElement(jo.Typography,{variant:"body2"},"Precomputed orthologs, one gene per species, looked up rather than searched for. No BLAST job to queue, and with the in-browser aligner no job at all."),N.default.createElement("div",null,N.default.createElement(ft,{className:n.selectField,value:p,onChange:d}),N.default.createElement(ht,{className:n.selectField,value:c,assemblyName:a.assemblyNames[0],onChange:l}),N.default.createElement(Fe,{className:n.selectField,value:m,onChange:b}),N.default.createElement(g,{variant:"outlined",label:"Rows to align",className:n.selectField,type:"number",value:S,onChange:_=>{v(_.target.value)},error:!$,helperText:$?Gr[p](F):"a whole number, 2 or more"})),N.default.createElement(R,{feature:t,...M})),N.default.createElement(X,{model:o,hint:N.default.createElement(ie,{status:I}),submitDisabled:!C||!$,onSubmit:_=>{P&&u(()=>Q({view:a,feature:P,placement:_,displayName:`Orthologs - ${te(t)} - ${fe(P)}`,...Te,orthologParams:{taxId:c,source:p,maxSpecies:F,geneCandidates:j,msaAlgorithm:m,selectedTranscript:P.toJSON(),proteinSequence:C}}))},onCancel:e}))}),Vo=Qr;var T=s(f()),Ce=s(we()),Ze=s(be()),Re=s(L()),Jo=s(ve()),Yo=s(V());var Ho=s(Qo());async function Wo(e,t){return(await(0,Ho.getAdapter)(e,"msa",t)).dataAdapter}async function Uo({config:e,pluginManager:t}){return(await Wo(t,e)).getMSAList()}async function zo({config:e,pluginManager:t,msaId:o}){return(await Wo(t,e)).getMSA(o)}var Ko=s(or());function Xe(e){return(0,Ko.readConfObject)(e,["msa","datasets"])}var Hr=(0,Yo.makeStyles)()({selectedContainer:{marginTop:50}}),Wr=(0,Jo.observer)(function({model:e,feature:t,handleClose:o,preferredTranscriptId:r}){let n=(0,Ze.getSession)(e),a=G(e),{classes:i}=Hr(),{pluginManager:u}=(0,Ze.getEnv)(e),{assemblyNames:c}=a,{launchError:l,submit:p}=oe(o),d=Xe(n.jbrowse),[m,b]=(0,T.useState)(d?.[0]?.datasetId),S=d?.find(B=>B.datasetId===m),{data:v,isLoading:j,error:M}=W(S?`${S.datasetId}-msa-list`:null,()=>Uo({config:S.adapter,pluginManager:u})),P=re({feature:t,view:a,validIds:v,preferredTranscriptId:r}),{selectedTranscript:C,proteinSequence:I,sequenceStatus:k}=P,F=C?v?.find(B=>se(C,B)):void 0,{data:$,isLoading:_,error:x}=W(F&&S?`${S.datasetId}-${F}-msa`:null,()=>zo({msaId:F,config:S.adapter,pluginManager:u})),ue=(0,T.useMemo)(()=>$?.map(B=>`>${B.get("refName")}
3
3
  ${B.get("seq")}`).join(`
4
4
  `)??"",[$]),J=Me(ue,I),Pe=vo(J,`${F??""}_${c[0]??""}`),er=M??x??P.error??l;return T.default.createElement(T.default.Fragment,null,T.default.createElement(Y,{error:er},T.default.createElement(g,{select:!0,label:"Select MSA dataset",value:m,onChange:B=>{b(B.target.value)}},d?.map(B=>T.default.createElement(Re.MenuItem,{key:B.datasetId,value:B.datasetId},B.name))),S?T.default.createElement("div",{className:i.selectedContainer},!j&&_?T.default.createElement(Ce.LoadingEllipses,{variant:"h6",message:`Loading MSA for ${fe(C)||F}`}):null,j?T.default.createElement(Ce.LoadingEllipses,{variant:"h6",message:`Loading available MSAs for (${S.name})`}):null,v?T.default.createElement("div",null,T.default.createElement(Ce.SanitizedHTML,{html:S.description}),T.default.createElement(R,{feature:t,...P}),ue?T.default.createElement(he,{...J,querySeqName:Pe}):null):null):null),T.default.createElement(X,{model:e,hint:_?T.default.createElement(Ce.LoadingEllipses,{message:"Loading alignment"}):$?.length&&!Pe?T.default.createElement(Re.Typography,{color:"textSecondary",variant:"body2"},"no row matches this transcript"):T.default.createElement(ie,{status:k}),submitDisabled:!C||!$?.length||!Pe,onSubmit:B=>{C&&ue&&p(()=>Q({view:a,feature:C,placement:B,displayName:te(C),drawNodeBubbles:!1,labelsAlignRight:!0,showBranchLen:!1,colWidth:10,rowHeight:12,colorSchemeName:"percent_identity_dynamic",querySeqName:Pe,querySeqOffset:J.querySeqOffset,data:{msa:ue}}))},onCancel:o}))}),Xo=Wr;var et=s(f());function Le({children:e,value:t,index:o}){let r=t===o,[n,a]=(0,et.useState)(r);return r&&!n&&a(!0),et.default.createElement("div",{role:"tabpanel",hidden:!r},n||r?e:null)}function Ur({handleClose:e,feature:t,model:o,preferredTranscriptId:r}){let n=(0,Ro.getSession)(o),i=!!Xe(n.jbrowse)?.length,[u,c]=(0,A.useState)("orthologs");return A.default.createElement(Zo.Dialog,{maxWidth:"xl",title:"Launch MSA view",open:!0,onClose:e},A.default.createElement(Wt,null,A.default.createElement("div",{style:{display:"flex",alignItems:"center"}},A.default.createElement(ye.Tabs,{value:u,onChange:(l,p)=>{c(p)}},A.default.createElement(ye.Tab,{label:"Orthologs",value:"orthologs"}),A.default.createElement(ye.Tab,{label:"BLAST query",value:"ncbi_blast"}),i?A.default.createElement(ye.Tab,{label:"Pre-loaded MSA datasets",value:"preloaded_msa"}):null,A.default.createElement(ye.Tab,{label:"Manual upload",value:"manual_msa"})),A.default.createElement(ct,null)),A.default.createElement(Le,{value:u,index:"orthologs"},A.default.createElement(Vo,{handleClose:e,feature:t,model:o,preferredTranscriptId:r})),A.default.createElement(Le,{value:u,index:"ncbi_blast"},A.default.createElement(ut,{handleClose:e,feature:t,model:o,preferredTranscriptId:r})),i?A.default.createElement(Le,{value:u,index:"preloaded_msa"},A.default.createElement(Xo,{model:o,feature:t,handleClose:e,preferredTranscriptId:r})):null,A.default.createElement(Le,{value:u,index:"manual_msa"},A.default.createElement(Po,{model:o,feature:t,handleClose:e,preferredTranscriptId:r}))))}export{Ur as default};
5
- //# sourceMappingURL=LaunchMsaViewDialog-HGL6P4E4.js.map
5
+ //# sourceMappingURL=LaunchMsaViewDialog-BG4MX2BW.js.map
@@ -1,3 +1,3 @@
1
1
  import{a as H,c as J,d as S,e as Q,f as Z,p as Y}from"./chunk-F726IWCW.js";import{a as Pe}from"./chunk-KSCGTF4R.js";import{a as Ne}from"./chunk-2IWD4OO4.js";import{a as Te,b as K}from"./chunk-FY3BTKY4.js";var Re=Te((bt,oe)=>{oe.exports=JBrowseExports["@jbrowse/core/util/translateTranscript"]});var M=K(Pe());function ut(e){return(0,M.getContainingView)(e)}function te(e){return typeof e=="string"&&e!==""}function ne(e){return[...new Set(e.filter(te))]}function re(e,t){return t.filter(te).join(e)}function Ee(e){let n=(e.get("subfeatures")??[]).filter(r=>(r.get("type")==="mRNA"||r.get("type")==="transcript")&&r.get("subfeatures")?.some(o=>o.get("type")==="CDS"));return n.length>0?n:[e]}function ee(e){let t=(0,M.sum)(e.get("subfeatures")?.filter(n=>n.get("type")==="CDS").map(n=>n.get("end")-n.get("start"))??[]);return{len:Math.floor(t/3),mod:t%3}}function mt(e){return e?.id()??""}function Me(e){return e?ne([e.id(),e.get("name"),e.get("id"),e.get("transcript_id")]):[]}function dt(e,t){return Me(e).includes(t)}function Ae(e){return e?re(" ",[e.get("name"),e.get("id")]):""}function _e(e){return e?re(" ",[e.get("gene_name")??e.get("name"),e.get("id")?`(${e.get("id")})`:void 0]):""}function lt(e,t){return`BLAST - ${_e(e)} - ${Ae(t)}`}function gt(e){return Ee(e).toSorted((n,r)=>ee(r).len-ee(n).len)}function ft(e){return e.replace(/[*&]+$/,"").replaceAll(/[*&]/g,"X")}function ht(e){return ne([e.id(),e.get("id"),e.get("name"),e.get("gene_id"),e.get("gene_name")])}var se=K(Ne());async function xt({start:e,end:t,refName:n,session:r,assemblyName:o}){let{assemblyManager:a,rpcManager:i}=r,c=await a.waitForAssembly(o);if(!c)throw new Error("assembly not found");return{seq:(await i.call("getSequence","CoreGetFeatures",{adapterConfig:(0,se.getConf)(c,["sequence","adapter"]),regions:[{start:e,end:t,refName:c.getCanonicalRefName(n)??n,assemblyName:o}]}))[0]?.get("seq")??"",assemblyGeneticCodeId:c.getGeneticCodeId(n)}}var $e="jbrowse-plugin-msaview",Oe="jbrowse2@berkeley.edu",ae="https://eutils.ncbi.nlm.nih.gov/entrez/eutils";function ce(e){return new URLSearchParams({...e,tool:$e,email:Oe})}function L(e,t){return`${ae}/${e}.fcgi?${ce(t).toString()}`}function _(e){return L("efetch",e)}function ue(e){return[`${ae}/efetch.fcgi`,{method:"POST",body:ce(e)}]}var ie=350,A=0;async function me(e){let t=Date.now(),n=Math.max(t,A);if(A=n+ie,n>t)try{await Q(n-t,e??void 0)}catch(r){throw A===n+ie&&(A=n),r}}async function B(e,t){return await me(t?.signal),J(e,t)}async function de(e,t){return await me(t?.signal),S(e,t)}var je={amp:"&",apos:"'",gt:">",lt:"<",quot:'"'};function k(e){return e.replaceAll(/&(#x[\da-f]+|#\d+|[a-z]+);/gi,(t,n)=>n.startsWith("#x")||n.startsWith("#X")?String.fromCodePoint(Number.parseInt(n.slice(2),16)):n.startsWith("#")?String.fromCodePoint(Number(n.slice(1))):je[n]??t)}var F="https://api.ncbi.nlm.nih.gov/datasets/v2",Le=100;function ke(e){return e.trim().replace(/^\w+:/,"").replace(/\.\d+$/,"")}function Fe(e,t){let n=e.toLowerCase();return(t.find(o=>o.symbol===e)??t.find(o=>o.synonyms?.includes(e))??t.find(o=>o.symbol?.toLowerCase()===n)??t[0])?.gene_id}async function ve(e,t,n){try{return((await S(`${F}/gene/symbol/${encodeURIComponent(e)}/taxon/${t}`,{signal:n})).reports??[]).flatMap(o=>o.gene?[o.gene]:[])}catch(r){if(r instanceof H&&(r.status===400||r.status===404))return[];throw r}}async function Ge(e,t,n){return(await de(L("esearch",{db:"gene",term:`${e}[Gene Name] AND ${t}[taxid]`,retmode:"json",retmax:"1"}),{signal:n})).esearchresult?.idlist?.[0]}async function Bt(e,t,n){let r=new Set,o=e.map(c=>c.trim()),a=c=>/^\d+$/.test(c);for(let c of o.filter(s=>!a(s))){let s=ke(c);if(!s||r.has(s))continue;r.add(s);let u=Fe(s,await ve(s,t,n))??await Ge(s,t,n);if(u)return{geneId:u,matched:s}}let i=o.find(a);return i?{geneId:i,matched:i}:void 0}async function Ve(e,{taxa:t,exclude:n,limit:r=Le,signal:o}={}){let a=await S(`${F}/gene/id/${e}/orthologs?returned_content=COMPLETE`,{signal:o}),i=new Map;for(let{gene:c}of a.reports??[]){let s=Number(c?.tax_id);if(c?.gene_id&&s!==n&&(t?.has(s)??!0)&&!i.has(s)&&i.set(s,{taxId:s,geneId:c.gene_id,scientificName:c.taxname??String(s),commonName:c.common_name}),i.size>=r)break}return[...i.values()]}var le=150;async function ge(e,t){let n=new Map;for(let r=0;r<e.length;r+=le){let o=e.slice(r,r+le),a=await S(`${F}/gene/id/${o.join(",")}/product_report?page_size=${o.length}`,{signal:t});for(let{product:i}of a.reports??[]){let c=(i?.transcripts??[]).map(u=>({acc:u.protein?.accession_version,len:u.protein?.length??0,mane:/select/i.test(u.select_category??"")})).filter(u=>!!u.acc),s=c.find(u=>u.mane)??[...c].sort((u,d)=>d.len-u.len).at(0);i?.gene_id&&s&&n.set(i.gene_id,s.acc)}}return n}function fe(e){let t=new Map,n,r=[];for(let o of e.split(`
2
- `))o.startsWith(">")?(n&&t.set(n,r.join("")),n=o.slice(1).split(/\s+/)[0],r=[]):r.push(o.trim());return n&&t.set(n,r.join("")),t}function qe(e){return e.replace(/[^A-Za-z0-9]+/g,"_").replace(/^_+|_+$/g,"")}function Ue(e){let t=new Set;return e.map(n=>{let r=qe(n)||"row",o=r,a=1;for(;t.has(o);)a+=1,o=`${r}_${a}`;return t.add(o),o})}async function Ct(e,t){let n=(await ge([e],t)).get(e);if(!n)return;let r=fe(await B(_({db:"protein",id:n,rettype:"fasta",retmode:"text"}),{signal:t})).get(n);return r?{accession:n,sequence:r}:void 0}async function Tt({geneId:e,taxa:t,exclude:n,limit:r,onProgress:o,signal:a}){o("Finding orthologs across species...");let i=await Ve(e,{taxa:t,exclude:n,limit:r,signal:a});if(i.length<2)throw new Error(`Only ${i.length} ortholog(s) found for this gene \u2014 not enough to align`);o("Selecting a representative protein per species...");let c=await ge(i.map(m=>m.geneId),a),s=i.filter(m=>c.has(m.geneId));if(s.length<2)throw new Error("Could not resolve representative proteins for the orthologs");o(`Fetching ${s.length} protein sequences...`);let u=s.map(m=>c.get(m.geneId)),[d,h]=ue({db:"protein",id:u.join(","),rettype:"fasta",retmode:"text"}),l=fe(await B(d,{...h,signal:a})),p=Ue(s.map(m=>m.commonName??m.scientificName)),w=s.map((m,b)=>{let g=c.get(m.geneId);return{taxId:m.taxId,label:p[b],scientificName:m.scientificName,commonName:m.commonName,geneId:m.geneId,protein:g,sequence:l.get(g)??""}}).filter(m=>m.sequence);if(w.length<2)throw new Error("Could not fetch protein sequences for the orthologs");return w}var V=(e,t)=>t.some(n=>e instanceof n),he,pe;function We(){return he||(he=[IDBIndex,IDBObjectStore,IDBCursor,IDBDatabase,IDBTransaction])}function ze(){return pe||(pe=["advance","continue","continuePrimaryKey"].map(e=>IDBCursor.prototype[e]))}var q=new WeakMap,v=new WeakMap,R=new WeakMap;function Xe(e){let t=new Promise((n,r)=>{let o=()=>{e.removeEventListener("success",a),e.removeEventListener("error",i)},a=()=>{n(y(e.result)),o()},i=()=>{r(e.error),o()};e.addEventListener("success",a),e.addEventListener("error",i)});return R.set(t,e),t}function Ke(e){if(q.has(e))return;let t=new Promise((n,r)=>{let o=()=>{e.removeEventListener("complete",a),e.removeEventListener("error",i),e.removeEventListener("abort",i)},a=()=>{n(),o()},i=()=>{r(e.error||new DOMException("AbortError","AbortError")),o()};e.addEventListener("complete",a),e.addEventListener("error",i),e.addEventListener("abort",i)});q.set(e,t)}var U={get(e,t,n){if(e instanceof IDBTransaction){if(t==="done")return q.get(e);if(t==="store")return n.objectStoreNames[1]?void 0:n.objectStore(n.objectStoreNames[0])}return y(e[t])},set(e,t,n){return e[t]=n,!0},has(e,t){return e instanceof IDBTransaction&&(t==="done"||t==="store")?!0:t in e}};function ye(e){U=e(U)}function He(e){return ze().includes(e)?function(...t){return e.apply(W(this),t),y(this.request)}:function(...t){return y(e.apply(W(this),t))}}function Je(e){return typeof e=="function"?He(e):(e instanceof IDBTransaction&&Ke(e),V(e,We())?new Proxy(e,U):e)}function y(e){if(e instanceof IDBRequest)return Xe(e);if(v.has(e))return v.get(e);let t=Je(e);return Object.is(t,e)||(v.set(e,t),R.set(t,e)),t}var W=e=>R.get(e);function Se(e,t,{blocked:n,upgrade:r,blocking:o,terminated:a}={}){let i=indexedDB.open(e,t),c=y(i);return r&&i.addEventListener("upgradeneeded",s=>{r(y(i.result),s.oldVersion,s.newVersion,y(i.transaction),s)}),n&&i.addEventListener("blocked",s=>n(s.oldVersion,s.newVersion,s)),c.then(s=>{a&&s.addEventListener("close",()=>a()),o&&s.addEventListener("versionchange",u=>o(u.oldVersion,u.newVersion,u))}).catch(()=>{}),c}var Qe=["get","getKey","getAll","getAllKeys","count"],Ze=["put","add","delete","clear"],G={};function be(e,t){if(!(e instanceof IDBDatabase&&!(t in e)&&typeof t=="string"))return;if(G[t])return G[t];let n=t.replace(/FromIndex$/,""),r=t!==n,o=Ze.includes(n);if(!(n in(r?IDBIndex:IDBObjectStore).prototype)||!(o||Qe.includes(n)))return;let a=async function(i,...c){let s=this.transaction(i,o?"readwrite":"readonly"),u=s.store;return r&&(u=u.index(c.shift())),(await Promise.all([u[n](...c),o&&s.done]))[0]};return G[t]=a}ye(e=>({...e,get:(t,n,r)=>be(t,n)||e.get(t,n,r),has:(t,n)=>!!be(t,n)||e.has(t,n)}));var Ye=["advance","continue","continuePrimaryKey"],xe={},z=new WeakMap,De=new WeakMap,et={get(e,t){if(!Ye.includes(t))return e[t];let n=xe[t];return n||(n=xe[t]=function(...r){z.set(this,De.get(this)[t](...r))}),n}};async function*tt(...e){let t=this;if(t instanceof IDBCursor||(t=await t.openCursor(...e)),!t)return;t=t;let n=new Proxy(t,et);for(De.set(n,t),R.set(n,W(t));t;)yield n,t=await(z.get(n)||t.continue()),z.delete(n)}function we(e,t){return t===Symbol.asyncIterator&&V(e,[IDBIndex,IDBObjectStore,IDBCursor])||t==="iterate"&&V(e,[IDBIndex,IDBObjectStore])}ye(e=>({...e,get(t,n,r){return we(t,n)?tt:e.get(t,n,r)},has(t,n){return we(t,n)||e.has(t,n)}}));function $(e,t,n){let r,o=()=>{r=void 0};return()=>(r??=new Promise((a,i)=>{let c=!1;Se(e,t,{upgrade:n,blocked(s){c=!0,i(new Error(`${e} is held open at version ${s} by another tab`))},blocking(s,u,d){d.target.close(),o()},terminated:o}).then(s=>{c?s.close():a(s)},i)}).catch(a=>{throw o(),a}),r)}async function C(e,t,n){try{return await t()}catch(r){return console.warn(`[msaview] ${e} failed, continuing without it:`,r),n}}var nt="jbrowse-msaview-blast-cache",f="blast-results",rt=2,Ie=50,X=$(nt,rt,(e,t)=>{t<2&&e.objectStoreNames.contains(f)&&e.deleteObjectStore(f),e.objectStoreNames.contains(f)||e.createObjectStore(f,{keyPath:"id"})});function ot({proteinSequence:e,blastDatabase:t,msaAlgorithm:n,searchProgram:r,transcriptId:o,maxHits:a}){let i=o?`:${o}`:"",c=a===void 0||a===Y?"":`:n${a}`;return r==="phmmer"?`phmmer:${t}${i}${c}:${e}`:`${t}:${n}${i}${c}:${e}`}function Rt({proteinSequence:e,blastDatabase:t,msaAlgorithm:n,searchProgram:r,maxHits:o,msa:a,tree:i,treeMetadata:c,rid:s,geneId:u,transcriptId:d,transcriptName:h,geneName:l}){return C("BLAST history write",async()=>{let p=await X(),w={id:ot({proteinSequence:e,blastDatabase:t,msaAlgorithm:n,searchProgram:r,transcriptId:d,maxHits:o}),proteinSequence:e,blastDatabase:t,msaAlgorithm:n,searchProgram:r,maxHits:o,msa:a,tree:i,treeMetadata:c,rid:s,timestamp:Date.now(),geneId:u,transcriptId:d,transcriptName:h,geneName:l};return await p.put(f,w),await st(p),w},void 0)}async function st(e){try{if(await e.count(f)<=Ie)return;let t=await e.getAll(f),n=t.toSorted((o,a)=>o.timestamp-a.timestamp).slice(0,t.length-Ie),r=e.transaction(f,"readwrite");await Promise.all([...n.map(o=>r.store.delete(o.id)),r.done])}catch(t){console.warn("Failed to evict old BLAST cache entries:",t)}}async function $t(){return(await(await X()).getAll(f)).toSorted((n,r)=>r.timestamp-n.timestamp)}async function Ot(e){await(await X()).delete(f,e)}var it="jbrowse-msaview-taxonomy-cache",T="common-names",at=2,Ce=$(it,at,e=>{e.objectStoreNames.contains(T)&&e.deleteObjectStore(T),e.createObjectStore(T,{keyPath:"taxid"})});function ct(e){return C("taxonomy cache read",async()=>{let n=(await Ce()).transaction(T,"readonly"),r=await Promise.all(e.map(o=>n.store.get(o)));return await n.done,r},[])}function Be(e){return C("taxonomy cache write",async()=>{let n=(await Ce()).transaction(T,"readwrite");for(let r of e)await n.store.put(r);await n.done},void 0)}async function vt(e,t,n){let r=[...new Set(e)],o=new Map,a=[],i=await ct(r);for(let u=0;u<r.length;u++){let d=r[u],h=i[u];h?o.set(d,{sciname:h.sciname,commonName:h.commonName}):a.push(d)}if(a.length===0)return o;let c=100,s=[];for(let u=0;u<a.length;u+=c){let d=a.slice(u,u+c),h=d.join(",");try{let l=await B(_({db:"taxonomy",id:h,retmode:"xml"}),{signal:t}),p=new Map,w=/<Taxon>\s*<TaxId>(\d+)<\/TaxId>/g,m;for(;(m=w.exec(l))!==null;){let b=Number(m[1]),g=m.index,D=1,x=g+m[0].length;for(;D>0&&x<l.length;){let O=l.indexOf("<Taxon>",x),j=l.indexOf("</Taxon>",x);if(j===-1)break;O!==-1&&O<j?(D++,x=O+7):(D--,x=j+8)}let N=l.slice(g,x),I=p.get(b),P=N.includes("<LineageEx>"),E=I?.includes("<LineageEx>");(!I||P&&!E)&&p.set(b,N)}for(let b of d){let g=p.get(b);if(g){let D=/<GenbankCommonName>(.*?)<\/GenbankCommonName>/.exec(g),x=/<CommonName>(.*?)<\/CommonName>/.exec(g),N=/<ScientificName>(.*?)<\/ScientificName>/.exec(g),I=D?.[1]??x?.[1],P=I&&k(I),E=k(N?.[1]??"");o.set(b,{sciname:E,commonName:P}),s.push({taxid:b,sciname:E,commonName:P})}}}catch(l){if(Z(l))throw await Be(s),l;console.error("Failed to fetch taxonomy data:",l),n?.(l)}}return s.length>0&&await Be(s),o}export{ut as a,Ee as b,ee as c,mt as d,dt as e,Ae as f,_e as g,lt as h,gt as i,ft as j,ht as k,Re as l,xt as m,$ as n,C as o,Rt as p,$t as q,Ot as r,L as s,_ as t,B as u,de as v,k as w,Le as x,ke as y,Bt as z,Ue as A,Ct as B,Tt as C,vt as D};
3
- //# sourceMappingURL=chunk-2XCUSA22.js.map
2
+ `))o.startsWith(">")?(n&&t.set(n,r.join("")),n=o.slice(1).split(/\s+/)[0],r=[]):r.push(o.trim());return n&&t.set(n,r.join("")),t}function qe(e){return e.replace(/[^A-Za-z0-9]+/g,"_").replace(/^_+|_+$/g,"")}function Ue(e){let t=new Set;return e.map(n=>{let r=qe(n)||"row",o=r,a=1;for(;t.has(o);)a+=1,o=`${r}_${a}`;return t.add(o),o})}async function Ct(e,t){let n=(await ge([e],t)).get(e);if(!n)return;let r=fe(await B(_({db:"protein",id:n,rettype:"fasta",retmode:"text"}),{signal:t})).get(n);return r?{accession:n,sequence:r}:void 0}async function Tt({geneId:e,taxa:t,exclude:n,limit:r,onProgress:o,signal:a}){o("Finding orthologs across species...");let i=await Ve(e,{taxa:t,exclude:n,limit:r,signal:a});if(i.length<2)throw new Error(`Only ${i.length} ortholog(s) found for this gene \u2014 not enough to align`);o("Selecting a representative protein per species...");let c=await ge(i.map(m=>m.geneId),a),s=i.filter(m=>c.has(m.geneId));if(s.length<2)throw new Error("Could not resolve representative proteins for the orthologs");o(`Fetching ${s.length} protein sequences...`);let u=s.map(m=>c.get(m.geneId)),[d,h]=ue({db:"protein",id:u.join(","),rettype:"fasta",retmode:"text"}),l=fe(await B(d,{...h,signal:a})),p=Ue(s.map(m=>m.commonName??m.scientificName)),y=s.map((m,b)=>{let g=c.get(m.geneId);return{taxId:m.taxId,label:p[b],scientificName:m.scientificName,commonName:m.commonName,geneId:m.geneId,protein:g,sequence:l.get(g)??""}}).filter(m=>m.sequence);if(y.length<2)throw new Error("Could not fetch protein sequences for the orthologs");return y}var V=(e,t)=>t.some(n=>e instanceof n),he,pe;function We(){return he||(he=[IDBIndex,IDBObjectStore,IDBCursor,IDBDatabase,IDBTransaction])}function ze(){return pe||(pe=["advance","continue","continuePrimaryKey"].map(e=>IDBCursor.prototype[e]))}var q=new WeakMap,v=new WeakMap,R=new WeakMap;function Xe(e){let t=new Promise((n,r)=>{let o=()=>{e.removeEventListener("success",a),e.removeEventListener("error",i)},a=()=>{n(w(e.result)),o()},i=()=>{r(e.error),o()};e.addEventListener("success",a),e.addEventListener("error",i)});return R.set(t,e),t}function Ke(e){if(q.has(e))return;let t=new Promise((n,r)=>{let o=()=>{e.removeEventListener("complete",a),e.removeEventListener("error",i),e.removeEventListener("abort",i)},a=()=>{n(),o()},i=()=>{r(e.error||new DOMException("AbortError","AbortError")),o()};e.addEventListener("complete",a),e.addEventListener("error",i),e.addEventListener("abort",i)});q.set(e,t)}var U={get(e,t,n){if(e instanceof IDBTransaction){if(t==="done")return q.get(e);if(t==="store")return n.objectStoreNames[1]?void 0:n.objectStore(n.objectStoreNames[0])}return w(e[t])},set(e,t,n){return e[t]=n,!0},has(e,t){return e instanceof IDBTransaction&&(t==="done"||t==="store")?!0:t in e}};function ye(e){U=e(U)}function He(e){return ze().includes(e)?function(...t){return e.apply(W(this),t),w(this.request)}:function(...t){return w(e.apply(W(this),t))}}function Je(e){return typeof e=="function"?He(e):(e instanceof IDBTransaction&&Ke(e),V(e,We())?new Proxy(e,U):e)}function w(e){if(e instanceof IDBRequest)return Xe(e);if(v.has(e))return v.get(e);let t=Je(e);return Object.is(t,e)||(v.set(e,t),R.set(t,e)),t}var W=e=>R.get(e);function Se(e,t,{blocked:n,upgrade:r,blocking:o,terminated:a}={}){let i=indexedDB.open(e,t),c=w(i);return r&&i.addEventListener("upgradeneeded",s=>{r(w(i.result),s.oldVersion,s.newVersion,w(i.transaction),s)}),n&&i.addEventListener("blocked",s=>n(s.oldVersion,s.newVersion,s)),c.then(s=>{a&&s.addEventListener("close",()=>a()),o&&s.addEventListener("versionchange",u=>o(u.oldVersion,u.newVersion,u))}).catch(()=>{}),c}function Pt(e,{blocked:t}={}){let n=indexedDB.deleteDatabase(e);return t&&n.addEventListener("blocked",r=>t(r.oldVersion,r)),w(n).then(()=>{})}var Qe=["get","getKey","getAll","getAllKeys","count"],Ze=["put","add","delete","clear"],G={};function be(e,t){if(!(e instanceof IDBDatabase&&!(t in e)&&typeof t=="string"))return;if(G[t])return G[t];let n=t.replace(/FromIndex$/,""),r=t!==n,o=Ze.includes(n);if(!(n in(r?IDBIndex:IDBObjectStore).prototype)||!(o||Qe.includes(n)))return;let a=async function(i,...c){let s=this.transaction(i,o?"readwrite":"readonly"),u=s.store;return r&&(u=u.index(c.shift())),(await Promise.all([u[n](...c),o&&s.done]))[0]};return G[t]=a}ye(e=>({...e,get:(t,n,r)=>be(t,n)||e.get(t,n,r),has:(t,n)=>!!be(t,n)||e.has(t,n)}));var Ye=["advance","continue","continuePrimaryKey"],xe={},z=new WeakMap,De=new WeakMap,et={get(e,t){if(!Ye.includes(t))return e[t];let n=xe[t];return n||(n=xe[t]=function(...r){z.set(this,De.get(this)[t](...r))}),n}};async function*tt(...e){let t=this;if(t instanceof IDBCursor||(t=await t.openCursor(...e)),!t)return;t=t;let n=new Proxy(t,et);for(De.set(n,t),R.set(n,W(t));t;)yield n,t=await(z.get(n)||t.continue()),z.delete(n)}function we(e,t){return t===Symbol.asyncIterator&&V(e,[IDBIndex,IDBObjectStore,IDBCursor])||t==="iterate"&&V(e,[IDBIndex,IDBObjectStore])}ye(e=>({...e,get(t,n,r){return we(t,n)?tt:e.get(t,n,r)},has(t,n){return we(t,n)||e.has(t,n)}}));function $(e,t,n){let r,o=()=>{r=void 0};return()=>(r??=new Promise((a,i)=>{let c=!1;Se(e,t,{upgrade:n,blocked(s){c=!0,i(new Error(`${e} is held open at version ${s} by another tab`))},blocking(s,u,d){d.target.close(),o()},terminated:o}).then(s=>{c?s.close():a(s)},i)}).catch(a=>{throw o(),a}),r)}async function C(e,t,n){try{return await t()}catch(r){return console.warn(`[msaview] ${e} failed, continuing without it:`,r),n}}var nt="jbrowse-msaview-blast-cache",f="blast-results",rt=2,Ie=50,X=$(nt,rt,(e,t)=>{t<2&&e.objectStoreNames.contains(f)&&e.deleteObjectStore(f),e.objectStoreNames.contains(f)||e.createObjectStore(f,{keyPath:"id"})});function ot({proteinSequence:e,blastDatabase:t,msaAlgorithm:n,searchProgram:r,transcriptId:o,maxHits:a}){let i=o?`:${o}`:"",c=a===void 0||a===Y?"":`:n${a}`;return r==="phmmer"?`phmmer:${t}${i}${c}:${e}`:`${t}:${n}${i}${c}:${e}`}function $t({proteinSequence:e,blastDatabase:t,msaAlgorithm:n,searchProgram:r,maxHits:o,msa:a,tree:i,treeMetadata:c,rid:s,geneId:u,transcriptId:d,transcriptName:h,geneName:l}){return C("BLAST history write",async()=>{let p=await X(),y={id:ot({proteinSequence:e,blastDatabase:t,msaAlgorithm:n,searchProgram:r,transcriptId:d,maxHits:o}),proteinSequence:e,blastDatabase:t,msaAlgorithm:n,searchProgram:r,maxHits:o,msa:a,tree:i,treeMetadata:c,rid:s,timestamp:Date.now(),geneId:u,transcriptId:d,transcriptName:h,geneName:l};return await p.put(f,y),await st(p),y},void 0)}async function st(e){try{if(await e.count(f)<=Ie)return;let t=await e.getAll(f),n=t.toSorted((o,a)=>o.timestamp-a.timestamp).slice(0,t.length-Ie),r=e.transaction(f,"readwrite");await Promise.all([...n.map(o=>r.store.delete(o.id)),r.done])}catch(t){console.warn("Failed to evict old BLAST cache entries:",t)}}async function Ot(){return(await(await X()).getAll(f)).toSorted((n,r)=>r.timestamp-n.timestamp)}async function jt(e){await(await X()).delete(f,e)}var it="jbrowse-msaview-taxonomy-cache",T="common-names",at=2,Ce=$(it,at,e=>{e.objectStoreNames.contains(T)&&e.deleteObjectStore(T),e.createObjectStore(T,{keyPath:"taxid"})});function ct(e){return C("taxonomy cache read",async()=>{let n=(await Ce()).transaction(T,"readonly"),r=await Promise.all(e.map(o=>n.store.get(o)));return await n.done,r},[])}function Be(e){return C("taxonomy cache write",async()=>{let n=(await Ce()).transaction(T,"readwrite");for(let r of e)await n.store.put(r);await n.done},void 0)}async function Gt(e,t,n){let r=[...new Set(e)],o=new Map,a=[],i=await ct(r);for(let u=0;u<r.length;u++){let d=r[u],h=i[u];h?o.set(d,{sciname:h.sciname,commonName:h.commonName}):a.push(d)}if(a.length===0)return o;let c=100,s=[];for(let u=0;u<a.length;u+=c){let d=a.slice(u,u+c),h=d.join(",");try{let l=await B(_({db:"taxonomy",id:h,retmode:"xml"}),{signal:t}),p=new Map,y=/<Taxon>\s*<TaxId>(\d+)<\/TaxId>/g,m;for(;(m=y.exec(l))!==null;){let b=Number(m[1]),g=m.index,D=1,x=g+m[0].length;for(;D>0&&x<l.length;){let O=l.indexOf("<Taxon>",x),j=l.indexOf("</Taxon>",x);if(j===-1)break;O!==-1&&O<j?(D++,x=O+7):(D--,x=j+8)}let N=l.slice(g,x),I=p.get(b),P=N.includes("<LineageEx>"),E=I?.includes("<LineageEx>");(!I||P&&!E)&&p.set(b,N)}for(let b of d){let g=p.get(b);if(g){let D=/<GenbankCommonName>(.*?)<\/GenbankCommonName>/.exec(g),x=/<CommonName>(.*?)<\/CommonName>/.exec(g),N=/<ScientificName>(.*?)<\/ScientificName>/.exec(g),I=D?.[1]??x?.[1],P=I&&k(I),E=k(N?.[1]??"");o.set(b,{sciname:E,commonName:P}),s.push({taxid:b,sciname:E,commonName:P})}}}catch(l){if(Z(l))throw await Be(s),l;console.error("Failed to fetch taxonomy data:",l),n?.(l)}}return s.length>0&&await Be(s),o}export{ut as a,Ee as b,ee as c,mt as d,dt as e,Ae as f,_e as g,lt as h,gt as i,ft as j,ht as k,Re as l,xt as m,Pt as n,$ as o,C as p,$t as q,Ot as r,jt as s,L as t,_ as u,B as v,de as w,k as x,Le as y,ke as z,Bt as A,Ue as B,Ct as C,Tt as D,Gt as E};
3
+ //# sourceMappingURL=chunk-4TEPHD3L.js.map