@jbrowse/plugin-data-management 2.6.2 → 2.6.3

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 (61) hide show
  1. package/dist/HierarchicalTrackSelectorWidget/components/faceted/FacetedSelector.js +4 -5
  2. package/dist/HierarchicalTrackSelectorWidget/components/tree/HamburgerMenu.js +35 -19
  3. package/dist/HierarchicalTrackSelectorWidget/components/tree/HierarchicalHeader.js +10 -6
  4. package/dist/HierarchicalTrackSelectorWidget/components/tree/HierarchicalTree.d.ts +2 -1
  5. package/dist/HierarchicalTrackSelectorWidget/components/tree/TrackCategory.js +22 -0
  6. package/dist/HierarchicalTrackSelectorWidget/components/tree/TrackLabel.js +1 -1
  7. package/dist/HierarchicalTrackSelectorWidget/components/util.d.ts +2 -1
  8. package/dist/HierarchicalTrackSelectorWidget/filterTracks.d.ts +12 -0
  9. package/dist/HierarchicalTrackSelectorWidget/filterTracks.js +32 -0
  10. package/dist/HierarchicalTrackSelectorWidget/generateHierarchy.d.ts +21 -0
  11. package/dist/HierarchicalTrackSelectorWidget/generateHierarchy.js +98 -0
  12. package/dist/HierarchicalTrackSelectorWidget/model.d.ts +68 -28
  13. package/dist/HierarchicalTrackSelectorWidget/model.js +149 -117
  14. package/dist/HierarchicalTrackSelectorWidget/util.d.ts +12 -0
  15. package/dist/HierarchicalTrackSelectorWidget/util.js +53 -0
  16. package/dist/PluginStoreWidget/components/AddCustomPluginDialog.d.ts +7 -0
  17. package/dist/PluginStoreWidget/components/{CustomPluginForm.js → AddCustomPluginDialog.js} +12 -21
  18. package/dist/PluginStoreWidget/components/DeletePluginDialog.d.ts +5 -0
  19. package/dist/PluginStoreWidget/components/DeletePluginDialog.js +28 -0
  20. package/dist/PluginStoreWidget/components/InstalledPlugin.d.ts +2 -5
  21. package/dist/PluginStoreWidget/components/InstalledPlugin.js +19 -50
  22. package/dist/PluginStoreWidget/components/InstalledPluginsList.d.ts +2 -3
  23. package/dist/PluginStoreWidget/components/InstalledPluginsList.js +6 -9
  24. package/dist/PluginStoreWidget/components/PluginCard.js +3 -5
  25. package/dist/PluginStoreWidget/components/PluginStoreWidget.js +11 -39
  26. package/dist/PluginStoreWidget/components/util.d.ts +5 -0
  27. package/dist/PluginStoreWidget/components/util.js +29 -0
  28. package/dist/PluginStoreWidget/model.d.ts +2 -2
  29. package/dist/PluginStoreWidget/model.js +2 -2
  30. package/esm/HierarchicalTrackSelectorWidget/components/faceted/FacetedSelector.js +1 -2
  31. package/esm/HierarchicalTrackSelectorWidget/components/tree/HamburgerMenu.js +34 -18
  32. package/esm/HierarchicalTrackSelectorWidget/components/tree/HierarchicalHeader.js +10 -6
  33. package/esm/HierarchicalTrackSelectorWidget/components/tree/HierarchicalTree.d.ts +2 -1
  34. package/esm/HierarchicalTrackSelectorWidget/components/tree/TrackCategory.js +22 -0
  35. package/esm/HierarchicalTrackSelectorWidget/components/tree/TrackLabel.js +1 -1
  36. package/esm/HierarchicalTrackSelectorWidget/components/util.d.ts +2 -1
  37. package/esm/HierarchicalTrackSelectorWidget/filterTracks.d.ts +12 -0
  38. package/esm/HierarchicalTrackSelectorWidget/filterTracks.js +28 -0
  39. package/esm/HierarchicalTrackSelectorWidget/generateHierarchy.d.ts +21 -0
  40. package/esm/HierarchicalTrackSelectorWidget/generateHierarchy.js +94 -0
  41. package/esm/HierarchicalTrackSelectorWidget/model.d.ts +68 -28
  42. package/esm/HierarchicalTrackSelectorWidget/model.js +151 -116
  43. package/esm/HierarchicalTrackSelectorWidget/util.d.ts +12 -0
  44. package/esm/HierarchicalTrackSelectorWidget/util.js +45 -0
  45. package/esm/PluginStoreWidget/components/AddCustomPluginDialog.d.ts +7 -0
  46. package/esm/PluginStoreWidget/components/{CustomPluginForm.js → AddCustomPluginDialog.js} +12 -21
  47. package/esm/PluginStoreWidget/components/DeletePluginDialog.d.ts +5 -0
  48. package/esm/PluginStoreWidget/components/DeletePluginDialog.js +22 -0
  49. package/esm/PluginStoreWidget/components/InstalledPlugin.d.ts +2 -5
  50. package/esm/PluginStoreWidget/components/InstalledPlugin.js +22 -53
  51. package/esm/PluginStoreWidget/components/InstalledPluginsList.d.ts +2 -3
  52. package/esm/PluginStoreWidget/components/InstalledPluginsList.js +6 -9
  53. package/esm/PluginStoreWidget/components/PluginCard.js +3 -5
  54. package/esm/PluginStoreWidget/components/PluginStoreWidget.js +12 -40
  55. package/esm/PluginStoreWidget/components/util.d.ts +5 -0
  56. package/esm/PluginStoreWidget/components/util.js +25 -0
  57. package/esm/PluginStoreWidget/model.d.ts +2 -2
  58. package/esm/PluginStoreWidget/model.js +1 -1
  59. package/package.json +2 -2
  60. package/dist/PluginStoreWidget/components/CustomPluginForm.d.ts +0 -9
  61. package/esm/PluginStoreWidget/components/CustomPluginForm.d.ts +0 -9
