@jbrowse/core 5.0.0-beta.2 → 5.0.0-beta.4

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 (142) hide show
  1. package/README.md +70 -40
  2. package/esm/BaseFeatureWidget/BaseFeatureDetail/FeatureDetails.d.ts +2 -3
  3. package/esm/BaseFeatureWidget/BaseFeatureDetail/ParentFeatureLine.d.ts +4 -0
  4. package/esm/BaseFeatureWidget/BaseFeatureDetail/ParentFeatureLine.js +17 -0
  5. package/esm/BaseFeatureWidget/BaseFeatureDetail/index.js +4 -3
  6. package/esm/BaseFeatureWidget/SequenceFeatureDetails/SequenceFeaturePanel.d.ts +2 -2
  7. package/esm/BaseFeatureWidget/index.d.ts +1 -1
  8. package/esm/BaseFeatureWidget/stateModelFactory.d.ts +8 -1
  9. package/esm/BaseFeatureWidget/stateModelFactory.js +6 -0
  10. package/esm/BaseFeatureWidget/types.d.ts +10 -2
  11. package/esm/PluginManager.d.ts +30 -1
  12. package/esm/PluginManager.js +107 -70
  13. package/esm/ReExports/BaseFeatureDetails.js +1 -1
  14. package/esm/ReExports/MuiDataGridReExports.d.ts +1 -0
  15. package/esm/ReExports/MuiDataGridReExports.js +2 -2
  16. package/esm/ReExports/barrelOnlyNames.d.ts +5 -0
  17. package/esm/ReExports/barrelOnlyNames.js +63 -0
  18. package/esm/ReExports/modules.js +28 -56
  19. package/esm/ReExports/publicTracks.d.ts +1 -0
  20. package/esm/ReExports/publicTracks.js +14 -0
  21. package/esm/ReExports/publicUi.d.ts +4 -0
  22. package/esm/ReExports/publicUi.js +33 -0
  23. package/esm/ReExports/publicUtil.d.ts +1 -1
  24. package/esm/ReExports/publicUtil.js +8 -4
  25. package/esm/ReExports/sharedModules.d.ts +1 -1
  26. package/esm/ReExports/sharedModules.js +8 -1
  27. package/esm/ReExports/uiStub.d.ts +1 -0
  28. package/esm/ReExports/uiStub.js +6 -8
  29. package/esm/ReExports/workerModules.js +9 -4
  30. package/esm/ReExports/workerNamespaceNames.d.ts +11 -0
  31. package/esm/ReExports/workerNamespaceNames.js +281 -0
  32. package/esm/configuration/configurationSchema.js +11 -0
  33. package/esm/configuration/index.d.ts +2 -2
  34. package/esm/configuration/index.js +1 -1
  35. package/esm/configuration/promotableDefaults.d.ts +54 -19
  36. package/esm/configuration/promotableDefaults.js +108 -45
  37. package/esm/configuration/promotablePin.d.ts +50 -40
  38. package/esm/configuration/promotableResolve.d.ts +1 -1
  39. package/esm/configuration/promotableResolve.js +1 -1
  40. package/esm/configuration/tabixIndexFields.d.ts +2 -2
  41. package/esm/configuration/tabixIndexFields.js +2 -2
  42. package/esm/data_adapters/BaseAdapter/BaseFeatureDataAdapter.js +4 -12
  43. package/esm/data_adapters/BaseAdapter/featureDensity.d.ts +12 -0
  44. package/esm/data_adapters/BaseAdapter/featureDensity.js +15 -0
  45. package/esm/data_adapters/BaseAdapter/index.d.ts +2 -2
  46. package/esm/data_adapters/BaseAdapter/index.js +1 -1
  47. package/esm/data_adapters/BaseAdapter/types.d.ts +2 -8
  48. package/esm/pluggableElementTypes/AdapterType.d.ts +2 -1
  49. package/esm/pluggableElementTypes/AdapterType.js +1 -1
  50. package/esm/pluggableElementTypes/DisplayType.d.ts +3 -10
  51. package/esm/pluggableElementTypes/DisplayType.js +3 -45
  52. package/esm/pluggableElementTypes/LazyStateModelElement.d.ts +27 -0
  53. package/esm/pluggableElementTypes/LazyStateModelElement.js +71 -0
  54. package/esm/pluggableElementTypes/ViewType.d.ts +3 -10
  55. package/esm/pluggableElementTypes/ViewType.js +6 -51
  56. package/esm/pluggableElementTypes/extendElementType.d.ts +1 -2
  57. package/esm/pluggableElementTypes/extendElementType.js +1 -2
  58. package/esm/pluggableElementTypes/models/BaseDisplayModel.d.ts +3 -3
  59. package/esm/pluggableElementTypes/models/BaseDisplayModel.js +1 -1
  60. package/esm/pluggableElementTypes/models/BaseTrackModel.js +1 -4
  61. package/esm/pluggableElementTypes/models/BaseViewModel.d.ts +34 -34
  62. package/esm/pluggableElementTypes/models/BaseViewModel.js +19 -30
  63. package/esm/pluggableElementTypes/models/assertDisplayContract.d.ts +4 -3
  64. package/esm/pluggableElementTypes/models/assertDisplayContract.js +2 -2
  65. package/esm/pluggableElementTypes/models/baseTrackConfig.js +7 -1
  66. package/esm/ui/BaseExportSvgDialog.d.ts +1 -1
  67. package/esm/ui/ErrorMessageStackTraceDialog.js +5 -6
  68. package/esm/ui/ExportSvgDialog.d.ts +1 -1
  69. package/esm/ui/MenuTypes.d.ts +3 -3
  70. package/esm/ui/PinAdornment.js +22 -40
  71. package/esm/ui/ScrollChrome.d.ts +16 -0
  72. package/esm/ui/ScrollChrome.js +12 -0
  73. package/esm/ui/ScrollZoomToggle.d.ts +4 -3
  74. package/esm/ui/ScrollZoomToggle.js +4 -3
  75. package/esm/ui/SizeSliderRow.js +1 -1
  76. package/esm/ui/index.d.ts +2 -2
  77. package/esm/ui/index.js +3 -3
  78. package/esm/ui/legendMenuItem.d.ts +9 -15
  79. package/esm/ui/legendMenuItem.js +8 -19
  80. package/esm/ui/menuItemAdornment.d.ts +2 -3
  81. package/esm/ui/menuItemAdornment.js +2 -3
  82. package/esm/ui/menuItems.d.ts +1 -2
  83. package/esm/ui/menuItems.js +0 -1
  84. package/esm/ui/palette.d.ts +11 -11
  85. package/esm/ui/palette.js +11 -11
  86. package/esm/ui/promotablePinCoverage.d.ts +16 -2
  87. package/esm/ui/promotablePinCoverage.js +38 -2
  88. package/esm/ui/theme.js +5 -0
  89. package/esm/ui/toggleMenuItems.d.ts +13 -6
  90. package/esm/ui/toggleMenuItems.js +32 -15
  91. package/esm/util/Base1DUtils.d.ts +4 -2
  92. package/esm/util/Base1DUtils.js +12 -4
  93. package/esm/util/SvgCanvas.js +4 -3
  94. package/esm/util/adapterConfigKey.d.ts +12 -0
  95. package/esm/util/adapterConfigKey.js +14 -0
  96. package/esm/util/adapterMetadata.js +2 -1
  97. package/esm/util/analytics.js +4 -5
  98. package/esm/util/clampToContig.d.ts +17 -0
  99. package/esm/util/clampToContig.js +19 -0
  100. package/esm/util/colorBits.d.ts +2 -1
  101. package/esm/util/colorBits.js +2 -5
  102. package/esm/util/createStopTokenRotation.d.ts +8 -7
  103. package/esm/util/featureTypes.d.ts +24 -0
  104. package/esm/util/featureTypes.js +35 -0
  105. package/esm/util/fetchPhases.d.ts +1 -1
  106. package/esm/util/index.d.ts +4 -2
  107. package/esm/util/index.js +3 -1
  108. package/esm/util/installFetch.d.ts +29 -18
  109. package/esm/util/installFetch.js +17 -17
  110. package/esm/util/installInitAutorun.d.ts +6 -5
  111. package/esm/util/installInitAutorun.js +2 -2
  112. package/esm/util/installPrerequisiteFetch.d.ts +86 -0
  113. package/esm/util/installPrerequisiteFetch.js +73 -0
  114. package/esm/util/openFeatureWidget.d.ts +5 -0
  115. package/esm/util/openFeatureWidget.js +1 -0
  116. package/esm/util/openViews.d.ts +16 -0
  117. package/esm/util/openViews.js +22 -0
  118. package/esm/util/parentWalk.d.ts +1 -1
  119. package/esm/util/parentWalk.js +1 -1
  120. package/esm/util/renderToStaticMarkup.js +10 -0
  121. package/esm/util/scheduleDetachedDestroy.d.ts +18 -0
  122. package/esm/util/scheduleDetachedDestroy.js +24 -0
  123. package/esm/util/scrollLatch.d.ts +1 -0
  124. package/esm/util/scrollLatch.js +8 -0
  125. package/esm/util/stopToken.d.ts +6 -5
  126. package/esm/util/trackConfigDelta.d.ts +6 -6
  127. package/esm/util/trackConfigDelta.js +3 -3
  128. package/esm/util/types/index.d.ts +25 -20
  129. package/esm/util/usePanelVirtualScroll.d.ts +6 -2
  130. package/esm/util/usePanelVirtualScroll.js +6 -2
  131. package/esm/util/useRowVirtualScroll.d.ts +1 -1
  132. package/esm/util/useRowVirtualScroll.js +1 -1
  133. package/esm/util/useVirtualScrollWheel.js +11 -1
  134. package/esm/util/wheelZoom.d.ts +3 -1
  135. package/esm/util/wheelZoom.js +39 -14
  136. package/esm/util/whenViewSettled.d.ts +31 -6
  137. package/esm/util/whenViewSettled.js +33 -5
  138. package/esm/util/withLaunchInput.d.ts +47 -2
  139. package/esm/util/withLaunchInput.js +56 -11
  140. package/package.json +10 -5
  141. package/esm/ui/promotableMenuItems.d.ts +0 -19
  142. package/esm/ui/promotableMenuItems.js +0 -91
