@jbrowse/plugin-grid-bookmark 2.6.3 → 2.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/GridBookmarkWidget/components/AssemblySelector.d.ts +3 -4
- package/dist/GridBookmarkWidget/components/AssemblySelector.js +27 -37
- package/dist/GridBookmarkWidget/components/BookmarkGrid.d.ts +6 -0
- package/dist/GridBookmarkWidget/components/BookmarkGrid.js +120 -0
- package/dist/GridBookmarkWidget/components/{ClearBookmarks.d.ts → DeleteBookmarks.d.ts} +2 -3
- package/dist/GridBookmarkWidget/components/DeleteBookmarks.js +41 -0
- package/dist/GridBookmarkWidget/components/DeleteBookmarksDialog.d.ts +7 -0
- package/dist/GridBookmarkWidget/components/DeleteBookmarksDialog.js +29 -0
- package/dist/GridBookmarkWidget/components/EditBookmarkLabelDialog.d.ts +8 -0
- package/dist/GridBookmarkWidget/components/EditBookmarkLabelDialog.js +50 -0
- package/dist/GridBookmarkWidget/components/ExportBookmarks.d.ts +6 -0
- package/dist/GridBookmarkWidget/components/{ClearBookmarks.js → ExportBookmarks.js} +9 -19
- package/dist/GridBookmarkWidget/components/ExportBookmarksDialog.d.ts +7 -0
- package/dist/GridBookmarkWidget/components/{DownloadBookmarks.js → ExportBookmarksDialog.js} +22 -20
- package/dist/GridBookmarkWidget/components/GridBookmarkWidget.d.ts +3 -4
- package/dist/GridBookmarkWidget/components/GridBookmarkWidget.js +28 -102
- package/dist/GridBookmarkWidget/components/ImportBookmarks.d.ts +3 -5
- package/dist/GridBookmarkWidget/components/ImportBookmarks.js +8 -64
- package/dist/GridBookmarkWidget/components/ImportBookmarksDialog.d.ts +7 -0
- package/dist/GridBookmarkWidget/components/ImportBookmarksDialog.js +129 -0
- package/{esm/GridBookmarkWidget/components/ClearBookmarks.d.ts → dist/GridBookmarkWidget/components/ShareBookmarks.d.ts} +2 -3
- package/dist/GridBookmarkWidget/components/ShareBookmarks.js +37 -0
- package/dist/GridBookmarkWidget/components/ShareBookmarksDialog.d.ts +7 -0
- package/dist/GridBookmarkWidget/components/ShareBookmarksDialog.js +106 -0
- package/dist/GridBookmarkWidget/model.d.ts +178 -11
- package/dist/GridBookmarkWidget/model.js +105 -27
- package/dist/GridBookmarkWidget/sessionSharing.d.ts +6 -0
- package/dist/GridBookmarkWidget/sessionSharing.js +96 -0
- package/dist/GridBookmarkWidget/utils.d.ts +19 -3
- package/dist/GridBookmarkWidget/utils.js +132 -40
- package/dist/index.d.ts +1 -1
- package/dist/index.js +100 -75
- package/esm/GridBookmarkWidget/components/AssemblySelector.d.ts +3 -4
- package/esm/GridBookmarkWidget/components/AssemblySelector.js +28 -38
- package/esm/GridBookmarkWidget/components/BookmarkGrid.d.ts +6 -0
- package/esm/GridBookmarkWidget/components/BookmarkGrid.js +92 -0
- package/{dist/GridBookmarkWidget/components/DownloadBookmarks.d.ts → esm/GridBookmarkWidget/components/DeleteBookmarks.d.ts} +2 -3
- package/esm/GridBookmarkWidget/components/DeleteBookmarks.js +13 -0
- package/esm/GridBookmarkWidget/components/DeleteBookmarksDialog.d.ts +7 -0
- package/esm/GridBookmarkWidget/components/DeleteBookmarksDialog.js +24 -0
- package/esm/GridBookmarkWidget/components/EditBookmarkLabelDialog.d.ts +8 -0
- package/esm/GridBookmarkWidget/components/EditBookmarkLabelDialog.js +25 -0
- package/esm/GridBookmarkWidget/components/ExportBookmarks.d.ts +6 -0
- package/esm/GridBookmarkWidget/components/ExportBookmarks.js +13 -0
- package/esm/GridBookmarkWidget/components/ExportBookmarksDialog.d.ts +7 -0
- package/esm/GridBookmarkWidget/components/ExportBookmarksDialog.js +35 -0
- package/esm/GridBookmarkWidget/components/GridBookmarkWidget.d.ts +3 -4
- package/esm/GridBookmarkWidget/components/GridBookmarkWidget.js +28 -79
- package/esm/GridBookmarkWidget/components/ImportBookmarks.d.ts +3 -5
- package/esm/GridBookmarkWidget/components/ImportBookmarks.js +10 -66
- package/esm/GridBookmarkWidget/components/ImportBookmarksDialog.d.ts +7 -0
- package/esm/GridBookmarkWidget/components/ImportBookmarksDialog.js +101 -0
- package/esm/GridBookmarkWidget/components/{DownloadBookmarks.d.ts → ShareBookmarks.d.ts} +2 -3
- package/esm/GridBookmarkWidget/components/ShareBookmarks.js +12 -0
- package/esm/GridBookmarkWidget/components/ShareBookmarksDialog.d.ts +7 -0
- package/esm/GridBookmarkWidget/components/ShareBookmarksDialog.js +78 -0
- package/esm/GridBookmarkWidget/model.d.ts +178 -11
- package/esm/GridBookmarkWidget/model.js +106 -28
- package/esm/GridBookmarkWidget/sessionSharing.d.ts +6 -0
- package/esm/GridBookmarkWidget/sessionSharing.js +68 -0
- package/esm/GridBookmarkWidget/utils.d.ts +19 -3
- package/esm/GridBookmarkWidget/utils.js +105 -39
- package/esm/index.d.ts +1 -1
- package/esm/index.js +101 -76
- package/package.json +4 -3
- package/dist/GridBookmarkWidget/components/DeleteBookmark.d.ts +0 -9
- package/dist/GridBookmarkWidget/components/DeleteBookmark.js +0 -31
- package/esm/GridBookmarkWidget/components/ClearBookmarks.js +0 -23
- package/esm/GridBookmarkWidget/components/DeleteBookmark.d.ts +0 -9
- package/esm/GridBookmarkWidget/components/DeleteBookmark.js +0 -26
- package/esm/GridBookmarkWidget/components/DownloadBookmarks.js +0 -33
|
@@ -1,88 +1,37 @@
|
|
|
1
|
-
import React
|
|
1
|
+
import React from 'react';
|
|
2
2
|
import { observer } from 'mobx-react';
|
|
3
|
-
import {
|
|
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
|
|
11
|
-
import
|
|
12
|
-
import
|
|
6
|
+
import BookmarkGrid from './BookmarkGrid';
|
|
7
|
+
import DeleteBookmarks from './DeleteBookmarks';
|
|
8
|
+
import ExportBookmarks from './ExportBookmarks';
|
|
13
9
|
import ImportBookmarks from './ImportBookmarks';
|
|
14
|
-
import
|
|
15
|
-
import
|
|
16
|
-
const useStyles = makeStyles()(
|
|
17
|
-
|
|
18
|
-
|
|
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
|
-
|
|
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
|
|
36
|
+
});
|
|
37
|
+
export default GridBookmarkWidget;
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { GridBookmarkModel } from '../model';
|
|
3
|
-
declare
|
|
3
|
+
declare const ImportBookmarks: ({ model, }: {
|
|
4
4
|
model: GridBookmarkModel;
|
|
5
|
-
|
|
6
|
-
|
|
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 {
|
|
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
|
|
13
|
-
|
|
14
|
-
|
|
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: () =>
|
|
30
|
-
React.createElement(
|
|
31
|
-
React.createElement(
|
|
32
|
-
|
|
33
|
-
|
|
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,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
|
|
3
|
+
declare function ShareBookmarks({ model }: {
|
|
4
4
|
model: GridBookmarkModel;
|
|
5
5
|
}): React.JSX.Element;
|
|
6
|
-
|
|
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,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
|
-
|
|
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
|
-
|
|
8
|
-
|
|
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
|
-
|
|
29
|
-
setSelectedAssembly(assembly: string): void;
|
|
193
|
+
clearSelectedBookmarks(): void;
|
|
30
194
|
} & {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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 {};
|