@apollo-annotation/jbrowse-plugin-apollo 0.1.21 → 0.2.1
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/index.esm.js +431 -570
- package/dist/index.esm.js.map +1 -1
- package/dist/jbrowse-plugin-apollo.cjs.development.js +439 -578
- package/dist/jbrowse-plugin-apollo.cjs.development.js.map +1 -1
- package/dist/jbrowse-plugin-apollo.cjs.production.min.js +1 -1
- package/dist/jbrowse-plugin-apollo.cjs.production.min.js.map +1 -1
- package/dist/jbrowse-plugin-apollo.umd.development.js +11064 -1091
- package/dist/jbrowse-plugin-apollo.umd.development.js.map +1 -1
- package/dist/jbrowse-plugin-apollo.umd.production.min.js +1 -1
- package/dist/jbrowse-plugin-apollo.umd.production.min.js.map +1 -1
- package/package.json +4 -5
- package/src/ApolloInternetAccount/components/AuthTypeSelector.tsx +4 -2
- package/src/ApolloInternetAccount/configSchema.ts +1 -1
- package/src/ApolloInternetAccount/model.ts +5 -10
- package/src/ApolloRefNameAliasAdapter/ApolloRefNameAliasAdapter.ts +1 -1
- package/src/ApolloSixFrameRenderer/components/ApolloRendering.tsx +4 -5
- package/src/BackendDrivers/DesktopFileDriver.ts +3 -2
- package/src/FeatureDetailsWidget/Attributes.tsx +1 -6
- package/src/FeatureDetailsWidget/NumberTextField.tsx +1 -0
- package/src/FeatureDetailsWidget/StringTextField.tsx +1 -0
- package/src/FeatureDetailsWidget/TranscriptBasic.tsx +131 -382
- package/src/FeatureDetailsWidget/TranscriptSequence.tsx +209 -284
- package/src/FeatureDetailsWidget/model.ts +4 -4
- package/src/LinearApolloDisplay/components/LinearApolloDisplay.tsx +1 -0
- package/src/LinearApolloDisplay/glyphs/BoxGlyph.ts +25 -3
- package/src/LinearApolloDisplay/glyphs/GeneGlyph.ts +95 -32
- package/src/LinearApolloDisplay/stateModel/base.ts +5 -3
- package/src/LinearApolloDisplay/stateModel/index.ts +1 -1
- package/src/LinearApolloDisplay/stateModel/mouseEvents.ts +1 -1
- package/src/LinearApolloDisplay/stateModel/rendering.ts +1 -1
- package/src/OntologyManager/OntologyStore/fulltext.ts +5 -2
- package/src/OntologyManager/OntologyStore/index.ts +25 -22
- package/src/OntologyManager/OntologyStore/indexeddb-storage.ts +8 -3
- package/src/OntologyManager/index.ts +31 -8
- package/src/SixFrameFeatureDisplay/stateModel.ts +1 -1
- package/src/TabularEditor/HybridGrid/HybridGrid.tsx +1 -0
- package/src/TabularEditor/HybridGrid/NumberCell.tsx +1 -0
- package/src/TabularEditor/model.ts +1 -1
- package/src/components/AddChildFeature.tsx +1 -0
- package/src/components/AddFeature.tsx +1 -1
- package/src/components/AddRefSeqAliases.tsx +1 -0
- package/src/components/CopyFeature.tsx +1 -0
- package/src/components/DeleteAssembly.tsx +1 -0
- package/src/components/DeleteFeature.tsx +1 -0
- package/src/components/LogOut.tsx +2 -1
- package/src/components/ManageChecks.tsx +1 -1
- package/src/components/ManageUsers.tsx +2 -1
- package/src/components/OntologyTermAutocomplete.tsx +7 -9
- package/src/components/OntologyTermMultiSelect.tsx +2 -1
- package/src/components/OpenLocalFile.tsx +3 -1
- package/src/components/ViewChangeLog.tsx +1 -0
- package/src/components/ViewCheckResults.tsx +1 -0
- package/src/config.ts +5 -0
- package/src/extensions/annotationFromPileup.ts +1 -1
- package/src/makeDisplayComponent.tsx +28 -7
- package/src/session/ClientDataStore.ts +1 -1
- package/src/session/session.ts +2 -1
|
@@ -24,10 +24,11 @@ var CloseIcon = require('@mui/icons-material/Close');
|
|
|
24
24
|
var mobxReact = require('mobx-react');
|
|
25
25
|
var mui = require('tss-react/mui');
|
|
26
26
|
var mst = require('@jbrowse/core/util/types/mst');
|
|
27
|
+
var withAsyncIttr = require('idb/with-async-ittr');
|
|
28
|
+
var aborting = require('@jbrowse/core/util/aborting');
|
|
27
29
|
var jsonpath = require('jsonpath');
|
|
28
30
|
var io = require('@jbrowse/core/util/io');
|
|
29
31
|
var equal = require('fast-deep-equal/es6');
|
|
30
|
-
var withAsyncIttr = require('idb/with-async-ittr');
|
|
31
32
|
var fileSaver = require('file-saver');
|
|
32
33
|
var Checkbox = require('@mui/material/Checkbox');
|
|
33
34
|
var FormControlLabel = require('@mui/material/FormControlLabel');
|
|
@@ -100,7 +101,7 @@ var ExpandMoreIcon__default = /*#__PURE__*/_interopDefaultLegacy(ExpandMoreIcon)
|
|
|
100
101
|
var ErrorIcon__default = /*#__PURE__*/_interopDefaultLegacy(ErrorIcon);
|
|
101
102
|
var SaveIcon__default = /*#__PURE__*/_interopDefaultLegacy(SaveIcon);
|
|
102
103
|
|
|
103
|
-
var version = "0.1
|
|
104
|
+
var version = "0.2.1";
|
|
104
105
|
|
|
105
106
|
const ApolloConfigSchema = configuration.ConfigurationSchema('ApolloInternetAccount', {
|
|
106
107
|
baseURL: {
|
|
@@ -696,7 +697,7 @@ function* getWords(node, jsonPaths, prefixes) {
|
|
|
696
697
|
async function textSearch(text, tx, signal) {
|
|
697
698
|
const db = await this.db;
|
|
698
699
|
const myTx = tx ?? db.transaction(['nodes']);
|
|
699
|
-
|
|
700
|
+
aborting.checkAbortSignal(signal);
|
|
700
701
|
const queryWords = [...wordsInString(text)];
|
|
701
702
|
const queries = [];
|
|
702
703
|
/**
|
|
@@ -706,10 +707,10 @@ async function textSearch(text, tx, signal) {
|
|
|
706
707
|
const initialMatches = new Map();
|
|
707
708
|
// find startsWith and complete matches
|
|
708
709
|
queries.push(...queryWords.map(async (queryWord, queryWordIndex) => {
|
|
709
|
-
|
|
710
|
+
aborting.checkAbortSignal(signal);
|
|
710
711
|
const idx = myTx.objectStore('nodes').index('full-text-words');
|
|
711
712
|
for await (const cursor of idx.iterate(IDBKeyRange.bound(queryWord, `${queryWord}\uFFFF`, false, false))) {
|
|
712
|
-
|
|
713
|
+
aborting.checkAbortSignal(signal);
|
|
713
714
|
const term = cursor.value;
|
|
714
715
|
const termMatches = initialMatches.get(term.id) ?? [
|
|
715
716
|
term,
|
|
@@ -720,11 +721,11 @@ async function textSearch(text, tx, signal) {
|
|
|
720
721
|
}
|
|
721
722
|
}));
|
|
722
723
|
await Promise.all(queries);
|
|
723
|
-
|
|
724
|
+
aborting.checkAbortSignal(signal);
|
|
724
725
|
// now rank the term matches and add some detail
|
|
725
726
|
const results = [];
|
|
726
727
|
for (const [, [term, wordIndexes]] of initialMatches) {
|
|
727
|
-
|
|
728
|
+
aborting.checkAbortSignal(signal);
|
|
728
729
|
results.push(...elaborateMatch(this.textIndexFields, term, wordIndexes, queryWords, this.prefixes));
|
|
729
730
|
}
|
|
730
731
|
// sort the terms by score descending
|
|
@@ -736,7 +737,7 @@ function elaborateMatch(textIndexPaths, term, queryWordIndexes, queryWords, pref
|
|
|
736
737
|
const sortedWordIndexes = [...queryWordIndexes].sort();
|
|
737
738
|
const matchedQueryWords = sortedWordIndexes.map((i) => queryWords[i]);
|
|
738
739
|
const queryWordRegexps = matchedQueryWords.map((queryWord) => {
|
|
739
|
-
const escaped = queryWord.replaceAll(/[$()*+./?[\\\]^{|}-]/g,
|
|
740
|
+
const escaped = queryWord.replaceAll(/[$()*+./?[\\\]^{|}-]/g, String.raw `\$&`);
|
|
740
741
|
return new RegExp(`\\b${escaped}`, 'gi');
|
|
741
742
|
});
|
|
742
743
|
// const needle = matchedQueryWords.join(' ')
|
|
@@ -883,7 +884,13 @@ async function loadOboGraphJson(db) {
|
|
|
883
884
|
// TODO: using file streaming along with an event-based json parser
|
|
884
885
|
// instead of JSON.parse and .readFile could probably make this faster
|
|
885
886
|
// and less memory intensive
|
|
886
|
-
|
|
887
|
+
let oboGraph;
|
|
888
|
+
try {
|
|
889
|
+
oboGraph = JSON.parse(await io.openLocation(this.sourceLocation).readFile('utf8'));
|
|
890
|
+
}
|
|
891
|
+
catch {
|
|
892
|
+
throw new Error('Error in loading ontology');
|
|
893
|
+
}
|
|
887
894
|
const parseTime = Date.now();
|
|
888
895
|
const [graph, ...additionalGraphs] = oboGraph.graphs ?? [];
|
|
889
896
|
if (!graph) {
|
|
@@ -962,12 +969,6 @@ async function isDatabaseCurrent(db) {
|
|
|
962
969
|
}
|
|
963
970
|
|
|
964
971
|
/* eslint-disable @typescript-eslint/only-throw-error */
|
|
965
|
-
/**
|
|
966
|
-
* @deprecated use the one from jbrowse core when it is published
|
|
967
|
-
**/
|
|
968
|
-
function isLocalPathLocation(location) {
|
|
969
|
-
return (typeof location === 'object' && location !== null && 'localPath' in location);
|
|
970
|
-
}
|
|
971
972
|
async function arrayFromAsync(iter) {
|
|
972
973
|
const a = [];
|
|
973
974
|
for await (const i of iter) {
|
|
@@ -1022,7 +1023,7 @@ class OntologyStore {
|
|
|
1022
1023
|
return 'obo-graph-json';
|
|
1023
1024
|
}
|
|
1024
1025
|
}
|
|
1025
|
-
else if (isLocalPathLocation(this.sourceLocation) &&
|
|
1026
|
+
else if (util.isLocalPathLocation(this.sourceLocation) &&
|
|
1026
1027
|
this.sourceLocation.localPath.endsWith('.json')) {
|
|
1027
1028
|
return 'obo-graph-json';
|
|
1028
1029
|
}
|
|
@@ -1042,14 +1043,21 @@ class OntologyStore {
|
|
|
1042
1043
|
if (await this.isDatabaseCurrent(db)) {
|
|
1043
1044
|
return db;
|
|
1044
1045
|
}
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1046
|
+
try {
|
|
1047
|
+
const { sourceLocation, sourceType } = this;
|
|
1048
|
+
if (sourceType === 'obo-graph-json') {
|
|
1049
|
+
await this.loadOboGraphJson(db);
|
|
1050
|
+
}
|
|
1051
|
+
else {
|
|
1052
|
+
throw new Error(`ontology source file ${JSON.stringify(sourceLocation)} has type ${sourceType}, which is not yet supported`);
|
|
1053
|
+
}
|
|
1054
|
+
return db;
|
|
1048
1055
|
}
|
|
1049
|
-
|
|
1050
|
-
|
|
1056
|
+
catch (error) {
|
|
1057
|
+
db.close();
|
|
1058
|
+
await withAsyncIttr.deleteDB(this.dbName);
|
|
1059
|
+
throw error;
|
|
1051
1060
|
}
|
|
1052
|
-
return db;
|
|
1053
1061
|
}
|
|
1054
1062
|
async termCount(tx) {
|
|
1055
1063
|
const db = await this.db;
|
|
@@ -1227,7 +1235,7 @@ class OntologyStore {
|
|
|
1227
1235
|
}
|
|
1228
1236
|
// fetch the full nodes and filter out deprecated ones
|
|
1229
1237
|
const terms = [];
|
|
1230
|
-
for
|
|
1238
|
+
for (const termId of termIds) {
|
|
1231
1239
|
const node = await myTx.objectStore('nodes').get(termId);
|
|
1232
1240
|
if (node && isOntologyClass(node) && !isDeprecated(node)) {
|
|
1233
1241
|
terms.push(node);
|
|
@@ -1285,15 +1293,22 @@ const OntologyManagerType = mobxStateTree.types
|
|
|
1285
1293
|
'SO:': 'http://purl.obolibrary.org/obo/SO_',
|
|
1286
1294
|
}),
|
|
1287
1295
|
})
|
|
1296
|
+
.views((self) => ({
|
|
1297
|
+
get featureTypeOntologyName() {
|
|
1298
|
+
const jbConfig = mobxStateTree.getRoot(self).jbrowse
|
|
1299
|
+
.configuration;
|
|
1300
|
+
const pluginConfiguration = jbConfig.ApolloPlugin;
|
|
1301
|
+
const featureTypeOntologyName = configuration.readConfObject(pluginConfiguration, 'featureTypeOntologyName');
|
|
1302
|
+
return featureTypeOntologyName;
|
|
1303
|
+
},
|
|
1304
|
+
}))
|
|
1288
1305
|
.views((self) => ({
|
|
1289
1306
|
/**
|
|
1290
1307
|
* gets the OntologyRecord for the ontology we should be
|
|
1291
1308
|
* using for feature types (e.g. SO or maybe biotypes)
|
|
1292
1309
|
**/
|
|
1293
1310
|
get featureTypeOntology() {
|
|
1294
|
-
|
|
1295
|
-
// we should be using. currently hardcoded to use SO.
|
|
1296
|
-
return this.findOntology('Sequence Ontology');
|
|
1311
|
+
return this.findOntology(self.featureTypeOntologyName);
|
|
1297
1312
|
},
|
|
1298
1313
|
findOntology(name, version) {
|
|
1299
1314
|
return self.ontologies.find((record) => {
|
|
@@ -1405,7 +1420,6 @@ function OntologyTermAutocomplete({ fetchValidTerms, filterTerms: filterTermsPro
|
|
|
1405
1420
|
// effect for clearing choices when not open
|
|
1406
1421
|
React.useEffect(() => {
|
|
1407
1422
|
if (!open) {
|
|
1408
|
-
// eslint-disable-next-line unicorn/no-useless-undefined
|
|
1409
1423
|
setTermChoices(undefined);
|
|
1410
1424
|
}
|
|
1411
1425
|
}, [open]);
|
|
@@ -1420,7 +1434,7 @@ function OntologyTermAutocomplete({ fetchValidTerms, filterTerms: filterTermsPro
|
|
|
1420
1434
|
setCurrentOntologyTerm(term);
|
|
1421
1435
|
}
|
|
1422
1436
|
}, (error) => {
|
|
1423
|
-
if (!signal.aborted && !
|
|
1437
|
+
if (!signal.aborted && !aborting.isAbortException(error)) {
|
|
1424
1438
|
setCurrentOntologyTermInvalid(String(error));
|
|
1425
1439
|
}
|
|
1426
1440
|
});
|
|
@@ -1439,8 +1453,8 @@ function OntologyTermAutocomplete({ fetchValidTerms, filterTerms: filterTermsPro
|
|
|
1439
1453
|
setTermChoices(soTerms);
|
|
1440
1454
|
}
|
|
1441
1455
|
}, (error) => {
|
|
1442
|
-
if (!signal.aborted && !
|
|
1443
|
-
session.notify(error.message, 'error');
|
|
1456
|
+
if (!signal.aborted && !aborting.isAbortException(error)) {
|
|
1457
|
+
session.notify(error instanceof Error ? error.message : String(error), 'error');
|
|
1444
1458
|
}
|
|
1445
1459
|
});
|
|
1446
1460
|
}
|
|
@@ -1459,7 +1473,6 @@ function OntologyTermAutocomplete({ fetchValidTerms, filterTerms: filterTermsPro
|
|
|
1459
1473
|
return;
|
|
1460
1474
|
}
|
|
1461
1475
|
if (typeof newValue === 'string') {
|
|
1462
|
-
// eslint-disable-next-line unicorn/no-useless-undefined
|
|
1463
1476
|
setCurrentOntologyTerm(undefined);
|
|
1464
1477
|
onChange(valueString, newValue);
|
|
1465
1478
|
}
|
|
@@ -1494,7 +1507,7 @@ async function getCurrentTerm(ontologyStore, currentTermLabel, filterTerms, _sig
|
|
|
1494
1507
|
}
|
|
1495
1508
|
// TODO: support prefixed IDs as ontology terms here (e.g. SO:001234)
|
|
1496
1509
|
const terms = await ontologyStore.getTermsWithLabelOrSynonym(currentTermLabel, { includeSubclasses: false });
|
|
1497
|
-
const term = terms.find(filterTerms ?? (() => true));
|
|
1510
|
+
const term = terms.find((term) => (filterTerms ?? (() => true))(term));
|
|
1498
1511
|
if (!term) {
|
|
1499
1512
|
throw new Error(`not a valid ${ontologyStore.ontologyName} term`);
|
|
1500
1513
|
}
|
|
@@ -1576,7 +1589,7 @@ function AddChildFeature({ changeManager, handleClose, session, sourceAssemblyId
|
|
|
1576
1589
|
React__default["default"].createElement(material.DialogContentText, { color: "error" }, errorMessage))) : null));
|
|
1577
1590
|
}
|
|
1578
1591
|
|
|
1579
|
-
/* eslint-disable @typescript-eslint/
|
|
1592
|
+
/* eslint-disable @typescript-eslint/unbound-method */
|
|
1580
1593
|
function AddFeature({ changeManager, handleClose, region, session, }) {
|
|
1581
1594
|
const { notify } = session;
|
|
1582
1595
|
const [end, setEnd] = React.useState(String(region.end));
|
|
@@ -1636,7 +1649,6 @@ function AddFeature({ changeManager, handleClose, region, session, }) {
|
|
|
1636
1649
|
break;
|
|
1637
1650
|
}
|
|
1638
1651
|
default: {
|
|
1639
|
-
// eslint-disable-next-line unicorn/no-useless-undefined
|
|
1640
1652
|
setStrand(undefined);
|
|
1641
1653
|
}
|
|
1642
1654
|
}
|
|
@@ -1851,7 +1863,7 @@ function CopyFeature({ changeManager, handleClose, session, sourceAssemblyId, so
|
|
|
1851
1863
|
React__default["default"].createElement(material.DialogContentText, { color: "error" }, errorMessage))) : null));
|
|
1852
1864
|
}
|
|
1853
1865
|
|
|
1854
|
-
/* eslint-disable @typescript-eslint/
|
|
1866
|
+
/* eslint-disable @typescript-eslint/unbound-method */
|
|
1855
1867
|
function DeleteAssembly({ changeManager, handleClose, session, }) {
|
|
1856
1868
|
const { internetAccounts } = mobxStateTree.getRoot(session);
|
|
1857
1869
|
const [selectedAssembly, setSelectedAssembly] = React.useState();
|
|
@@ -2234,6 +2246,7 @@ function ImportFeatures({ changeManager, handleClose, session, }) {
|
|
|
2234
2246
|
React__default["default"].createElement(material.DialogContentText, { color: "error" }, errorMessage))) : null));
|
|
2235
2247
|
}
|
|
2236
2248
|
|
|
2249
|
+
/* eslint-disable @typescript-eslint/unbound-method */
|
|
2237
2250
|
function LogOut({ handleClose, session }) {
|
|
2238
2251
|
const { internetAccounts } = mobxStateTree.getRoot(session);
|
|
2239
2252
|
const [errorMessage, setErrorMessage] = React.useState('');
|
|
@@ -2253,7 +2266,7 @@ function LogOut({ handleClose, session }) {
|
|
|
2253
2266
|
event.preventDefault();
|
|
2254
2267
|
setErrorMessage('');
|
|
2255
2268
|
selectedInternetAccount.removeToken();
|
|
2256
|
-
|
|
2269
|
+
globalThis.location.reload();
|
|
2257
2270
|
}
|
|
2258
2271
|
return (React__default["default"].createElement(Dialog, { open: true, title: "Log out", handleClose: handleClose, maxWidth: false, "data-testid": "log-out" },
|
|
2259
2272
|
React__default["default"].createElement("form", { onSubmit: onSubmit },
|
|
@@ -2374,7 +2387,7 @@ function ManageChecks({ handleClose, session }) {
|
|
|
2374
2387
|
}
|
|
2375
2388
|
else {
|
|
2376
2389
|
const index = checks.indexOf(_id, 0);
|
|
2377
|
-
if (index
|
|
2390
|
+
if (index !== -1) {
|
|
2378
2391
|
checks.splice(index, 1);
|
|
2379
2392
|
}
|
|
2380
2393
|
setSelectedChecks(checks);
|
|
@@ -2415,7 +2428,7 @@ function ManageChecks({ handleClose, session }) {
|
|
|
2415
2428
|
React__default["default"].createElement(material.DialogContentText, { color: "error" }, errorMessage))) : null));
|
|
2416
2429
|
}
|
|
2417
2430
|
|
|
2418
|
-
/* eslint-disable @typescript-eslint/
|
|
2431
|
+
/* eslint-disable @typescript-eslint/unbound-method */
|
|
2419
2432
|
function ManageUsers({ changeManager, handleClose, session, }) {
|
|
2420
2433
|
const { internetAccounts } = mobxStateTree.getRoot(session);
|
|
2421
2434
|
const apolloInternetAccounts = internetAccounts.filter((ia) => ia.type === 'ApolloInternetAccount' && ia.role?.includes('admin'));
|
|
@@ -2499,7 +2512,7 @@ function ManageUsers({ changeManager, handleClose, session, }) {
|
|
|
2499
2512
|
type: 'actions',
|
|
2500
2513
|
getActions: (params) => [
|
|
2501
2514
|
React__default["default"].createElement(xDataGrid.GridActionsCellItem, { key: `delete-${params.id}`, icon: React__default["default"].createElement(DeleteIcon__default["default"], null), onClick: async () => {
|
|
2502
|
-
if (
|
|
2515
|
+
if (globalThis.confirm('Delete this user?')) {
|
|
2503
2516
|
await deleteUser(params.id);
|
|
2504
2517
|
}
|
|
2505
2518
|
}, disabled: isCurrentUser(params.id), label: "Delete" }),
|
|
@@ -2539,7 +2552,7 @@ function ManageUsers({ changeManager, handleClose, session, }) {
|
|
|
2539
2552
|
React__default["default"].createElement(material.DialogContentText, { color: "error" }, errorMessage))) : null));
|
|
2540
2553
|
}
|
|
2541
2554
|
|
|
2542
|
-
/* eslint-disable @typescript-eslint/
|
|
2555
|
+
/* eslint-disable @typescript-eslint/unbound-method */
|
|
2543
2556
|
// interface TermAutocompleteResult extends TermValue {
|
|
2544
2557
|
// label: string[]
|
|
2545
2558
|
// match: string
|
|
@@ -2625,7 +2638,7 @@ function OntologyTermMultiSelect({ includeDeprecated, onChange, ontologyName, on
|
|
|
2625
2638
|
callback(options);
|
|
2626
2639
|
}
|
|
2627
2640
|
catch (error) {
|
|
2628
|
-
if (!
|
|
2641
|
+
if (!aborting.isAbortException(error)) {
|
|
2629
2642
|
setErrorMessage(String(error));
|
|
2630
2643
|
}
|
|
2631
2644
|
}
|
|
@@ -2951,7 +2964,7 @@ function ModifyFeatureAttribute({ changeManager, handleClose, session, sourceAss
|
|
|
2951
2964
|
React__default["default"].createElement(material.Button, { variant: "outlined", type: "submit", disabled: showAddNewForm, onClick: handleClose }, "Cancel")))));
|
|
2952
2965
|
}
|
|
2953
2966
|
|
|
2954
|
-
/* eslint-disable @typescript-eslint/no-
|
|
2967
|
+
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
|
2955
2968
|
function OpenLocalFile({ handleClose, session }) {
|
|
2956
2969
|
const { apolloDataStore } = session;
|
|
2957
2970
|
const { addAssembly, addSessionAssembly, assemblyManager, notify } = session;
|
|
@@ -3047,7 +3060,7 @@ function OpenLocalFile({ handleClose, session }) {
|
|
|
3047
3060
|
React__default["default"].createElement(material.DialogContentText, { color: "error" }, errorMessage))) : null));
|
|
3048
3061
|
}
|
|
3049
3062
|
|
|
3050
|
-
/* eslint-disable @typescript-eslint/
|
|
3063
|
+
/* eslint-disable @typescript-eslint/unbound-method */
|
|
3051
3064
|
const useStyles$d = mui.makeStyles()((theme) => ({
|
|
3052
3065
|
changeTextarea: {
|
|
3053
3066
|
fontFamily: 'monospace',
|
|
@@ -3571,7 +3584,9 @@ const AuthTypeSelector = ({ baseURL, handleClose, name, }) => {
|
|
|
3571
3584
|
setLoginTypes(data);
|
|
3572
3585
|
}
|
|
3573
3586
|
getAuthTypes().catch((error) => {
|
|
3574
|
-
|
|
3587
|
+
if (!aborting.isAbortException(error)) {
|
|
3588
|
+
setErrorMessage(String(error));
|
|
3589
|
+
}
|
|
3575
3590
|
});
|
|
3576
3591
|
return () => {
|
|
3577
3592
|
controller.abort();
|
|
@@ -3694,7 +3709,7 @@ const stateModelFactory$2 = (configSchema) => {
|
|
|
3694
3709
|
async openAuthWindow(type, resolve, reject) {
|
|
3695
3710
|
const redirectUri = util.isElectron
|
|
3696
3711
|
? 'http://localhost/auth'
|
|
3697
|
-
:
|
|
3712
|
+
: globalThis.location.origin + globalThis.location.pathname;
|
|
3698
3713
|
const url = new URL('auth/login', self.baseURL);
|
|
3699
3714
|
const params = new URLSearchParams({
|
|
3700
3715
|
type,
|
|
@@ -3703,7 +3718,7 @@ const stateModelFactory$2 = (configSchema) => {
|
|
|
3703
3718
|
url.search = params.toString();
|
|
3704
3719
|
const eventName = `JBrowseAuthWindow-${self.internetAccountId}`;
|
|
3705
3720
|
if (util.isElectron) {
|
|
3706
|
-
const { ipcRenderer } =
|
|
3721
|
+
const { ipcRenderer } = globalThis.require('electron');
|
|
3707
3722
|
const redirectUriFromElectron = await ipcRenderer.invoke('openAuthWindow', {
|
|
3708
3723
|
internetAccountId: self.internetAccountId,
|
|
3709
3724
|
data: { redirect_uri: redirectUri },
|
|
@@ -3877,14 +3892,9 @@ const stateModelFactory$2 = (configSchema) => {
|
|
|
3877
3892
|
}
|
|
3878
3893
|
});
|
|
3879
3894
|
socket.on('REQUEST_INFORMATION', (message) => {
|
|
3880
|
-
const { channel,
|
|
3895
|
+
const { channel, userSessionId } = message;
|
|
3881
3896
|
if (channel === 'REQUEST_INFORMATION' && userSessionId !== token) {
|
|
3882
|
-
|
|
3883
|
-
case 'CURRENT_LOCATION': {
|
|
3884
|
-
session.broadcastLocations();
|
|
3885
|
-
break;
|
|
3886
|
-
}
|
|
3887
|
-
}
|
|
3897
|
+
session.broadcastLocations();
|
|
3888
3898
|
}
|
|
3889
3899
|
});
|
|
3890
3900
|
},
|
|
@@ -4556,7 +4566,6 @@ function ApolloRendering(props) {
|
|
|
4556
4566
|
}
|
|
4557
4567
|
await changeManager.submit(change);
|
|
4558
4568
|
}
|
|
4559
|
-
// eslint-disable-next-line unicorn/no-useless-undefined
|
|
4560
4569
|
setDragging(undefined);
|
|
4561
4570
|
setMovedDuringLastMouseDown(false);
|
|
4562
4571
|
}
|
|
@@ -4569,7 +4578,6 @@ function ApolloRendering(props) {
|
|
|
4569
4578
|
React__default["default"].createElement(material.Menu, { open: Boolean(contextMenuFeature), anchorReference: "anchorPosition", anchorPosition: contextCoord
|
|
4570
4579
|
? { left: contextCoord[0], top: contextCoord[1] }
|
|
4571
4580
|
: undefined, "data-testid": "base_linear_display_context_menu", onClose: () => {
|
|
4572
|
-
// eslint-disable-next-line unicorn/no-useless-undefined
|
|
4573
4581
|
setContextMenuFeature(undefined);
|
|
4574
4582
|
} },
|
|
4575
4583
|
React__default["default"].createElement(material.MenuItem, { disabled: isReadOnly, key: 1, value: 1, onClick: () => {
|
|
@@ -4583,7 +4591,6 @@ function ApolloRendering(props) {
|
|
|
4583
4591
|
session,
|
|
4584
4592
|
handleClose: () => {
|
|
4585
4593
|
doneCallback();
|
|
4586
|
-
// eslint-disable-next-line unicorn/no-useless-undefined
|
|
4587
4594
|
setContextMenuFeature(undefined);
|
|
4588
4595
|
},
|
|
4589
4596
|
changeManager,
|
|
@@ -4604,7 +4611,6 @@ function ApolloRendering(props) {
|
|
|
4604
4611
|
session,
|
|
4605
4612
|
handleClose: () => {
|
|
4606
4613
|
doneCallback();
|
|
4607
|
-
// eslint-disable-next-line unicorn/no-useless-undefined
|
|
4608
4614
|
setContextMenuFeature(undefined);
|
|
4609
4615
|
},
|
|
4610
4616
|
changeManager,
|
|
@@ -4624,7 +4630,6 @@ function ApolloRendering(props) {
|
|
|
4624
4630
|
session,
|
|
4625
4631
|
handleClose: () => {
|
|
4626
4632
|
doneCallback();
|
|
4627
|
-
// eslint-disable-next-line unicorn/no-useless-undefined
|
|
4628
4633
|
setContextMenuFeature(undefined);
|
|
4629
4634
|
},
|
|
4630
4635
|
changeManager,
|
|
@@ -4742,11 +4747,16 @@ function installApolloTextSearchAdapter(pluginManager) {
|
|
|
4742
4747
|
|
|
4743
4748
|
const ApolloPluginConfigurationSchema = configuration.ConfigurationSchema('ApolloPlugin', {
|
|
4744
4749
|
ontologies: mobxStateTree.types.array(OntologyRecordConfiguration),
|
|
4750
|
+
featureTypeOntologyName: {
|
|
4751
|
+
description: 'Name of the feature type ontology',
|
|
4752
|
+
type: 'string',
|
|
4753
|
+
defaultValue: 'Sequence Ontology',
|
|
4754
|
+
},
|
|
4745
4755
|
});
|
|
4746
4756
|
|
|
4747
4757
|
function parseCigar(cigar) {
|
|
4748
4758
|
return (cigar.toUpperCase().match(/\d+\D/g) ?? []).map((op) => {
|
|
4749
|
-
return [(
|
|
4759
|
+
return [(/\D/.exec(op) ?? [])[0], Number.parseInt(op, 10)];
|
|
4750
4760
|
});
|
|
4751
4761
|
}
|
|
4752
4762
|
function annotationFromPileup(pluggableElement) {
|
|
@@ -4918,7 +4928,7 @@ function annotationFromPileup(pluggableElement) {
|
|
|
4918
4928
|
return pluggableElement;
|
|
4919
4929
|
}
|
|
4920
4930
|
|
|
4921
|
-
/* eslint-disable @typescript-eslint/
|
|
4931
|
+
/* eslint-disable @typescript-eslint/unbound-method */
|
|
4922
4932
|
const StringTextField = mobxReact.observer(function StringTextField({ onChangeCommitted, value: initialValue, ...props }) {
|
|
4923
4933
|
const [value, setValue] = React.useState(String(initialValue));
|
|
4924
4934
|
const [blur, setBlur] = React.useState(false);
|
|
@@ -5123,7 +5133,7 @@ const Attributes = mobxReact.observer(function Attributes({ assembly, editable,
|
|
|
5123
5133
|
}
|
|
5124
5134
|
}
|
|
5125
5135
|
return (React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
5126
|
-
React__default["default"].createElement(material.Typography, {
|
|
5136
|
+
React__default["default"].createElement(material.Typography, { variant: "h5" }, "Attributes"),
|
|
5127
5137
|
React__default["default"].createElement(material.Grid, { container: true, direction: "column", spacing: 1 },
|
|
5128
5138
|
Object.entries(attributes).map(([key, value]) => {
|
|
5129
5139
|
if (key === '') {
|
|
@@ -5172,7 +5182,7 @@ const Attributes = mobxReact.observer(function Attributes({ assembly, editable,
|
|
|
5172
5182
|
errorMessage ? (React__default["default"].createElement(material.Typography, { color: "error" }, errorMessage)) : null));
|
|
5173
5183
|
});
|
|
5174
5184
|
|
|
5175
|
-
/* eslint-disable @typescript-eslint/
|
|
5185
|
+
/* eslint-disable @typescript-eslint/unbound-method */
|
|
5176
5186
|
const NumberTextField = mobxReact.observer(function NumberTextField({ onChangeCommitted, value: initialValue, ...props }) {
|
|
5177
5187
|
const [value, setValue] = React.useState(String(initialValue));
|
|
5178
5188
|
const [blur, setBlur] = React.useState(false);
|
|
@@ -5299,7 +5309,7 @@ const BasicInformation = mobxReact.observer(function BasicInformation({ assembly
|
|
|
5299
5309
|
errorMessage ? (React__default["default"].createElement(material.Typography, { color: "error" }, errorMessage)) : null));
|
|
5300
5310
|
});
|
|
5301
5311
|
|
|
5302
|
-
function formatSequence
|
|
5312
|
+
function formatSequence(seq, refName, start, end, wrap) {
|
|
5303
5313
|
const header = `>${refName}:${start + 1}–${end}\n`;
|
|
5304
5314
|
const body = wrap === undefined ? seq : shared.splitStringIntoChunks(seq, wrap).join('\n');
|
|
5305
5315
|
return `${header}${body}`;
|
|
@@ -5329,7 +5339,7 @@ const Sequence = mobxReact.observer(function Sequence({ assembly, feature, refNa
|
|
|
5329
5339
|
if (showSequence) {
|
|
5330
5340
|
sequence = refSeq.getSequence(min, max);
|
|
5331
5341
|
if (sequence) {
|
|
5332
|
-
sequence = formatSequence
|
|
5342
|
+
sequence = formatSequence(sequence, refName, min, max);
|
|
5333
5343
|
}
|
|
5334
5344
|
else {
|
|
5335
5345
|
void session.apolloDataStore.loadRefSeq([
|
|
@@ -5469,383 +5479,219 @@ const ApolloTranscriptDetailsModel = mobxStateTree.types
|
|
|
5469
5479
|
},
|
|
5470
5480
|
}));
|
|
5471
5481
|
|
|
5472
|
-
/**
|
|
5473
|
-
* Get single feature by featureId
|
|
5474
|
-
* @param feature -
|
|
5475
|
-
* @param featureId -
|
|
5476
|
-
* @returns
|
|
5477
|
-
*/
|
|
5478
|
-
function getFeatureFromId(feature, featureId) {
|
|
5479
|
-
if (feature._id === featureId) {
|
|
5480
|
-
return feature;
|
|
5481
|
-
}
|
|
5482
|
-
// Check if there is also childFeatures in parent feature and it's not empty
|
|
5483
|
-
// Let's get featureId from recursive method
|
|
5484
|
-
if (!feature.children) {
|
|
5485
|
-
return;
|
|
5486
|
-
}
|
|
5487
|
-
for (const [, childFeature] of feature.children) {
|
|
5488
|
-
const subFeature = getFeatureFromId(childFeature, featureId);
|
|
5489
|
-
if (subFeature) {
|
|
5490
|
-
return subFeature;
|
|
5491
|
-
}
|
|
5492
|
-
}
|
|
5493
|
-
return;
|
|
5494
|
-
}
|
|
5495
|
-
function findExonInRange(exons, pairStart, pairEnd) {
|
|
5496
|
-
for (const exon of exons) {
|
|
5497
|
-
if (Number(exon.min) <= pairStart && Number(exon.max) >= pairEnd) {
|
|
5498
|
-
return exon;
|
|
5499
|
-
}
|
|
5500
|
-
}
|
|
5501
|
-
return null;
|
|
5502
|
-
}
|
|
5503
|
-
function removeMatchingExon(exons, matchStart, matchEnd) {
|
|
5504
|
-
// Filter the array to remove elements matching the specified start and end
|
|
5505
|
-
return exons.filter((exon) => !(exon.min === matchStart && exon.max === matchEnd));
|
|
5506
|
-
}
|
|
5507
5482
|
const TranscriptBasicInformation = mobxReact.observer(function TranscriptBasicInformation({ assembly, feature, refName, session, }) {
|
|
5508
5483
|
const { notify } = session;
|
|
5509
5484
|
const currentAssembly = session.apolloDataStore.assemblies.get(assembly);
|
|
5510
5485
|
const refData = currentAssembly?.getByRefName(refName);
|
|
5511
5486
|
const { changeManager } = session.apolloDataStore;
|
|
5512
|
-
|
|
5513
|
-
|
|
5514
|
-
|
|
5515
|
-
|
|
5516
|
-
notify('Feature start cannot be less than parent starts', 'error');
|
|
5517
|
-
return;
|
|
5518
|
-
}
|
|
5519
|
-
const subFeature = getFeatureFromId(feature, featureId);
|
|
5520
|
-
if (!subFeature?.children) {
|
|
5521
|
-
return;
|
|
5487
|
+
const theme = material.useTheme();
|
|
5488
|
+
function handleLocationChange(oldLocation, newLocation, feature, isMin) {
|
|
5489
|
+
if (!feature.children) {
|
|
5490
|
+
throw new Error('Transcript should have child features');
|
|
5522
5491
|
}
|
|
5523
|
-
|
|
5524
|
-
|
|
5525
|
-
if ((child[1].type === 'CDS' || child[1].type === 'exon') &&
|
|
5526
|
-
child[1].min === oldStart) {
|
|
5492
|
+
for (const [, child] of feature.children) {
|
|
5493
|
+
if (isMin && oldLocation - 1 === child.min) {
|
|
5527
5494
|
const change = new shared.LocationStartChange({
|
|
5528
5495
|
typeName: 'LocationStartChange',
|
|
5529
|
-
changedIds: [child
|
|
5530
|
-
featureId,
|
|
5531
|
-
oldStart,
|
|
5532
|
-
newStart,
|
|
5496
|
+
changedIds: [child._id],
|
|
5497
|
+
featureId: feature._id,
|
|
5498
|
+
oldStart: oldLocation - 1,
|
|
5499
|
+
newStart: newLocation - 1,
|
|
5533
5500
|
assembly,
|
|
5534
5501
|
});
|
|
5535
5502
|
changeManager.submit(change).catch(() => {
|
|
5536
5503
|
notify('Error updating feature start position', 'error');
|
|
5537
5504
|
});
|
|
5505
|
+
return;
|
|
5538
5506
|
}
|
|
5539
|
-
|
|
5540
|
-
return;
|
|
5541
|
-
}
|
|
5542
|
-
function handleEndChange(newEnd, featureId, oldEnd) {
|
|
5543
|
-
const subFeature = getFeatureFromId(feature, featureId);
|
|
5544
|
-
if (newEnd > feature.max) {
|
|
5545
|
-
notify('Feature start cannot be greater than parent end', 'error');
|
|
5546
|
-
return;
|
|
5547
|
-
}
|
|
5548
|
-
if (!subFeature?.children) {
|
|
5549
|
-
return;
|
|
5550
|
-
}
|
|
5551
|
-
// Let's check CDS start and end values. And possibly update those too
|
|
5552
|
-
for (const child of subFeature.children) {
|
|
5553
|
-
if ((child[1].type === 'CDS' || child[1].type === 'exon') &&
|
|
5554
|
-
child[1].max === oldEnd) {
|
|
5507
|
+
if (!isMin && newLocation === child.max) {
|
|
5555
5508
|
const change = new shared.LocationEndChange({
|
|
5556
5509
|
typeName: 'LocationEndChange',
|
|
5557
|
-
changedIds: [child
|
|
5558
|
-
featureId,
|
|
5559
|
-
oldEnd,
|
|
5560
|
-
newEnd,
|
|
5510
|
+
changedIds: [child._id],
|
|
5511
|
+
featureId: feature._id,
|
|
5512
|
+
oldEnd: child.max,
|
|
5513
|
+
newEnd: newLocation,
|
|
5561
5514
|
assembly,
|
|
5562
5515
|
});
|
|
5563
5516
|
changeManager.submit(change).catch(() => {
|
|
5564
|
-
notify('Error updating feature
|
|
5517
|
+
notify('Error updating feature start position', 'error');
|
|
5565
5518
|
});
|
|
5519
|
+
return;
|
|
5566
5520
|
}
|
|
5567
5521
|
}
|
|
5568
|
-
return;
|
|
5569
5522
|
}
|
|
5570
|
-
|
|
5571
|
-
|
|
5572
|
-
const traverse = (currentFeature) => {
|
|
5573
|
-
if (currentFeature.type === 'exon') {
|
|
5574
|
-
exonsArray.push({
|
|
5575
|
-
min: currentFeature.min + 1,
|
|
5576
|
-
max: currentFeature.max,
|
|
5577
|
-
});
|
|
5578
|
-
}
|
|
5579
|
-
if (currentFeature.children) {
|
|
5580
|
-
for (const child of currentFeature.children) {
|
|
5581
|
-
traverse(child[1]);
|
|
5582
|
-
}
|
|
5583
|
-
}
|
|
5584
|
-
};
|
|
5585
|
-
traverse(featureNew);
|
|
5586
|
-
const CDSresult = [];
|
|
5587
|
-
const CDSData = featureNew.cdsLocations;
|
|
5588
|
-
if (refData) {
|
|
5589
|
-
for (const CDSDatum of CDSData) {
|
|
5590
|
-
for (const dataPoint of CDSDatum) {
|
|
5591
|
-
let startSeq = refData.getSequence(Number(dataPoint.min) - 2, Number(dataPoint.min));
|
|
5592
|
-
let endSeq = refData.getSequence(Number(dataPoint.max), Number(dataPoint.max) + 2);
|
|
5593
|
-
if (featureNew.strand === -1 && startSeq && endSeq) {
|
|
5594
|
-
startSeq = util.revcom(startSeq);
|
|
5595
|
-
endSeq = util.revcom(endSeq);
|
|
5596
|
-
}
|
|
5597
|
-
const oneCDS = {
|
|
5598
|
-
id: featureNew._id,
|
|
5599
|
-
type: 'CDS',
|
|
5600
|
-
strand: Number(featureNew.strand),
|
|
5601
|
-
min: dataPoint.min + 1,
|
|
5602
|
-
max: dataPoint.max,
|
|
5603
|
-
oldMin: dataPoint.min + 1,
|
|
5604
|
-
oldMax: dataPoint.max,
|
|
5605
|
-
startSeq,
|
|
5606
|
-
endSeq,
|
|
5607
|
-
};
|
|
5608
|
-
// CDSresult.push(oneCDS)
|
|
5609
|
-
// Check if there is already an object with the same start and end
|
|
5610
|
-
const exists = CDSresult.some((obj) => obj.min === oneCDS.min &&
|
|
5611
|
-
obj.max === oneCDS.max &&
|
|
5612
|
-
obj.type === oneCDS.type);
|
|
5613
|
-
// If no such object exists, add the new object to the array
|
|
5614
|
-
if (!exists) {
|
|
5615
|
-
CDSresult.push(oneCDS);
|
|
5616
|
-
}
|
|
5617
|
-
// Add possible UTRs
|
|
5618
|
-
const foundExon = findExonInRange(exonsArray, dataPoint.min + 1, dataPoint.max);
|
|
5619
|
-
if (foundExon && Number(foundExon.min) < dataPoint.min) {
|
|
5620
|
-
if (feature.strand === 1) {
|
|
5621
|
-
const oneCDS = {
|
|
5622
|
-
id: feature._id,
|
|
5623
|
-
type: 'five_prime_UTR',
|
|
5624
|
-
strand: Number(feature.strand),
|
|
5625
|
-
min: foundExon.min,
|
|
5626
|
-
max: dataPoint.min,
|
|
5627
|
-
oldMin: foundExon.min,
|
|
5628
|
-
oldMax: dataPoint.min,
|
|
5629
|
-
startSeq: '',
|
|
5630
|
-
endSeq: '',
|
|
5631
|
-
};
|
|
5632
|
-
CDSresult.push(oneCDS);
|
|
5633
|
-
}
|
|
5634
|
-
else {
|
|
5635
|
-
const oneCDS = {
|
|
5636
|
-
id: feature._id,
|
|
5637
|
-
type: 'three_prime_UTR',
|
|
5638
|
-
strand: Number(feature.strand),
|
|
5639
|
-
min: dataPoint.min + 1,
|
|
5640
|
-
max: foundExon.min + 1,
|
|
5641
|
-
oldMin: dataPoint.min + 1,
|
|
5642
|
-
oldMax: foundExon.min + 1,
|
|
5643
|
-
startSeq: '',
|
|
5644
|
-
endSeq: '',
|
|
5645
|
-
};
|
|
5646
|
-
CDSresult.push(oneCDS);
|
|
5647
|
-
}
|
|
5648
|
-
exonsArray = removeMatchingExon(exonsArray, foundExon.min, foundExon.max);
|
|
5649
|
-
}
|
|
5650
|
-
if (foundExon && Number(foundExon.max) > dataPoint.max) {
|
|
5651
|
-
if (feature.strand === 1) {
|
|
5652
|
-
const oneCDS = {
|
|
5653
|
-
id: feature._id,
|
|
5654
|
-
type: 'three_prime_UTR',
|
|
5655
|
-
strand: Number(feature.strand),
|
|
5656
|
-
min: dataPoint.max + 1,
|
|
5657
|
-
max: foundExon.max,
|
|
5658
|
-
oldMin: dataPoint.max + 1,
|
|
5659
|
-
oldMax: foundExon.max,
|
|
5660
|
-
startSeq: '',
|
|
5661
|
-
endSeq: '',
|
|
5662
|
-
};
|
|
5663
|
-
CDSresult.push(oneCDS);
|
|
5664
|
-
}
|
|
5665
|
-
else {
|
|
5666
|
-
const oneCDS = {
|
|
5667
|
-
id: feature._id,
|
|
5668
|
-
type: 'five_prime_UTR',
|
|
5669
|
-
strand: Number(feature.strand),
|
|
5670
|
-
min: dataPoint.min + 1,
|
|
5671
|
-
max: foundExon.max,
|
|
5672
|
-
oldMin: dataPoint.min + 1,
|
|
5673
|
-
oldMax: foundExon.max,
|
|
5674
|
-
startSeq: '',
|
|
5675
|
-
endSeq: '',
|
|
5676
|
-
};
|
|
5677
|
-
CDSresult.push(oneCDS);
|
|
5678
|
-
}
|
|
5679
|
-
exonsArray = removeMatchingExon(exonsArray, foundExon.min, foundExon.max);
|
|
5680
|
-
}
|
|
5681
|
-
if (dataPoint.min + 1 === foundExon?.min &&
|
|
5682
|
-
dataPoint.max === foundExon.max) {
|
|
5683
|
-
exonsArray = removeMatchingExon(exonsArray, foundExon.min, foundExon.max);
|
|
5684
|
-
}
|
|
5685
|
-
}
|
|
5686
|
-
}
|
|
5687
|
-
}
|
|
5688
|
-
// Add remaining UTRs if any
|
|
5689
|
-
if (exonsArray.length > 0) {
|
|
5690
|
-
// eslint-disable-next-line unicorn/no-array-for-each
|
|
5691
|
-
exonsArray.forEach((element) => {
|
|
5692
|
-
if (featureNew.strand === 1) {
|
|
5693
|
-
const oneCDS = {
|
|
5694
|
-
id: featureNew._id,
|
|
5695
|
-
type: 'five_prime_UTR',
|
|
5696
|
-
strand: Number(featureNew.strand),
|
|
5697
|
-
min: element.min + 1,
|
|
5698
|
-
max: element.max,
|
|
5699
|
-
oldMin: element.min + 1,
|
|
5700
|
-
oldMax: element.max,
|
|
5701
|
-
startSeq: '',
|
|
5702
|
-
endSeq: '',
|
|
5703
|
-
};
|
|
5704
|
-
CDSresult.push(oneCDS);
|
|
5705
|
-
}
|
|
5706
|
-
else {
|
|
5707
|
-
const oneCDS = {
|
|
5708
|
-
id: featureNew._id,
|
|
5709
|
-
type: 'three_prime_UTR',
|
|
5710
|
-
strand: Number(featureNew.strand),
|
|
5711
|
-
min: element.min + 1,
|
|
5712
|
-
max: element.max + 1,
|
|
5713
|
-
oldMin: element.min + 1,
|
|
5714
|
-
oldMax: element.max + 1,
|
|
5715
|
-
startSeq: '',
|
|
5716
|
-
endSeq: '',
|
|
5717
|
-
};
|
|
5718
|
-
CDSresult.push(oneCDS);
|
|
5719
|
-
}
|
|
5720
|
-
exonsArray = removeMatchingExon(exonsArray, element.min, element.max);
|
|
5721
|
-
});
|
|
5523
|
+
if (!refData) {
|
|
5524
|
+
return null;
|
|
5722
5525
|
}
|
|
5723
|
-
|
|
5724
|
-
|
|
5725
|
-
|
|
5726
|
-
|
|
5727
|
-
|
|
5728
|
-
|
|
5729
|
-
|
|
5730
|
-
|
|
5731
|
-
|
|
5732
|
-
|
|
5733
|
-
|
|
5734
|
-
|
|
5735
|
-
|
|
5736
|
-
|
|
5737
|
-
|
|
5738
|
-
|
|
5739
|
-
|
|
5526
|
+
const { strand, transcriptParts } = feature;
|
|
5527
|
+
const [firstLocation] = transcriptParts;
|
|
5528
|
+
const locationData = firstLocation
|
|
5529
|
+
.map((loc, idx) => {
|
|
5530
|
+
const { max, min, type } = loc;
|
|
5531
|
+
let label = type;
|
|
5532
|
+
if (label === 'threePrimeUTR') {
|
|
5533
|
+
label = '3` UTR';
|
|
5534
|
+
}
|
|
5535
|
+
else if (label === 'fivePrimeUTR') {
|
|
5536
|
+
label = '5` UTR';
|
|
5537
|
+
}
|
|
5538
|
+
let fivePrimeSpliceSite;
|
|
5539
|
+
let threePrimeSpliceSite;
|
|
5540
|
+
let frameColor;
|
|
5541
|
+
if (type === 'CDS') {
|
|
5542
|
+
const { phase } = loc;
|
|
5543
|
+
const frame = util.getFrame(min, max, strand ?? 1, phase);
|
|
5544
|
+
frameColor = theme.palette.framesCDS.at(frame)?.main;
|
|
5545
|
+
const previousLoc = firstLocation.at(idx - 1);
|
|
5546
|
+
const nextLoc = firstLocation.at(idx + 1);
|
|
5547
|
+
if (strand === 1) {
|
|
5548
|
+
if (previousLoc?.type === 'intron') {
|
|
5549
|
+
fivePrimeSpliceSite = refData.getSequence(min - 2, min);
|
|
5550
|
+
}
|
|
5551
|
+
if (nextLoc?.type === 'intron') {
|
|
5552
|
+
threePrimeSpliceSite = refData.getSequence(max, max + 2);
|
|
5553
|
+
}
|
|
5740
5554
|
}
|
|
5741
|
-
|
|
5742
|
-
|
|
5743
|
-
|
|
5744
|
-
|
|
5555
|
+
else {
|
|
5556
|
+
if (previousLoc?.type === 'intron') {
|
|
5557
|
+
fivePrimeSpliceSite = util.revcom(refData.getSequence(max, max + 2));
|
|
5558
|
+
}
|
|
5559
|
+
if (nextLoc?.type === 'intron') {
|
|
5560
|
+
threePrimeSpliceSite = util.revcom(refData.getSequence(min - 2, min));
|
|
5561
|
+
}
|
|
5745
5562
|
}
|
|
5746
5563
|
}
|
|
5747
|
-
|
|
5748
|
-
|
|
5564
|
+
return {
|
|
5565
|
+
min,
|
|
5566
|
+
max,
|
|
5567
|
+
label,
|
|
5568
|
+
fivePrimeSpliceSite,
|
|
5569
|
+
threePrimeSpliceSite,
|
|
5570
|
+
frameColor,
|
|
5571
|
+
};
|
|
5572
|
+
})
|
|
5573
|
+
.filter((loc) => loc.label !== 'intron');
|
|
5749
5574
|
return (React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
5750
|
-
React__default["default"].createElement(material.Typography, { variant: "h5"
|
|
5751
|
-
React__default["default"].createElement(
|
|
5752
|
-
|
|
5753
|
-
|
|
5754
|
-
|
|
5755
|
-
|
|
5756
|
-
|
|
5757
|
-
|
|
5758
|
-
|
|
5759
|
-
|
|
5760
|
-
|
|
5761
|
-
|
|
5762
|
-
|
|
5763
|
-
|
|
5764
|
-
:
|
|
5765
|
-
|
|
5766
|
-
|
|
5767
|
-
|
|
5768
|
-
|
|
5769
|
-
|
|
5770
|
-
width: '150px',
|
|
5771
|
-
backgroundColor: item.endSeq.trim() === '' &&
|
|
5772
|
-
index + 1 !== transcriptItems.length
|
|
5773
|
-
? 'lightblue'
|
|
5774
|
-
: 'inherit',
|
|
5775
|
-
}, variant: "outlined", value: item.max, onChangeCommitted: (newEnd) => {
|
|
5776
|
-
handleEndChange(newEnd, item.id, Number(item.oldMax));
|
|
5777
|
-
} }),
|
|
5778
|
-
React__default["default"].createElement("span", { style: { marginLeft: '8px', fontWeight: 'bold' } }, item.endSeq)))))));
|
|
5575
|
+
React__default["default"].createElement(material.Typography, { variant: "h5" }, "Structure"),
|
|
5576
|
+
React__default["default"].createElement(material.Typography, { variant: "h6" },
|
|
5577
|
+
strand === 1 ? 'Forward' : 'Reverse',
|
|
5578
|
+
" strand"),
|
|
5579
|
+
React__default["default"].createElement(material.TableContainer, { component: material.Paper },
|
|
5580
|
+
React__default["default"].createElement(material.Table, { size: "small" },
|
|
5581
|
+
React__default["default"].createElement(material.TableBody, null, locationData.map((loc) => (React__default["default"].createElement(material.TableRow, { key: `${loc.label}:${loc.min}-${loc.max}` },
|
|
5582
|
+
React__default["default"].createElement(material.TableCell, { component: "th", scope: "row", style: { background: loc.frameColor } }, loc.label),
|
|
5583
|
+
React__default["default"].createElement(material.TableCell, null, loc.fivePrimeSpliceSite ?? ''),
|
|
5584
|
+
React__default["default"].createElement(material.TableCell, { padding: "none" },
|
|
5585
|
+
React__default["default"].createElement(NumberTextField, { margin: "dense", variant: "outlined", value: strand === 1 ? loc.min + 1 : loc.max, onChangeCommitted: (newLocation) => {
|
|
5586
|
+
handleLocationChange(strand === 1 ? loc.min + 1 : loc.max, newLocation, feature, strand === 1);
|
|
5587
|
+
} })),
|
|
5588
|
+
React__default["default"].createElement(material.TableCell, { padding: "none" },
|
|
5589
|
+
React__default["default"].createElement(NumberTextField, { margin: "dense",
|
|
5590
|
+
// disabled={item.type !== 'CDS'}
|
|
5591
|
+
variant: "outlined", value: strand === 1 ? loc.max : loc.min + 1, onChangeCommitted: (newLocation) => {
|
|
5592
|
+
handleLocationChange(strand === 1 ? loc.max : loc.min + 1, newLocation, feature, strand !== 1);
|
|
5593
|
+
} })),
|
|
5594
|
+
React__default["default"].createElement(material.TableCell, null, loc.threePrimeSpliceSite ?? '')))))))));
|
|
5779
5595
|
});
|
|
5780
5596
|
|
|
5781
|
-
const
|
|
5782
|
-
|
|
5783
|
-
const
|
|
5784
|
-
|
|
5785
|
-
|
|
5786
|
-
|
|
5787
|
-
|
|
5788
|
-
|
|
5789
|
-
|
|
5790
|
-
|
|
5791
|
-
|
|
5792
|
-
|
|
5793
|
-
|
|
5794
|
-
|
|
5795
|
-
|
|
5796
|
-
|
|
5797
|
-
|
|
5798
|
-
|
|
5799
|
-
|
|
5800
|
-
|
|
5801
|
-
|
|
5802
|
-
|
|
5803
|
-
|
|
5804
|
-
|
|
5805
|
-
|
|
5806
|
-
|
|
5807
|
-
|
|
5808
|
-
|
|
5809
|
-
|
|
5597
|
+
const SEQUENCE_WRAP_LENGTH = 60;
|
|
5598
|
+
function getSequenceSegments(segmentType, feature, getSequence) {
|
|
5599
|
+
const segments = [];
|
|
5600
|
+
const { cdsLocations, strand, transcriptParts } = feature;
|
|
5601
|
+
switch (segmentType) {
|
|
5602
|
+
case 'genomic':
|
|
5603
|
+
case 'cDNA': {
|
|
5604
|
+
const [firstLocation] = transcriptParts;
|
|
5605
|
+
for (const loc of firstLocation) {
|
|
5606
|
+
if (segmentType === 'cDNA' && loc.type === 'intron') {
|
|
5607
|
+
continue;
|
|
5608
|
+
}
|
|
5609
|
+
let sequence = getSequence(loc.min, loc.max);
|
|
5610
|
+
if (strand === -1) {
|
|
5611
|
+
sequence = util.revcom(sequence);
|
|
5612
|
+
}
|
|
5613
|
+
const type = loc.type === 'fivePrimeUTR' || loc.type === 'threePrimeUTR'
|
|
5614
|
+
? 'UTR'
|
|
5615
|
+
: loc.type;
|
|
5616
|
+
const previousSegment = segments.at(-1);
|
|
5617
|
+
if (!previousSegment) {
|
|
5618
|
+
const sequenceLines = shared.splitStringIntoChunks(sequence, SEQUENCE_WRAP_LENGTH);
|
|
5619
|
+
segments.push({
|
|
5620
|
+
type,
|
|
5621
|
+
sequenceLines,
|
|
5622
|
+
locs: [{ min: loc.min, max: loc.max }],
|
|
5623
|
+
});
|
|
5624
|
+
continue;
|
|
5625
|
+
}
|
|
5626
|
+
if (previousSegment.type === type) {
|
|
5627
|
+
const [previousSegmentFirstLine, ...previousSegmentFollowingLines] = previousSegment.sequenceLines;
|
|
5628
|
+
const newSequence = previousSegmentFollowingLines.join('') + sequence;
|
|
5629
|
+
previousSegment.sequenceLines = [
|
|
5630
|
+
previousSegmentFirstLine,
|
|
5631
|
+
...shared.splitStringIntoChunks(newSequence, SEQUENCE_WRAP_LENGTH),
|
|
5632
|
+
];
|
|
5633
|
+
previousSegment.locs.push({ min: loc.min, max: loc.max });
|
|
5634
|
+
}
|
|
5635
|
+
else {
|
|
5636
|
+
const count = segments.reduce((accumulator, currentSegment) => accumulator +
|
|
5637
|
+
currentSegment.sequenceLines.reduce((subAccumulator, currentLine) => subAccumulator + currentLine.length, 0), 0);
|
|
5638
|
+
const previousLineLength = count % SEQUENCE_WRAP_LENGTH;
|
|
5639
|
+
const newSegmentFirstLineLength = SEQUENCE_WRAP_LENGTH - previousLineLength;
|
|
5640
|
+
const newSegmentFirstLine = sequence.slice(0, newSegmentFirstLineLength);
|
|
5641
|
+
const newSegmentRemainderLines = shared.splitStringIntoChunks(sequence.slice(newSegmentFirstLineLength), SEQUENCE_WRAP_LENGTH);
|
|
5642
|
+
segments.push({
|
|
5643
|
+
type,
|
|
5644
|
+
sequenceLines: [newSegmentFirstLine, ...newSegmentRemainderLines],
|
|
5645
|
+
locs: [{ min: loc.min, max: loc.max }],
|
|
5646
|
+
});
|
|
5647
|
+
}
|
|
5810
5648
|
}
|
|
5649
|
+
return segments;
|
|
5811
5650
|
}
|
|
5812
|
-
|
|
5813
|
-
|
|
5814
|
-
|
|
5815
|
-
|
|
5816
|
-
|
|
5817
|
-
|
|
5818
|
-
|
|
5819
|
-
|
|
5820
|
-
|
|
5821
|
-
|
|
5822
|
-
|
|
5823
|
-
if (i > 0 && CDSresult[i].min === CDSresult[i - 1].max) {
|
|
5824
|
-
// Clear "startSeq" if the current item's "start" is equal to the previous item's "end"
|
|
5825
|
-
CDSresult[i].startSeq = '';
|
|
5826
|
-
}
|
|
5827
|
-
if (i < CDSresult.length - 1 &&
|
|
5828
|
-
CDSresult[i].max === CDSresult[i + 1].min) {
|
|
5829
|
-
// Clear "endSeq" if the next item's "start" is equal to the current item's "end"
|
|
5830
|
-
CDSresult[i].endSeq = '';
|
|
5651
|
+
case 'CDS': {
|
|
5652
|
+
let wholeSequence = '';
|
|
5653
|
+
const [firstLocation] = cdsLocations;
|
|
5654
|
+
const locs = [];
|
|
5655
|
+
for (const loc of firstLocation) {
|
|
5656
|
+
let sequence = getSequence(loc.min, loc.max);
|
|
5657
|
+
if (strand === -1) {
|
|
5658
|
+
sequence = util.revcom(sequence);
|
|
5659
|
+
}
|
|
5660
|
+
wholeSequence += sequence;
|
|
5661
|
+
locs.push({ min: loc.min, max: loc.max });
|
|
5831
5662
|
}
|
|
5663
|
+
const sequenceLines = shared.splitStringIntoChunks(wholeSequence, SEQUENCE_WRAP_LENGTH);
|
|
5664
|
+
segments.push({ type: 'CDS', sequenceLines, locs });
|
|
5665
|
+
return segments;
|
|
5666
|
+
}
|
|
5667
|
+
}
|
|
5668
|
+
}
|
|
5669
|
+
function getSegmentColor(type) {
|
|
5670
|
+
switch (type) {
|
|
5671
|
+
case 'upOrDownstream': {
|
|
5672
|
+
return 'rgb(255,255,255)';
|
|
5673
|
+
}
|
|
5674
|
+
case 'UTR': {
|
|
5675
|
+
return 'rgb(194,106,119)';
|
|
5676
|
+
}
|
|
5677
|
+
case 'CDS': {
|
|
5678
|
+
return 'rgb(93,168,153)';
|
|
5679
|
+
}
|
|
5680
|
+
case 'intron': {
|
|
5681
|
+
return 'rgb(187,187,187)';
|
|
5682
|
+
}
|
|
5683
|
+
case 'protein': {
|
|
5684
|
+
return 'rgb(148,203,236)';
|
|
5832
5685
|
}
|
|
5833
5686
|
}
|
|
5834
|
-
return CDSresult;
|
|
5835
|
-
};
|
|
5836
|
-
function formatSequence(seq, refName, start, end, wrap) {
|
|
5837
|
-
const header = `>${refName}:${start + 1}–${end}\n`;
|
|
5838
|
-
const body = wrap === undefined ? seq : shared.splitStringIntoChunks(seq, wrap).join('\n');
|
|
5839
|
-
return `${header}${body}`;
|
|
5840
5687
|
}
|
|
5841
|
-
const utrColor = 'rgb(20,200,200)'; // Slightly brighter cyan
|
|
5842
|
-
const cdsColor = 'rgb(240,200,20)'; // Slightly brighter yellow
|
|
5843
|
-
let textSegments = [{ text: '', color: '' }];
|
|
5844
5688
|
const TranscriptSequence = mobxReact.observer(function TranscriptSequence({ assembly, feature, refName, session, }) {
|
|
5845
5689
|
const currentAssembly = session.apolloDataStore.assemblies.get(assembly);
|
|
5846
5690
|
const refData = currentAssembly?.getByRefName(refName);
|
|
5847
5691
|
const [showSequence, setShowSequence] = React.useState(false);
|
|
5848
|
-
const [selectedOption, setSelectedOption] = React.useState('
|
|
5692
|
+
const [selectedOption, setSelectedOption] = React.useState('CDS');
|
|
5693
|
+
const theme = material.useTheme();
|
|
5694
|
+
const seqRef = React.useRef(null);
|
|
5849
5695
|
if (!(currentAssembly && refData)) {
|
|
5850
5696
|
return null;
|
|
5851
5697
|
}
|
|
@@ -5853,150 +5699,85 @@ const TranscriptSequence = mobxReact.observer(function TranscriptSequence({ asse
|
|
|
5853
5699
|
if (!refSeq) {
|
|
5854
5700
|
return null;
|
|
5855
5701
|
}
|
|
5856
|
-
|
|
5857
|
-
|
|
5858
|
-
let sequence = '';
|
|
5859
|
-
if (showSequence) {
|
|
5860
|
-
getSequenceAsString(min, max);
|
|
5861
|
-
}
|
|
5862
|
-
function getSequenceAsString(start, end) {
|
|
5863
|
-
sequence = refSeq?.getSequence(start, end) ?? '';
|
|
5864
|
-
if (sequence === '') {
|
|
5865
|
-
void session.apolloDataStore.loadRefSeq([
|
|
5866
|
-
{ assemblyName: assembly, refName, start, end },
|
|
5867
|
-
]);
|
|
5868
|
-
}
|
|
5869
|
-
else {
|
|
5870
|
-
sequence = formatSequence(sequence, refName, start, end);
|
|
5871
|
-
}
|
|
5872
|
-
getSequenceAsTextSegment(selectedOption); // For color coded sequence
|
|
5873
|
-
return sequence;
|
|
5702
|
+
if (feature.type !== 'mRNA') {
|
|
5703
|
+
return null;
|
|
5874
5704
|
}
|
|
5875
5705
|
const handleSeqButtonClick = () => {
|
|
5876
5706
|
setShowSequence(!showSequence);
|
|
5877
5707
|
};
|
|
5878
|
-
function getSequenceAsTextSegment(option) {
|
|
5879
|
-
let seqData = '';
|
|
5880
|
-
textSegments = [];
|
|
5881
|
-
if (!refData) {
|
|
5882
|
-
return;
|
|
5883
|
-
}
|
|
5884
|
-
switch (option) {
|
|
5885
|
-
case 'CDS': {
|
|
5886
|
-
textSegments.push({ text: `>${refName} : CDS\n`, color: 'black' });
|
|
5887
|
-
for (const item of transcriptItems) {
|
|
5888
|
-
if (item.type === 'CDS') {
|
|
5889
|
-
const refSeq = refData.getSequence(Number(item.min + 1), Number(item.max));
|
|
5890
|
-
seqData += item.strand === -1 && refSeq ? util.revcom(refSeq) : refSeq;
|
|
5891
|
-
textSegments.push({ text: seqData, color: cdsColor });
|
|
5892
|
-
}
|
|
5893
|
-
}
|
|
5894
|
-
break;
|
|
5895
|
-
}
|
|
5896
|
-
case 'cDNA': {
|
|
5897
|
-
textSegments.push({ text: `>${refName} : cDNA\n`, color: 'black' });
|
|
5898
|
-
for (const item of transcriptItems) {
|
|
5899
|
-
if (item.type === 'CDS' ||
|
|
5900
|
-
item.type === 'three_prime_UTR' ||
|
|
5901
|
-
item.type === 'five_prime_UTR') {
|
|
5902
|
-
const refSeq = refData.getSequence(Number(item.min + 1), Number(item.max));
|
|
5903
|
-
seqData += item.strand === -1 && refSeq ? util.revcom(refSeq) : refSeq;
|
|
5904
|
-
if (item.type === 'CDS') {
|
|
5905
|
-
textSegments.push({ text: seqData, color: cdsColor });
|
|
5906
|
-
}
|
|
5907
|
-
else {
|
|
5908
|
-
textSegments.push({ text: seqData, color: utrColor });
|
|
5909
|
-
}
|
|
5910
|
-
}
|
|
5911
|
-
}
|
|
5912
|
-
break;
|
|
5913
|
-
}
|
|
5914
|
-
case 'Full': {
|
|
5915
|
-
textSegments.push({
|
|
5916
|
-
text: `>${refName} : Full genomic\n`,
|
|
5917
|
-
color: 'black',
|
|
5918
|
-
});
|
|
5919
|
-
let lastEnd = 0;
|
|
5920
|
-
let count = 0;
|
|
5921
|
-
for (const item of transcriptItems) {
|
|
5922
|
-
count++;
|
|
5923
|
-
if (lastEnd != 0 &&
|
|
5924
|
-
lastEnd != Number(item.min) &&
|
|
5925
|
-
count != transcriptItems.length) {
|
|
5926
|
-
// Intron etc. between CDS/UTRs. No need to check this on very last item
|
|
5927
|
-
const refSeq = refData.getSequence(lastEnd + 1, Number(item.min) - 1);
|
|
5928
|
-
seqData += item.strand === -1 && refSeq ? util.revcom(refSeq) : refSeq;
|
|
5929
|
-
textSegments.push({ text: seqData, color: 'black' });
|
|
5930
|
-
}
|
|
5931
|
-
if (item.type === 'CDS' ||
|
|
5932
|
-
item.type === 'three_prime_UTR' ||
|
|
5933
|
-
item.type === 'five_prime_UTR') {
|
|
5934
|
-
const refSeq = refData.getSequence(Number(item.min + 1), Number(item.max));
|
|
5935
|
-
seqData += item.strand === -1 && refSeq ? util.revcom(refSeq) : refSeq;
|
|
5936
|
-
switch (item.type) {
|
|
5937
|
-
case 'CDS': {
|
|
5938
|
-
textSegments.push({ text: seqData, color: cdsColor });
|
|
5939
|
-
break;
|
|
5940
|
-
}
|
|
5941
|
-
case 'three_prime_UTR': {
|
|
5942
|
-
textSegments.push({ text: seqData, color: utrColor });
|
|
5943
|
-
break;
|
|
5944
|
-
}
|
|
5945
|
-
case 'five_prime_UTR': {
|
|
5946
|
-
textSegments.push({ text: seqData, color: utrColor });
|
|
5947
|
-
break;
|
|
5948
|
-
}
|
|
5949
|
-
default: {
|
|
5950
|
-
textSegments.push({ text: seqData, color: 'black' });
|
|
5951
|
-
break;
|
|
5952
|
-
}
|
|
5953
|
-
}
|
|
5954
|
-
}
|
|
5955
|
-
lastEnd = Number(item.max);
|
|
5956
|
-
}
|
|
5957
|
-
break;
|
|
5958
|
-
}
|
|
5959
|
-
}
|
|
5960
|
-
}
|
|
5961
5708
|
function handleChangeSeqOption(e) {
|
|
5962
5709
|
const option = e.target.value;
|
|
5963
5710
|
setSelectedOption(option);
|
|
5964
|
-
getSequenceAsTextSegment(option);
|
|
5965
5711
|
}
|
|
5966
5712
|
// Function to copy text to clipboard
|
|
5967
5713
|
const copyToClipboard = () => {
|
|
5968
|
-
const
|
|
5969
|
-
if (
|
|
5970
|
-
|
|
5971
|
-
.writeText(textToCopy)
|
|
5972
|
-
.then(() => {
|
|
5973
|
-
// console.log('Text copied to clipboard!')
|
|
5974
|
-
})
|
|
5975
|
-
.catch((error) => {
|
|
5976
|
-
console.error('Failed to copy text to clipboard', error);
|
|
5977
|
-
});
|
|
5714
|
+
const seqDiv = seqRef.current;
|
|
5715
|
+
if (!seqDiv) {
|
|
5716
|
+
return;
|
|
5978
5717
|
}
|
|
5718
|
+
const textBlob = new Blob([seqDiv.outerText], { type: 'text/plain' });
|
|
5719
|
+
const htmlBlob = new Blob([seqDiv.outerHTML], { type: 'text/html' });
|
|
5720
|
+
const clipboardItem = new ClipboardItem({
|
|
5721
|
+
[textBlob.type]: textBlob,
|
|
5722
|
+
[htmlBlob.type]: htmlBlob,
|
|
5723
|
+
});
|
|
5724
|
+
void navigator.clipboard.write([clipboardItem]);
|
|
5979
5725
|
};
|
|
5980
|
-
const
|
|
5981
|
-
|
|
5982
|
-
|
|
5726
|
+
const sequenceSegments = showSequence
|
|
5727
|
+
? getSequenceSegments(selectedOption, feature, (min, max) => refData.getSequence(min, max))
|
|
5728
|
+
: [];
|
|
5729
|
+
const locationIntervals = [];
|
|
5730
|
+
if (showSequence) {
|
|
5731
|
+
const allLocs = sequenceSegments.flatMap((segment) => segment.locs);
|
|
5732
|
+
let [previous] = allLocs;
|
|
5733
|
+
for (let i = 1; i < allLocs.length; i++) {
|
|
5734
|
+
if (previous.min === allLocs[i].max || previous.max === allLocs[i].min) {
|
|
5735
|
+
previous = {
|
|
5736
|
+
min: Math.min(previous.min, allLocs[i].min),
|
|
5737
|
+
max: Math.max(previous.max, allLocs[i].max),
|
|
5738
|
+
};
|
|
5739
|
+
}
|
|
5740
|
+
else {
|
|
5741
|
+
locationIntervals.push(previous);
|
|
5742
|
+
previous = allLocs[i];
|
|
5743
|
+
}
|
|
5744
|
+
}
|
|
5745
|
+
locationIntervals.push(previous);
|
|
5746
|
+
}
|
|
5983
5747
|
return (React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
5984
|
-
React__default["default"].createElement(material.Typography, {
|
|
5748
|
+
React__default["default"].createElement(material.Typography, { variant: "h5" }, "Sequence"),
|
|
5985
5749
|
React__default["default"].createElement("div", null,
|
|
5986
|
-
React__default["default"].createElement(material.Button, { variant: "contained",
|
|
5987
|
-
React__default["default"].createElement(
|
|
5988
|
-
React__default["default"].createElement(material.
|
|
5989
|
-
|
|
5990
|
-
|
|
5991
|
-
|
|
5992
|
-
|
|
5993
|
-
|
|
5994
|
-
|
|
5995
|
-
|
|
5996
|
-
|
|
5997
|
-
|
|
5998
|
-
|
|
5999
|
-
|
|
5750
|
+
React__default["default"].createElement(material.Button, { variant: "contained", onClick: handleSeqButtonClick }, showSequence ? 'Hide sequence' : 'Show sequence')),
|
|
5751
|
+
showSequence && (React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
5752
|
+
React__default["default"].createElement(material.Select, { defaultValue: "CDS", value: selectedOption, onChange: handleChangeSeqOption },
|
|
5753
|
+
React__default["default"].createElement(material.MenuItem, { value: "CDS" }, "CDS"),
|
|
5754
|
+
React__default["default"].createElement(material.MenuItem, { value: "cDNA" }, "cDNA"),
|
|
5755
|
+
React__default["default"].createElement(material.MenuItem, { value: "genomic" }, "Genomic")),
|
|
5756
|
+
React__default["default"].createElement(material.Paper, { style: {
|
|
5757
|
+
fontFamily: 'monospace',
|
|
5758
|
+
padding: theme.spacing(),
|
|
5759
|
+
overflowX: 'auto',
|
|
5760
|
+
}, ref: seqRef },
|
|
5761
|
+
">",
|
|
5762
|
+
refSeq.name,
|
|
5763
|
+
":",
|
|
5764
|
+
locationIntervals
|
|
5765
|
+
.map((interval) => feature.strand === 1
|
|
5766
|
+
? `${interval.min + 1}-${interval.max}`
|
|
5767
|
+
: `${interval.max}-${interval.min + 1}`)
|
|
5768
|
+
.join(';'),
|
|
5769
|
+
"(",
|
|
5770
|
+
feature.strand === 1 ? '+' : '-',
|
|
5771
|
+
")",
|
|
5772
|
+
React__default["default"].createElement("br", null),
|
|
5773
|
+
sequenceSegments.map((segment, index) => (React__default["default"].createElement("span", { key: `${segment.type}-${index}`, style: {
|
|
5774
|
+
background: getSegmentColor(segment.type),
|
|
5775
|
+
color: theme.palette.getContrastText(getSegmentColor(segment.type)),
|
|
5776
|
+
} }, segment.sequenceLines.map((sequenceLine, idx) => (React__default["default"].createElement(React__default["default"].Fragment, { key: `${sequenceLine.slice(0, 5)}-${idx}` },
|
|
5777
|
+
sequenceLine,
|
|
5778
|
+
idx === segment.sequenceLines.length - 1 &&
|
|
5779
|
+
sequenceLine.length !== SEQUENCE_WRAP_LENGTH ? null : (React__default["default"].createElement("br", null))))))))),
|
|
5780
|
+
React__default["default"].createElement(material.Button, { variant: "contained", onClick: copyToClipboard }, "Copy sequence")))));
|
|
6000
5781
|
});
|
|
6001
5782
|
|
|
6002
5783
|
const useStyles$7 = mui.makeStyles()((theme) => ({
|
|
@@ -6227,7 +6008,7 @@ function featureContextMenuItems(feature, region, getAssemblyId, selectedFeature
|
|
|
6227
6008
|
return menuItems;
|
|
6228
6009
|
}
|
|
6229
6010
|
|
|
6230
|
-
/* eslint-disable @typescript-eslint/
|
|
6011
|
+
/* eslint-disable @typescript-eslint/unbound-method */
|
|
6231
6012
|
const useStyles$5 = mui.makeStyles()((theme) => ({
|
|
6232
6013
|
inputWrapper: {
|
|
6233
6014
|
position: 'relative',
|
|
@@ -6456,7 +6237,9 @@ function baseModelFactory(_pluginManager, configSchema) {
|
|
|
6456
6237
|
return;
|
|
6457
6238
|
}
|
|
6458
6239
|
void self.session.apolloDataStore.loadFeatures(self.regions);
|
|
6459
|
-
|
|
6240
|
+
if (self.lgv.bpPerPx <= 3) {
|
|
6241
|
+
void self.session.apolloDataStore.loadRefSeq(self.regions);
|
|
6242
|
+
}
|
|
6460
6243
|
}, { name: 'LinearApolloDisplayLoadFeatures', delay: 1000 }));
|
|
6461
6244
|
},
|
|
6462
6245
|
}));
|
|
@@ -7341,7 +7124,7 @@ function drawTooltip$2(display, context) {
|
|
|
7341
7124
|
if (!position) {
|
|
7342
7125
|
return;
|
|
7343
7126
|
}
|
|
7344
|
-
const { layoutIndex, layoutRow } = position;
|
|
7127
|
+
const { featureRow, layoutIndex, layoutRow } = position;
|
|
7345
7128
|
const { bpPerPx, displayedRegions, offsetPx } = lgv;
|
|
7346
7129
|
const displayedRegion = displayedRegions[layoutIndex];
|
|
7347
7130
|
const { refName, reversed } = displayedRegion;
|
|
@@ -7353,7 +7136,7 @@ function drawTooltip$2(display, context) {
|
|
|
7353
7136
|
coord: reversed ? max : min,
|
|
7354
7137
|
regionNumber: layoutIndex,
|
|
7355
7138
|
})?.offsetPx ?? 0) - offsetPx;
|
|
7356
|
-
const top = layoutRow * apolloRowHeight;
|
|
7139
|
+
const top = (layoutRow + featureRow) * apolloRowHeight;
|
|
7357
7140
|
const widthPx = length / bpPerPx;
|
|
7358
7141
|
const featureType = `Type: ${feature.type}`;
|
|
7359
7142
|
const { attributes } = feature;
|
|
@@ -7499,6 +7282,20 @@ function getContextMenuItems$2(display) {
|
|
|
7499
7282
|
session.showWidget(apolloFeatureWidget);
|
|
7500
7283
|
},
|
|
7501
7284
|
});
|
|
7285
|
+
if (sourceFeature.type === 'mRNA' && util.isSessionModelWithWidgets(session)) {
|
|
7286
|
+
menuItems.push({
|
|
7287
|
+
label: 'Edit transcript details',
|
|
7288
|
+
onClick: () => {
|
|
7289
|
+
const apolloTranscriptWidget = session.addWidget('ApolloTranscriptDetails', 'apolloTranscriptDetails', {
|
|
7290
|
+
feature: sourceFeature,
|
|
7291
|
+
assembly: currentAssemblyId,
|
|
7292
|
+
changeManager,
|
|
7293
|
+
refName: region.refName,
|
|
7294
|
+
});
|
|
7295
|
+
session.showWidget(apolloTranscriptWidget);
|
|
7296
|
+
},
|
|
7297
|
+
});
|
|
7298
|
+
}
|
|
7502
7299
|
return menuItems;
|
|
7503
7300
|
}
|
|
7504
7301
|
function getFeatureFromLayout$2(feature, _bp, _row) {
|
|
@@ -7583,35 +7380,49 @@ const boxGlyph = {
|
|
|
7583
7380
|
onMouseUp: onMouseUp$2,
|
|
7584
7381
|
};
|
|
7585
7382
|
|
|
7586
|
-
let
|
|
7587
|
-
let
|
|
7588
|
-
|
|
7383
|
+
let forwardFillLight = null;
|
|
7384
|
+
let backwardFillLight = null;
|
|
7385
|
+
let forwardFillDark = null;
|
|
7386
|
+
let backwardFillDark = null;
|
|
7387
|
+
if ('document' in globalThis) {
|
|
7589
7388
|
for (const direction of ['forward', 'backward']) {
|
|
7590
|
-
const
|
|
7591
|
-
|
|
7592
|
-
|
|
7593
|
-
|
|
7594
|
-
|
|
7595
|
-
|
|
7596
|
-
|
|
7597
|
-
|
|
7598
|
-
|
|
7599
|
-
|
|
7600
|
-
|
|
7601
|
-
|
|
7602
|
-
|
|
7603
|
-
|
|
7604
|
-
|
|
7605
|
-
|
|
7606
|
-
|
|
7607
|
-
|
|
7608
|
-
|
|
7609
|
-
|
|
7610
|
-
|
|
7611
|
-
|
|
7612
|
-
|
|
7613
|
-
|
|
7614
|
-
|
|
7389
|
+
for (const themeMode of ['light', 'dark']) {
|
|
7390
|
+
const canvas = document.createElement('canvas');
|
|
7391
|
+
const canvasSize = 10;
|
|
7392
|
+
canvas.width = canvas.height = canvasSize;
|
|
7393
|
+
const ctx = canvas.getContext('2d');
|
|
7394
|
+
if (ctx) {
|
|
7395
|
+
const stripeColor1 = themeMode === 'light' ? 'rgba(0,0,0,0)' : 'rgba(0,0,0,0.75)';
|
|
7396
|
+
const stripeColor2 = themeMode === 'light' ? 'rgba(255,255,255,0.25)' : 'rgba(0,0,0,0.50)';
|
|
7397
|
+
const gradient = direction === 'forward'
|
|
7398
|
+
? ctx.createLinearGradient(0, canvasSize, canvasSize, 0)
|
|
7399
|
+
: ctx.createLinearGradient(0, 0, canvasSize, canvasSize);
|
|
7400
|
+
gradient.addColorStop(0, stripeColor1);
|
|
7401
|
+
gradient.addColorStop(0.25, stripeColor1);
|
|
7402
|
+
gradient.addColorStop(0.25, stripeColor2);
|
|
7403
|
+
gradient.addColorStop(0.5, stripeColor2);
|
|
7404
|
+
gradient.addColorStop(0.5, stripeColor1);
|
|
7405
|
+
gradient.addColorStop(0.75, stripeColor1);
|
|
7406
|
+
gradient.addColorStop(0.75, stripeColor2);
|
|
7407
|
+
gradient.addColorStop(1, stripeColor2);
|
|
7408
|
+
ctx.fillStyle = gradient;
|
|
7409
|
+
ctx.fillRect(0, 0, 10, 10);
|
|
7410
|
+
if (direction === 'forward') {
|
|
7411
|
+
if (themeMode === 'light') {
|
|
7412
|
+
forwardFillLight = ctx.createPattern(canvas, 'repeat');
|
|
7413
|
+
}
|
|
7414
|
+
else {
|
|
7415
|
+
forwardFillDark = ctx.createPattern(canvas, 'repeat');
|
|
7416
|
+
}
|
|
7417
|
+
}
|
|
7418
|
+
else {
|
|
7419
|
+
if (themeMode === 'light') {
|
|
7420
|
+
backwardFillLight = ctx.createPattern(canvas, 'repeat');
|
|
7421
|
+
}
|
|
7422
|
+
else {
|
|
7423
|
+
backwardFillDark = ctx.createPattern(canvas, 'repeat');
|
|
7424
|
+
}
|
|
7425
|
+
}
|
|
7615
7426
|
}
|
|
7616
7427
|
}
|
|
7617
7428
|
}
|
|
@@ -7624,12 +7435,25 @@ function draw$1(ctx, feature, row, stateModel, displayedRegionIndex) {
|
|
|
7624
7435
|
const rowHeight = apolloRowHeight;
|
|
7625
7436
|
const exonHeight = Math.round(0.6 * rowHeight);
|
|
7626
7437
|
const cdsHeight = Math.round(0.9 * rowHeight);
|
|
7627
|
-
const { strand } = feature;
|
|
7628
|
-
const { children } = feature;
|
|
7438
|
+
const { children, min, strand } = feature;
|
|
7629
7439
|
if (!children) {
|
|
7630
7440
|
return;
|
|
7631
7441
|
}
|
|
7632
7442
|
const { apolloSelectedFeature } = session;
|
|
7443
|
+
// Draw background for gene
|
|
7444
|
+
const topLevelFeatureMinX = (lgv.bpToPx({
|
|
7445
|
+
refName,
|
|
7446
|
+
coord: min,
|
|
7447
|
+
regionNumber: displayedRegionIndex,
|
|
7448
|
+
})?.offsetPx ?? 0) - offsetPx;
|
|
7449
|
+
const topLevelFeatureWidthPx = feature.length / bpPerPx;
|
|
7450
|
+
const topLevelFeatureStartPx = reversed
|
|
7451
|
+
? topLevelFeatureMinX - topLevelFeatureWidthPx
|
|
7452
|
+
: topLevelFeatureMinX;
|
|
7453
|
+
const topLevelFeatureTop = row * rowHeight;
|
|
7454
|
+
const topLevelFeatureHeight = getRowCount$1(feature) * rowHeight;
|
|
7455
|
+
ctx.fillStyle = material.alpha(theme?.palette.background.paper ?? '#ffffff', 0.6);
|
|
7456
|
+
ctx.fillRect(topLevelFeatureStartPx, topLevelFeatureTop, topLevelFeatureWidthPx, topLevelFeatureHeight);
|
|
7633
7457
|
// Draw lines on different rows for each mRNA
|
|
7634
7458
|
let currentRow = 0;
|
|
7635
7459
|
for (const [, mrna] of children) {
|
|
@@ -7661,6 +7485,8 @@ function draw$1(ctx, feature, row, stateModel, displayedRegionIndex) {
|
|
|
7661
7485
|
currentRow += 1;
|
|
7662
7486
|
}
|
|
7663
7487
|
}
|
|
7488
|
+
const forwardFill = theme?.palette.mode === 'dark' ? forwardFillDark : forwardFillLight;
|
|
7489
|
+
const backwardFill = theme?.palette.mode === 'dark' ? backwardFillDark : backwardFillLight;
|
|
7664
7490
|
// Draw exon and CDS for each mRNA
|
|
7665
7491
|
currentRow = 0;
|
|
7666
7492
|
for (const [, child] of children) {
|
|
@@ -7797,11 +7623,31 @@ function drawHover$1(stateModel, ctx) {
|
|
|
7797
7623
|
ctx.fillRect(startPx, top, widthPx, apolloRowHeight * getRowCount$1(feature));
|
|
7798
7624
|
}
|
|
7799
7625
|
function getFeatureFromLayout$1(feature, bp, row) {
|
|
7800
|
-
const featureInThisRow = featuresForRow$1(feature)[row];
|
|
7626
|
+
const featureInThisRow = featuresForRow$1(feature)[row] || [];
|
|
7801
7627
|
for (const f of featureInThisRow) {
|
|
7628
|
+
let featureObj;
|
|
7802
7629
|
if (bp >= f.min && bp <= f.max && f.parent) {
|
|
7803
|
-
|
|
7630
|
+
featureObj = f;
|
|
7631
|
+
}
|
|
7632
|
+
if (!featureObj) {
|
|
7633
|
+
continue;
|
|
7634
|
+
}
|
|
7635
|
+
if (featureObj.type === 'CDS' &&
|
|
7636
|
+
featureObj.parent &&
|
|
7637
|
+
featureObj.parent.type === 'mRNA') {
|
|
7638
|
+
const { cdsLocations } = featureObj.parent;
|
|
7639
|
+
for (const cdsLoc of cdsLocations) {
|
|
7640
|
+
for (const loc of cdsLoc) {
|
|
7641
|
+
if (bp >= loc.min && bp <= loc.max) {
|
|
7642
|
+
return featureObj;
|
|
7643
|
+
}
|
|
7644
|
+
}
|
|
7645
|
+
}
|
|
7646
|
+
// If mouse position is in the intron region, return the mRNA
|
|
7647
|
+
return featureObj.parent;
|
|
7804
7648
|
}
|
|
7649
|
+
// If mouse position is in a feature that is not a CDS, return the feature
|
|
7650
|
+
return featureObj;
|
|
7805
7651
|
}
|
|
7806
7652
|
return feature;
|
|
7807
7653
|
}
|
|
@@ -8264,6 +8110,7 @@ async function fetchValidTypeTerms(feature, ontologyStore, _signal) {
|
|
|
8264
8110
|
return;
|
|
8265
8111
|
}
|
|
8266
8112
|
|
|
8113
|
+
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
|
8267
8114
|
const useStyles$3 = mui.makeStyles()((theme) => ({
|
|
8268
8115
|
scrollableTable: {
|
|
8269
8116
|
width: '100%',
|
|
@@ -8436,7 +8283,7 @@ function stateModelFactory$1(pluginManager, configSchema) {
|
|
|
8436
8283
|
.named('LinearApolloDisplay');
|
|
8437
8284
|
}
|
|
8438
8285
|
|
|
8439
|
-
/* eslint-disable @typescript-eslint/
|
|
8286
|
+
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
|
8440
8287
|
const useStyles$1 = mui.makeStyles()((theme) => ({
|
|
8441
8288
|
canvasContainer: {
|
|
8442
8289
|
position: 'relative',
|
|
@@ -8603,6 +8450,11 @@ const useStyles = mui.makeStyles()((theme) => ({
|
|
|
8603
8450
|
// position: 'relative',
|
|
8604
8451
|
userSelect: 'none',
|
|
8605
8452
|
},
|
|
8453
|
+
alertContainer: {
|
|
8454
|
+
display: 'flex',
|
|
8455
|
+
alignItems: 'center',
|
|
8456
|
+
justifyContent: 'center',
|
|
8457
|
+
},
|
|
8606
8458
|
}));
|
|
8607
8459
|
function scrollSelectedFeatureIntoView(model, scrollContainerRef) {
|
|
8608
8460
|
const { apolloRowHeight, selectedFeature } = model;
|
|
@@ -8625,18 +8477,18 @@ const ResizeHandle = ({ onResize, }) => {
|
|
|
8625
8477
|
const cancelDrag = React.useCallback((event) => {
|
|
8626
8478
|
event.stopPropagation();
|
|
8627
8479
|
event.preventDefault();
|
|
8628
|
-
|
|
8629
|
-
|
|
8630
|
-
|
|
8480
|
+
globalThis.removeEventListener('mousemove', mouseMove);
|
|
8481
|
+
globalThis.removeEventListener('mouseup', cancelDrag);
|
|
8482
|
+
globalThis.removeEventListener('mouseleave', cancelDrag);
|
|
8631
8483
|
}, [mouseMove]);
|
|
8632
8484
|
return (
|
|
8633
8485
|
// TODO: a11y
|
|
8634
8486
|
// eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions
|
|
8635
8487
|
React__default["default"].createElement("div", { onMouseDown: (event) => {
|
|
8636
8488
|
event.stopPropagation();
|
|
8637
|
-
|
|
8638
|
-
|
|
8639
|
-
|
|
8489
|
+
globalThis.addEventListener('mousemove', mouseMove);
|
|
8490
|
+
globalThis.addEventListener('mouseup', cancelDrag);
|
|
8491
|
+
globalThis.addEventListener('mouseleave', cancelDrag);
|
|
8640
8492
|
}, onClick: (e) => {
|
|
8641
8493
|
e.stopPropagation();
|
|
8642
8494
|
e.preventDefault();
|
|
@@ -8651,6 +8503,10 @@ const AccordionControl = mobxReact.observer(function AccordionControl({ onClick,
|
|
|
8651
8503
|
title ? (React__default["default"].createElement(material.Typography, { className: classes.title, variant: "caption", component: "span" }, title)) : null)));
|
|
8652
8504
|
});
|
|
8653
8505
|
const DisplayComponent = mobxReact.observer(function DisplayComponent({ model, ...other }) {
|
|
8506
|
+
const session = util.getSession(model);
|
|
8507
|
+
const { ontologyManager } = session.apolloDataStore;
|
|
8508
|
+
const { featureTypeOntology } = ontologyManager;
|
|
8509
|
+
const ontologyStore = featureTypeOntology?.dataStore;
|
|
8654
8510
|
const { classes } = useStyles();
|
|
8655
8511
|
const { detailsHeight, graphical, height: overallHeight, isShown, selectedFeature, table, tabularEditor, toggleShown, } = model;
|
|
8656
8512
|
const canvasScrollContainerRef = React.useRef(null);
|
|
@@ -8660,6 +8516,10 @@ const DisplayComponent = mobxReact.observer(function DisplayComponent({ model, .
|
|
|
8660
8516
|
const onDetailsResize = (delta) => {
|
|
8661
8517
|
model.setDetailsHeight(detailsHeight - delta);
|
|
8662
8518
|
};
|
|
8519
|
+
if (!ontologyStore) {
|
|
8520
|
+
return (React__default["default"].createElement("div", { className: classes.alertContainer },
|
|
8521
|
+
React__default["default"].createElement(material.Alert, { severity: "error" }, "Could not load feature type ontology.")));
|
|
8522
|
+
}
|
|
8663
8523
|
if (graphical && table) {
|
|
8664
8524
|
const tabularHeight = tabularEditor.isShown ? detailsHeight : 0;
|
|
8665
8525
|
const featureAreaHeight = isShown
|
|
@@ -9229,7 +9089,7 @@ class DesktopFileDriver extends BackendDriver {
|
|
|
9229
9089
|
throw new Error(`Assembly ${assemblyName} not found`);
|
|
9230
9090
|
}
|
|
9231
9091
|
const { file } = configuration.getConf(assembly, ['sequence', 'metadata']);
|
|
9232
|
-
// eslint-disable-next-line @typescript-eslint/no-
|
|
9092
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
9233
9093
|
const fs = require('node:fs');
|
|
9234
9094
|
const fileContents = await fs.promises.readFile(file, 'utf8');
|
|
9235
9095
|
return loadAssemblyIntoClient(assemblyName, fileContents, this.clientStore);
|
|
@@ -9339,7 +9199,7 @@ class DesktopFileDriver extends BackendDriver {
|
|
|
9339
9199
|
});
|
|
9340
9200
|
}
|
|
9341
9201
|
const gff3Contents = gff__default["default"].formatSync(gff3Items);
|
|
9342
|
-
// eslint-disable-next-line @typescript-eslint/no-
|
|
9202
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
9343
9203
|
const fs = require('node:fs');
|
|
9344
9204
|
await fs.promises.writeFile(file, gff3Contents, 'utf8');
|
|
9345
9205
|
const results = new shared.ValidationResultSet();
|
|
@@ -9356,6 +9216,7 @@ function clientDataStoreFactory(AnnotationFeatureExtended) {
|
|
|
9356
9216
|
typeName: mobxStateTree.types.optional(mobxStateTree.types.literal('Client'), 'Client'),
|
|
9357
9217
|
assemblies: mobxStateTree.types.map(mst$1.ApolloAssembly),
|
|
9358
9218
|
checkResults: mobxStateTree.types.map(mst$1.CheckResult),
|
|
9219
|
+
ontologyManager: mobxStateTree.types.optional(OntologyManagerType, {}),
|
|
9359
9220
|
})
|
|
9360
9221
|
.views((self) => ({
|
|
9361
9222
|
get internetAccounts() {
|
|
@@ -9429,7 +9290,6 @@ function clientDataStoreFactory(AnnotationFeatureExtended) {
|
|
|
9429
9290
|
desktopFileDriver: util.isElectron
|
|
9430
9291
|
? new DesktopFileDriver(self)
|
|
9431
9292
|
: undefined,
|
|
9432
|
-
ontologyManager: OntologyManagerType.create(),
|
|
9433
9293
|
}))
|
|
9434
9294
|
.actions((self) => ({
|
|
9435
9295
|
afterCreate() {
|
|
@@ -9882,6 +9742,7 @@ function extendSession(pluginManager, sessionModel) {
|
|
|
9882
9742
|
postProcessor(snap) {
|
|
9883
9743
|
snap.apolloSelectedFeature = undefined;
|
|
9884
9744
|
const assemblies = Object.fromEntries(Object.entries(snap.apolloDataStore.assemblies).filter(([, assembly]) => assembly.backendDriverType === 'InMemoryFileDriver'));
|
|
9745
|
+
// @ts-expect-error ontologyManager isn't actually required
|
|
9885
9746
|
snap.apolloDataStore = {
|
|
9886
9747
|
typeName: 'Client',
|
|
9887
9748
|
assemblies,
|
|
@@ -10316,7 +10177,7 @@ class RefNameAliasAdapter extends BaseAdapter.BaseAdapter {
|
|
|
10316
10177
|
this.refNameAliases = refNameAliases;
|
|
10317
10178
|
return refNameAliases;
|
|
10318
10179
|
}
|
|
10319
|
-
|
|
10180
|
+
freeResources() {
|
|
10320
10181
|
// no resources to free
|
|
10321
10182
|
}
|
|
10322
10183
|
}
|