package/README.md CHANGED
@@ -149,12 +149,11 @@ default" action, which passes the slots it actually listed
149
149
 
150
150
  **`slots` is required, and an all-slots default is not the convenience it looks
151
151
  like.** It reaches further than any list a dialog can have shown: a promoted
152
- default the track _customized_ over, or one promoted to a value equal to
153
- `promotedBase`, is `inherited: false` and so appears in no row, yet still
154
- governs sibling tracks — so clearing it from a dialog that never showed it moves
155
- tracks other than the one whose badge was clicked. Clearing every promoted
156
- default at once is a preferences-scope action, and Preferences → "Reset to
157
- defaults" is where it lives (`clearPreferenceOverrides`).
152
+ default the track _customized_ over is `inherited: false` and so appears in no
153
+ row, yet still governs sibling tracks — so clearing it from a dialog that never
154
+ showed it moves tracks other than the one whose badge was clicked. Clearing
155
+ every promoted default at once is a preferences-scope action, and Preferences →
156
+ "Reset to defaults" is where it lives (`clearPreferenceOverrides`).
158
157
 
159
158
  ```js
160
159
  // type signature
@@ -423,10 +422,10 @@ default" predicate for a promotable slot: comparing the resolved value to the
423
422
  base instead reads as at-default for a track merely _following_ a non-base
424
423
  promoted default, so the reset control lights up on a no-op.
425
424
 
426
- `SLOT` is constrained the way `getConf`'s is. A pin or a reset over a slot name
427
- the schema does not declare is inert and silent — `resolveSlot` answers about
428
- nothing, so the control draws outline forever — and a widened `self` switches
429
- the check off (`HostChecksSlotNames`).
425
+ `SLOT` is constrained the way `getConf`'s is, and a widened `self` switches the
426
+ check off (`HostChecksSlotNames`). A slot name the schema does not declare
427
+ throws at the first read (`getSlotDefinition`), and a declared but
428
+ non-promotable one throws in `resolveSlotIn`.
430
429
 
431
430
  ```js
