@jbrowse/plugin-grid-bookmark 2.6.3 → 2.7.0

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 (71) hide show
  1. package/dist/GridBookmarkWidget/components/AssemblySelector.d.ts +3 -4
  2. package/dist/GridBookmarkWidget/components/AssemblySelector.js +27 -37
  3. package/dist/GridBookmarkWidget/components/BookmarkGrid.d.ts +6 -0
  4. package/dist/GridBookmarkWidget/components/BookmarkGrid.js +120 -0
  5. package/dist/GridBookmarkWidget/components/{ClearBookmarks.d.ts → DeleteBookmarks.d.ts} +2 -3
  6. package/dist/GridBookmarkWidget/components/DeleteBookmarks.js +41 -0
  7. package/dist/GridBookmarkWidget/components/DeleteBookmarksDialog.d.ts +7 -0
  8. package/dist/GridBookmarkWidget/components/DeleteBookmarksDialog.js +29 -0
  9. package/dist/GridBookmarkWidget/components/EditBookmarkLabelDialog.d.ts +8 -0
  10. package/dist/GridBookmarkWidget/components/EditBookmarkLabelDialog.js +50 -0
  11. package/dist/GridBookmarkWidget/components/ExportBookmarks.d.ts +6 -0
  12. package/dist/GridBookmarkWidget/components/{ClearBookmarks.js → ExportBookmarks.js} +9 -19
  13. package/dist/GridBookmarkWidget/components/ExportBookmarksDialog.d.ts +7 -0
  14. package/dist/GridBookmarkWidget/components/{DownloadBookmarks.js → ExportBookmarksDialog.js} +22 -20
  15. package/dist/GridBookmarkWidget/components/GridBookmarkWidget.d.ts +3 -4
  16. package/dist/GridBookmarkWidget/components/GridBookmarkWidget.js +28 -102
  17. package/dist/GridBookmarkWidget/components/ImportBookmarks.d.ts +3 -5
  18. package/dist/GridBookmarkWidget/components/ImportBookmarks.js +8 -64
  19. package/dist/GridBookmarkWidget/components/ImportBookmarksDialog.d.ts +7 -0
  20. package/dist/GridBookmarkWidget/components/ImportBookmarksDialog.js +129 -0
  21. package/{esm/GridBookmarkWidget/components/ClearBookmarks.d.ts → dist/GridBookmarkWidget/components/ShareBookmarks.d.ts} +2 -3
  22. package/dist/GridBookmarkWidget/components/ShareBookmarks.js +37 -0
  23. package/dist/GridBookmarkWidget/components/ShareBookmarksDialog.d.ts +7 -0
  24. package/dist/GridBookmarkWidget/components/ShareBookmarksDialog.js +106 -0
  25. package/dist/GridBookmarkWidget/model.d.ts +178 -11
  26. package/dist/GridBookmarkWidget/model.js +105 -27
  27. package/dist/GridBookmarkWidget/sessionSharing.d.ts +6 -0
  28. package/dist/GridBookmarkWidget/sessionSharing.js +96 -0
  29. package/dist/GridBookmarkWidget/utils.d.ts +19 -3
  30. package/dist/GridBookmarkWidget/utils.js +132 -40
  31. package/dist/index.d.ts +1 -1
  32. package/dist/index.js +100 -75
  33. package/esm/GridBookmarkWidget/components/AssemblySelector.d.ts +3 -4
  34. package/esm/GridBookmarkWidget/components/AssemblySelector.js +28 -38
  35. package/esm/GridBookmarkWidget/components/BookmarkGrid.d.ts +6 -0
  36. package/esm/GridBookmarkWidget/components/BookmarkGrid.js +92 -0
  37. package/{dist/GridBookmarkWidget/components/DownloadBookmarks.d.ts → esm/GridBookmarkWidget/components/DeleteBookmarks.d.ts} +2 -3
  38. package/esm/GridBookmarkWidget/components/DeleteBookmarks.js +13 -0
  39. package/esm/GridBookmarkWidget/components/DeleteBookmarksDialog.d.ts +7 -0
  40. package/esm/GridBookmarkWidget/components/DeleteBookmarksDialog.js +24 -0
  41. package/esm/GridBookmarkWidget/components/EditBookmarkLabelDialog.d.ts +8 -0
  42. package/esm/GridBookmarkWidget/components/EditBookmarkLabelDialog.js +25 -0
  43. package/esm/GridBookmarkWidget/components/ExportBookmarks.d.ts +6 -0
  44. package/esm/GridBookmarkWidget/components/ExportBookmarks.js +13 -0
  45. package/esm/GridBookmarkWidget/components/ExportBookmarksDialog.d.ts +7 -0
  46. package/esm/GridBookmarkWidget/components/ExportBookmarksDialog.js +35 -0
  47. package/esm/GridBookmarkWidget/components/GridBookmarkWidget.d.ts +3 -4
  48. package/esm/GridBookmarkWidget/components/GridBookmarkWidget.js +28 -79
  49. package/esm/GridBookmarkWidget/components/ImportBookmarks.d.ts +3 -5
  50. package/esm/GridBookmarkWidget/components/ImportBookmarks.js +10 -66
  51. package/esm/GridBookmarkWidget/components/ImportBookmarksDialog.d.ts +7 -0
  52. package/esm/GridBookmarkWidget/components/ImportBookmarksDialog.js +101 -0
  53. package/esm/GridBookmarkWidget/components/{DownloadBookmarks.d.ts → ShareBookmarks.d.ts} +2 -3
  54. package/esm/GridBookmarkWidget/components/ShareBookmarks.js +12 -0
  55. package/esm/GridBookmarkWidget/components/ShareBookmarksDialog.d.ts +7 -0
  56. package/esm/GridBookmarkWidget/components/ShareBookmarksDialog.js +78 -0
  57. package/esm/GridBookmarkWidget/model.d.ts +178 -11
  58. package/esm/GridBookmarkWidget/model.js +106 -28
  59. package/esm/GridBookmarkWidget/sessionSharing.d.ts +6 -0
  60. package/esm/GridBookmarkWidget/sessionSharing.js +68 -0
  61. package/esm/GridBookmarkWidget/utils.d.ts +19 -3
  62. package/esm/GridBookmarkWidget/utils.js +105 -39
  63. package/esm/index.d.ts +1 -1
  64. package/esm/index.js +101 -76
  65. package/package.json +4 -3
  66. package/dist/GridBookmarkWidget/components/DeleteBookmark.d.ts +0 -9
  67. package/dist/GridBookmarkWidget/components/DeleteBookmark.js +0 -31
  68. package/esm/GridBookmarkWidget/components/ClearBookmarks.js +0 -23
  69. package/esm/GridBookmarkWidget/components/DeleteBookmark.d.ts +0 -9
  70. package/esm/GridBookmarkWidget/components/DeleteBookmark.js +0 -26
  71. package/esm/GridBookmarkWidget/components/DownloadBookmarks.js +0 -33
