jbrowse-plugin-protein3d 0.4.11 → 0.4.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/dist/LaunchProteinView/components/LaunchSettingsDialog.d.ts +5 -0
  2. package/dist/LaunchProteinView/components/LaunchSettingsDialog.js +23 -0
  3. package/dist/LaunchProteinView/components/ProteinViewActions.js +13 -2
  4. package/dist/LaunchProteinView/hooks/useAlphaFoldDBSearch.js +12 -3
  5. package/dist/LaunchProteinView/hooks/useAlphaFoldData.d.ts +1 -0
  6. package/dist/LaunchProteinView/hooks/useAlphaFoldData.js +2 -1
  7. package/dist/LaunchProteinView/hooks/useAlphaFoldSequenceSearch.d.ts +1 -0
  8. package/dist/LaunchProteinView/hooks/useAlphaFoldSequenceSearch.js +2 -1
  9. package/dist/LaunchProteinView/hooks/useFoldseekSearch.js +47 -12
  10. package/dist/LaunchProteinView/hooks/useStructureFileSequence.d.ts +1 -0
  11. package/dist/LaunchProteinView/hooks/useStructureFileSequence.js +5 -2
  12. package/dist/LaunchProteinView/services/foldseekApi.d.ts +23 -5
  13. package/dist/LaunchProteinView/services/foldseekApi.js +21 -13
  14. package/dist/LaunchProteinView/utils/launchViewUtils.d.ts +2 -1
  15. package/dist/LaunchProteinView/utils/launchViewUtils.js +7 -2
  16. package/dist/LaunchProteinView/utils/sideBySide.d.ts +11 -0
  17. package/dist/LaunchProteinView/utils/sideBySide.js +33 -0
  18. package/dist/LaunchProteinViewExtensionPoint/index.js +9 -2
  19. package/dist/ProteinView/applyColorTheme.d.ts +1 -1
  20. package/dist/ProteinView/loadStructureData.d.ts +18 -0
  21. package/dist/ProteinView/loadStructureData.js +22 -0
  22. package/dist/ProteinView/model.d.ts +2 -2
  23. package/dist/ProteinView/model.js +6 -36
  24. package/dist/ProteinView/structureLoader.d.ts +30 -0
  25. package/dist/ProteinView/structureLoader.js +58 -0
  26. package/dist/config.json +1 -1
  27. package/dist/fetchUtils.d.ts +1 -1
  28. package/dist/fetchUtils.js +18 -2
  29. package/dist/jbrowse-plugin-protein3d.umd.production.min.js +15 -15
  30. package/dist/jbrowse-plugin-protein3d.umd.production.min.js.map +4 -4
  31. package/dist/molstar-chunk.js.map +1 -1
  32. package/dist/version.d.ts +1 -1
  33. package/dist/version.js +1 -1
  34. package/package.json +4 -2
  35. package/src/LaunchProteinView/components/LaunchSettingsDialog.tsx +63 -0
  36. package/src/LaunchProteinView/components/ProteinViewActions.tsx +21 -1
  37. package/src/LaunchProteinView/hooks/useAlphaFoldDBSearch.ts +13 -1
  38. package/src/LaunchProteinView/hooks/useAlphaFoldData.ts +3 -1
  39. package/src/LaunchProteinView/hooks/useAlphaFoldSequenceSearch.ts +12 -10
  40. package/src/LaunchProteinView/hooks/useFoldseekSearch.ts +49 -12
  41. package/src/LaunchProteinView/hooks/useStructureFileSequence.ts +5 -2
  42. package/src/LaunchProteinView/services/foldseekApi.ts +57 -23
  43. package/src/LaunchProteinView/utils/launchViewUtils.ts +10 -1
  44. package/src/LaunchProteinView/utils/sideBySide.ts +55 -0
  45. package/src/LaunchProteinViewExtensionPoint/index.ts +17 -1
  46. package/src/ProteinView/loadStructureData.ts +36 -0
  47. package/src/ProteinView/model.ts +6 -47
  48. package/src/ProteinView/structureLoader.test.ts +102 -0
  49. package/src/ProteinView/structureLoader.ts +74 -0
  50. package/src/fetchUtils.test.ts +27 -0
  51. package/src/fetchUtils.ts +22 -2
  52. package/src/version.ts +1 -1
@@ -4,11 +4,9 @@ import { addDisposer, types } from '@jbrowse/mobx-state-tree';
4
4
  import SettingsIcon from '@mui/icons-material/Settings';
