@jbrowse/product-core 4.3.0 → 5.0.0-beta.10
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/esm/RootModel/BaseRootModel.d.ts +514 -323
- package/esm/RootModel/BaseRootModel.js +141 -14
- package/esm/RootModel/HierarchicalConfig.d.ts +30 -20
- package/esm/RootModel/HierarchicalConfig.js +36 -0
- package/esm/RootModel/InternetAccounts.d.ts +18 -1
- package/esm/RootModel/InternetAccounts.js +120 -22
- package/esm/RootModel/PreferencesConfig.d.ts +37 -0
- package/esm/RootModel/PreferencesConfig.js +75 -0
- package/esm/RootModel/createConfigModel.d.ts +257 -0
- package/esm/RootModel/createConfigModel.js +77 -0
- package/esm/RootModel/index.d.ts +10 -5
- package/esm/RootModel/index.js +10 -5
- package/esm/RootModel/menuItems.d.ts +24 -0
- package/esm/RootModel/menuItems.js +141 -0
- package/esm/Session/BaseSession.d.ts +285 -11
- package/esm/Session/BaseSession.js +383 -15
- package/esm/Session/Connections.d.ts +115 -8
- package/esm/Session/Connections.js +196 -74
- package/esm/Session/DrawerWidgets.d.ts +145 -13
- package/esm/Session/DrawerWidgets.js +219 -49
- package/esm/Session/MultipleViews.d.ts +1067 -1177
- package/esm/Session/MultipleViews.js +395 -64
- package/esm/Session/Preferences.d.ts +1389 -0
- package/esm/Session/Preferences.js +58 -0
- package/esm/Session/ReferenceManagement.d.ts +28 -3
- package/esm/Session/ReferenceManagement.js +56 -41
- package/esm/Session/SessionTracks.d.ts +1101 -1180
- package/esm/Session/SessionTracks.js +584 -34
- package/esm/Session/Themes.d.ts +136 -2
- package/esm/Session/Themes.js +267 -21
- package/esm/Session/TrackMenu.d.ts +88 -0
- package/esm/Session/TrackMenu.js +175 -0
- package/esm/Session/TrackMenuSessionMixin.d.ts +27 -0
- package/esm/Session/TrackMenuSessionMixin.js +42 -0
- package/esm/Session/Tracks.d.ts +945 -1159
- package/esm/Session/Tracks.js +229 -30
- package/esm/Session/assertSessionModel.d.ts +21 -0
- package/esm/Session/assertSessionModel.js +1 -0
- package/esm/Session/copyTrackSnapshot.d.ts +21 -0
- package/esm/Session/copyTrackSnapshot.js +20 -0
- package/esm/Session/developerMode.d.ts +7 -0
- package/esm/Session/developerMode.js +43 -0
- package/esm/Session/finalizeSession.d.ts +15 -0
- package/esm/Session/finalizeSession.js +28 -0
- package/esm/Session/hydratedForms.d.ts +16 -0
- package/esm/Session/hydratedForms.js +13 -0
- package/esm/Session/index.d.ts +27 -10
- package/esm/Session/index.js +16 -10
- package/esm/Session/pluginExtraTrackItems.d.ts +11 -0
- package/esm/Session/pluginExtraTrackItems.js +13 -0
- package/esm/Session/readdedTrackConf.d.ts +8 -0
- package/esm/Session/readdedTrackConf.js +24 -0
- package/esm/Session/shareableSnapshot.d.ts +23 -0
- package/esm/Session/shareableSnapshot.js +66 -0
- package/esm/Session/temporaryAssemblyTracks.d.ts +24 -0
- package/esm/Session/temporaryAssemblyTracks.js +37 -0
- package/esm/assertExtends.d.ts +55 -0
- package/esm/assertExtends.js +1 -0
- package/esm/controllerTracks.d.ts +76 -0
- package/esm/controllerTracks.js +125 -0
- package/esm/destroyViewState.d.ts +21 -0
- package/esm/destroyViewState.js +29 -0
- package/esm/embeddedController.d.ts +57 -0
- package/esm/embeddedController.js +100 -0
- package/esm/index.d.ts +32 -4
- package/esm/index.js +31 -4
- package/esm/loadPlugins.d.ts +38 -0
- package/esm/loadPlugins.js +45 -0
- package/esm/localFiles.d.ts +74 -0
- package/esm/localFiles.js +156 -0
- package/esm/observeSession.d.ts +55 -0
- package/esm/observeSession.js +90 -0
- package/esm/parallelChunkLoading.d.ts +30 -0
- package/esm/parallelChunkLoading.js +71 -0
- package/esm/pluginInput.d.ts +32 -0
- package/esm/pluginInput.js +19 -0
- package/esm/pruneUnbuildableNodes.d.ts +109 -0
- package/esm/pruneUnbuildableNodes.js +562 -0
- package/esm/resolveAssemblies.d.ts +68 -0
- package/esm/resolveAssemblies.js +77 -0
- package/esm/rpcWorker.d.ts +36 -4
- package/esm/rpcWorker.js +126 -20
- package/esm/sessionMigrations/index.d.ts +15 -0
- package/esm/sessionMigrations/index.js +178 -0
- package/esm/sessionUrl.d.ts +40 -0
- package/esm/sessionUrl.js +66 -0
- package/esm/sessionUtils.d.ts +74 -0
- package/esm/sessionUtils.js +599 -0
- package/esm/siblingCast.d.ts +14 -0
- package/esm/siblingCast.js +16 -0
- package/esm/snapshotUtils.d.ts +8 -0
- package/esm/snapshotUtils.js +12 -0
- package/esm/ui/AboutDialog.d.ts +8 -3
- package/esm/ui/AboutDialog.js +14 -5
- package/esm/ui/AboutDialogContents.d.ts +2 -6
- package/esm/ui/AboutDialogContents.js +13 -17
- package/esm/ui/AssemblyInfoPanel.d.ts +5 -0
- package/esm/ui/AssemblyInfoPanel.js +63 -0
- package/esm/ui/DescriptionPanel.d.ts +3 -0
- package/esm/ui/DescriptionPanel.js +25 -0
- package/esm/ui/Drawer.d.ts +21 -0
- package/esm/ui/Drawer.js +60 -0
- package/esm/ui/DrawerControls.d.ts +5 -0
- package/esm/ui/DrawerControls.js +28 -0
- package/esm/ui/DrawerHeader.d.ts +6 -0
- package/esm/ui/DrawerHeader.js +36 -0
- package/esm/ui/DrawerWidget.d.ts +5 -0
- package/esm/ui/DrawerWidget.js +12 -0
- package/esm/ui/DrawerWidgetSelector.d.ts +5 -0
- package/esm/ui/DrawerWidgetSelector.js +40 -0
- package/esm/ui/FileInfoPanel.d.ts +3 -6
- package/esm/ui/FileInfoPanel.js +36 -26
- package/esm/ui/GeneralPreferencesTab.d.ts +17 -0
- package/esm/ui/GeneralPreferencesTab.js +34 -0
- package/esm/ui/HeaderButtons.d.ts +2 -1
- package/esm/ui/HeaderButtons.js +15 -17
- package/esm/ui/ModalWidget.d.ts +13 -0
- package/esm/ui/ModalWidget.js +48 -0
- package/esm/ui/ModalWidgetAppBar.d.ts +8 -0
- package/esm/ui/ModalWidgetAppBar.js +9 -0
- package/esm/ui/PreferenceCheckbox.d.ts +6 -0
- package/esm/ui/PreferenceCheckbox.js +16 -0
- package/esm/ui/PreferencesDialog.d.ts +34 -0
- package/esm/ui/PreferencesDialog.js +55 -0
- package/esm/ui/PreferencesResetDialog.d.ts +8 -0
- package/esm/ui/PreferencesResetDialog.js +19 -0
- package/esm/ui/RefNameAliasesDialog.d.ts +9 -0
- package/esm/ui/RefNameAliasesDialog.js +65 -0
- package/esm/ui/RefNameInfoDialog.d.ts +3 -6
- package/esm/ui/RefNameInfoDialog.js +45 -63
- package/esm/ui/ViewPreferencesTab.d.ts +12 -0
- package/esm/ui/ViewPreferencesTab.js +15 -0
- package/esm/ui/WidgetBody.d.ts +18 -0
- package/esm/ui/WidgetBody.js +22 -0
- package/esm/ui/WidgetHeading.d.ts +7 -0
- package/esm/ui/WidgetHeading.js +7 -0
- package/esm/ui/aboutTestUtils.d.ts +140 -0
- package/esm/ui/aboutTestUtils.js +25 -0
- package/esm/ui/descriptionHtml.d.ts +25 -0
- package/esm/ui/descriptionHtml.js +64 -0
- package/esm/ui/drawerLayout.d.ts +18 -0
- package/esm/ui/drawerLayout.js +22 -0
- package/esm/ui/index.d.ts +15 -1
- package/esm/ui/index.js +13 -1
- package/esm/ui/preferencesReset.d.ts +18 -0
- package/esm/ui/preferencesReset.js +69 -0
- package/esm/ui/util.d.ts +22 -7
- package/esm/ui/util.js +19 -41
- package/esm/useEngineLifecycle.d.ts +19 -0
- package/esm/useEngineLifecycle.js +44 -0
- package/package.json +15 -18
- package/esm/RootModel/FormatAbout.d.ts +0 -12
- package/esm/RootModel/FormatAbout.js +0 -15
- package/esm/RootModel/FormatDetails.d.ts +0 -24
- package/esm/RootModel/FormatDetails.js +0 -27
- package/esm/Session/DialogQueue.d.ts +0 -17
- package/esm/Session/DialogQueue.js +0 -31
package/esm/ui/AboutDialog.js
CHANGED
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import Attributes from '@jbrowse/core/BaseFeatureWidget/BaseFeatureDetail/Attributes';
|
|
3
|
+
import BaseCard from '@jbrowse/core/BaseFeatureWidget/BaseFeatureDetail/BaseCard';
|
|
4
|
+
import { hydrateTrackConfig } from '@jbrowse/core/configuration';
|
|
5
|
+
import { PluggableComponent } from '@jbrowse/core/ui';
|
|
2
6
|
import Dialog from '@jbrowse/core/ui/Dialog';
|
|
3
7
|
import { getEnv } from '@jbrowse/core/util';
|
|
4
8
|
import { getTrackName } from '@jbrowse/core/util/tracks';
|
|
5
|
-
import
|
|
6
|
-
|
|
7
|
-
|
|
9
|
+
import { isStateTreeNode } from '@jbrowse/mobx-state-tree';
|
|
10
|
+
import AboutContents from './AboutDialogContents.js';
|
|
11
|
+
export default function AboutDialog({ config, session, handleClose, }) {
|
|
8
12
|
const { pluginManager } = getEnv(session);
|
|
9
|
-
|
|
10
|
-
|
|
13
|
+
// hydrated once here, so every panel and every plugin on the two About points
|
|
14
|
+
// reads one live node: "Copy config" gives the same JSON whichever menu
|
|
15
|
+
// opened the dialog, and a jexl `formatAbout` slot has an env to evaluate in
|
|
16
|
+
const live = isStateTreeNode(config)
|
|
17
|
+
? config
|
|
18
|
+
: hydrateTrackConfig(pluginManager, config);
|
|
19
|
+
return (_jsx(Dialog, { open: true, onClose: handleClose, title: getTrackName(config, session), maxWidth: "xl", children: live ? (_jsx(PluggableComponent, { pluginManager: pluginManager, name: "Core-replaceAbout", component: AboutContents, props: { config: live, session } })) : (_jsx(BaseCard, { title: "Configuration", children: _jsx(Attributes, { attributes: config }) })) }));
|
|
11
20
|
}
|
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
declare const AboutDialogContents: ({ config, session, }: {
|
|
4
|
-
config: AnyConfigurationModel | Record<string, unknown>;
|
|
5
|
-
session: AbstractSessionModel;
|
|
6
|
-
}) => import("react/jsx-runtime").JSX.Element;
|
|
1
|
+
import type { AboutPanelProps } from './util.ts';
|
|
2
|
+
declare const AboutDialogContents: ({ config, session, }: AboutPanelProps) => import("react").JSX.Element;
|
|
7
3
|
export default AboutDialogContents;
|
|
@@ -2,35 +2,31 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { useState } from 'react';
|
|
3
3
|
import Attributes from '@jbrowse/core/BaseFeatureWidget/BaseFeatureDetail/Attributes';
|
|
4
4
|
import BaseCard from '@jbrowse/core/BaseFeatureWidget/BaseFeatureDetail/BaseCard';
|
|
5
|
-
import {
|
|
5
|
+
import { readConfObject } from '@jbrowse/core/configuration';
|
|
6
|
+
import PluggableComponents from '@jbrowse/core/ui/PluggableComponents';
|
|
6
7
|
import { getEnv } from '@jbrowse/core/util';
|
|
7
8
|
import { makeStyles } from '@jbrowse/core/util/tss-react';
|
|
8
|
-
import { getSnapshot, isStateTreeNode } from '@jbrowse/mobx-state-tree';
|
|
9
9
|
import { observer } from 'mobx-react';
|
|
10
|
-
import
|
|
11
|
-
import
|
|
12
|
-
import
|
|
13
|
-
import
|
|
10
|
+
import AssemblyInfoPanel from './AssemblyInfoPanel.js';
|
|
11
|
+
import DescriptionPanel from './DescriptionPanel.js';
|
|
12
|
+
import FileInfoPanel from './FileInfoPanel.js';
|
|
13
|
+
import HeaderButtons from './HeaderButtons.js';
|
|
14
|
+
import RefNameInfoDialog from './RefNameInfoDialog.js';
|
|
15
|
+
import { getAboutDialogConfig } from './util.js';
|
|
14
16
|
const useStyles = makeStyles()({
|
|
15
17
|
content: {
|
|
16
18
|
minWidth: 800,
|
|
17
19
|
},
|
|
18
20
|
});
|
|
21
|
+
const hideFields = ['displays', 'baseUri', 'refNames', 'formatAbout'];
|
|
19
22
|
const AboutDialogContents = observer(function AboutDialogContents({ config, session, }) {
|
|
20
|
-
const conf = isStateTreeNode(config) ? getSnapshot(config) : config;
|
|
21
23
|
const { classes } = useStyles();
|
|
22
24
|
const [showRefNames, setShowRefNames] = useState(false);
|
|
23
|
-
const hideUris = getConf(session, ['formatAbout', 'hideUris']) ||
|
|
24
|
-
readConf(config, ['formatAbout', 'hideUris']);
|
|
25
25
|
const { pluginManager } = getEnv(session);
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
});
|
|
31
|
-
const ExtraPanel = pluginManager.evaluateExtensionPoint('Core-extraAboutPanel', null, { session, config });
|
|
32
|
-
const hideFields = ['displays', 'baseUri', 'refNames', 'formatAbout'];
|
|
33
|
-
return (_jsxs("div", { className: classes.content, children: [_jsxs(BaseCard, { title: "Configuration", children: [!hideUris ? (_jsx(HeaderButtons, { conf: conf, setShowRefNames: setShowRefNames })) : null, _jsx(Attributes, { attributes: confPostExt.config, omit: [...hideFields, 'metadata'], hideUris: hideUris })] }), confPostExt.config.metadata ? (_jsx(BaseCard, { title: "Metadata", children: _jsx(Attributes, { attributes: confPostExt.config.metadata, omit: hideFields, hideUris: hideUris }) })) : null, ExtraPanel ? (_jsx(BaseCard, { title: ExtraPanel.name, children: _jsx(ExtraPanel.Component, { config: config }) })) : null, _jsx(FileInfoPanel, { config: config, session: session }), showRefNames ? (_jsx(RefNameInfoDialog, { session: session, config: config, onClose: () => {
|
|
26
|
+
const { config: shown, hideUris } = getAboutDialogConfig({ config, session });
|
|
27
|
+
return (_jsxs("div", { className: classes.content, children: [_jsxs(BaseCard, { title: "Configuration", children: [_jsx(HeaderButtons, { conf: readConfObject(config), hideUris: hideUris, setShowRefNames: setShowRefNames }), _jsx(Attributes, { attributes: shown, omit: [...hideFields, 'metadata'], hideUris: hideUris })] }), shown.metadata ? (_jsx(BaseCard, { title: "Metadata", children: _jsx(Attributes, { attributes: shown.metadata, hideUris: hideUris }) })) : null, _jsx(DescriptionPanel, { config: config, session: session }), _jsx(AssemblyInfoPanel, { config: config, session: session, hideUris: hideUris }), _jsx(PluggableComponents, { pluginManager: pluginManager,
|
|
28
|
+
/** #extensionPoint Core-extraAboutPanel | sync | Add extra panels to a track's About dialog */
|
|
29
|
+
name: "Core-extraAboutPanel", props: { session, config } }), hideUris ? null : _jsx(FileInfoPanel, { config: config, session: session }), showRefNames ? (_jsx(RefNameInfoDialog, { session: session, config: config, onClose: () => {
|
|
34
30
|
setShowRefNames(false);
|
|
35
31
|
} })) : null] }));
|
|
36
32
|
});
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import Attributes from '@jbrowse/core/BaseFeatureWidget/BaseFeatureDetail/Attributes';
|
|
4
|
+
import BaseCard from '@jbrowse/core/BaseFeatureWidget/BaseFeatureDetail/BaseCard';
|
|
5
|
+
import { readConfObject } from '@jbrowse/core/configuration';
|
|
6
|
+
import { CopyToClipboardButton } from '@jbrowse/core/ui';
|
|
7
|
+
import { stripBaseUris } from '@jbrowse/core/util/addRelativeUris';
|
|
8
|
+
import { makeStyles } from '@jbrowse/core/util/tss-react';
|
|
9
|
+
import { getParent, hasParent } from '@jbrowse/mobx-state-tree';
|
|
10
|
+
import { Button } from '@mui/material';
|
|
11
|
+
import { observer } from 'mobx-react';
|
|
12
|
+
import RefNameAliasesDialog from './RefNameAliasesDialog.js';
|
|
13
|
+
// `Attributes` omits these at every depth, which is what reaches the two that
|
|
14
|
+
// are nested:
|
|
15
|
+
// - `sequence` is the config of the very track this dialog is about, in the
|
|
16
|
+
// card above
|
|
17
|
+
// - `features` is an inline adapter's whole data payload. An assembly whose
|
|
18
|
+
// aliases or cytobands are written into the config rather than fetched from a
|
|
19
|
+
// file rendered them here as a spreadsheet of the raw rows, which buried the
|
|
20
|
+
// four lines anyone opened the card for — and it is the same data the alias
|
|
21
|
+
// listing shows resolved, one button over
|
|
22
|
+
// - `adapterId` is a generated hash, and `baseUri` is where the config was
|
|
23
|
+
// loaded from rather than anything about the assembly
|
|
24
|
+
//
|
|
25
|
+
// Nothing is hidden from "Copy assembly config", which copies the config whole.
|
|
26
|
+
const hideFields = ['sequence', 'features', 'adapterId', 'baseUri'];
|
|
27
|
+
const useStyles = makeStyles()(theme => ({
|
|
28
|
+
buttons: {
|
|
29
|
+
float: 'right',
|
|
30
|
+
display: 'flex',
|
|
31
|
+
gap: theme.spacing(1),
|
|
32
|
+
},
|
|
33
|
+
}));
|
|
34
|
+
/**
|
|
35
|
+
* The assembly config a `ReferenceSequenceTrack` config hangs off, and
|
|
36
|
+
* undefined for every other track.
|
|
37
|
+
*
|
|
38
|
+
* A reference sequence track declares no `assemblyNames` slot — the config node
|
|
39
|
+
* holding it *is* its assembly, the same walk `getConfAssemblyNames` makes.
|
|
40
|
+
* Compared by identity against that node's `sequence`, so the card is the
|
|
41
|
+
* assembly of the track the dialog is already showing.
|
|
42
|
+
*/
|
|
43
|
+
function getAssemblyConf(config) {
|
|
44
|
+
const parent = hasParent(config)
|
|
45
|
+
? getParent(config)
|
|
46
|
+
: undefined;
|
|
47
|
+
return parent?.sequence === config ? parent : undefined;
|
|
48
|
+
}
|
|
49
|
+
const AssemblyCard = observer(function AssemblyCard({ assemblyConf, session, hideUris, }) {
|
|
50
|
+
const { classes } = useStyles();
|
|
51
|
+
const [showAliases, setShowAliases] = useState(false);
|
|
52
|
+
const conf = readConfObject(assemblyConf);
|
|
53
|
+
return (_jsxs(BaseCard, { title: "Assembly", children: [_jsxs("span", { className: classes.buttons, children: [_jsx(Button, { variant: "contained", color: "secondary", onClick: () => {
|
|
54
|
+
setShowAliases(true);
|
|
55
|
+
}, children: "Show ref name aliases" }), hideUris ? null : (_jsx(CopyToClipboardButton, { variant: "contained", value: () => JSON.stringify(stripBaseUris(structuredClone(conf)), null, 2), children: "Copy assembly config" }))] }), _jsx(Attributes, { attributes: conf, omit: hideFields, hideUris: hideUris }), showAliases ? (_jsx(RefNameAliasesDialog, { assemblyName: readConfObject(assemblyConf, 'name'), session: session, onClose: () => {
|
|
56
|
+
setShowAliases(false);
|
|
57
|
+
} })) : null] }));
|
|
58
|
+
});
|
|
59
|
+
const AssemblyInfoPanel = observer(function AssemblyInfoPanel({ config, session, hideUris, }) {
|
|
60
|
+
const assemblyConf = getAssemblyConf(config);
|
|
61
|
+
return assemblyConf ? (_jsx(AssemblyCard, { assemblyConf: assemblyConf, session: session, hideUris: hideUris })) : null;
|
|
62
|
+
});
|
|
63
|
+
export default AssemblyInfoPanel;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import BaseCard from '@jbrowse/core/BaseFeatureWidget/BaseFeatureDetail/BaseCard';
|
|
3
|
+
import { readConfObject } from '@jbrowse/core/configuration';
|
|
4
|
+
import { ErrorBanner, LoadingEllipses, SanitizedHTML } from '@jbrowse/core/ui';
|
|
5
|
+
import { openLocation } from '@jbrowse/core/util/io';
|
|
6
|
+
import { makeStyles } from '@jbrowse/core/util/tss-react';
|
|
7
|
+
import { useFetch } from '@jbrowse/core/util/useFetch';
|
|
8
|
+
import { Link, Typography } from '@mui/material';
|
|
9
|
+
import { observer } from 'mobx-react';
|
|
10
|
+
import { getDescriptionHtmlUrl, rebaseDescriptionHtml, } from './descriptionHtml.js';
|
|
11
|
+
const useStyles = makeStyles()(theme => ({
|
|
12
|
+
provenance: {
|
|
13
|
+
marginBottom: theme.spacing(1),
|
|
14
|
+
},
|
|
15
|
+
}));
|
|
16
|
+
const DescriptionCard = observer(function DescriptionCard({ url, }) {
|
|
17
|
+
const { classes } = useStyles();
|
|
18
|
+
const { data: html, error, isLoading, } = useFetch(['trackDescriptionHtml', url], async (_name, url) => rebaseDescriptionHtml(await openLocation({ uri: url, locationType: 'UriLocation' }).readFile('utf8'), url));
|
|
19
|
+
return (_jsxs(BaseCard, { title: "Description", children: [_jsxs(Typography, { variant: "caption", color: "textSecondary", component: "div", className: classes.provenance, children: ["From the track hub, written for the UCSC Genome Browser \u2014 some display options it describes differ in JBrowse.", ' ', _jsx(Link, { href: url, target: "_blank", rel: "noopener noreferrer", children: "View original" })] }), error ? (_jsx(ErrorBanner, { error: error })) : isLoading || html === undefined ? (_jsx(LoadingEllipses, { message: "Loading description" })) : (_jsx(SanitizedHTML, { html: html }))] }));
|
|
20
|
+
});
|
|
21
|
+
const DescriptionPanel = observer(function DescriptionPanel({ config, }) {
|
|
22
|
+
const url = getDescriptionHtmlUrl(readConfObject(config, 'metadata'));
|
|
23
|
+
return url ? _jsx(DescriptionCard, { url: url }) : null;
|
|
24
|
+
});
|
|
25
|
+
export default DescriptionPanel;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { DrawerPosition } from '@jbrowse/core/util';
|
|
2
|
+
/**
|
|
3
|
+
* All the chrome needs of a session, narrowed the way
|
|
4
|
+
* `PreferencesDialogSession` is: the drawer is the one widget surface an
|
|
5
|
+
* embedder can mount against a session of their own shape.
|
|
6
|
+
*/
|
|
7
|
+
export interface DrawerChromeSession {
|
|
8
|
+
drawerPosition: DrawerPosition;
|
|
9
|
+
resizeDrawer: (distance: number, availableWidth?: number) => number;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* The drawer's chrome: the paper it sits on and the handle that resizes it.
|
|
13
|
+
* Focus tracking is left to the caller through `ref`, since only the app shell
|
|
14
|
+
* has a focused-view concept to wire it to.
|
|
15
|
+
*/
|
|
16
|
+
declare const Drawer: ({ session, children, ref, }: {
|
|
17
|
+
session: DrawerChromeSession;
|
|
18
|
+
children: React.ReactNode;
|
|
19
|
+
ref?: React.Ref<HTMLDivElement>;
|
|
20
|
+
}) => import("react").JSX.Element;
|
|
21
|
+
export default Drawer;
|
package/esm/ui/Drawer.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useRef } from 'react';
|
|
3
|
+
import ResizeHandle from '@jbrowse/core/ui/ResizeHandle';
|
|
4
|
+
import { DRAWER_Z_INDEX } from '@jbrowse/core/ui/zIndexes';
|
|
5
|
+
import { makeStyles } from '@jbrowse/core/util/tss-react';
|
|
6
|
+
import { Paper } from '@mui/material';
|
|
7
|
+
import { observer } from 'mobx-react';
|
|
8
|
+
const useStyles = makeStyles()(theme => ({
|
|
9
|
+
// The grid item, and the handle's containing block. Its own box rather than
|
|
10
|
+
// the Paper's because the Paper is the thing that SCROLLS: a handle
|
|
11
|
+
// positioned against it starts at the top of the scrolled content and rides
|
|
12
|
+
// away with it, and one taken out of flow with `position: fixed` is measured
|
|
13
|
+
// against the window instead — which is the same box only in a full-window
|
|
14
|
+
// app, and put a page-tall col-resize strip down an embedded view's page.
|
|
15
|
+
root: {
|
|
16
|
+
// the drawer places itself, so a host renders it once wherever it likes
|
|
17
|
+
// rather than on the side matching `drawerPosition` (see
|
|
18
|
+
// `drawerGridTemplateColumns`)
|
|
19
|
+
gridColumn: 'drawer',
|
|
20
|
+
position: 'relative',
|
|
21
|
+
height: '100%',
|
|
22
|
+
minWidth: 0,
|
|
23
|
+
},
|
|
24
|
+
paper: {
|
|
25
|
+
overflowY: 'auto',
|
|
26
|
+
height: '100%',
|
|
27
|
+
// widgets position their own overlays against this
|
|
28
|
+
position: 'relative',
|
|
29
|
+
zIndex: DRAWER_Z_INDEX,
|
|
30
|
+
outline: 'none',
|
|
31
|
+
background: theme.palette.background.default,
|
|
32
|
+
},
|
|
33
|
+
resizeHandle: {
|
|
34
|
+
position: 'absolute',
|
|
35
|
+
top: 0,
|
|
36
|
+
zIndex: DRAWER_Z_INDEX + 1,
|
|
37
|
+
},
|
|
38
|
+
// whichever edge faces the main content
|
|
39
|
+
handleForLeftDrawer: { right: 0 },
|
|
40
|
+
handleForRightDrawer: { left: 0 },
|
|
41
|
+
}));
|
|
42
|
+
/**
|
|
43
|
+
* The drawer's chrome: the paper it sits on and the handle that resizes it.
|
|
44
|
+
* Focus tracking is left to the caller through `ref`, since only the app shell
|
|
45
|
+
* has a focused-view concept to wire it to.
|
|
46
|
+
*/
|
|
47
|
+
const Drawer = observer(function Drawer({ session, children, ref, }) {
|
|
48
|
+
const { drawerPosition } = session;
|
|
49
|
+
const { classes, cx } = useStyles();
|
|
50
|
+
const rootRef = useRef(null);
|
|
51
|
+
return (_jsxs("div", { ref: rootRef, className: classes.root, children: [_jsx(Paper, { ref: ref, className: classes.paper, elevation: 16, square: true, "data-testid": "drawer-widget", children: children }), _jsx(ResizeHandle, { onDrag: distance => {
|
|
52
|
+
// the width the drawer and the main area share: both are columns of
|
|
53
|
+
// the grid this is an item of, and the clamp needs the container
|
|
54
|
+
// rather than the window
|
|
55
|
+
session.resizeDrawer(distance, rootRef.current?.parentElement?.clientWidth);
|
|
56
|
+
}, className: cx(classes.resizeHandle, drawerPosition === 'left'
|
|
57
|
+
? classes.handleForLeftDrawer
|
|
58
|
+
: classes.handleForRightDrawer), vertical: true, bar: true })] }));
|
|
59
|
+
});
|
|
60
|
+
export default Drawer;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import CloseIcon from '@mui/icons-material/Close';
|
|
4
|
+
import MinimizeIcon from '@mui/icons-material/Minimize';
|
|
5
|
+
import MoreVertIcon from '@mui/icons-material/MoreVert';
|
|
6
|
+
import { IconButton, Menu, MenuItem, Tooltip } from '@mui/material';
|
|
7
|
+
import { observer } from 'mobx-react';
|
|
8
|
+
const drawerPositionOptions = ['left', 'right'];
|
|
9
|
+
const DrawerControls = observer(function DrawerControls({ session, }) {
|
|
10
|
+
const [anchorEl, setAnchorEl] = useState(null);
|
|
11
|
+
const { drawerPosition, visibleWidget } = session;
|
|
12
|
+
return (_jsxs(_Fragment, { children: [_jsx(Tooltip, { title: "Drawer position", children: _jsx(IconButton, { "data-testid": "drawer-position-button", color: "inherit", onClick: event => {
|
|
13
|
+
setAnchorEl(event.currentTarget);
|
|
14
|
+
}, children: _jsx(MoreVertIcon, {}) }) }), _jsx(Tooltip, { title: "Minimize drawer", children: _jsx(IconButton, { "data-testid": "drawer-minimize", color: "inherit", onClick: () => {
|
|
15
|
+
session.notify(`Drawer minimized, click button on ${drawerPosition} side of screen to re-open`, 'info');
|
|
16
|
+
session.minimizeWidgetDrawer();
|
|
17
|
+
}, children: _jsx(MinimizeIcon, {}) }) }), _jsx(Tooltip, { title: "Close drawer", children: _jsx(IconButton, { color: "inherit", onClick: () => {
|
|
18
|
+
if (visibleWidget) {
|
|
19
|
+
session.hideWidget(visibleWidget);
|
|
20
|
+
}
|
|
21
|
+
}, children: _jsx(CloseIcon, {}) }) }), _jsx(Menu, { anchorEl: anchorEl, open: Boolean(anchorEl), onClose: () => {
|
|
22
|
+
setAnchorEl(null);
|
|
23
|
+
}, children: drawerPositionOptions.map(option => (_jsx(MenuItem, { selected: drawerPosition === option, onClick: () => {
|
|
24
|
+
session.setDrawerPosition(option);
|
|
25
|
+
setAnchorEl(null);
|
|
26
|
+
}, children: option }, option))) })] }));
|
|
27
|
+
});
|
|
28
|
+
export default DrawerControls;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { SessionWithDrawerWidgets } from '@jbrowse/core/util';
|
|
2
|
+
declare const DrawerHeader: ({ session, setToolbarHeight, }: {
|
|
3
|
+
session: SessionWithDrawerWidgets;
|
|
4
|
+
setToolbarHeight: (arg: number) => void;
|
|
5
|
+
}) => import("react").JSX.Element;
|
|
6
|
+
export default DrawerHeader;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback } from 'react';
|
|
3
|
+
import { makeStyles } from '@jbrowse/core/util/tss-react';
|
|
4
|
+
import { AppBar, Toolbar } from '@mui/material';
|
|
5
|
+
import { observer } from 'mobx-react';
|
|
6
|
+
import DrawerControls from './DrawerControls.js';
|
|
7
|
+
import DrawerWidgetSelector from './DrawerWidgetSelector.js';
|
|
8
|
+
const useStyles = makeStyles()(theme => ({
|
|
9
|
+
appBar: {
|
|
10
|
+
background: theme.palette.secondary.main,
|
|
11
|
+
},
|
|
12
|
+
spacer: {
|
|
13
|
+
flexGrow: 1,
|
|
14
|
+
},
|
|
15
|
+
}));
|
|
16
|
+
const DrawerHeader = observer(function DrawerHeader({ session, setToolbarHeight, }) {
|
|
17
|
+
const { classes } = useStyles();
|
|
18
|
+
// Measured, and re-measured: the toolbar's height is the room a virtualized
|
|
19
|
+
// widget subtracts from the box it is given, and it changes without this
|
|
20
|
+
// component re-rendering -- MUI's Toolbar is 56px under the `sm` breakpoint
|
|
21
|
+
// and 64 above it, and grows again with the root font size. Read once at
|
|
22
|
+
// mount, a widget's list was that much too tall for the rest of the session.
|
|
23
|
+
const appBarRef = useCallback((node) => {
|
|
24
|
+
const publish = () => {
|
|
25
|
+
setToolbarHeight(node.getBoundingClientRect().height);
|
|
26
|
+
};
|
|
27
|
+
publish();
|
|
28
|
+
const observer = new ResizeObserver(publish);
|
|
29
|
+
observer.observe(node);
|
|
30
|
+
return () => {
|
|
31
|
+
observer.disconnect();
|
|
32
|
+
};
|
|
33
|
+
}, [setToolbarHeight]);
|
|
34
|
+
return (_jsx(AppBar, { position: "sticky", className: classes.appBar, ref: appBarRef, children: _jsxs(Toolbar, { disableGutters: true, children: [_jsx(DrawerWidgetSelector, { session: session }), _jsx("div", { className: classes.spacer }), _jsx(DrawerControls, { session: session })] }) }));
|
|
35
|
+
});
|
|
36
|
+
export default DrawerHeader;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { observer } from 'mobx-react';
|
|
4
|
+
import Drawer from './Drawer.js';
|
|
5
|
+
import DrawerHeader from './DrawerHeader.js';
|
|
6
|
+
import WidgetBody from './WidgetBody.js';
|
|
7
|
+
const DrawerWidget = observer(function DrawerWidget({ session, }) {
|
|
8
|
+
const { visibleWidget } = session;
|
|
9
|
+
const [toolbarHeight, setToolbarHeight] = useState(0);
|
|
10
|
+
return (_jsxs(Drawer, { session: session, children: [_jsx(DrawerHeader, { session: session, setToolbarHeight: setToolbarHeight }), visibleWidget ? (_jsx(WidgetBody, { session: session, widget: visibleWidget, toolbarHeight: toolbarHeight })) : null] }));
|
|
11
|
+
});
|
|
12
|
+
export default DrawerWidget;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { getEnv } from '@jbrowse/core/util';
|
|
3
|
+
import { makeStyles } from '@jbrowse/core/util/tss-react';
|
|
4
|
+
import DeleteIcon from '@mui/icons-material/Delete';
|
|
5
|
+
import { FormControl, IconButton, MenuItem, Select, Typography, } from '@mui/material';
|
|
6
|
+
import { observer } from 'mobx-react';
|
|
7
|
+
import WidgetHeading from './WidgetHeading.js';
|
|
8
|
+
const useStyles = makeStyles()(theme => ({
|
|
9
|
+
formControl: {
|
|
10
|
+
margin: 0,
|
|
11
|
+
},
|
|
12
|
+
drawerSelect: {
|
|
13
|
+
margin: 0,
|
|
14
|
+
color: theme.palette.secondary.contrastText,
|
|
15
|
+
},
|
|
16
|
+
dropDownIcon: {
|
|
17
|
+
color: theme.palette.secondary.contrastText,
|
|
18
|
+
},
|
|
19
|
+
}));
|
|
20
|
+
const DrawerWidgetSelector = observer(function DrawerWidgetSelector({ session, }) {
|
|
21
|
+
const { visibleWidget, activeWidgets } = session;
|
|
22
|
+
const { classes } = useStyles();
|
|
23
|
+
const { pluginManager } = getEnv(session);
|
|
24
|
+
return (_jsx(FormControl, { className: classes.formControl, children: _jsx(Select, { value: visibleWidget?.id ?? '', "data-testid": "widget-drawer-selects", className: classes.drawerSelect, classes: { icon: classes.dropDownIcon }, renderValue: widgetId => {
|
|
25
|
+
const widget = session.activeWidgets.get(widgetId);
|
|
26
|
+
return widget ? (_jsx(WidgetHeading, { pluginManager: pluginManager, widget: widget })) : (_jsx(Typography, { variant: "h6", color: "inherit", children: "Unknown widget" }));
|
|
27
|
+
}, onChange: e => {
|
|
28
|
+
const w = session.activeWidgets.get(e.target.value);
|
|
29
|
+
if (w) {
|
|
30
|
+
session.showWidget(w);
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
session.notify(`Widget not found ${e.target.value}`, 'warning');
|
|
34
|
+
}
|
|
35
|
+
}, children: [...activeWidgets.values()].map(widget => (_jsxs(MenuItem, { "data-testid": `widget-drawer-selects-item-${widget.type}`, value: widget.id, children: [_jsx(WidgetHeading, { pluginManager: pluginManager, widget: widget }), _jsx(IconButton, { "data-testid": `${widget.type}-drawer-delete`, color: "inherit", "aria-label": "Delete", onClick: e => {
|
|
36
|
+
e.stopPropagation();
|
|
37
|
+
session.hideWidget(widget);
|
|
38
|
+
}, children: _jsx(DeleteIcon, {}) })] }, widget.id))) }) }));
|
|
39
|
+
});
|
|
40
|
+
export default DrawerWidgetSelector;
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
export default
|
|
4
|
-
config: AnyConfigurationModel | Record<string, unknown>;
|
|
5
|
-
session: AbstractSessionModel;
|
|
6
|
-
}): import("react/jsx-runtime").JSX.Element;
|
|
1
|
+
import type { AboutPanelProps } from './util.ts';
|
|
2
|
+
declare const FileInfoPanel: ({ config, session, }: AboutPanelProps) => import("react").JSX.Element | null;
|
|
3
|
+
export default FileInfoPanel;
|
package/esm/ui/FileInfoPanel.js
CHANGED
|
@@ -1,36 +1,46 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { useEffect, useState } from 'react';
|
|
3
2
|
import Attributes from '@jbrowse/core/BaseFeatureWidget/BaseFeatureDetail/Attributes';
|
|
4
3
|
import BaseCard from '@jbrowse/core/BaseFeatureWidget/BaseFeatureDetail/BaseCard';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
4
|
+
import { readConfObject } from '@jbrowse/core/configuration';
|
|
5
|
+
import { ErrorBanner, LoadingEllipses } from '@jbrowse/core/ui';
|
|
6
|
+
import { statusProgressLabel } from '@jbrowse/core/util';
|
|
7
|
+
import { getConfAssemblyNamesOrNone, getConfRpcSessionId, } from '@jbrowse/core/util/tracks';
|
|
8
|
+
import { useFetch } from '@jbrowse/core/util/useFetch';
|
|
9
|
+
import { observer } from 'mobx-react';
|
|
10
|
+
const FileInfoPanel = observer(function FileInfoPanel({ config, session, }) {
|
|
10
11
|
const { rpcManager } = session;
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
})();
|
|
27
|
-
}, [config, rpcManager, trackId]);
|
|
12
|
+
const adapterConfig = readConfObject(config, 'adapter');
|
|
13
|
+
const sessionId = getConfRpcSessionId(config);
|
|
14
|
+
// named so a reference-reading adapter resolves to the instance the track's
|
|
15
|
+
// own requests built, not a spare one
|
|
16
|
+
const [assemblyName] = getConfAssemblyNamesOrNone(config);
|
|
17
|
+
const { data: info, error, isLoading, status, } = useFetch(['CoreGetInfo', sessionId],
|
|
18
|
+
// reading a header can mean walking a v8 .hic's norm-vector index or a
|
|
19
|
+
// multi-megabyte VCF header, so it gets both handles: closing the About
|
|
20
|
+
// dialog stops it, and the wait says what it is
|
|
21
|
+
async (_name, _sessionId, signal, statusCallback) => (await rpcManager.call(sessionId, 'CoreGetInfo', {
|
|
22
|
+
adapterConfig,
|
|
23
|
+
assemblyName,
|
|
24
|
+
signal,
|
|
25
|
+
statusCallback,
|
|
26
|
+
})));
|
|
28
27
|
const details = typeof info === 'string'
|
|
29
28
|
? {
|
|
30
29
|
header: `<pre>${info
|
|
30
|
+
.replaceAll('&', '&')
|
|
31
31
|
.replaceAll('<', '<')
|
|
32
32
|
.replaceAll('>', '>')}</pre>`,
|
|
33
33
|
}
|
|
34
|
-
: info
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
: (info ?? {});
|
|
35
|
+
// `BaseFeatureDataAdapter.getHeader` returns null unless an adapter overrides
|
|
36
|
+
// it, and `CoreGetInfo` returns null outright for anything that isn't a
|
|
37
|
+
// feature adapter — so most tracks reached this with nothing to say and got a
|
|
38
|
+
// FILE INFO heading with blank space under it. A panel with no content is not
|
|
39
|
+
// a panel
|
|
40
|
+
const empty = Object.values(details).every(v => v == null);
|
|
41
|
+
if (!error && !isLoading && empty) {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
return (_jsx(BaseCard, { title: "File info", children: error ? (_jsx(ErrorBanner, { error: error })) : isLoading ? (_jsx(LoadingEllipses, { message: statusProgressLabel(status) || 'Loading file data' })) : (_jsx(Attributes, { attributes: details })) }));
|
|
45
|
+
});
|
|
46
|
+
export default FileInfoPanel;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ThemeModeSelection } from '../Session/Themes.ts';
|
|
2
|
+
import type { ThemeMap } from '@jbrowse/core/ui';
|
|
3
|
+
import type { AnimationMode } from '@jbrowse/core/util';
|
|
4
|
+
export interface GeneralPreferencesSession {
|
|
5
|
+
allThemes: () => ThemeMap;
|
|
6
|
+
themeName?: string;
|
|
7
|
+
setThemeName: (arg: string) => void;
|
|
8
|
+
themeMode: ThemeModeSelection;
|
|
9
|
+
setThemeMode: (arg: ThemeModeSelection) => void;
|
|
10
|
+
animationMode: AnimationMode;
|
|
11
|
+
numberGrouping: boolean;
|
|
12
|
+
setPreferenceOverride: (key: string, value: unknown) => void;
|
|
13
|
+
}
|
|
14
|
+
declare const GeneralPreferencesTab: ({ session, }: {
|
|
15
|
+
session: GeneralPreferencesSession;
|
|
16
|
+
}) => import("react").JSX.Element;
|
|
17
|
+
export default GeneralPreferencesTab;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { makeStyles } from '@jbrowse/core/util/tss-react';
|
|
3
|
+
import { FormGroup, MenuItem, TextField } from '@mui/material';
|
|
4
|
+
import { observer } from 'mobx-react';
|
|
5
|
+
import PreferenceCheckbox from './PreferenceCheckbox.js';
|
|
6
|
+
const useStyles = makeStyles()({
|
|
7
|
+
field: {
|
|
8
|
+
marginTop: 16,
|
|
9
|
+
display: 'block',
|
|
10
|
+
},
|
|
11
|
+
});
|
|
12
|
+
const THEME_MODES = [
|
|
13
|
+
{ value: 'light', label: 'Light' },
|
|
14
|
+
{ value: 'dark', label: 'Dark' },
|
|
15
|
+
{ value: 'system', label: 'Follow system' },
|
|
16
|
+
];
|
|
17
|
+
const ANIMATION_MODES = [
|
|
18
|
+
{ value: 'system', label: 'Follow system (reduced motion)' },
|
|
19
|
+
{ value: 'enabled', label: 'Always on' },
|
|
20
|
+
{ value: 'disabled', label: 'Off' },
|
|
21
|
+
];
|
|
22
|
+
const GeneralPreferencesTab = observer(function GeneralPreferencesTab({ session, }) {
|
|
23
|
+
const { classes } = useStyles();
|
|
24
|
+
return (_jsxs(_Fragment, { children: [_jsx(TextField, { select: true, variant: "outlined", className: classes.field, label: "Theme", value: session.themeName, onChange: event => {
|
|
25
|
+
session.setThemeName(event.target.value);
|
|
26
|
+
}, children: Object.entries(session.allThemes()).map(([key, val]) => (_jsx(MenuItem, { value: key, children: val.name || '(Unknown name)' }, key))) }), _jsx(TextField, { select: true, variant: "outlined", className: classes.field, label: "Light/dark", value: session.themeMode, onChange: event => {
|
|
27
|
+
session.setThemeMode(event.target.value);
|
|
28
|
+
}, children: THEME_MODES.map(opt => (_jsx(MenuItem, { value: opt.value, children: opt.label }, opt.value))) }), _jsx(TextField, { select: true, variant: "outlined", className: classes.field, label: "Animations", value: session.animationMode, onChange: event => {
|
|
29
|
+
session.setPreferenceOverride('animationMode', event.target.value);
|
|
30
|
+
}, children: ANIMATION_MODES.map(opt => (_jsx(MenuItem, { value: opt.value, children: opt.label }, opt.value))) }), _jsx(FormGroup, { children: _jsx(PreferenceCheckbox, { checked: session.numberGrouping, label: "Thousand separators in numbers", help: "Shows chr1:1,234,567 rather than chr1:1234567. Takes effect after reloading the page.", onChange: checked => {
|
|
31
|
+
session.setPreferenceOverride('numberGrouping', checked);
|
|
32
|
+
} }) })] }));
|
|
33
|
+
});
|
|
34
|
+
export default GeneralPreferencesTab;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
interface HeaderButtonsProps {
|
|
2
2
|
conf: Record<string, unknown>;
|
|
3
|
+
hideUris?: boolean;
|
|
3
4
|
setShowRefNames: (show: boolean) => void;
|
|
4
5
|
}
|
|
5
|
-
declare function HeaderButtons({ conf, setShowRefNames }: HeaderButtonsProps): import("react
|
|
6
|
+
declare function HeaderButtons({ conf, hideUris, setShowRefNames, }: HeaderButtonsProps): import("react").JSX.Element;
|
|
6
7
|
export default HeaderButtons;
|
package/esm/ui/HeaderButtons.js
CHANGED
|
@@ -1,26 +1,24 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { CopyToClipboardButton } from '@jbrowse/core/ui';
|
|
3
|
+
import { stripBaseUris } from '@jbrowse/core/util/addRelativeUris';
|
|
3
4
|
import { makeStyles } from '@jbrowse/core/util/tss-react';
|
|
4
5
|
import { Button } from '@mui/material';
|
|
5
|
-
|
|
6
|
-
const useStyles = makeStyles()({
|
|
6
|
+
const useStyles = makeStyles()(theme => ({
|
|
7
7
|
button: {
|
|
8
8
|
float: 'right',
|
|
9
9
|
},
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
// JSX drops the whitespace between two elements on separate lines, so the two
|
|
11
|
+
// contained buttons rendered edge to edge, reading as one two-tone control
|
|
12
|
+
buttons: {
|
|
13
|
+
display: 'flex',
|
|
14
|
+
gap: theme.spacing(1),
|
|
15
|
+
justifyContent: 'flex-end',
|
|
16
|
+
},
|
|
17
|
+
}));
|
|
18
|
+
function HeaderButtons({ conf, hideUris, setShowRefNames, }) {
|
|
13
19
|
const { classes } = useStyles();
|
|
14
|
-
return (
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const { default: copy } = await import('copy-to-clipboard');
|
|
18
|
-
const snap = removeAttr(structuredClone(conf), 'baseUri');
|
|
19
|
-
copy(JSON.stringify(snap, null, 2));
|
|
20
|
-
setCopied(true);
|
|
21
|
-
setTimeout(() => {
|
|
22
|
-
setCopied(false);
|
|
23
|
-
}, 1000);
|
|
24
|
-
}, children: copied ? 'Copied to clipboard!' : 'Copy config' })] }));
|
|
20
|
+
return (_jsx("span", { className: classes.button, children: _jsxs("span", { className: classes.buttons, children: [_jsx(Button, { variant: "contained", color: "secondary", onClick: () => {
|
|
21
|
+
setShowRefNames(true);
|
|
22
|
+
}, children: "Show ref names" }), hideUris ? null : (_jsx(CopyToClipboardButton, { variant: "contained", value: () => JSON.stringify(stripBaseUris(structuredClone(conf)), null, 2), children: "Copy config" }))] }) }));
|
|
25
23
|
}
|
|
26
24
|
export default HeaderButtons;
|