@@ -1,88 +1,37 @@
1
- import React, { useState } from 'react';
1
+ import React from 'react';
2
2
  import { observer } from 'mobx-react';
3
- import { Link, IconButton, Typography } from '@mui/material';
3
+ import { Alert } from '@mui/material';
4
4
  import { makeStyles } from 'tss-react/mui';
5
- import { DataGrid } from '@mui/x-data-grid';
6
- import { getSession, assembleLocString, measureGridWidth, } from '@jbrowse/core/util';
7
- // icons
8
- import DeleteIcon from '@mui/icons-material/Delete';
9
5
  // locals
10
- import AssemblySelector from './AssemblySelector';
11
- import DeleteBookmarkDialog from './DeleteBookmark';
12
- import DownloadBookmarks from './DownloadBookmarks';
6
+ import BookmarkGrid from './BookmarkGrid';
7
+ import DeleteBookmarks from './DeleteBookmarks';
8
+ import ExportBookmarks from './ExportBookmarks';
13
9
  import ImportBookmarks from './ImportBookmarks';
14
- import ClearBookmarks from './ClearBookmarks';
15
- import { navToBookmark } from '../utils';
16
- const useStyles = makeStyles()(theme => ({
17
- link: {
18
- cursor: 'pointer',
19
- },
20
- margin: {
21
- margin: theme.spacing(2),
10
+ import AssemblySelector from './AssemblySelector';
11
+ import ShareBookmarks from './ShareBookmarks';
12
+ const useStyles = makeStyles()({
13
+ card: {
14
+ marginTop: 5,
22
15
  },
23
- }));
24
- const BookmarkGrid = observer(({ model }) => {
25
- const { classes } = useStyles();
26
- const [dialogRowNumber, setDialogRowNumber] = useState();
27
- const { bookmarkedRegions, selectedAssembly } = model;
28
- const session = getSession(model);
29
- const bookmarkRows = bookmarkedRegions
30
- .filter(r => selectedAssembly === 'all' || r.assemblyName === selectedAssembly)
31
- .map((region, index) => {
32
- const { assemblyName, ...rest } = region;
33
- return {
34
- ...region,
35
- id: index,
36
- delete: index,
37
- locString: assembleLocString(selectedAssembly === 'all' ? region : rest),
38
- };
39
- });
40
- return (React.createElement(React.Fragment, null,
41
- React.createElement(DataGrid, { density: "compact", rows: bookmarkRows, columns: [
42
- {
43
- field: 'locString',
44
- headerName: 'bookmark link',
45
- width: measureGridWidth(bookmarkRows.map(row => row.locString)),
46
- renderCell: params => (React.createElement(Link, { className: classes.link, href: "#", onClick: async (event) => {
47
- event.preventDefault();
48
- await navToBookmark(params.value, session.views, model);
49
- } }, params.value)),
50
- },
51
- {
52
- field: 'label',
53
- width: measureGridWidth(bookmarkRows.map(row => row.label)),
54
- editable: true,
55
- },
56
- {
57
- field: 'delete',
58
- width: 100,
59
- renderCell: params => (React.createElement(IconButton, { "data-testid": "deleteBookmark", "aria-label": "delete", onClick: () => {
60
- if (params.value != null) {
61
- setDialogRowNumber(+params.value);
62
- }
63
- } },
64
- React.createElement(DeleteIcon, null))),
65
- },
66
- ], processRowUpdate: row => {
67
- model.updateBookmarkLabel(row.id, row.label);
68
- return row;
69
- }, onProcessRowUpdateError: e => {
70
- session.notify(e.message, 'error');
71
- }, disableRowSelectionOnClick: true }),
72
- React.createElement(DeleteBookmarkDialog, { rowNumber: dialogRowNumber, model: model, onClose: () => setDialogRowNumber(undefined) })));
73
16
  });
74
- function GridBookmarkWidget({ model }) {
75
- const { selectedAssembly } = model;
17
+ const GridBookmarkWidget = observer(function GridBookmarkWidget({ model, }) {
76
18
  const { classes } = useStyles();
77
- return (React.createElement(React.Fragment, null,
19
+ if (!model) {
20
+ return null;
21
+ }
22
+ return (React.createElement("div", { className: classes.card },
23
+ React.createElement("div", null,
24
+ React.createElement(ExportBookmarks, { model: model }),
25
+ React.createElement(ImportBookmarks, { model: model }),
26
+ React.createElement(ShareBookmarks, { model: model }),
27
+ React.createElement(DeleteBookmarks, { model: model })),
28
+ React.createElement(Alert, { severity: "info" },
29
+ "Click and type within the ",
30
+ React.createElement("strong", null, "label"),
31
+ " field to annotate your bookmark. Double click the ",
32
+ React.createElement("strong", null, "label"),
33
+ " field to do so within a dialog."),
78
34
  React.createElement(AssemblySelector, { model: model }),
79
- React.createElement(DownloadBookmarks, { model: model }),
80
- React.createElement(ImportBookmarks, { model: model, assemblyName: selectedAssembly }),
81
- React.createElement(ClearBookmarks, { model: model }),
82
- React.createElement(Typography, { className: classes.margin },
83
- "Note: you can double click the ",
84
- React.createElement("code", null, "label"),
85
- " field to add your own custom notes"),
86
35
  React.createElement(BookmarkGrid, { model: model })));
87
- }
88
- export default observer(GridBookmarkWidget);
36
+ });
37
+ export default GridBookmarkWidget;
@@ -1,8 +1,6 @@
1
1
  import React from 'react';
2
2
  import { GridBookmarkModel } from '../model';
3
- declare function ImportBookmarks({ model, assemblyName, }: {
3
+ declare const ImportBookmarks: ({ model, }: {
4
4
  model: GridBookmarkModel;
5
- assemblyName: string;
6
- }): React.JSX.Element;
7
- declare const _default: typeof ImportBookmarks;
8
- export default _default;
5
+ }) => React.JSX.Element;
6
+ export default ImportBookmarks;
@@ -1,70 +1,14 @@
1
- import React, { useState } from 'react';
1
+ import React, { useState, Suspense, lazy } from 'react';
2
2
  import { observer } from 'mobx-react';
3
- import { getSession } from '@jbrowse/core/util';
4
- import AssemblySelector from '@jbrowse/core/ui/AssemblySelector';
5
- import { FileSelector } from '@jbrowse/core/ui';
6
- import { openLocation } from '@jbrowse/core/util/io';
7
- import { Button, DialogContent, DialogActions, Typography } from '@mui/material';
8
- import { Dialog } from '@jbrowse/core/ui';
9
- import { makeStyles } from 'tss-react/mui';
3
+ import { Button } from '@mui/material';
10
4
  // icons
11
5
  import ImportIcon from '@mui/icons-material/Publish';
12
- const useStyles = makeStyles()(() => ({
13
- dialogContainer: {
14
- margin: 15,
15
- },
16
- flexItem: {
17
- margin: 5,
18
- },
19
- }));
20
- function ImportBookmarks({ model, assemblyName, }) {
21
- const { classes } = useStyles();
22
- const session = getSession(model);
23
- const { assemblyNames } = session;
24
- const [dialogOpen, setDialogOpen] = useState(false);
25
- const [location, setLocation] = useState();
26
- const [error, setError] = useState();
27
- const [selectedAsm, setSelectedAsm] = useState(assemblyName || assemblyNames[0]);
6
+ const ImportBookmarksDialog = lazy(() => import('./ImportBookmarksDialog'));
7
+ const ImportBookmarks = observer(function ({ model, }) {
8
+ const [open, setOpen] = useState(false);
28
9
  return (React.createElement(React.Fragment, null,
29
- React.createElement(Button, { startIcon: React.createElement(ImportIcon, null), onClick: () => setDialogOpen(true) }, "Import"),
30
- React.createElement(Dialog, { open: dialogOpen, onClose: () => setDialogOpen(false), maxWidth: "xl", title: "Import bookmarks" },
31
- React.createElement(DialogContent, null,
32
- React.createElement(Typography, null, "Choose a BED format file to import. The first 4 columns will be used"),
33
- React.createElement(FileSelector, { location: location, setLocation: setLocation, name: "File" }),
34
- React.createElement(Typography, null, "Select assembly that your data belongs to"),
35
- React.createElement(AssemblySelector, { onChange: val => setSelectedAsm(val), session: session, selected: selectedAsm }),
36
- error ? (React.createElement(Typography, { color: "error", variant: "h6" }, `${error}`)) : null),
37
- React.createElement(DialogActions, null,
38
- React.createElement(Button, { variant: "contained", color: "secondary", onClick: () => setDialogOpen(false) }, "Cancel"),
39
- React.createElement(Button, { className: classes.flexItem, "data-testid": "dialogImport", variant: "contained", color: "primary", disabled: !location, startIcon: React.createElement(ImportIcon, null), onClick: async () => {
40
- try {
41
- if (!location) {
42
- return;
43
- }
44
- const data = await openLocation(location).readFile('utf8');
45
- const regions = data
46
- .split(/\n|\r\n|\r/)
47
- .filter(f => !!f.trim())
48
- .filter(f => !f.startsWith('#') &&
49
- !f.startsWith('track') &&
50
- !f.startsWith('browser'))
51
- .map(line => {
52
- const [refName, start, end, name] = line.split('\t');
53
- return {
54
- assemblyName: selectedAsm,
55
- refName,
56
- start: +start,
57
- end: +end,
58
- label: name === '.' ? undefined : name,
59
- };
60
- });
61
- model.importBookmarks(regions);
62
- setDialogOpen(false);
63
- }
64
- catch (e) {
65
- console.error(e);
66
- setError(e);
67
- }
68
- } }, "Import")))));
69
- }
70
- export default observer(ImportBookmarks);
10
+ React.createElement(Button, { startIcon: React.createElement(ImportIcon, null), onClick: () => setOpen(true) }, "Import"),
11
+ open ? (React.createElement(Suspense, { fallback: React.createElement(React.Fragment, null) },
12
+ React.createElement(ImportBookmarksDialog, { onClose: () => setOpen(false), model: model }))) : null));
13
+ });
14
+ export default ImportBookmarks;
@@ -0,0 +1,7 @@
1
+ import React from 'react';
2
+ import { GridBookmarkModel } from '../model';
3
+ declare const ImportBookmarksDialog: ({ onClose, model, }: {
4
+ onClose: () => void;
5
+ model: GridBookmarkModel;
6
+ }) => React.JSX.Element;
7
+ export default ImportBookmarksDialog;
@@ -0,0 +1,101 @@
1
+ import React, { useState } from 'react';
2
+ import { observer } from 'mobx-react';
3
+ import { getSession } from '@jbrowse/core/util';
4
+ import { isSessionWithShareURL } from '@jbrowse/core/util/types';
5
+ import { FileSelector } from '@jbrowse/core/ui';
6
+ import { Button, DialogContent, DialogActions, Typography, TextField, Accordion, AccordionSummary, AccordionDetails, Tooltip, } from '@mui/material';
7
+ import { openLocation } from '@jbrowse/core/util/io';
8
+ import { Dialog } from '@jbrowse/core/ui';
9
+ import AssemblySelector from '@jbrowse/core/ui/AssemblySelector';
10
+ import { makeStyles } from 'tss-react/mui';
11
+ // icons
12
+ import ImportIcon from '@mui/icons-material/Publish';
13
+ import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
14
+ import HelpIcon from '@mui/icons-material/Help';
15
+ import { fromUrlSafeB64 } from '../utils';
16
+ import { readSessionFromDynamo } from '../sessionSharing';
17
+ const useStyles = makeStyles()(theme => {
18
+ var _a;
19
+ return ({
20
+ flexItem: {
21
+ margin: 5,
22
+ },
23
+ expandIcon: {
24
+ color: ((_a = theme.palette.tertiary) === null || _a === void 0 ? void 0 : _a.contrastText) || '#fff',
25
+ },
26
+ });
27
+ });
28
+ async function getBookmarksFromShareLink(shareLink, shareURL) {
29
+ const defaultURL = 'https://share.jbrowse.org/api/v1/';
30
+ const urlParams = new URL(shareLink);
31
+ const sessionQueryParam = urlParams.searchParams.get('bookmarks');
32
+ const password = urlParams.searchParams.get('password');
33
+ const decryptedSession = await readSessionFromDynamo(`${shareURL !== null && shareURL !== void 0 ? shareURL : defaultURL}load`, sessionQueryParam || '', password || '');
34
+ const sharedSession = JSON.parse(await fromUrlSafeB64(decryptedSession));
35
+ return sharedSession.sharedBookmarks;
36
+ }
37
+ async function getBookmarksFromFile(location, selectedAsm) {
38
+ const data = await openLocation(location).readFile('utf8');
39
+ return data
40
+ .split(/\n|\r\n|\r/)
41
+ .filter(f => !!f.trim())
42
+ .filter(f => !f.startsWith('#') &&
43
+ !f.startsWith('track') &&
44
+ !f.startsWith('browser'))
45
+ .map(line => {
46
+ const [refName, start, end, label, assembly] = line.split('\t');
47
+ return {
48
+ assemblyName: assembly !== null && assembly !== void 0 ? assembly : selectedAsm,
49
+ refName,
50
+ start: +start,
51
+ end: +end,
52
+ label: label === '.' ? undefined : label,
53
+ };
54
+ });
55
+ }
56
+ const ImportBookmarksDialog = observer(function ({ onClose, model, }) {
57
+ const { classes } = useStyles();
58
+ const [location, setLocation] = useState();
59
+ const [error, setError] = useState();
60
+ const [shareLink, setShareLink] = useState('');
61
+ const session = getSession(model);
62
+ const { assemblyNames } = session;
63
+ const [selectedAsm, setSelectedAsm] = useState(assemblyNames[0]);
64
+ const [expanded, setExpanded] = useState('shareLinkAccordion');
65
+ return (React.createElement(Dialog, { open: true, onClose: onClose, maxWidth: "xl", title: "Import bookmarks" },
66
+ React.createElement(DialogContent, null,
67
+ React.createElement(Accordion, { expanded: expanded === 'shareLinkAccordion', onChange: () => setExpanded('shareLinkAccordion') },
68
+ React.createElement(AccordionSummary, { expandIcon: React.createElement(ExpandMoreIcon, { className: classes.expandIcon }) },
69
+ React.createElement(Typography, { style: { display: 'flex', alignItems: 'center', gap: '5px' } },
70
+ "Import from share link",
71
+ ' ',
72
+ React.createElement(Tooltip, { title: "The appropriate share link for sharing bookmarks is one generated via the 'Share' button in the 'Bookmarked regions' drawer. Paste it below to import shared bookmarks." },
73
+ React.createElement(HelpIcon, null)))),
74
+ React.createElement(AccordionDetails, null,
75
+ React.createElement(TextField, { label: "Enter URL", variant: "outlined", style: { width: '100%' }, value: shareLink, onChange: e => setShareLink(e.target.value) }))),
76
+ React.createElement(Accordion, { expanded: expanded === 'fileAccordion', onChange: () => setExpanded('fileAccordion') },
77
+ React.createElement(AccordionSummary, { expandIcon: React.createElement(ExpandMoreIcon, { className: classes.expandIcon }) },
78
+ React.createElement(Typography, null, "Import from file")),
79
+ React.createElement(AccordionDetails, null,
80
+ React.createElement(FileSelector, { location: location, setLocation: setLocation, name: "File", description: "Choose a BED or TSV format file to import." }),
81
+ React.createElement(AssemblySelector, { onChange: val => setSelectedAsm(val), helperText: `Select the assembly your bookmarks belong to (BED or TSV without assembly column).`, session: session, selected: selectedAsm }))),
82
+ error ? (React.createElement(Typography, { color: "error", variant: "h6" }, `${error}`)) : null),
83
+ React.createElement(DialogActions, null,
84
+ React.createElement(Button, { variant: "contained", color: "secondary", onClick: onClose }, "Cancel"),
85
+ React.createElement(Button, { className: classes.flexItem, "data-testid": "dialogImport", variant: "contained", color: "primary", disabled: !location && !shareLink, startIcon: React.createElement(ImportIcon, null), onClick: async () => {
86
+ try {
87
+ if (location) {
88
+ model.importBookmarks(await getBookmarksFromFile(location, selectedAsm));
89
+ }
90
+ else if (shareLink && isSessionWithShareURL(session)) {
91
+ model.importBookmarks(await getBookmarksFromShareLink(shareLink, session.shareURL));
92
+ }
93
+ onClose();
94
+ }
95
+ catch (e) {
96
+ console.error(e);
97
+ setError(e);
98
+ }
99
+ } }, "Import"))));
100
+ });
101
+ export default ImportBookmarksDialog;
@@ -1,7 +1,6 @@
1
1
  import React from 'react';
2
2
  import { GridBookmarkModel } from '../model';
3
- declare function DownloadBookmarks({ model }: {
3
+ declare function ShareBookmarks({ model }: {
4
4
  model: GridBookmarkModel;
5
5
  }): React.JSX.Element;
6
- declare const _default: typeof DownloadBookmarks;
7
- export default _default;
6
+ export default ShareBookmarks;
@@ -0,0 +1,12 @@
1
+ import React, { Suspense, lazy, useState } from 'react';
2
+ import { Button } from '@mui/material';
3
+ import { ContentCopy as ContentCopyIcon } from '@jbrowse/core/ui/Icons';
4
+ const ShareBookmarksDialog = lazy(() => import('./ShareBookmarksDialog'));
5
+ function ShareBookmarks({ model }) {
6
+ const [open, setOpen] = useState(false);
7
+ return (React.createElement(React.Fragment, null,
8
+ React.createElement(Button, { startIcon: React.createElement(ContentCopyIcon, null), onClick: () => setOpen(true) }, "Share"),
9
+ open ? (React.createElement(Suspense, { fallback: React.createElement(React.Fragment, null) },
10
+ React.createElement(ShareBookmarksDialog, { onClose: () => setOpen(false), model: model }))) : null));
11
+ }
12
+ export default ShareBookmarks;
@@ -0,0 +1,7 @@
1
+ import React from 'react';
2
+ import { GridBookmarkModel } from '../model';
3
+ declare const ShareBookmarksDialog: ({ onClose, model, }: {
4
+ onClose: () => void;
5
+ model: GridBookmarkModel;
6
+ }) => React.JSX.Element;
7
+ export default ShareBookmarksDialog;
@@ -0,0 +1,78 @@
1
+ import React, { useEffect, useState } from 'react';
2
+ import { observer } from 'mobx-react';
3
+ import { getSnapshot } from 'mobx-state-tree';
4
+ import { Alert, Button, DialogActions, DialogContent, DialogContentText, TextField, Typography, } from '@mui/material';
5
+ import { makeStyles } from 'tss-react/mui';
6
+ import copy from 'copy-to-clipboard';
7
+ import { getSession, isSessionWithShareURL } from '@jbrowse/core/util';
8
+ import { Dialog, ErrorMessage } from '@jbrowse/core/ui';
9
+ import { ContentCopy as ContentCopyIcon } from '@jbrowse/core/ui/Icons';
10
+ // locals
11
+ import { shareSessionToDynamo } from '../sessionSharing';
12
+ const useStyles = makeStyles()(() => ({
13
+ flexItem: {
14
+ margin: 5,
15
+ },
16
+ }));
17
+ const ShareBookmarksDialog = observer(function ({ onClose, model, }) {
18
+ const { classes } = useStyles();
19
+ const [url, setUrl] = useState('');
20
+ const [error, setError] = useState();
21
+ const [loading, setLoading] = useState(true);
22
+ const session = getSession(model);
23
+ const { selectedBookmarks } = model;
24
+ const shareAll = selectedBookmarks.length === 0;
25
+ const bookmarksToShare = selectedBookmarks.length === 0
26
+ ? model.allBookmarksModel
27
+ : model.sharedBookmarksModel;
28
+ useEffect(() => {
29
+ let cancelled = false;
30
+ (async () => {
31
+ try {
32
+ if (!isSessionWithShareURL(session)) {
33
+ throw new Error('No shareURL configured');
34
+ }
35
+ setLoading(true);
36
+ const snap = getSnapshot(bookmarksToShare);
37
+ const locationUrl = new URL(window.location.href);
38
+ const result = await shareSessionToDynamo(snap, session.shareURL, locationUrl.href);
39
+ if (!cancelled) {
40
+ const params = new URLSearchParams(locationUrl.search);
41
+ params.set('bookmarks', `share-${result.json.sessionId}`);
42
+ params.set('password', result.password);
43
+ locationUrl.search = params.toString();
44
+ setUrl(locationUrl.href);
45
+ setLoading(false);
46
+ }
47
+ }
48
+ catch (e) {
49
+ setError(e);
50
+ }
51
+ finally {
52
+ setLoading(false);
53
+ }
54
+ })();
55
+ return () => {
56
+ cancelled = true;
57
+ };
58
+ }, [bookmarksToShare, session]);
59
+ return (React.createElement(Dialog, { open: true, onClose: onClose, title: "Share bookmarks" },
60
+ React.createElement(DialogContent, { style: { display: 'flex', flexFlow: 'column', gap: '5px' } },
61
+ React.createElement(Alert, { severity: "info" }, shareAll ? (React.createElement(React.Fragment, null,
62
+ React.createElement("span", null, "All bookmarks will be shared."),
63
+ React.createElement("br", null),
64
+ React.createElement("span", null, "Use the checkboxes to select individual bookmarks to share."))) : ('Only selected bookmarks will be shared.')),
65
+ React.createElement(DialogContentText, null, "Copy the URL below to share your bookmarks."),
66
+ error ? (React.createElement(ErrorMessage, { error: error })) : loading ? (React.createElement(Typography, null, "Generating short URL...")) : (React.createElement(TextField, { label: "URL", value: url, InputProps: { readOnly: true }, variant: "filled", fullWidth: true, onClick: event => {
67
+ const target = event.target;
68
+ target.select();
69
+ } })),
70
+ React.createElement(DialogContentText, null, "The URL should be pasted into the \"Import from share link\" field in the \"Import\" form found in the \"Bookmarked regions\" drawer.")),
71
+ React.createElement(DialogActions, null,
72
+ React.createElement(Button, { className: classes.flexItem, "data-testid": "dialogShare", variant: "contained", color: "primary", disabled: loading, startIcon: React.createElement(ContentCopyIcon, null), onClick: async () => {
73
+ copy(url);
74
+ session.notify('Copied to clipboard', 'success');
75
+ onClose();
76
+ } }, "Copy share link"))));
77
+ });
78
+ export default ShareBookmarksDialog;
@@ -1,11 +1,48 @@
1
- import { Instance } from 'mobx-state-tree';
1
+ import { Instance, SnapshotIn, IMSTArray } from 'mobx-state-tree';
2
2
  import PluginManager from '@jbrowse/core/PluginManager';
3
3
  import { Region } from '@jbrowse/core/util/types';
4
- export default function f(pluginManager: PluginManager): import("mobx-state-tree").IModelType<{
4
+ declare const LabeledRegionModel: import("mobx-state-tree").IModelType<{
5
+ refName: import("mobx-state-tree").ISimpleType<string>;
6
+ start: import("mobx-state-tree").ISimpleType<number>;
7
+ end: import("mobx-state-tree").ISimpleType<number>;
8
+ reversed: import("mobx-state-tree").IOptionalIType<import("mobx-state-tree").ISimpleType<boolean>, [undefined]>;
9
+ } & {
10
+ assemblyName: import("mobx-state-tree").ISimpleType<string>;
11
+ } & {
12
+ label: import("mobx-state-tree").IOptionalIType<import("mobx-state-tree").ISimpleType<string>, [undefined]>;
13
+ }, {
14
+ setRefName(newRefName: string): void;
15
+ } & {
16
+ setLabel(label: string): void;
17
+ }, import("mobx-state-tree")._NotCustomized, import("mobx-state-tree")._NotCustomized>;
18
+ export interface ILabeledRegionModel extends SnapshotIn<typeof LabeledRegionModel> {
19
+ refName: string;
20
+ start: number;
21
+ end: number;
22
+ reversed: boolean;
23
+ assemblyName: string;
24
+ label: string;
25
+ setRefName: (newRefName: string) => void;
26
+ setLabel: (label: string) => void;
27
+ }
28
+ export interface IExtendedLabeledRegionModel extends ILabeledRegionModel {
29
+ id: number;
30
+ correspondingObj: ILabeledRegionModel;
31
+ }
32
+ export default function f(_pluginManager: PluginManager): import("mobx-state-tree").IModelType<{
33
+ /**
34
+ * #property
35
+ */
5
36
  id: import("mobx-state-tree").IOptionalIType<import("mobx-state-tree").ISimpleType<string>, [undefined]>;
37
+ /**
38
+ * #property
39
+ */
6
40
  type: import("mobx-state-tree").ISimpleType<"GridBookmarkWidget">;
7
- view: import("mobx-state-tree").IMaybe<import("mobx-state-tree").IReferenceType<import("mobx-state-tree").IAnyType>>;
8
- bookmarkedRegions: import("mobx-state-tree").IArrayType<import("mobx-state-tree").IModelType<{
41
+ /**
42
+ * #property
43
+ * removed by postProcessSnapshot, only loaded from localStorage
44
+ */
45
+ bookmarks: import("mobx-state-tree").IOptionalIType<import("mobx-state-tree").IArrayType<import("mobx-state-tree").IModelType<{
9
46
  refName: import("mobx-state-tree").ISimpleType<string>;
10
47
  start: import("mobx-state-tree").ISimpleType<number>;
11
48
  end: import("mobx-state-tree").ISimpleType<number>;
@@ -18,18 +55,148 @@ export default function f(pluginManager: PluginManager): import("mobx-state-tree
18
55
  setRefName(newRefName: string): void;
19
56
  } & {
20
57
  setLabel(label: string): void;
21
- }, import("mobx-state-tree")._NotCustomized, import("mobx-state-tree")._NotCustomized>>;
22
- modelSelectedAssembly: import("mobx-state-tree").IType<string | undefined, string, string>;
58
+ }, import("mobx-state-tree")._NotCustomized, import("mobx-state-tree")._NotCustomized>>, [undefined]>;
23
59
  }, {
60
+ selectedBookmarks: IExtendedLabeledRegionModel[];
61
+ selectedAssembliesPre: string[] | undefined;
62
+ } & {
63
+ readonly bookmarkAssemblies: string[];
64
+ readonly validAssemblies: Set<string>;
65
+ } & {
66
+ readonly bookmarksWithValidAssemblies: ({
67
+ refName: string;
68
+ start: number;
69
+ end: number;
70
+ reversed: boolean;
71
+ assemblyName: string;
72
+ label: string;
73
+ } & import("mobx-state-tree/dist/internal").NonEmptyObject & {
74
+ setRefName(newRefName: string): void;
75
+ } & {
76
+ setLabel(label: string): void;
77
+ } & import("mobx-state-tree").IStateTreeNode<import("mobx-state-tree").IModelType<{
78
+ refName: import("mobx-state-tree").ISimpleType<string>;
79
+ start: import("mobx-state-tree").ISimpleType<number>;
80
+ end: import("mobx-state-tree").ISimpleType<number>;
81
+ reversed: import("mobx-state-tree").IOptionalIType<import("mobx-state-tree").ISimpleType<boolean>, [undefined]>;
82
+ } & {
83
+ assemblyName: import("mobx-state-tree").ISimpleType<string>;
84
+ } & {
85
+ label: import("mobx-state-tree").IOptionalIType<import("mobx-state-tree").ISimpleType<string>, [undefined]>;
86
+ }, {
87
+ setRefName(newRefName: string): void;
88
+ } & {
89
+ setLabel(label: string): void;
90
+ }, import("mobx-state-tree")._NotCustomized, import("mobx-state-tree")._NotCustomized>>)[];
91
+ } & {
92
+ readonly sharedBookmarksModel: {
93
+ sharedBookmarks: (IMSTArray<import("mobx-state-tree").IModelType<{
94
+ refName: import("mobx-state-tree").ISimpleType<string>;
95
+ start: import("mobx-state-tree").ISimpleType<number>;
96
+ end: import("mobx-state-tree").ISimpleType<number>;
97
+ reversed: import("mobx-state-tree").IOptionalIType<import("mobx-state-tree").ISimpleType<boolean>, [undefined]>;
98
+ } & {
99
+ assemblyName: import("mobx-state-tree").ISimpleType<string>;
100
+ } & {
101
+ label: import("mobx-state-tree").IOptionalIType<import("mobx-state-tree").ISimpleType<string>, [undefined]>;
102
+ }, {
103
+ setRefName(newRefName: string): void;
104
+ } & {
105
+ setLabel(label: string): void;
106
+ }, import("mobx-state-tree")._NotCustomized, import("mobx-state-tree")._NotCustomized>> & import("mobx-state-tree").IStateTreeNode<import("mobx-state-tree").IMaybe<import("mobx-state-tree").IArrayType<import("mobx-state-tree").IModelType<{
107
+ refName: import("mobx-state-tree").ISimpleType<string>;
108
+ start: import("mobx-state-tree").ISimpleType<number>;
109
+ end: import("mobx-state-tree").ISimpleType<number>;
110
+ reversed: import("mobx-state-tree").IOptionalIType<import("mobx-state-tree").ISimpleType<boolean>, [undefined]>;
111
+ } & {
112
+ assemblyName: import("mobx-state-tree").ISimpleType<string>;
113
+ } & {
114
+ label: import("mobx-state-tree").IOptionalIType<import("mobx-state-tree").ISimpleType<string>, [undefined]>;
115
+ }, {
116
+ setRefName(newRefName: string): void;
117
+ } & {
118
+ setLabel(label: string): void;
119
+ }, import("mobx-state-tree")._NotCustomized, import("mobx-state-tree")._NotCustomized>>>>) | undefined;
120
+ } & import("mobx-state-tree/dist/internal").NonEmptyObject & import("mobx-state-tree").IStateTreeNode<import("mobx-state-tree").IModelType<{
121
+ sharedBookmarks: import("mobx-state-tree").IMaybe<import("mobx-state-tree").IArrayType<import("mobx-state-tree").IModelType<{
122
+ refName: import("mobx-state-tree").ISimpleType<string>;
123
+ start: import("mobx-state-tree").ISimpleType<number>;
124
+ end: import("mobx-state-tree").ISimpleType<number>;
125
+ reversed: import("mobx-state-tree").IOptionalIType<import("mobx-state-tree").ISimpleType<boolean>, [undefined]>;
126
+ } & {
127
+ assemblyName: import("mobx-state-tree").ISimpleType<string>;
128
+ } & {
129
+ label: import("mobx-state-tree").IOptionalIType<import("mobx-state-tree").ISimpleType<string>, [undefined]>;
130
+ }, {
131
+ setRefName(newRefName: string): void;
132
+ } & {
133
+ setLabel(label: string): void;
134
+ }, import("mobx-state-tree")._NotCustomized, import("mobx-state-tree")._NotCustomized>>>;
135
+ }, {}, import("mobx-state-tree")._NotCustomized, import("mobx-state-tree")._NotCustomized>>;
136
+ readonly allBookmarksModel: {
137
+ sharedBookmarks: (IMSTArray<import("mobx-state-tree").IModelType<{
138
+ refName: import("mobx-state-tree").ISimpleType<string>;
139
+ start: import("mobx-state-tree").ISimpleType<number>;
140
+ end: import("mobx-state-tree").ISimpleType<number>;
141
+ reversed: import("mobx-state-tree").IOptionalIType<import("mobx-state-tree").ISimpleType<boolean>, [undefined]>;
142
+ } & {
143
+ assemblyName: import("mobx-state-tree").ISimpleType<string>;
144
+ } & {
145
+ label: import("mobx-state-tree").IOptionalIType<import("mobx-state-tree").ISimpleType<string>, [undefined]>;
146
+ }, {
147
+ setRefName(newRefName: string): void;
148
+ } & {
149
+ setLabel(label: string): void;
150
+ }, import("mobx-state-tree")._NotCustomized, import("mobx-state-tree")._NotCustomized>> & import("mobx-state-tree").IStateTreeNode<import("mobx-state-tree").IMaybe<import("mobx-state-tree").IArrayType<import("mobx-state-tree").IModelType<{
151
+ refName: import("mobx-state-tree").ISimpleType<string>;
152
+ start: import("mobx-state-tree").ISimpleType<number>;
153
+ end: import("mobx-state-tree").ISimpleType<number>;
154
+ reversed: import("mobx-state-tree").IOptionalIType<import("mobx-state-tree").ISimpleType<boolean>, [undefined]>;
155
+ } & {
156
+ assemblyName: import("mobx-state-tree").ISimpleType<string>;
157
+ } & {
158
+ label: import("mobx-state-tree").IOptionalIType<import("mobx-state-tree").ISimpleType<string>, [undefined]>;
159
+ }, {
160
+ setRefName(newRefName: string): void;
161
+ } & {
162
+ setLabel(label: string): void;
163
+ }, import("mobx-state-tree")._NotCustomized, import("mobx-state-tree")._NotCustomized>>>>) | undefined;
164
+ } & import("mobx-state-tree/dist/internal").NonEmptyObject & import("mobx-state-tree").IStateTreeNode<import("mobx-state-tree").IModelType<{
165
+ sharedBookmarks: import("mobx-state-tree").IMaybe<import("mobx-state-tree").IArrayType<import("mobx-state-tree").IModelType<{
166
+ refName: import("mobx-state-tree").ISimpleType<string>;
167
+ start: import("mobx-state-tree").ISimpleType<number>;
168
+ end: import("mobx-state-tree").ISimpleType<number>;
169
+ reversed: import("mobx-state-tree").IOptionalIType<import("mobx-state-tree").ISimpleType<boolean>, [undefined]>;
170
+ } & {
171
+ assemblyName: import("mobx-state-tree").ISimpleType<string>;
172
+ } & {
173
+ label: import("mobx-state-tree").IOptionalIType<import("mobx-state-tree").ISimpleType<string>, [undefined]>;
174
+ }, {
175
+ setRefName(newRefName: string): void;
176
+ } & {
177
+ setLabel(label: string): void;
178
+ }, import("mobx-state-tree")._NotCustomized, import("mobx-state-tree")._NotCustomized>>>;
179
+ }, {}, import("mobx-state-tree")._NotCustomized, import("mobx-state-tree")._NotCustomized>>;
180
+ } & {
181
+ setSelectedAssemblies(assemblies?: string[]): void;
182
+ } & {
183
+ readonly selectedAssemblies: string[];
184
+ } & {
24
185
  importBookmarks(regions: Region[]): void;
25
186
  addBookmark(region: Region): void;
26
187
  removeBookmark(index: number): void;
188
+ updateBookmarkLabel(bookmark: IExtendedLabeledRegionModel, label: string): void;
189
+ setSelectedBookmarks(bookmarks: IExtendedLabeledRegionModel[]): void;
190
+ setBookmarkedRegions(regions: IMSTArray<typeof LabeledRegionModel>): void;
191
+ } & {
27
192
  clearAllBookmarks(): void;
28
- updateBookmarkLabel(index: number, label: string): void;
29
- setSelectedAssembly(assembly: string): void;
193
+ clearSelectedBookmarks(): void;
30
194
  } & {
31
- readonly selectedAssembly: string;
32
- readonly assemblies: string[];
33
- }, import("mobx-state-tree")._NotCustomized, import("mobx-state-tree")._NotCustomized>;
195
+ afterAttach(): void;
196
+ }, import("mobx-state-tree")._NotCustomized, {
197
+ type: "GridBookmarkWidget";
198
+ id: string;
199
+ }>;
34
200
  export type GridBookmarkStateModel = ReturnType<typeof f>;
35
201
  export type GridBookmarkModel = Instance<GridBookmarkStateModel>;
202
+ export {};