5
5
  import Visibility from '@mui/icons-material/Visibility';
6
6
  import { autorun } from 'mobx';
7
- import { addStructureFromData } from './addStructureFromData';
8
- import { addStructureFromURL } from './addStructureFromURL';
9
7
  import { COLOR_SCHEMES, COLOR_SCHEME_VALUES, applyColorTheme, } from './applyColorTheme';
10
- import { extractPerResidueConfidence } from './extractPerResidueConfidence';
11
- import { extractStructureSequences } from './extractStructureSequences';
8
+ import { loadStructureData } from './loadStructureData';
9
+ import { makeStructureLoader } from './structureLoader';
12
10
  import Structure from './structureModel';
13
11
  import { superposeStructures } from './superposeStructures';
14
12
  import { DEFAULT_ALIGNMENT_ALGORITHM } from './types';
@@ -21,18 +19,6 @@ const PERSISTED_SETTINGS = [
21
19
  'autoScrollAlignment',
22
20
  'compactTracks',
23
21
  ];
24
- async function loadStructureData({ structure, plugin, }) {
25
- const { model } = structure.data
26
- ? await addStructureFromData({ data: structure.data, plugin })
27
- : structure.url
28
- ? await addStructureFromURL({ url: structure.url, plugin })
29
- : { model: undefined };
30
- const sequences = model ? extractStructureSequences(model) : undefined;
31
- const confidence = model
32
- ? extractPerResidueConfidence(model, sequences?.[0]?.length)
33
- : undefined;
34
- return { sequences, confidence };
35
- }
36
22
  /**
37
23
  * #stateModel Protein3dViewPlugin
38
24
  * extends
@@ -347,26 +333,10 @@ function stateModelFactory() {
347
333
  });
348
334
  }
349
335
  }));
350
- addDisposer(self, autorun(async () => {
351
- const { structures, molstarPluginContext } = self;
352
- if (molstarPluginContext) {
353
- for (const structure of structures) {
354
- if (!structure.loadedToMolstar) {
355
- try {
356
- structure.setStructureData(await loadStructureData({
357
- structure,
358
- plugin: molstarPluginContext,
359
- }));
360
- structure.setLoadedToMolstar(true);
361
- }
362
- catch (e) {
363
- self.setError(e);
364
- console.error(e);
365
- }
366
- }
367
- }
368
- }
369
- }));
336
+ // Load structures into Molstar as they appear or whenever the plugin
337
+ // context changes. See makeStructureLoader for why the autorun body is
338
+ // synchronous and how it guards against duplicate/stale loads.
339
+ addDisposer(self, autorun(makeStructureLoader(self)));
370
340
  },
371
341
  }))
372
342
  .views(self => ({
@@ -0,0 +1,30 @@
1
+ import type StructureModel from './structureModel';
2
+ import type { IAnyStateTreeNode, Instance } from '@jbrowse/mobx-state-tree';
3
+ import type { PluginContext } from 'molstar/lib/mol-plugin/context';
4
+ type StructureInstance = Instance<typeof StructureModel>;
5
+ export type StructureLoaderHost = IAnyStateTreeNode & {
6
+ readonly molstarPluginContext: PluginContext | undefined;
7
+ readonly structures: StructureInstance[];
8
+ setError: (error: unknown) => void;
9
+ };
10
+ /**
11
+ * Builds the body of the autorun that loads structures into Molstar.
12
+ *
13
+ * The returned callback is synchronous on purpose: MobX only tracks
14
+ * observables read before the first `await`, so an async autorun body would
15
+ * stop reacting to later structures/plugin changes. Instead it reads its
16
+ * dependencies synchronously and dispatches a guarded fire-and-forget load for
17
+ * each structure that is neither loaded nor already loading. The guards handle
18
+ * the lifecycle hazards of an external GPU resource:
19
+ *
20
+ * - a non-observable in-flight Set stops a re-entrant run (a new structure
21
+ * pushed, or the plugin swapped mid-load) from starting a duplicate load of
22
+ * the same structure;
23
+ * - a load whose plugin was replaced or whose model was destroyed while
24
+ * awaiting has its result discarded rather than written into a torn-down
25
+ * plugin;
26
+ * - if the plugin was merely swapped (e.g. a view remount), the structure is
27
+ * reloaded into the current plugin so it isn't left stranded unloaded.
28
+ */
29
+ export declare function makeStructureLoader(host: StructureLoaderHost): () => void;
30
+ export {};
@@ -0,0 +1,58 @@
1
+ import { isAlive } from '@jbrowse/mobx-state-tree';
2
+ import { loadStructureData } from './loadStructureData';
3
+ /**
4
+ * Builds the body of the autorun that loads structures into Molstar.
5
+ *
6
+ * The returned callback is synchronous on purpose: MobX only tracks
7
+ * observables read before the first `await`, so an async autorun body would
8
+ * stop reacting to later structures/plugin changes. Instead it reads its
9
+ * dependencies synchronously and dispatches a guarded fire-and-forget load for
10
+ * each structure that is neither loaded nor already loading. The guards handle
11
+ * the lifecycle hazards of an external GPU resource:
12
+ *
13
+ * - a non-observable in-flight Set stops a re-entrant run (a new structure
14
+ * pushed, or the plugin swapped mid-load) from starting a duplicate load of
15
+ * the same structure;
16
+ * - a load whose plugin was replaced or whose model was destroyed while
17
+ * awaiting has its result discarded rather than written into a torn-down
18
+ * plugin;
19
+ * - if the plugin was merely swapped (e.g. a view remount), the structure is
20
+ * reloaded into the current plugin so it isn't left stranded unloaded.
21
+ */
22
+ export function makeStructureLoader(host) {
23
+ const loadingStructures = new Set();
24
+ function loadInto(structure, plugin) {
25
+ loadingStructures.add(structure);
26
+ loadStructureData({ structure, plugin })
27
+ .then(data => {
28
+ const current = isAlive(structure)
29
+ ? host.molstarPluginContext
30
+ : undefined;
31
+ if (current === plugin) {
32
+ structure.setStructureData(data);
33
+ structure.setLoadedToMolstar(true);
34
+ }
35
+ loadingStructures.delete(structure);
36
+ if (current && current !== plugin && !structure.loadedToMolstar) {
37
+ loadInto(structure, current);
38
+ }
39
+ })
40
+ .catch((e) => {
41
+ loadingStructures.delete(structure);
42
+ if (isAlive(host)) {
43
+ host.setError(e);
44
+ console.error(e);
45
+ }
46
+ });
47
+ }
48
+ return function loadPendingStructures() {
49
+ const { structures, molstarPluginContext } = host;
50
+ if (molstarPluginContext) {
51
+ for (const structure of structures) {
52
+ if (!structure.loadedToMolstar && !loadingStructures.has(structure)) {
53
+ loadInto(structure, molstarPluginContext);
54
+ }
55
+ }
56
+ }
57
+ };
58
+ }
package/dist/config.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "plugins": [
3
3
  {
4
4
  "name": "Protein3d",
5
- "url": "https://unpkg.com/jbrowse-plugin-protein3d/dist/jbrowse-plugin-protein3d.umd.production.min.js"
5
+ "url": "https://jbrowse.org/plugins/jbrowse-plugin-protein3d/latest/dist/jbrowse-plugin-protein3d.umd.production.min.js"
6
6
  }
7
7
  ],