@@ -1,21 +1,14 @@
1
- import React, { useState } from 'react';
1
+ import React, { Suspense, lazy, useState } from 'react';
2
2
  import { observer } from 'mobx-react';
3
- import { getParent } from 'mobx-state-tree';
4
- import { Button, Dialog, DialogTitle, DialogActions, DialogContent, IconButton, ListItem, Tooltip, Typography, } from '@mui/material';
3
+ import { IconButton, ListItem, Tooltip, Typography } from '@mui/material';
5
4
  import { makeStyles } from 'tss-react/mui';
6
5
  import CloseIcon from '@mui/icons-material/Close';
7
6
  import LockIcon from '@mui/icons-material/Lock';
8
- import { getSession } from '@jbrowse/core/util';
7
+ import { getEnv, getSession } from '@jbrowse/core/util';
9
8
  import { isSessionWithSessionPlugins, } from '@jbrowse/core/util/types';
9
+ // lazies
10
+ const DeletePluginDialog = lazy(() => import('./DeletePluginDialog'));
10
11
  const useStyles = makeStyles()(() => ({
11
- closeDialog: {
12
- position: 'absolute',
13
- right: 0,
14
- top: 0,
15
- },
16
- dialogContainer: {
17
- margin: 15,
18
- },
19
12
  lockedPluginTooltip: {
20
13
  marginRight: '0.5rem',
21
14
  },
@@ -25,52 +18,28 @@ function LockedPlugin() {
25
18
  return (React.createElement(Tooltip, { className: classes.lockedPluginTooltip, title: "This plugin was installed by an administrator, you cannot remove it." },
26
19
  React.createElement(LockIcon, null)));
27
20
  }
28
- function PluginDialog({ onClose, plugin, }) {
29
- const { classes } = useStyles();
30
- return (React.createElement(Dialog, { open: true, onClose: () => onClose() },
31
- React.createElement(DialogTitle, null,
32
- React.createElement(IconButton, { className: classes.closeDialog, "aria-label": "close-dialog", onClick: () => onClose() },
33
- React.createElement(CloseIcon, null))),
34
- React.createElement(DialogContent, null,
35
- React.createElement(Typography, null,
36
- "Please confirm that you want to remove ",
37
- plugin,
38
- ". Note: if any resources in this session still use this plugin, it may cause your session to crash"),
39
- React.createElement(DialogActions, null,
40
- React.createElement(Button, { variant: "contained", color: "primary", onClick: () => {
41
- // avoid showing runtime plugin warning
42
- window.setTimeout(() => {
43
- onClose(plugin);
44
- }, 500);
45
- } }, "Confirm"),
46
- React.createElement(Button, { variant: "contained", color: "secondary", onClick: () => {
47
- onClose();
48
- } }, "Cancel")))));
49
- }
50
- function InstalledPlugin({ plugin, model, pluginManager, }) {
21
+ export default observer(function ({ plugin, model, }) {
51
22
  const [dialogPlugin, setDialogPlugin] = useState();
23
+ const { pluginManager } = getEnv(model);
52
24
  const session = getSession(model);
53
- const { sessionPlugins } = session;
54
- const isSessionPlugin = sessionPlugins === null || sessionPlugins === void 0 ? void 0 : sessionPlugins.some(p => pluginManager.pluginMetadata[plugin.name].url === p.url);
55
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
56
- const rootModel = getParent(model, 3);
57
- const { jbrowse, adminMode } = rootModel;
25
+ const { jbrowse, adminMode, sessionPlugins } = session;
26
+ const isSessionPlugin = sessionPlugins === null || sessionPlugins === void 0 ? void 0 : sessionPlugins.some((p) => pluginManager.pluginMetadata[plugin.name].url === p.url);
58
27
  return (React.createElement(React.Fragment, null,
59
- dialogPlugin ? (React.createElement(PluginDialog, { plugin: dialogPlugin, onClose: name => {
60
- if (name) {
61
- const pluginMetadata = pluginManager.pluginMetadata[plugin.name];
62
- if (adminMode) {
63
- jbrowse.removePlugin(pluginMetadata);
64
- }
65
- else if (isSessionWithSessionPlugins(session)) {
66
- session.removeSessionPlugin(pluginMetadata);
28
+ dialogPlugin ? (React.createElement(Suspense, { fallback: React.createElement(React.Fragment, null) },
29
+ React.createElement(DeletePluginDialog, { plugin: dialogPlugin, onClose: name => {
30
+ if (name) {
31
+ const pluginMetadata = pluginManager.pluginMetadata[plugin.name];
32
+ if (adminMode) {
33
+ jbrowse.removePlugin(pluginMetadata);
34
+ }
35
+ else if (isSessionWithSessionPlugins(session)) {
36
+ session.removeSessionPlugin(pluginMetadata);
37
+ }
67
38
  }
68
- }
69
- setDialogPlugin(undefined);
70
- } })) : null,
39
+ setDialogPlugin(undefined);
40
+ } }))) : null,
71
41
  React.createElement(ListItem, { key: plugin.name },
72
42
  adminMode || isSessionPlugin ? (React.createElement(IconButton, { "aria-label": "removePlugin", "data-testid": `removePlugin-${plugin.name}`, onClick: () => setDialogPlugin(plugin.name) },
73
43
  React.createElement(CloseIcon, null))) : (React.createElement(LockedPlugin, null)),
74
44
  React.createElement(Typography, null, plugin.name))));
75
- }
76
- export default observer(InstalledPlugin);
45
+ });
@@ -1,9 +1,8 @@
1
1
  import React from 'react';
2
2
  import PluginManager from '@jbrowse/core/PluginManager';
3
3
  import { PluginStoreModel } from '../model';
4
- declare function InstalledPluginsList({ pluginManager, model, }: {
4
+ declare const _default: ({ pluginManager, model, }: {
5
5
  pluginManager: PluginManager;
6
6
  model: PluginStoreModel;
7
- }): React.JSX.Element;
8
- declare const _default: typeof InstalledPluginsList;
7
+ }) => React.JSX.Element;
9
8
  export default _default;
@@ -2,14 +2,11 @@ import React from 'react';
2
2
  import { observer } from 'mobx-react';
3
3
  import { List, Typography } from '@mui/material';
4
4
  import InstalledPlugin from './InstalledPlugin';
5
- function InstalledPluginsList({ pluginManager, model, }) {
5
+ export default observer(function InstalledPluginsList({ pluginManager, model, }) {
6
6
  const { plugins } = pluginManager;
7
- const corePlugins = new Set(plugins
8
- .filter(p => { var _a; return (_a = pluginManager.pluginMetadata[p.name]) === null || _a === void 0 ? void 0 : _a.isCore; })
9
- .map(p => p.name));
10
- const externalPlugins = plugins.filter(plugin => !corePlugins.has(plugin.name));
7
+ const { filterText } = model;
8
+ const externalPlugins = plugins.filter(p => { var _a; return !((_a = pluginManager.pluginMetadata[p.name]) === null || _a === void 0 ? void 0 : _a.isCore); });
11
9
  return (React.createElement(List, null, externalPlugins.length > 0 ? (externalPlugins
12
- .filter(plugin => plugin.name.toLowerCase().includes(model.filterText.toLowerCase()))
13
- .map(plugin => (React.createElement(InstalledPlugin, { key: plugin.name, plugin: plugin, model: model, pluginManager: pluginManager })))) : (React.createElement(Typography, null, "No plugins currently installed"))));
14
- }
15
- export default observer(InstalledPluginsList);
10
+ .filter(p => p.name.toLowerCase().includes(filterText.toLowerCase()))
11
+ .map(p => React.createElement(InstalledPlugin, { key: p.name, plugin: p, model: model }))) : (React.createElement(Typography, null, "No plugins currently installed"))));
12
+ });
@@ -11,7 +11,7 @@ import AddIcon from '@mui/icons-material/Add';
11
11
  import CheckIcon from '@mui/icons-material/Check';
12
12
  const useStyles = makeStyles()({
13
13
  card: {
14
- margin: '1em',
14
+ margin: '0.5em',
15
15
  },
16
16
  icon: {
17
17
  marginLeft: '0.5em',
@@ -23,7 +23,6 @@ const useStyles = makeStyles()({
23
23
  dataField: {
24
24
  display: 'flex',
25
25
  alignItems: 'center',
26
- margin: '0.4em 0em',
27
26
  },
28
27
  });
29
28
  export default observer(function PluginCard({ plugin, model, adminMode, }) {
@@ -39,9 +38,8 @@ export default observer(function PluginCard({ plugin, model, adminMode, }) {
39
38
  const { jbrowse } = rootModel;
40
39
  return (React.createElement(Card, { variant: "outlined", key: plugin.name, className: classes.card },
41
40
  React.createElement(CardContent, null,
42
- React.createElement("div", { className: classes.dataField },
43
- React.createElement(Typography, { variant: "h5" },
44
- React.createElement(Link, { href: `${plugin.location}#readme`, target: "_blank", rel: "noopener" }, plugin.name))),
41
+ React.createElement(Typography, { variant: "h5" },
42
+ React.createElement(Link, { href: `${plugin.location}#readme`, target: "_blank", rel: "noopener" }, plugin.name)),
45
43
  React.createElement("div", { className: classes.dataField },
46
44
  React.createElement(PersonIcon, { style: { marginRight: '0.5em' } }),
47
45
  React.createElement(Typography, null, plugin.authors.join(', '))),
@@ -1,4 +1,4 @@
1
- import React, { useState, useEffect } from 'react';
1
+ import React, { useState, lazy, Suspense } from 'react';
2
2
  import { Accordion, AccordionSummary, Button, IconButton, InputAdornment, TextField, Typography, } from '@mui/material';
3
3
  import { makeStyles } from 'tss-react/mui';
4
4
  import { observer } from 'mobx-react';
@@ -12,16 +12,14 @@ import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined';
12
12
  // locals
13
13
  import InstalledPluginsList from './InstalledPluginsList';
14
14
  import PluginCard from './PluginCard';
15
- import CustomPluginForm from './CustomPluginForm';
15
+ import { useFetchPlugins } from './util';
16
+ // lazies
17
+ const AddCustomPluginDialog = lazy(() => import('./AddCustomPluginDialog'));
16
18
  const useStyles = makeStyles()(theme => ({
17
- root: {
18
- margin: theme.spacing(1),
19
- },
20
19
  expandIcon: {
21
20
  color: theme.palette.tertiary.contrastText,
22
21
  },
23
22
  adminBadge: {
24
- margin: '0.5em',
25
23
  borderRadius: 3,
26
24
  backgroundColor: theme.palette.quaternary.main,
27
25
  padding: '1em',
@@ -29,43 +27,17 @@ const useStyles = makeStyles()(theme => ({
29
27
  alignContent: 'center',
30
28
  },
31
29
  customPluginButton: {
32
- margin: '0.5em',
30
+ margin: '1em auto',
33
31
  display: 'flex',
34
- justifyContent: 'center',
35
32
  },
36
33
  }));
37
34
  function PluginStoreWidget({ model }) {
38
35
  const { classes } = useStyles();
39
- const [pluginArray, setPluginArray] = useState();
40
- const [error, setError] = useState();
41
- const [customPluginFormOpen, setCustomPluginFormOpen] = useState(false);
36
+ const { plugins, error } = useFetchPlugins();
37
+ const [open, setOpen] = useState(false);
42
38
  const { adminMode } = getSession(model);
43
39
  const { pluginManager } = getEnv(model);
44
- useEffect(() => {
45
- const controller = new AbortController();
46
- const { signal } = controller;
47
- (async () => {
48
- try {
49
- const response = await fetch('https://jbrowse.org/plugin-store/plugins.json', { signal });
50
- if (!response.ok) {
51
- const err = await response.text();
52
- throw new Error(`Failed to fetch plugin data: ${response.status} ${response.statusText} ${err}`);
53
- }
54
- const array = await response.json();
55
- if (!signal.aborted) {
56
- setPluginArray(array.plugins);
57
- }
58
- }
59
- catch (e) {
60
- console.error(e);
61
- setError(e);
62
- }
63
- })();
64
- return () => {
65
- controller.abort();
66
- };
67
- }, []);
68
- return (React.createElement("div", { className: classes.root },
40
+ return (React.createElement("div", null,
69
41
  adminMode && (React.createElement(React.Fragment, null,
70
42
  !isElectron && (React.createElement("div", { className: classes.adminBadge },
71
43
  React.createElement(InfoOutlinedIcon, { style: { marginRight: '0.3em' } }),
@@ -73,9 +45,9 @@ function PluginStoreWidget({ model }) {
73
45
  "You are using the ",
74
46
  React.createElement("code", null, "admin-server"),
75
47
  ". Any changes you make will be saved to your configuration file. You also have the ability to add custom plugins that are not in the store."))),
76
- React.createElement("div", { className: classes.customPluginButton },
77
- React.createElement(Button, { variant: "contained", onClick: () => setCustomPluginFormOpen(true) }, "Add custom plugin")),
78
- React.createElement(CustomPluginForm, { open: customPluginFormOpen, onClose: () => setCustomPluginFormOpen(false), model: model }))),
48
+ React.createElement(Button, { className: classes.customPluginButton, variant: "contained", onClick: () => setOpen(true) }, "Add custom plugin"),
49
+ open ? (React.createElement(Suspense, { fallback: React.createElement(React.Fragment, null) },
50
+ React.createElement(AddCustomPluginDialog, { onClose: () => setOpen(false), model: model }))) : null)),
79
51
  React.createElement(TextField, { label: "Filter plugins", value: model.filterText, onChange: event => model.setFilterText(event.target.value), fullWidth: true, InputProps: {
80
52
  endAdornment: (React.createElement(InputAdornment, { position: "end" },
81
53
  React.createElement(IconButton, { onClick: () => model.clearFilterText() },
@@ -89,7 +61,7 @@ function PluginStoreWidget({ model }) {
89
61
  React.createElement(Accordion, { defaultExpanded: true },
90
62
  React.createElement(AccordionSummary, { expandIcon: React.createElement(ExpandMoreIcon, { className: classes.expandIcon }) },
91
63
  React.createElement(Typography, { variant: "h5" }, "Available plugins")),
92
- error ? (React.createElement(Typography, { color: "error" }, `${error}`)) : pluginArray ? (pluginArray
64
+ error ? (React.createElement(Typography, { color: "error" }, `${error}`)) : plugins ? (plugins
93
65
  .filter(plugin => {
94
66
  // If plugin only has cjsUrl, don't display outside desktop
95
67
  return (!(isElectron && plugin.cjsUrl) &&
@@ -0,0 +1,5 @@
1
+ import { JBrowsePlugin } from '@jbrowse/core/util/types';
2
+ export declare function useFetchPlugins(): {
3
+ plugins: JBrowsePlugin[] | undefined;
4
+ error: unknown;
5
+ };
@@ -0,0 +1,25 @@
1
+ import { useState, useEffect } from 'react';
2
+ export function useFetchPlugins() {
3
+ const [plugins, setPlugins] = useState();
4
+ const [error, setError] = useState();
5
+ useEffect(() => {
6
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
7
+ ;
8
+ (async () => {
9
+ try {
10
+ const res = await fetch('https://jbrowse.org/plugin-store/plugins.json');
11
+ if (!res.ok) {
12
+ const err = await res.text();
13
+ throw new Error(`HTTP ${res.status} fetching plugins: ${err}`);
14
+ }
15
+ const array = await res.json();
16
+ setPlugins(array.plugins);
17
+ }
18
+ catch (e) {
19
+ console.error(e);
20
+ setError(e);
21
+ }
22
+ })();
23
+ }, []);
24
+ return { plugins, error };
25
+ }
@@ -1,6 +1,6 @@
1
1
  import { Instance } from 'mobx-state-tree';
2
2
  import PluginManager from '@jbrowse/core/PluginManager';
3
- export default function f(pluginManager: PluginManager): import("mobx-state-tree").IModelType<{
3
+ export default function stateModelFactory(pluginManager: PluginManager): import("mobx-state-tree").IModelType<{
4
4
  id: import("mobx-state-tree").IOptionalIType<import("mobx-state-tree").ISimpleType<string>, [undefined]>;
5
5
  type: import("mobx-state-tree").ISimpleType<"PluginStoreWidget">;
6
6
  filterText: import("mobx-state-tree").IType<string | undefined, string, string>;
@@ -9,5 +9,5 @@ export default function f(pluginManager: PluginManager): import("mobx-state-tree
9
9
  clearFilterText(): void;
10
10
  setFilterText(newText: string): void;
11
11
  }, import("mobx-state-tree")._NotCustomized, import("mobx-state-tree")._NotCustomized>;
12
- export type PluginStoreStateModel = ReturnType<typeof f>;
12
+ export type PluginStoreStateModel = ReturnType<typeof stateModelFactory>;
13
13
  export type PluginStoreModel = Instance<PluginStoreStateModel>;
@@ -1,6 +1,6 @@
1
1
  import { types } from 'mobx-state-tree';
2
2
  import { ElementId } from '@jbrowse/core/util/types/mst';
3
- export default function f(pluginManager) {
3
+ export default function stateModelFactory(pluginManager) {
4
4
  return types
5
5
  .model('PluginStoreModel', {
6
6
  id: ElementId,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jbrowse/plugin-data-management",
3
- "version": "2.6.2",
3
+ "version": "2.6.3",
4
4
  "description": "JBrowse 2 linear genome view",
5
5
  "keywords": [
6
6
  "jbrowse",
@@ -60,5 +60,5 @@
60
60
  "distModule": "esm/index.js",
61
61
  "srcModule": "src/index.ts",
62
62
  "module": "esm/index.js",
63
- "gitHead": "bbea587a402d9974acdd804a33f4b77f31a2fd5f"
63
+ "gitHead": "ed402c87efb0904858d602c363bd1757d5742129"
64
64
  }
@@ -1,9 +0,0 @@
1
- import React from 'react';
2
- import { PluginStoreModel } from '../model';
3
- declare function CustomPluginForm({ open, onClose, model, }: {
4
- open: boolean;
5
- onClose(): void;
6
- model: PluginStoreModel;
7
- }): React.JSX.Element;
8
- declare const _default: typeof CustomPluginForm;
9
- export default _default;
@@ -1,9 +0,0 @@
1
- import React from 'react';
2
- import { PluginStoreModel } from '../model';
3
- declare function CustomPluginForm({ open, onClose, model, }: {
4
- open: boolean;
5
- onClose(): void;
6
- model: PluginStoreModel;
7
- }): React.JSX.Element;
8
- declare const _default: typeof CustomPluginForm;
9
- export default _default;