jbrowse-plugin-msaview 2.3.2 → 2.3.5
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/dist/BgzipFastaMsaAdapter/BgzipFastaMsaAdapter.js +2 -11
- package/dist/BgzipFastaMsaAdapter/BgzipFastaMsaAdapter.js.map +1 -1
- package/dist/LaunchMsaView/components/NCBIBlastQuery/CachedBlastResults.js +24 -47
- package/dist/LaunchMsaView/components/NCBIBlastQuery/CachedBlastResults.js.map +1 -1
- package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastAutomaticPanel.js +5 -20
- package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastAutomaticPanel.js.map +1 -1
- package/dist/LaunchMsaView/components/NCBIBlastQuery/useCachedBlastResults.d.ts +7 -0
- package/dist/LaunchMsaView/components/NCBIBlastQuery/useCachedBlastResults.js +29 -0
- package/dist/LaunchMsaView/components/NCBIBlastQuery/useCachedBlastResults.js.map +1 -0
- package/dist/LaunchMsaView/components/useTranscriptSelection.js +15 -14
- package/dist/LaunchMsaView/components/useTranscriptSelection.js.map +1 -1
- package/dist/MsaViewPanel/afterCreateAutoruns.js +14 -9
- package/dist/MsaViewPanel/afterCreateAutoruns.js.map +1 -1
- package/dist/MsaViewPanel/components/ErrorBoundary.d.ts +19 -0
- package/dist/MsaViewPanel/components/ErrorBoundary.js +22 -0
- package/dist/MsaViewPanel/components/ErrorBoundary.js.map +1 -0
- package/dist/MsaViewPanel/components/MsaViewPanel.js +4 -2
- package/dist/MsaViewPanel/components/MsaViewPanel.js.map +1 -1
- package/dist/MsaViewPanel/model.d.ts +0 -12
- package/dist/MsaViewPanel/model.js +1 -1
- package/dist/MsaViewPanel/model.js.map +1 -1
- package/dist/MsaViewPanel/pairwiseAlignment.js +9 -4
- package/dist/MsaViewPanel/pairwiseAlignment.js.map +1 -1
- package/dist/jbrowse-plugin-msaview.umd.production.min.js +26 -26
- package/dist/jbrowse-plugin-msaview.umd.production.min.js.map +4 -4
- package/dist/utils/blastCache.js +2 -3
- package/dist/utils/blastCache.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/package.json +35 -34
- package/src/BgzipFastaMsaAdapter/BgzipFastaMsaAdapter.ts +2 -11
- package/src/LaunchMsaView/components/NCBIBlastQuery/CachedBlastResults.tsx +23 -49
- package/src/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastAutomaticPanel.tsx +6 -20
- package/src/LaunchMsaView/components/NCBIBlastQuery/useCachedBlastResults.ts +49 -0
- package/src/LaunchMsaView/components/useTranscriptSelection.ts +25 -17
- package/src/MsaViewPanel/afterCreateAutoruns.ts +26 -9
- package/src/MsaViewPanel/components/ErrorBoundary.tsx +40 -0
- package/src/MsaViewPanel/components/MsaViewPanel.tsx +14 -11
- package/src/MsaViewPanel/model.ts +32 -21
- package/src/MsaViewPanel/pairwiseAlignment.ts +9 -4
- package/src/utils/blastCache.ts +2 -3
- package/src/version.ts +1 -1
package/dist/utils/blastCache.js
CHANGED
|
@@ -15,11 +15,10 @@ async function getDB() {
|
|
|
15
15
|
});
|
|
16
16
|
}
|
|
17
17
|
function createCacheKey(proteinSequence, blastDatabase, blastProgram, transcriptId) {
|
|
18
|
-
const seqKey = proteinSequence.slice(0, 100);
|
|
19
18
|
if (transcriptId) {
|
|
20
|
-
return `${blastDatabase}:${blastProgram}:${transcriptId}:${
|
|
19
|
+
return `${blastDatabase}:${blastProgram}:${transcriptId}:${proteinSequence}`;
|
|
21
20
|
}
|
|
22
|
-
return `${blastDatabase}:${blastProgram}:${
|
|
21
|
+
return `${blastDatabase}:${blastProgram}:${proteinSequence}`;
|
|
23
22
|
}
|
|
24
23
|
export async function getCachedBlastResult({ proteinSequence, blastDatabase, blastProgram, transcriptId, }) {
|
|
25
24
|
const db = await getDB();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"blastCache.js","sourceRoot":"","sources":["../../src/utils/blastCache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,CAAA;AAE5B,MAAM,OAAO,GAAG,6BAA6B,CAAA;AAC7C,MAAM,UAAU,GAAG,eAAe,CAAA;AAClC,MAAM,UAAU,GAAG,CAAC,CAAA;AAmBpB,KAAK,UAAU,KAAK;IAClB,OAAO,MAAM,CAAC,OAAO,EAAE,UAAU,EAAE;QACjC,OAAO,CAAC,EAAE,EAAE,UAAU;YACpB,IAAI,UAAU,GAAG,CAAC,IAAI,EAAE,CAAC,gBAAgB,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;gBAC/D,EAAE,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAA;YAClC,CAAC;YACD,IAAI,CAAC,EAAE,CAAC,gBAAgB,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;gBAC9C,EAAE,CAAC,iBAAiB,CAAC,UAAU,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAA;YACrD,CAAC;QACH,CAAC;KACF,CAAC,CAAA;AACJ,CAAC;AAED,SAAS,cAAc,CACrB,eAAuB,EACvB,aAAqB,EACrB,YAAoB,EACpB,YAAqB;IAErB,
|
|
1
|
+
{"version":3,"file":"blastCache.js","sourceRoot":"","sources":["../../src/utils/blastCache.ts"],"names":[],"mappings":"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"}
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const version = "2.
|
|
1
|
+
export declare const version = "2.3.5";
|
package/dist/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const version = '2.
|
|
1
|
+
export const version = '2.3.5';
|
|
2
2
|
//# sourceMappingURL=version.js.map
|
package/dist/version.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,OAAO,GAAG,
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "2.3.
|
|
2
|
+
"version": "2.3.5",
|
|
3
3
|
"license": "MIT",
|
|
4
4
|
"name": "jbrowse-plugin-msaview",
|
|
5
5
|
"repository": {
|
|
@@ -15,65 +15,66 @@
|
|
|
15
15
|
"dist",
|
|
16
16
|
"src"
|
|
17
17
|
],
|
|
18
|
-
"scripts": {
|
|
19
|
-
"clean": "rimraf dist",
|
|
20
|
-
"start": "node esbuild.mjs --watch",
|
|
21
|
-
"format": "prettier --write .",
|
|
22
|
-
"build": "tsc && NODE_ENV=production node esbuild.mjs && cp distconfig.json dist/config.json",
|
|
23
|
-
"prebuild": "yarn clean",
|
|
24
|
-
"lint": "eslint --report-unused-disable-directives --max-warnings 0",
|
|
25
|
-
"pretest": "rm -rf .test-jbrowse && npx @jbrowse/cli create .test-jbrowse --nightly",
|
|
26
|
-
"test": "vitest run",
|
|
27
|
-
"test:watch": "vitest",
|
|
28
|
-
"test:setup": "node scripts/test-versions.mjs setup",
|
|
29
|
-
"test:setup:version": "node scripts/test-versions.mjs setup",
|
|
30
|
-
"test:versions": "node scripts/test-versions.mjs run",
|
|
31
|
-
"test:version": "node scripts/test-versions.mjs run",
|
|
32
|
-
"prepack": "yarn build",
|
|
33
|
-
"postversion": "node -e \"console.log('export const version = \\'' + require('./package.json').version + '\\'')\" > src/version.ts && git add -A src && git diff --cached --quiet || git commit -m '[skip ci] Bump version.ts' && git push --follow-tags",
|
|
34
|
-
"preversion": "yarn lint"
|
|
35
|
-
},
|
|
36
18
|
"dependencies": {
|
|
37
19
|
"@emotion/styled": "^11.14.1",
|
|
38
|
-
"g2p_mapper": "^2.0.
|
|
20
|
+
"g2p_mapper": "^2.0.1",
|
|
39
21
|
"idb": "^8.0.3",
|
|
40
22
|
"pako-esm2": "^2.0.2",
|
|
41
|
-
"react-msaview": "^5.0.
|
|
23
|
+
"react-msaview": "^5.0.16",
|
|
42
24
|
"swr": "^2.4.1"
|
|
43
25
|
},
|
|
44
26
|
"devDependencies": {
|
|
45
27
|
"@emotion/react": "^11.14.0",
|
|
46
|
-
"@eslint/js": "^
|
|
28
|
+
"@eslint/js": "^10.0.1",
|
|
47
29
|
"@fal-works/esbuild-plugin-global-externals": "^2.1.2",
|
|
48
|
-
"@jbrowse/core": "^4.
|
|
30
|
+
"@jbrowse/core": "^4.2.0",
|
|
49
31
|
"@jbrowse/mobx-state-tree": "^5.6.0",
|
|
50
|
-
"@jbrowse/plugin-linear-genome-view": "^4.
|
|
32
|
+
"@jbrowse/plugin-linear-genome-view": "^4.2.0",
|
|
51
33
|
"@mui/icons-material": "^7.3.10",
|
|
52
34
|
"@mui/material": "^7.3.10",
|
|
53
35
|
"@mui/system": "^7.3.10",
|
|
54
36
|
"@mui/x-data-grid": "^8.28.2",
|
|
55
37
|
"@types/node": "^25.6.0",
|
|
56
38
|
"@types/react": "^19.2.14",
|
|
39
|
+
"@typescript-eslint/eslint-plugin": "^8.59.1",
|
|
40
|
+
"@typescript-eslint/parser": "^8.59.1",
|
|
57
41
|
"esbuild": "^0.28.0",
|
|
58
|
-
"eslint": "^
|
|
59
|
-
"eslint-plugin-import": "^
|
|
42
|
+
"eslint": "^10.2.1",
|
|
43
|
+
"eslint-plugin-import-x": "^4.16.2",
|
|
60
44
|
"eslint-plugin-react": "^7.37.5",
|
|
61
|
-
"eslint-plugin-react-hooks": "^7.
|
|
62
|
-
"eslint-plugin-react-refresh": "^0.5.2",
|
|
45
|
+
"eslint-plugin-react-hooks": "^7.1.1",
|
|
63
46
|
"eslint-plugin-unicorn": "^64.0.0",
|
|
64
47
|
"mobx": "^6.15.0",
|
|
65
48
|
"mobx-react": "^9.2.1",
|
|
66
|
-
"prettier": "^3.8.
|
|
49
|
+
"prettier": "^3.8.3",
|
|
67
50
|
"pretty-bytes": "^7.1.0",
|
|
68
|
-
"puppeteer": "^24.
|
|
51
|
+
"puppeteer": "^24.42.0",
|
|
69
52
|
"react": "^19.2.5",
|
|
70
53
|
"react-dom": "^19.2.5",
|
|
71
54
|
"rimraf": "^6.1.3",
|
|
72
55
|
"rxjs": "^7.8.2",
|
|
73
56
|
"serve": "^14.2.6",
|
|
74
57
|
"tss-react": "^4.9.20",
|
|
75
|
-
"typescript": "^6.0.
|
|
76
|
-
"typescript-eslint": "^8.
|
|
77
|
-
"vitest": "^4.1.
|
|
58
|
+
"typescript": "^6.0.3",
|
|
59
|
+
"typescript-eslint": "^8.59.1",
|
|
60
|
+
"vitest": "^4.1.5"
|
|
61
|
+
},
|
|
62
|
+
"scripts": {
|
|
63
|
+
"clean": "rimraf dist",
|
|
64
|
+
"start": "node esbuild.mjs --watch",
|
|
65
|
+
"format": "pnpm prettier --write .",
|
|
66
|
+
"build": "tsc && NODE_ENV=production node esbuild.mjs && cp distconfig.json dist/config.json",
|
|
67
|
+
"prebuild": "pnpm clean",
|
|
68
|
+
"lint": "eslint src --report-unused-disable-directives --max-warnings 0",
|
|
69
|
+
"pretest": "rm -rf .test-jbrowse && npx @jbrowse/cli create .test-jbrowse --nightly",
|
|
70
|
+
"test": "vitest run",
|
|
71
|
+
"test:watch": "vitest",
|
|
72
|
+
"test:setup": "node scripts/test-versions.mjs setup",
|
|
73
|
+
"test:setup:version": "node scripts/test-versions.mjs setup",
|
|
74
|
+
"test:versions": "node scripts/test-versions.mjs run",
|
|
75
|
+
"test:version": "node scripts/test-versions.mjs run",
|
|
76
|
+
"preversion": "pnpm lint",
|
|
77
|
+
"version": "node -e \"console.log('export const version = \\'' + require('./package.json').version + '\\'')\" > src/version.ts && git add src/version.ts",
|
|
78
|
+
"postversion": "git push --follow-tags"
|
|
78
79
|
}
|
|
79
|
-
}
|
|
80
|
+
}
|
|
@@ -42,25 +42,16 @@ export default class BgzipFastaMsaAdapter extends BaseAdapter {
|
|
|
42
42
|
|
|
43
43
|
async getMSAList() {
|
|
44
44
|
const refNames = await this.getMSARefs()
|
|
45
|
-
const list = new Set<string>()
|
|
46
45
|
const val = this.getConf('msaRegex')
|
|
47
46
|
const re = new RegExp(val)
|
|
48
|
-
|
|
49
|
-
list.add(refNames[i]!.split(re)[0]!)
|
|
50
|
-
}
|
|
47
|
+
const list = new Set(refNames.map(name => name.split(re)[0]!))
|
|
51
48
|
return [...list]
|
|
52
49
|
}
|
|
53
50
|
|
|
54
51
|
async getMSA(id: string) {
|
|
55
52
|
const adapter = await this.configure()
|
|
56
53
|
const refNames = await adapter.getRefNames()
|
|
57
|
-
const rows =
|
|
58
|
-
for (let i = 0, l = refNames.length; i < l; i++) {
|
|
59
|
-
const refName = refNames[i]!
|
|
60
|
-
if (refName.startsWith(id)) {
|
|
61
|
-
rows.push(refName)
|
|
62
|
-
}
|
|
63
|
-
}
|
|
54
|
+
const rows = refNames.filter(refName => refName.startsWith(id))
|
|
64
55
|
return firstValueFrom(
|
|
65
56
|
adapter
|
|
66
57
|
.getFeaturesInMultipleRegions(
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, { useMemo, useState } from 'react'
|
|
2
2
|
|
|
3
3
|
import { ErrorMessage } from '@jbrowse/core/ui'
|
|
4
4
|
import { getContainingView } from '@jbrowse/core/util'
|
|
@@ -15,11 +15,7 @@ import {
|
|
|
15
15
|
import { observer } from 'mobx-react'
|
|
16
16
|
|
|
17
17
|
import { blastLaunchViewFromCache } from './blastLaunchView'
|
|
18
|
-
import {
|
|
19
|
-
clearAllCachedResults,
|
|
20
|
-
deleteCachedResult,
|
|
21
|
-
getAllCachedResults,
|
|
22
|
-
} from '../../../utils/blastCache'
|
|
18
|
+
import { useCachedBlastResults } from './useCachedBlastResults'
|
|
23
19
|
import { getGeneIdentifiers } from '../../util'
|
|
24
20
|
|
|
25
21
|
import type { CachedBlastResult } from '../../../utils/blastCache'
|
|
@@ -49,44 +45,13 @@ const CachedBlastResults = observer(function ({
|
|
|
49
45
|
handleClose: () => void
|
|
50
46
|
feature: Feature
|
|
51
47
|
}) {
|
|
52
|
-
const [results, setResults] = useState<CachedBlastResult[]>([])
|
|
53
|
-
const [loading, setLoading] = useState(true)
|
|
54
|
-
const [error, setError] = useState<unknown>()
|
|
55
48
|
const view = getContainingView(model) as LinearGenomeViewModel
|
|
49
|
+
const [operationError, setOperationError] = useState<unknown>()
|
|
56
50
|
|
|
57
51
|
const geneIds = useMemo(() => getGeneIdentifiers(feature), [feature])
|
|
58
52
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
;(async () => {
|
|
62
|
-
try {
|
|
63
|
-
const cached = await getAllCachedResults()
|
|
64
|
-
setResults(cached.filter(r => r.geneId && geneIds.includes(r.geneId)))
|
|
65
|
-
setLoading(false)
|
|
66
|
-
} catch (e) {
|
|
67
|
-
console.error(e)
|
|
68
|
-
setError(e)
|
|
69
|
-
}
|
|
70
|
-
})()
|
|
71
|
-
}, [geneIds])
|
|
72
|
-
|
|
73
|
-
const handleDelete = async (id: string) => {
|
|
74
|
-
try {
|
|
75
|
-
await deleteCachedResult(id)
|
|
76
|
-
setResults(r => r.filter(result => result.id !== id))
|
|
77
|
-
} catch (e) {
|
|
78
|
-
setError(e)
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
const handleClearAll = async () => {
|
|
83
|
-
try {
|
|
84
|
-
await clearAllCachedResults()
|
|
85
|
-
setResults([])
|
|
86
|
-
} catch (e) {
|
|
87
|
-
setError(e)
|
|
88
|
-
}
|
|
89
|
-
}
|
|
53
|
+
const { results, error, isLoading, handleDelete, handleClearAll } =
|
|
54
|
+
useCachedBlastResults(geneIds)
|
|
90
55
|
|
|
91
56
|
const handleUseCached = (cached: CachedBlastResult) => {
|
|
92
57
|
blastLaunchViewFromCache({
|
|
@@ -97,11 +62,12 @@ const CachedBlastResults = observer(function ({
|
|
|
97
62
|
handleClose()
|
|
98
63
|
}
|
|
99
64
|
|
|
100
|
-
|
|
101
|
-
|
|
65
|
+
const displayError = error ?? operationError
|
|
66
|
+
if (displayError) {
|
|
67
|
+
return <ErrorMessage error={displayError} />
|
|
102
68
|
}
|
|
103
69
|
|
|
104
|
-
if (
|
|
70
|
+
if (isLoading) {
|
|
105
71
|
return <Typography>Loading cached results...</Typography>
|
|
106
72
|
}
|
|
107
73
|
|
|
@@ -130,9 +96,13 @@ const CachedBlastResults = observer(function ({
|
|
|
130
96
|
<Button
|
|
131
97
|
size="small"
|
|
132
98
|
color="error"
|
|
133
|
-
onClick={() => {
|
|
134
|
-
|
|
135
|
-
|
|
99
|
+
onClick={async () => {
|
|
100
|
+
try {
|
|
101
|
+
setOperationError(undefined)
|
|
102
|
+
await handleClearAll()
|
|
103
|
+
} catch (e) {
|
|
104
|
+
setOperationError(e)
|
|
105
|
+
}
|
|
136
106
|
}}
|
|
137
107
|
>
|
|
138
108
|
Clear All
|
|
@@ -147,10 +117,14 @@ const CachedBlastResults = observer(function ({
|
|
|
147
117
|
<IconButton
|
|
148
118
|
edge="end"
|
|
149
119
|
size="small"
|
|
150
|
-
onClick={e => {
|
|
120
|
+
onClick={async e => {
|
|
151
121
|
e.stopPropagation()
|
|
152
|
-
|
|
153
|
-
|
|
122
|
+
try {
|
|
123
|
+
setOperationError(undefined)
|
|
124
|
+
await handleDelete(result.id)
|
|
125
|
+
} catch (err) {
|
|
126
|
+
setOperationError(err)
|
|
127
|
+
}
|
|
154
128
|
}}
|
|
155
129
|
>
|
|
156
130
|
<DeleteIcon fontSize="small" />
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, { useMemo, useState } from 'react'
|
|
2
2
|
|
|
3
3
|
import { ErrorMessage } from '@jbrowse/core/ui'
|
|
4
4
|
import { getContainingView } from '@jbrowse/core/util'
|
|
@@ -19,8 +19,8 @@ import { makeStyles } from 'tss-react/mui'
|
|
|
19
19
|
import CachedBlastResults from './CachedBlastResults'
|
|
20
20
|
import { blastLaunchView } from './blastLaunchView'
|
|
21
21
|
import { msaAlgorithms } from './consts'
|
|
22
|
+
import { useCachedBlastResults } from './useCachedBlastResults'
|
|
22
23
|
import TextField2 from '../../../components/TextField2'
|
|
23
|
-
import { getAllCachedResults } from '../../../utils/blastCache'
|
|
24
24
|
import {
|
|
25
25
|
getGeneDisplayName,
|
|
26
26
|
getGeneIdentifiers,
|
|
@@ -83,24 +83,10 @@ const NCBIBlastAutomaticPanel = observer(function ({
|
|
|
83
83
|
useState<MsaAlgorithm>('clustalo')
|
|
84
84
|
const [selectedBlastProgram, setSelectedBlastProgram] =
|
|
85
85
|
useState<blastProgramsT>('quick-blastp')
|
|
86
|
-
const [hasCachedResults, setHasCachedResults] = useState(false)
|
|
87
|
-
const [error, setError] = useState<unknown>()
|
|
88
86
|
|
|
89
87
|
const geneIds = useMemo(() => getGeneIdentifiers(feature), [feature])
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
;(async () => {
|
|
93
|
-
try {
|
|
94
|
-
const results = await getAllCachedResults()
|
|
95
|
-
setHasCachedResults(
|
|
96
|
-
results.some(r => r.geneId && geneIds.includes(r.geneId)),
|
|
97
|
-
)
|
|
98
|
-
} catch (e) {
|
|
99
|
-
console.error(e)
|
|
100
|
-
setError(e)
|
|
101
|
-
}
|
|
102
|
-
})()
|
|
103
|
-
}, [geneIds])
|
|
88
|
+
const { results: cachedResults, error: cachedResultsError } =
|
|
89
|
+
useCachedBlastResults(geneIds)
|
|
104
90
|
|
|
105
91
|
const {
|
|
106
92
|
options,
|
|
@@ -110,7 +96,7 @@ const NCBIBlastAutomaticPanel = observer(function ({
|
|
|
110
96
|
proteinSequence,
|
|
111
97
|
error: proteinSequenceError,
|
|
112
98
|
} = useTranscriptSelection({ feature, view })
|
|
113
|
-
const e = proteinSequenceError ?? launchViewError ??
|
|
99
|
+
const e = proteinSequenceError ?? launchViewError ?? cachedResultsError
|
|
114
100
|
return (
|
|
115
101
|
<>
|
|
116
102
|
<DialogContent className={classes.dialogContent}>
|
|
@@ -205,7 +191,7 @@ const NCBIBlastAutomaticPanel = observer(function ({
|
|
|
205
191
|
submitting BLAST yourself and downloading the resulting files
|
|
206
192
|
</Typography>
|
|
207
193
|
|
|
208
|
-
{
|
|
194
|
+
{cachedResults.length > 0 ? (
|
|
209
195
|
<Accordion className={classes.cachedResultsAccordion}>
|
|
210
196
|
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
|
|
211
197
|
<Typography>Previous BLAST Results</Typography>
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import useSWR from 'swr'
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
clearAllCachedResults,
|
|
5
|
+
deleteCachedResult,
|
|
6
|
+
getAllCachedResults,
|
|
7
|
+
} from '../../../utils/blastCache'
|
|
8
|
+
|
|
9
|
+
const swrConfig = {
|
|
10
|
+
revalidateOnFocus: false,
|
|
11
|
+
revalidateOnReconnect: false,
|
|
12
|
+
revalidateIfStale: false,
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function useCachedBlastResults(geneIds: string[]) {
|
|
16
|
+
const {
|
|
17
|
+
data: results,
|
|
18
|
+
error,
|
|
19
|
+
mutate,
|
|
20
|
+
} = useSWR(
|
|
21
|
+
`cached-blast-${geneIds.join(',')}`,
|
|
22
|
+
async () => {
|
|
23
|
+
const cached = await getAllCachedResults()
|
|
24
|
+
return cached.filter(r => r.geneId && geneIds.includes(r.geneId))
|
|
25
|
+
},
|
|
26
|
+
swrConfig,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
const handleDelete = async (id: string) => {
|
|
30
|
+
await deleteCachedResult(id)
|
|
31
|
+
await mutate(
|
|
32
|
+
results => results?.filter(result => result.id !== id) ?? [],
|
|
33
|
+
false,
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const handleClearAll = async () => {
|
|
38
|
+
await clearAllCachedResults()
|
|
39
|
+
await mutate([], false)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return {
|
|
43
|
+
results: results ?? [],
|
|
44
|
+
error,
|
|
45
|
+
isLoading: !results && !error,
|
|
46
|
+
handleDelete,
|
|
47
|
+
handleClearAll,
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useMemo, useState } from 'react'
|
|
2
2
|
|
|
3
3
|
import { featureMatchesId, getId, getSortedTranscriptFeatures } from '../util'
|
|
4
4
|
import { useFeatureSequence } from './useFeatureSequence'
|
|
@@ -9,6 +9,24 @@ function featureInValidIds(feature: Feature, validIds: string[]): boolean {
|
|
|
9
9
|
return validIds.some(id => featureMatchesId(feature, id))
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
+
function findValidSelection(
|
|
13
|
+
currentId: string,
|
|
14
|
+
options: Feature[],
|
|
15
|
+
validIds: string[] | undefined,
|
|
16
|
+
): string | undefined {
|
|
17
|
+
if (!validIds || validIds.length === 0) {
|
|
18
|
+
return undefined
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const currentFeature = options.find(opt => getId(opt) === currentId)
|
|
22
|
+
if (!currentFeature || featureInValidIds(currentFeature, validIds)) {
|
|
23
|
+
return undefined
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const validOption = options.find(opt => featureInValidIds(opt, validIds))
|
|
27
|
+
return validOption ? getId(validOption) : undefined
|
|
28
|
+
}
|
|
29
|
+
|
|
12
30
|
export function useTranscriptSelection({
|
|
13
31
|
feature,
|
|
14
32
|
view,
|
|
@@ -20,29 +38,19 @@ export function useTranscriptSelection({
|
|
|
20
38
|
}) {
|
|
21
39
|
const options = useMemo(() => getSortedTranscriptFeatures(feature), [feature])
|
|
22
40
|
const [selectedId, setSelectedId] = useState(() => getId(options[0]))
|
|
23
|
-
const
|
|
41
|
+
const validatedSelectedId =
|
|
42
|
+
findValidSelection(selectedId, options, validIds) || selectedId
|
|
43
|
+
const selectedTranscript = options.find(
|
|
44
|
+
val => getId(val) === validatedSelectedId,
|
|
45
|
+
)
|
|
24
46
|
const { proteinSequence, error } = useFeatureSequence({
|
|
25
47
|
view,
|
|
26
48
|
feature: selectedTranscript,
|
|
27
49
|
})
|
|
28
50
|
|
|
29
|
-
useEffect(() => {
|
|
30
|
-
if (validIds && validIds.length > 0) {
|
|
31
|
-
const currentFeature = options.find(opt => getId(opt) === selectedId)
|
|
32
|
-
if (currentFeature && !featureInValidIds(currentFeature, validIds)) {
|
|
33
|
-
const validOption = options.find(opt =>
|
|
34
|
-
featureInValidIds(opt, validIds),
|
|
35
|
-
)
|
|
36
|
-
if (validOption) {
|
|
37
|
-
setSelectedId(getId(validOption))
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}, [validIds, options, selectedId])
|
|
42
|
-
|
|
43
51
|
return {
|
|
44
52
|
options,
|
|
45
|
-
selectedId,
|
|
53
|
+
selectedId: validatedSelectedId,
|
|
46
54
|
setSelectedId,
|
|
47
55
|
selectedTranscript,
|
|
48
56
|
proteinSequence,
|
|
@@ -13,6 +13,22 @@ import { getUniprotIdFromAlphaFoldUrl } from './util'
|
|
|
13
13
|
|
|
14
14
|
import type { JBrowsePluginMsaViewModel } from './model'
|
|
15
15
|
|
|
16
|
+
interface ProteinView {
|
|
17
|
+
type: 'ProteinView'
|
|
18
|
+
id: string
|
|
19
|
+
structures: {
|
|
20
|
+
connectedViewId?: string
|
|
21
|
+
uniprotId?: string
|
|
22
|
+
structureSequences?: unknown[]
|
|
23
|
+
hoverGenomeHighlights?: { start: number; end: number }[]
|
|
24
|
+
}[]
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function isProteinView(view: unknown): view is ProteinView {
|
|
28
|
+
const v = view as Record<string, unknown>
|
|
29
|
+
return v.type === 'ProteinView' && Array.isArray(v.structures)
|
|
30
|
+
}
|
|
31
|
+
|
|
16
32
|
export function loadStoredData(self: JBrowsePluginMsaViewModel) {
|
|
17
33
|
const { dataStoreId, rows } = self
|
|
18
34
|
if (dataStoreId && rows.length === 0) {
|
|
@@ -202,10 +218,10 @@ export function autoConnectStructures(self: JBrowsePluginMsaViewModel) {
|
|
|
202
218
|
}
|
|
203
219
|
|
|
204
220
|
for (const view of views) {
|
|
205
|
-
|
|
206
|
-
if (v.type !== 'ProteinView' || !v.structures) {
|
|
221
|
+
if (!isProteinView(view)) {
|
|
207
222
|
continue
|
|
208
223
|
}
|
|
224
|
+
const v = view
|
|
209
225
|
|
|
210
226
|
for (
|
|
211
227
|
let structureIdx = 0;
|
|
@@ -213,6 +229,9 @@ export function autoConnectStructures(self: JBrowsePluginMsaViewModel) {
|
|
|
213
229
|
structureIdx++
|
|
214
230
|
) {
|
|
215
231
|
const structure = v.structures[structureIdx]
|
|
232
|
+
if (!structure) {
|
|
233
|
+
continue
|
|
234
|
+
}
|
|
216
235
|
|
|
217
236
|
if (structure.connectedViewId !== connectedViewId) {
|
|
218
237
|
continue
|
|
@@ -250,13 +269,13 @@ export function observeProteinHighlights(self: JBrowsePluginMsaViewModel) {
|
|
|
250
269
|
return
|
|
251
270
|
}
|
|
252
271
|
|
|
253
|
-
const columns
|
|
272
|
+
const columns = new Set<number>()
|
|
254
273
|
|
|
255
274
|
for (const view of views) {
|
|
256
|
-
|
|
257
|
-
if (v.type !== 'ProteinView' || !v.structures) {
|
|
275
|
+
if (!isProteinView(view)) {
|
|
258
276
|
continue
|
|
259
277
|
}
|
|
278
|
+
const v = view
|
|
260
279
|
|
|
261
280
|
for (const structure of v.structures) {
|
|
262
281
|
if (structure.connectedViewId !== connectedViewId) {
|
|
@@ -274,16 +293,14 @@ export function observeProteinHighlights(self: JBrowsePluginMsaViewModel) {
|
|
|
274
293
|
const proteinPos = g2p[coord]
|
|
275
294
|
if (proteinPos !== undefined) {
|
|
276
295
|
const col = self.seqPosToGlobalCol(querySeqName, proteinPos)
|
|
277
|
-
|
|
278
|
-
columns.push(col)
|
|
279
|
-
}
|
|
296
|
+
columns.add(col)
|
|
280
297
|
}
|
|
281
298
|
}
|
|
282
299
|
}
|
|
283
300
|
}
|
|
284
301
|
}
|
|
285
302
|
|
|
286
|
-
const visibleColumns = columns
|
|
303
|
+
const visibleColumns = Array.from(columns)
|
|
287
304
|
.map(col => self.globalColToVisibleCol(col))
|
|
288
305
|
.filter((col): col is number => col !== undefined)
|
|
289
306
|
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { ReactNode } from 'react'
|
|
2
|
+
import React, { Component } from 'react'
|
|
3
|
+
|
|
4
|
+
import { ErrorMessage } from '@jbrowse/core/ui'
|
|
5
|
+
|
|
6
|
+
interface Props {
|
|
7
|
+
children: ReactNode
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
interface State {
|
|
11
|
+
hasError: boolean
|
|
12
|
+
error: unknown
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export class ErrorBoundary extends Component<Props, State> {
|
|
16
|
+
constructor(props: Props) {
|
|
17
|
+
super(props)
|
|
18
|
+
this.state = { hasError: false, error: null }
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
static getDerivedStateFromError(error: unknown) {
|
|
22
|
+
return { hasError: true, error }
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
componentDidCatch(error: unknown, info: React.ErrorInfo) {
|
|
26
|
+
console.error('MsaViewPanel error:', error, info.componentStack)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
render() {
|
|
30
|
+
if (this.state.hasError) {
|
|
31
|
+
return (
|
|
32
|
+
<div style={{ padding: 20 }}>
|
|
33
|
+
<ErrorMessage error={this.state.error} />
|
|
34
|
+
</div>
|
|
35
|
+
)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return this.props.children
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -4,6 +4,7 @@ import { LoadingEllipses } from '@jbrowse/core/ui'
|
|
|
4
4
|
import { observer } from 'mobx-react'
|
|
5
5
|
import { MSAView } from 'react-msaview'
|
|
6
6
|
|
|
7
|
+
import { ErrorBoundary } from './ErrorBoundary'
|
|
7
8
|
import LoadingBLAST from './LoadingBLAST'
|
|
8
9
|
|
|
9
10
|
import type { JBrowsePluginMsaViewModel } from '../model'
|
|
@@ -15,17 +16,19 @@ const MsaViewPanel = observer(function MsaViewPanel2({
|
|
|
15
16
|
}) {
|
|
16
17
|
const { blastParams, loadingStoredData } = model
|
|
17
18
|
return (
|
|
18
|
-
<
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
<
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
19
|
+
<ErrorBoundary>
|
|
20
|
+
<div>
|
|
21
|
+
{blastParams ? (
|
|
22
|
+
<LoadingBLAST model={model} baseUrl={blastParams.baseUrl} />
|
|
23
|
+
) : loadingStoredData ? (
|
|
24
|
+
<div style={{ padding: 20 }}>
|
|
25
|
+
<LoadingEllipses message="Loading MSA data" variant="h6" />
|
|
26
|
+
</div>
|
|
27
|
+
) : (
|
|
28
|
+
<MSAView model={model} />
|
|
29
|
+
)}
|
|
30
|
+
</div>
|
|
31
|
+
</ErrorBoundary>
|
|
29
32
|
)
|
|
30
33
|
})
|
|
31
34
|
|