432
431
  // type signature
@@ -449,20 +448,22 @@ synchronous `addOrReplaceView` requires it loaded already.
449
448
 
450
449
  ### makePin
451
450
 
452
- The pin for one promotable slot: "apply this value to every open track of this
451
+ The pin on a radio or slider row: "apply this value to every open track of this
453
452
  display type", and — via the snackbar it raises — "keep it as the default for
454
453
  the ones opened later".
455
454
 
456
455
  `value` chooses between the subsystem's two meanings, which are otherwise
457
456
  identical:
458
457
 
459
- - **Give it** for a per-value pin — "make _arcs_ the default" — independent of
460
- what the track currently shows. Use on an always-visible pin so it can never
461
- promote a meaningless value, and so two rows sharing one slot (arcs `'arc'` vs
462
- read cloud `'cloud'`; sashimi `'down'` vs `'auto'`) stay independent.
458
+ - **Give it** for a per-value pin — "make _compact_ the default" — independent
459
+ of what the track currently shows. Use on an always-visible pin so it can
460
+ never promote a meaningless value, and so two rows sharing one slot (sashimi
461
+ `'down'` vs `'auto'`) stay independent.
463
462
  - **Omit it** for "whatever I'm showing", resolved through the cascade. Use for
464
- a symmetric or continuous setting where no fixed on-value makes sense (wiggle
465
- point size, arc line width, `mismatchAlpha`).
463
+ a continuous setting where no fixed on-value makes sense (wiggle point size,
464
+ arc line width).
465
+
466
+ A checkbox row takes neither: makeTogglePin.
466
467
 
467
468
  One function with an optional argument, rather than the two exported builders it
468
469
  replaces — a per-value one and a `…CurrentValue…` one, the second of which was
@@ -472,7 +473,32 @@ argument now says what the longer name said.
472
473
 
473
474
  ```js
474
475
  // type signature
475
- <CONFMODEL extends AnyConfigurationModel, SLOT extends ConfigurationSlotName<…>>(self: ResolvableDisplay<CONFMODEL>, slot: SLOT, ...value: [] | [...]) => Pin
476
+ <CONFMODEL extends AnyConfigurationModel, SLOT extends ConfigurationSlotName<…>>(self: ResolvableDisplay<CONFMODEL>, slot: SLOT, ...value: [] | [...]) => ValuePin
477
+ ```
478
+
479
+ [Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/core/src/configuration/promotableDefaults.ts)
480
+
481
+ ### makeTogglePin
482
+
483
+ The pin on a checkbox row: the row's own checkbox, acting on every open track of
484
+ the display type. `active` mirrors the row, so the pin draws filled exactly when
485
+ the box is ticked; a click flips the row's state on every open track and offers
486
+ the new state as the display type's default. It never clears a default the way
487
+ makePin's filled pin does — flipping back and taking the offer promotes the
488
+ other value, and promoting the base value clears the default
489
+ (`applyAndOfferDefault`).
490
+
491
+ Replaces a symmetric `makePin(self, slot)` on these rows, which carried the
492
+ row's current state: beside an unchecked box that applied _off_ everywhere and
493
+ visibly did nothing. It also replaces the per-value `makePin` a checkbox row
494
+ over a shared enum slot used to carry, which gave two checkbox rows in one
495
+ submenu two different pins: one filled when its value was promoted and clearing
496
+ on a second click, the other filled when the box was ticked and flipping. With
497
+ `states`, a checkbox row is always the toggle kind.
498
+
499
+ ```js
500
+ // type signature
501
+ <…>(self: ResolvableDisplay<CONFMODEL>, slot: SLOT, ...states: ConfigurationSlotValueResolved<...> extends boolean ? [] | [...] : [...]) => TogglePin
476
502
  ```
477
503
 
478
504
  [Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/core/src/configuration/promotableDefaults.ts)
@@ -505,28 +531,12 @@ each display whether it has anything to promote.
505
531
  ### Pin
506
532
 
507
533
  The "apply this to every open track of this type" affordance on a menu row — the