8
8
  "assemblies": [
@@ -1,3 +1,3 @@
1
1
  export declare function myfetch(url: string, args?: RequestInit): Promise<Response>;
2
2
  export declare function jsonfetch<T = unknown>(url: string, args?: RequestInit): Promise<T>;
3
- export declare function timeout(time: number): Promise<unknown>;
3
+ export declare function timeout(time: number, signal?: AbortSignal): Promise<void>;
@@ -9,6 +9,22 @@ export async function jsonfetch(url, args) {
9
9
  const response = await myfetch(url, args);
10
10
  return response.json();
11
11
  }
12
- export function timeout(time) {
13
- return new Promise(res => setTimeout(res, time));
12
+ function abortError(signal) {
13
+ return signal.reason instanceof Error
14
+ ? signal.reason
15
+ : new Error('Aborted', { cause: signal.reason });
16
+ }
17
+ export function timeout(time, signal) {
18
+ return new Promise((resolve, reject) => {
19
+ if (signal?.aborted) {
20
+ reject(abortError(signal));
21
+ }
22
+ else {
23
+ const id = setTimeout(resolve, time);
24
+ signal?.addEventListener('abort', () => {
25
+ clearTimeout(id);
26
+ reject(abortError(signal));
27
+ }, { once: true });
28
+ }
29
+ });
14
30
  }