508
- trailing `PushPin`, bundled so the row consumes it as one prop. Built by
509
- makePin.
510
-
511
- `active` = this value is currently the session default (a filled pin), which is
512
- the state, not the click. `toggle` **applies the value to every open track of
513
- the display type** and raises a snackbar whose one action promotes it to the
514
- display type's default; on an already-promoted value it clears that default
515
- instead, touching no track (see `applyPinClick`).
516
-
517
- **`toggle` rather than an `apply`/`clear` pair**, which was tried and dropped:
518
- the sole renderer is a MUI `ToggleButton` whose `onChange` means exactly "flip",
519
- so splitting it adds a member _and_ a branch at the one call site that never
520
- needed one. `active` is already public for a caller that wants to state a
521
- direction. (The house preference for explicit setters over toggles is about MST
522
- actions, where a toggle destroys the ability to set a known state; nothing here
523
- stores a value.)
524
-
525
- Lives here, alone and with no imports, rather than beside `makePin` in
526
- `promotableDefaults.ts`: the menu types describe a pin without building one, and
527
- `MenuTypes.ts` taking this one interface from that module gave a React-free type
528
- file a type closure of 374 files. See
529
- `agent-docs/ideas/barrels-block-extraction.md` and `scripts/moduleClosure.ts`.
534
+ trailing `PushPin`, bundled so the row consumes it as one prop.
535
+
536
+ `kind` is what the adornment words itself from and what the row builders check:
537
+ a checkbox row takes a TogglePin, a radio or slider row a ValuePin. The two used
538
+ to be told apart by `typeof onValue === 'boolean'`, which let a value pin over a
539
+ boolean slot compile and read as a toggle while clearing on its second click.
530
540
 
531
541
  [Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/core/src/configuration/promotablePin.ts)
532
542
 
@@ -796,6 +806,16 @@ never baked into the color string.
796
806
 
797
807
  [Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/core/src/util/colorRamp.ts)
798
808
 
809
+ ### TogglePin
810
+
811
+ The pin on a checkbox row, built by makeTogglePin: the row's own checkbox over
812
+ every open track of the display type. `active` mirrors the row, `onValue` is the
813
+ state a click applies (the row's opposite), and `toggle` applies it everywhere
814
+ and offers it as the default. It never clears a default on its own — promoting
815
+ the slot's base value is what clears one.
816
+
817
+ [Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/core/src/configuration/promotablePin.ts)
818
+
799
819
  ### TrackConfigWithPromotables
800
820
 
801
821
  A track config snapshot with every display's `promotable` slots resolved, plus
@@ -827,6 +847,16 @@ reader has promoted in their own browser. Pinned by
827
847
 
828
848
  [Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/core/src/configuration/promotableDefaults.ts)
829
849
 
850
+ ### ValuePin
851
+
852
+ The pin on a radio or slider row, built by makePin: `onValue` is the row's own
853
+ value, `active` means that value is the display type's promoted default, and
854
+ `toggle` on an outline pin applies the value to every open track and offers it
855
+ as the default, while on a filled pin it clears that default and touches no
856
+ track (`applyAndOfferDefault` / `clearDefault`).
857
+
858
+ [Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/core/src/configuration/promotablePin.ts)
859
+
830
860
  ### VIRIDIS_STOPS
831
861
 
832
862
  The 256 viridis stops, fully opaque. Feed them to buildColorRampLut for the
@@ -1,8 +1,7 @@
1
1
  import type { SimpleFeatureSerialized } from '../../util/index.ts';
2
- import type { Descriptors, FeatureFormatter } from '../types.tsx';
3
- import type { IAnyStateTreeNode } from '@jbrowse/mobx-state-tree';
2
+ import type { Descriptors, FeatureDetailsModel, FeatureFormatter } from '../types.tsx';
4
3
  interface FeatureDetailsProps {
5
- model: IAnyStateTreeNode;
4
+ model: FeatureDetailsModel;
6
5
  feature: SimpleFeatureSerialized;
7
6
  depth?: number;
8
7
  omit?: string[];
@@ -0,0 +1,4 @@
1
+ import type { ParentFeatureSummary } from '../../util/index.ts';
2
+ export default function ParentFeatureLine({ parentFeature, }: {
3
+ parentFeature: ParentFeatureSummary;
4
+ }): import("react").JSX.Element;
@@ -0,0 +1,17 @@
1
+ import { jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Typography } from '@mui/material';
3
+ import { makeStyles } from '../../util/tss-react/index.js';
4
+ const useStyles = makeStyles()(theme => ({
5
+ line: {
6
+ padding: theme.spacing(0.5, 1, 0),
7
+ },
8
+ }));
9
+ // Which gene a transcript came out of, above the card naming the transcript.
10
+ // The panel is opened on the exact isoform the click resolved to, and that
11
+ // isoform's own record is regularly the only place its accession appears --
12
+ // nothing in `NM_004006.2 - mRNA` says DMD.
13
+ export default function ParentFeatureLine({ parentFeature, }) {
14
+ const { classes } = useStyles();
15
+ const { name, type } = parentFeature;
16
+ return (_jsxs(Typography, { variant: "body2", color: "textSecondary", className: classes.line, "data-testid": "parent-feature-line", children: ["in ", type ? `${type} ` : '', name] }));
17
+ }
@@ -1,11 +1,12 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { observer } from 'mobx-react';
3
3
  import { ErrorBanner } from '../../ui/index.js';
4
4
  import FeatureDetails from './FeatureDetails.js';
5
5
  import FeatureWash from './FeatureWash.js';
6
+ import ParentFeatureLine from './ParentFeatureLine.js';
6
7
  import { isEmpty } from './util.js';
7
8
  const BaseFeatureDetail = observer(function BaseFeatureDetail({ model, }) {
8
- const { error, featureData } = model;
9
+ const { error, featureData, parentFeature } = model;
9
10
  // annotated to shed the MST node brand types.frozen() carries on the instance
10
11
  const descriptions = model.descriptions;
11
12
  // A field is hidden by a formatDetails callback returning undefined (jexl
@@ -19,7 +20,7 @@ const BaseFeatureDetail = observer(function BaseFeatureDetail({ model, }) {
19
20
  return null;
20
21
  }
21
22
  else {
22
- return (_jsx(FeatureWash, { uniqueId: featureData.uniqueId, children: _jsx(FeatureDetails, { model: model, feature: featureData, descriptions: descriptions }) }));
23
+ return (_jsxs(FeatureWash, { uniqueId: featureData.uniqueId, children: [parentFeature ? (_jsx(ParentFeatureLine, { parentFeature: parentFeature })) : null, _jsx(FeatureDetails, { model: model, feature: featureData, descriptions: descriptions })] }));
23
24
  }
24
25
  });
25
26
  export default BaseFeatureDetail;
@@ -1,7 +1,7 @@
1
1
  import type { SimpleFeatureSerialized } from '../../util/index.ts';
2
- import type { BaseFeatureWidgetModel } from '../stateModelFactory.ts';
2
+ import type { FeatureDetailsModel } from '../types.tsx';
3
3
  declare const SequenceFeaturePanel: ({ model, feature, }: {
4
- model: BaseFeatureWidgetModel;
4
+ model: FeatureDetailsModel;
5
5
  feature: SimpleFeatureSerialized;
6
6
  }) => import("react").JSX.Element;
7
7
  export default SequenceFeaturePanel;
@@ -1,5 +1,5 @@
1
1
  export { configSchema } from './configSchema.ts';
2
- export type { Descriptors, MaybeSerializedFeat } from './types.tsx';
2
+ export type { Descriptors, FeatureDetailsModel, MaybeSerializedFeat, } from './types.tsx';
3
3
  export type { SequenceHoverPosition, ShowCoordinatesMode, } from './SequenceFeatureDetails/model.ts';
4
4
  export { stateModelFactory } from './stateModelFactory.ts';
5
5
  export type { BaseFeatureWidgetModel, BaseFeatureWidgetStateModel, } from './stateModelFactory.ts';
@@ -1,5 +1,5 @@
1
1
  import type PluginManager from '../PluginManager.ts';
2
- import type { SimpleFeatureSerialized } from '../util/index.ts';
2
+ import type { ParentFeatureSummary, SimpleFeatureSerialized } from '../util/index.ts';
3
3
  import type { SequenceHoverPosition } from './SequenceFeatureDetails/model.ts';
4
4
  import type { Descriptors, MaybeSerializedFeat } from './types.tsx';
5
5
  import type { Instance } from '@jbrowse/mobx-state-tree';
@@ -69,6 +69,12 @@ export declare function stateModelFactory(pluginManager: PluginManager): import(
69
69
  * #property
70
70
  */
71
71
  descriptions: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").IType<Descriptors | undefined, Descriptors | undefined, Descriptors | undefined>, [undefined]>;
72
+ /**
73
+ * #property
74
+ * names the feature this one was reached through, when it was reached
75
+ * through one -- a transcript clicked inside its gene
76
+ */
77
+ parentFeature: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").IType<ParentFeatureSummary | undefined, ParentFeatureSummary | undefined, ParentFeatureSummary | undefined>, [undefined]>;
72
78
  }, {
73
79
  error: unknown;
74
80
  sequenceHoverPosition: SequenceHoverPosition | undefined;
@@ -113,6 +119,7 @@ export declare function stateModelFactory(pluginManager: PluginManager): import(
113
119
  maxDepth: number | undefined;
114
120
  sequenceFeatureDetails: import("@jbrowse/mobx-state-tree").ModelSnapshotType<{}>;
115
121
  descriptions: Descriptors | undefined;
122
+ parentFeature: ParentFeatureSummary | undefined;
116
123
  finalizedFeatureData: any;
117
124
  }>;
118
125
  export type BaseFeatureWidgetStateModel = ReturnType<typeof stateModelFactory>;
@@ -59,6 +59,12 @@ export function stateModelFactory(pluginManager) {
59
59
  * #property
60
60
  */
61
61
  descriptions: types.optional(types.frozen(), undefined),
62
+ /**
63
+ * #property
64
+ * names the feature this one was reached through, when it was reached
65
+ * through one -- a transcript clicked inside its gene
66
+ */
67
+ parentFeature: types.optional(types.frozen(), undefined),
62
68
  })
63
69
  .volatile(() => ({
64
70
  /**
@@ -1,6 +1,14 @@
1
1
  import type { SimpleFeatureSerialized } from '../util/simpleFeature.ts';
2
- import type { BaseFeatureWidgetModel } from './stateModelFactory.ts';
2
+ import type { SequenceFeatureDetailsModel, SequenceHoverTarget } from './SequenceFeatureDetails/model.ts';
3
+ import type { IStateTreeNode } from '@jbrowse/mobx-state-tree';
3
4
  import type React from 'react';
5
+ export interface FeatureDetailsModel extends IStateTreeNode, SequenceHoverTarget {
6
+ maxDepth: number | undefined;
7
+ sequenceFeatureDetails: SequenceFeatureDetailsModel;
8
+ view: {
9
+ assemblyNames: string[];
10
+ } | undefined;
11
+ }
4
12
  export interface Descriptors {
5
13
  [key: string]: React.ReactNode | Descriptors;
6
14
  }
@@ -9,7 +17,7 @@ export interface BaseProps extends BaseCardProps {
9
17
  feature: SimpleFeatureSerialized;
10
18
  formatter?: FeatureFormatter;
11
19
  descriptions?: Descriptors;
12
- model?: BaseFeatureWidgetModel;
20
+ model?: FeatureDetailsModel;
13
21
  }
14
22
  export interface BaseCardProps {
15
23
  title?: string;
@@ -1,6 +1,7 @@
1
1
  import PhasedScheduler from './PhasedScheduler.ts';
2
2
  import './util/tracks.ts';
3
3
  import type Plugin from './Plugin.ts';
4
+ import type { PluginConstructor } from './Plugin.ts';
4
5
  import type AdapterType from './pluggableElementTypes/AdapterType.ts';
5
6
  import type AddTrackWorkflowType from './pluggableElementTypes/AddTrackWorkflowType.ts';
6
7
  import type ConnectionType from './pluggableElementTypes/ConnectionType.ts';
@@ -290,6 +291,15 @@ export interface PluginLoadRecord {
290
291
  metadata?: PluginMetadata;
291
292
  plugin: Plugin;
292
293
  }
294
+ /**
295
+ * Instantiate an application's bundled plugin list as `isCore` load records —
296
+ * what tells the plugin store these came with the bundle rather than being
297
+ * installed by the user, so `InstalledPluginsList` filters them out and the
298
+ * About widget lists them. Every product and every test harness builds its
299
+ * manager from one of these lists, and a harness that passed bare instances
300
+ * silently disagreed with the app it was testing.
301
+ */
302
+ export declare function corePluginRecords(plugins: PluginConstructor[]): PluginLoadRecord[];
293
303
  export interface RuntimePluginLoadRecord extends PluginLoadRecord {
294
304
  definition: PluginDefinition;
295
305
  }
@@ -367,6 +377,14 @@ export default class PluginManager {
367
377
  pluggableMstType(groupName: PluggableElementTypeGroup, fieldName: string, fallback?: IAnyType): IAnyType;
368
378
  /** get a MST type for the union of all specified pluggable config schemas */
369
379
  pluggableConfigSchemaType(typeGroup: PluggableElementTypeGroup, fieldName?: string): IAnyType;
380
+ /**
381
+ * An adapter union dispatches on `type`, so a config still spelling an
382
+ * adapter's old name has to be rewritten to the name it registers under
383
+ * before the union sees it. Here rather than in each schema holding an
384
+ * adapter slot, so a track, an assembly's sequence and a connection all take
385
+ * it.
386
+ */
387
+ private canonicalizeAdapterSnapshot;
370
388
  jbrequireCache: Map<any, any>;
371
389
  get lib(): Record<string, unknown>;
372
390
  load: <FTYPE extends AnyFunction>(lib: FTYPE) => ReturnType<FTYPE>;
@@ -380,6 +398,12 @@ export default class PluginManager {
380
398
  default: AnyFunction;
381
399
  }) => any;
382
400
  getAdapterType(typeName: string): AdapterType;
401
+ /**
402
+ * The name an adapter `type` registers under: itself, or the adapter that
403
+ * declares it in `aliases`. A name nothing answers to comes back as written,
404
+ * so the registered-names error still names what the config said.
405
+ */
406
+ canonicalAdapterTypeName(typeName: string): string;
383
407
  /**
384
408
  * Whether an adapter type is registered, for a caller walking a config where
385
409
  * `type` names a track, a display and an adapter alike — `getAdapterType`
@@ -394,7 +418,12 @@ export default class PluginManager {
394
418
  stateModel: ViewTypeRegistry[N];
395
419
  };
396
420
  getViewType(typeName: string): ViewType;
397
- private sessionTypeNames;
421
+ /**
422
+ * The registered view and display types a snapshot names, from every `type`
423
+ * string anywhere in it — `heldForMissingPlugins` included. Over-collection
424
+ * is harmless: a name that resolves to neither is dropped here.
425
+ */
426
+ private sessionElementTypes;
398
427
  /**
399
428
  * Every async code path that hands a snapshot to a synchronous session
400
429
  * instantiation (`setSession`, `cast`) must await this first.
@@ -3,6 +3,7 @@ import CorePlugin from './CorePlugin.js';
3
3
  import PhasedScheduler from './PhasedScheduler.js';
4
4
  import { getReExportRegistry } from './ReExports/registry.js';
5
5
  import { ConfigurationSchema, isBareConfigurationSchemaType, } from './configuration/index.js';
6
+ import LazyStateModelElement from './pluggableElementTypes/LazyStateModelElement.js';
6
7
  import createJexlInstance from './util/jexl.js';
7
8
  import { expandLooseTrackConfig } from './util/tracks.js';
8
9
  /**
@@ -24,6 +25,9 @@ export const pluggableElementTypeGroups = [
24
25
  'internet account',
25
26
  'add track workflow',
26
27
  ];
28
+ function isUnloadedLazyElement(element) {
29
+ return element instanceof LazyStateModelElement && !element.isStateModelLoaded;
30
+ }
27
31
  /** internal class that holds the info for a certain element type */
28
32
  class TypeRecord {
29
33
  registeredTypes = {};
@@ -90,6 +94,17 @@ function nextAccumulator(name, accumulator, result) {
90
94
  function logCallbackError(name, error) {
91
95
  console.error(`error in a ${name} extension point callback`, error);
92
96
  }
97
+ /**
98
+ * Instantiate an application's bundled plugin list as `isCore` load records —
99
+ * what tells the plugin store these came with the bundle rather than being
100
+ * installed by the user, so `InstalledPluginsList` filters them out and the
101
+ * About widget lists them. Every product and every test harness builds its
102
+ * manager from one of these lists, and a harness that passed bare instances
103
+ * silently disagreed with the app it was testing.
104
+ */
105
+ export function corePluginRecords(plugins) {
106
+ return plugins.map(P => ({ plugin: new P(), metadata: { isCore: true } }));
107
+ }
93
108
  export default class PluginManager {
94
109
  plugins = [];
95
110
  jexl = createJexlInstance();
@@ -307,9 +322,28 @@ export default class PluginManager {
307
322
  console.warn(`${groupName} ${newElement.name} already registered, cannot register it again`);
308
323
  }
309
324
  else {
310
- typeRecord.add(newElement.name, this.evaluateExtensionPoint(
325
+ const extend = () => this.evaluateExtensionPoint(
311
326
  /** #extensionPoint Core-extendPluggableElement | sync | Mutate any pluggable element after it is created */
312
- 'Core-extendPluggableElement', newElement, { group: groupName }));
327
+ 'Core-extendPluggableElement', newElement, { group: groupName });
328
+ // A lazily registered state model is not there for a callback to
329
+ // extend yet, so the point fires when the loader resolves instead.
330
+ // agent-docs/reference/EAGER_BUNDLE.md
331
+ if (isUnloadedLazyElement(newElement)) {
332
+ newElement.onStateModelLoaded = () => {
333
+ const extended = extend();
334
+ if (extended !== newElement) {
335
+ typeRecord.add(newElement.name, extended);
336
+ if (extended instanceof LazyStateModelElement &&
337
+ extended.isStateModelLoaded) {
338
+ newElement.stateModel = extended.stateModel;
339
+ }
340
+ }
341
+ };
342
+ typeRecord.add(newElement.name, newElement);
343
+ }
344
+ else {
345
+ typeRecord.add(newElement.name, extend());
346
+ }
313
347
  }
314
348
  });
315
349
  return this;
@@ -348,18 +382,20 @@ export default class PluginManager {
348
382
  */
349
383
  pluggableMstType(groupName, fieldName, fallback = types.maybe(types.null)) {
350
384
  const record = this.getElementTypeRecord(groupName);
385
+ const fieldOf = (t) => isUnloadedLazyElement(t)
386
+ ? undefined
387
+ : t[fieldName];
351
388
  const anyMember = record.all().some(t => {
352
- const element = t;
353
- const field = element[fieldName];
389
+ const field = fieldOf(t);
354
390
  return ((isType(field) && isModelType(field)) ||
355
- typeof element[`${fieldName}Loader`] === 'function');
391
+ typeof t[`${fieldName}Loader`] === 'function');
356
392
  });
357
393
  if (!anyMember) {
358
394
  return fallback;
359
395
  }
360
396
  const modelsOf = () => record
361
397
  .all()
362
- .map(t => t[fieldName])
398
+ .map(t => fieldOf(t))
363
399
  .filter(t => isType(t) && isModelType(t));
364
400
  let members = modelsOf();
365
401
  return types.union({
@@ -395,7 +431,28 @@ export default class PluginManager {
395
431
  ? types.snapshotProcessor(union, {
396
432
  preProcessor: (snap) => expandLooseTrackConfig(snap, this),
397
433
  })
398
- : union;
434
+ : typeGroup === 'adapter'
435
+ ? types.snapshotProcessor(union, {
436
+ preProcessor: (snap) => this.canonicalizeAdapterSnapshot(snap),
437
+ })
438
+ : union;
439
+ }
440
+ /**
441
+ * An adapter union dispatches on `type`, so a config still spelling an
442
+ * adapter's old name has to be rewritten to the name it registers under
443
+ * before the union sees it. Here rather than in each schema holding an
444
+ * adapter slot, so a track, an assembly's sequence and a connection all take
445
+ * it.
446
+ */
447
+ canonicalizeAdapterSnapshot(snap) {
448
+ if (typeof snap === 'object' &&
449
+ snap !== null &&
450
+ 'type' in snap &&
451
+ typeof snap.type === 'string') {
452
+ const canonical = this.canonicalAdapterTypeName(snap.type);
453
+ return canonical === snap.type ? snap : { ...snap, type: canonical };
454
+ }
455
+ return snap;
399
456
  }
400
457
  jbrequireCache = new Map();
401
458
  // populated by PluginLoader once a runtime plugin is actually being loaded,
@@ -434,7 +491,18 @@ export default class PluginManager {
434
491
  throw new TypeError('lib passed to jbrequire must be either a string or a function');
435
492
  };
436
493
  getAdapterType(typeName) {
437
- return this.adapterTypes.get(typeName);
494
+ return this.adapterTypes.get(this.canonicalAdapterTypeName(typeName));
495
+ }
496
+ /**
497
+ * The name an adapter `type` registers under: itself, or the adapter that
498
+ * declares it in `aliases`. A name nothing answers to comes back as written,
499
+ * so the registered-names error still names what the config said.
500
+ */
501
+ canonicalAdapterTypeName(typeName) {
502
+ return this.adapterTypes.has(typeName)
503
+ ? typeName
504
+ : (this.adapterTypes.all().find(t => t.aliases?.includes(typeName))
505
+ ?.name ?? typeName);
438
506
  }
439
507
  /**
440
508
  * Whether an adapter type is registered, for a caller walking a config where
@@ -443,7 +511,7 @@ export default class PluginManager {
443
511
  * claims to be an adapter and wrong when you are asking whether it is one.
444
512
  */
445
513
  hasAdapterType(typeName) {
446
- return this.adapterTypes.has(typeName);
514
+ return this.adapterTypes.has(this.canonicalAdapterTypeName(typeName));
447
515
  }
448
516
  getTextSearchAdapterType(typeName) {
449
517
  return this.textSearchAdapterTypes.get(typeName);
@@ -457,81 +525,50 @@ export default class PluginManager {
457
525
  getViewType(typeName) {
458
526
  return this.viewTypes.get(typeName);
459
527
  }
460
- sessionTypeNames(sessionSnapshot) {
461
- const viewNames = new Set();
462
- const displayNames = new Set();
463
- const collectTracks = (tracks) => {
464
- if (Array.isArray(tracks)) {
465
- for (const track of tracks) {
466
- const { displays } = track && typeof track === 'object'
467
- ? track
468
- : {};
469
- if (Array.isArray(displays)) {
470
- for (const display of displays) {
471
- const type = display && typeof display === 'object'
472
- ? display.type
473
- : undefined;
474
- if (typeof type === 'string') {
475
- displayNames.add(type);
476
- }
477
- }
478
- }
528
+ /**
529
+ * The registered view and display types a snapshot names, from every `type`
530
+ * string anywhere in it — `heldForMissingPlugins` included. Over-collection
531
+ * is harmless: a name that resolves to neither is dropped here.
532
+ */
533
+ sessionElementTypes(sessionSnapshot) {
534
+ const names = new Set();
535
+ const walk = (node) => {
536
+ if (Array.isArray(node)) {
537
+ for (const item of node) {
538
+ walk(item);
479
539
  }
480
540
  }
481
- };
482
- const collectViews = (views) => {
483
- if (Array.isArray(views)) {
484
- for (const view of views) {
485
- if (view && typeof view === 'object') {
486
- const { type, views: children, tracks, levels, } = view;
487
- if (typeof type === 'string') {
488
- viewNames.add(type);
489
- }
490
- collectViews(children);
491
- collectTracks(tracks);
492
- if (Array.isArray(levels)) {
493
- for (const level of levels) {
494
- collectTracks(level && typeof level === 'object'
495
- ? level.tracks
496
- : undefined);
497
- }
498
- }
541
+ else if (node && typeof node === 'object') {
542
+ for (const [key, value] of Object.entries(node)) {
543
+ if (key === 'type' && typeof value === 'string') {
544
+ names.add(value);
545
+ }
546
+ else {
547
+ walk(value);
499
548
  }
500
549
  }
501
550
  }
502
551
  };
503
- if (sessionSnapshot && typeof sessionSnapshot === 'object') {
504
- const { view, views } = sessionSnapshot;
505
- collectViews(views);
506
- collectViews(view ? [view] : undefined);
507
- }
508
- return { viewNames, displayNames };
552
+ walk(sessionSnapshot);
553
+ return [...names].flatMap(name => {
554
+ const display = this.resolveDisplayTypeRecord(name);
555
+ return [
556
+ ...(this.viewTypes.has(name) ? [this.getViewType(name)] : []),
557
+ ...(display ? [display] : []),
558
+ ];
559
+ });
509
560
  }
510
561
  /**
511
562
  * Every async code path that hands a snapshot to a synchronous session
512
563
  * instantiation (`setSession`, `cast`) must await this first.
513
564
  */
514
565
  async preloadSessionTypes(sessionSnapshot) {
515
- const { viewNames, displayNames } = this.sessionTypeNames(sessionSnapshot);
516
- await Promise.all([
517
- ...[...viewNames]
518
- .filter(name => this.viewTypes.has(name))
519
- .map(name => this.getViewType(name).loadStateModel()),
520
- ...[...displayNames]
521
- .map(name => this.resolveDisplayTypeRecord(name))
522
- .flatMap(display => (display ? [display.loadStateModel()] : [])),
523
- ]);
566
+ await Promise.all(this.sessionElementTypes(sessionSnapshot).map(t => t.loadStateModel()));
524
567
  }
525
568
  unloadedSessionTypes(sessionSnapshot) {
526
- const { viewNames, displayNames } = this.sessionTypeNames(sessionSnapshot);
527
- return [
528
- ...[...viewNames].filter(name => this.viewTypes.has(name) &&
529
- !this.getViewType(name).isStateModelLoaded),
530
- ...[...displayNames].filter(name => {
531
- const display = this.resolveDisplayTypeRecord(name);
532
- return display !== undefined && !display.isStateModelLoaded;
533
- }),
534
- ];
569
+ return this.sessionElementTypes(sessionSnapshot)
570
+ .filter(t => !t.isStateModelLoaded)
571
+ .map(t => t.name);
535
572
  }
536
573
  /**
537
574
  * Without this, a snapshot naming an unloaded lazy type fails inside MST as
@@ -7,4 +7,4 @@ export const BaseFeatureDetail = lazyMap({
7
7
  BaseCard: lazy(() => import('../BaseFeatureWidget/BaseFeatureDetail/BaseCard.js')),
8
8
  BaseAttributes: lazy(() => import('../BaseFeatureWidget/BaseFeatureDetail/BaseAttributes.js')),
9
9
  BaseCoreDetails: lazy(() => import('../BaseFeatureWidget/BaseFeatureDetail/BaseCoreDetails.js')),
10
- }, '@jbrowse/core/BaseFeatureWidget/BaseFeatureDetail/');
10
+ });