@vitessce/vit-s 3.9.0 → 3.9.2
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/index.js +15424 -15385
- package/dist-tsc/DebugWindow.d.ts +1 -1
- package/dist-tsc/DebugWindow.d.ts.map +1 -1
- package/dist-tsc/TitleInfo.d.ts.map +1 -1
- package/dist-tsc/TitleInfo.js +4 -2
- package/dist-tsc/VitS.d.ts.map +1 -1
- package/dist-tsc/VitS.js +41 -3
- package/dist-tsc/Warning.d.ts +1 -1
- package/dist-tsc/Warning.d.ts.map +1 -1
- package/dist-tsc/shared-mui/container.js +1 -1
- package/dist-tsc/shared-mui/styles.js +4 -1
- package/dist-tsc/title-styles.d.ts.map +1 -1
- package/dist-tsc/title-styles.js +19 -9
- package/package.json +14 -12
- package/src/TitleInfo.js +7 -3
- package/src/VitS.js +48 -3
- package/src/shared-mui/container.js +1 -1
- package/src/shared-mui/styles.js +4 -1
- package/src/title-styles.js +19 -9
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DebugWindow.d.ts","sourceRoot":"","sources":["../src/DebugWindow.js"],"names":[],"mappings":"AAIA;;
|
|
1
|
+
{"version":3,"file":"DebugWindow.d.ts","sourceRoot":"","sources":["../src/DebugWindow.js"],"names":[],"mappings":"AAIA;;gCA8BC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TitleInfo.d.ts","sourceRoot":"","sources":["../src/TitleInfo.js"],"names":[],"mappings":"AAmNA,
|
|
1
|
+
{"version":3,"file":"TitleInfo.d.ts","sourceRoot":"","sources":["../src/TitleInfo.js"],"names":[],"mappings":"AAmNA,mDAwEC"}
|
package/dist-tsc/TitleInfo.js
CHANGED
|
@@ -102,15 +102,17 @@ export function TitleInfo(props) {
|
|
|
102
102
|
const { title, info, children, isScroll, isSpatial, removeGridComponent, urls, isReady, options, closeButtonVisible = true, downloadButtonVisible = true, helpText, withPadding = true, errors: errorsProp, } = props;
|
|
103
103
|
const errors = errorsProp?.filter(Boolean);
|
|
104
104
|
const { classes } = useTitleStyles();
|
|
105
|
+
const hasInfoText = Boolean(info);
|
|
105
106
|
return (
|
|
106
107
|
// d-flex without wrapping div is not always full height; I don't understand the root cause.
|
|
107
|
-
_jsxs(_Fragment, { children: [_jsxs("div", { className: classes.title, role: "banner", children: [_jsx("div", { className: classes.titleLeft, role: "heading", "aria-level": "1", children: title }),
|
|
108
|
+
_jsxs(_Fragment, { children: [_jsxs("div", { className: classes.title, role: "banner", children: [_jsx("div", { className: classes.titleLeft, role: "heading", "aria-level": "1", children: title }), _jsxs("div", { className: classes.titleButtons, role: "toolbar", "aria-label": "Plot options and controls", children: [_jsx(PlotOptions, { options: options }), downloadButtonVisible ? (_jsx(DownloadOptions, { urls: urls })) : null, Array.isArray(errors) && errors.length > 0 ? (_jsx(ErrorInfo, { errors: errors })) : null, helpText ? (_jsx(HelpButton, { helpText: helpText })) : null, closeButtonVisible && removeGridComponent ? (_jsx(ClosePaneButton, { removeGridComponent: removeGridComponent })) : null] })] }), _jsxs("div", { className: clsx(TOOLTIP_ANCESTOR, classes.card, {
|
|
108
109
|
[classes.scrollCard]: isScroll,
|
|
109
110
|
[classes.spatialCard]: isSpatial,
|
|
110
111
|
[classes.noScrollCard]: !isScroll && !isSpatial,
|
|
111
112
|
[classes.noPaddingCard]: !withPadding,
|
|
112
113
|
[classes.paddingCard]: withPadding,
|
|
113
|
-
|
|
114
|
+
[classes.cardWithoutInfoText]: !hasInfoText,
|
|
115
|
+
}), "aria-busy": !isReady, role: "main", children: [!isReady ? _jsx(LoadingIndicator, {}) : null, children] }), hasInfoText ? (_jsx("div", { className: classes.infoText, title: info, role: "note", children: info })) : null] })
|
|
114
116
|
// "pl-2" only matters when the window is very narrow.
|
|
115
117
|
);
|
|
116
118
|
}
|
package/dist-tsc/VitS.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VitS.d.ts","sourceRoot":"","sources":["../src/VitS.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"VitS.d.ts","sourceRoot":"","sources":["../src/VitS.js"],"names":[],"mappings":"AAwCA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,4BApCG;IAAsB,MAAM,EAApB,MAAM;IAGkB,SAAS,EAAjC,SAAS,GAAC,MAAM;IACF,MAAM,EAApB,MAAM;IACQ,KAAK,EAAnB,MAAM;IAEU,MAAM;IACN,cAAc;IAEd,cAAc;IAEf,cAAc,EAA7B,OAAO;IAIQ,sBAAsB,EAArC,OAAO;IAGY,GAAG,EAAtB,IAAI,GAAC,MAAM;IAGW,cAAc,EAApC,SAAS,GAAC,IAAI;IAEC,kBAAkB,EAAjC,OAAO;IAEM,SAAS,EAAtB,KAAK;IACQ,SAAS,EAAtB,KAAK;IACQ,cAAc,EAA3B,KAAK;IACQ,iBAAiB,EAA9B,KAAK;IACc,OAAO,EAA1B,IAAI,GAAC,MAAM;IACI,QAAQ,EAAvB,OAAO;IACQ,SAAS,EAAxB,OAAO;IACY,QAAQ,EAA3B,IAAI,GAAC,MAAM;CAErB,eAsSA"}
|
package/dist-tsc/VitS.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import React, { useState, useEffect, useMemo, useCallback, useLayoutEffect } from 'react';
|
|
3
3
|
import { ThemeProvider, CacheProvider, createCache, } from '@vitessce/styles';
|
|
4
|
+
// eslint-disable-next-line import/no-unresolved
|
|
5
|
+
import ZipFileStore from '@zarrita/storage/zip';
|
|
6
|
+
import { transformEntriesForZipFileStore } from '@vitessce/zarr-utils';
|
|
4
7
|
import { QueryCache, QueryClient, QueryClientProvider, } from '@tanstack/react-query';
|
|
5
8
|
import { isEqual } from 'lodash-es';
|
|
6
9
|
import { buildConfigSchema, latestConfigSchema } from '@vitessce/schemas';
|
|
@@ -54,7 +57,7 @@ import { AsyncFunctionsContext } from './contexts.js';
|
|
|
54
57
|
* provided by the parent.
|
|
55
58
|
*/
|
|
56
59
|
export function VitS(props) {
|
|
57
|
-
const { config, stores, rowHeight, height, theme, onWarn, onConfigChange, onLoaderChange, validateConfig = true, validateOnConfigChange = false, isBounded = false, uid = null, styleContainer, remountOnUidChange = true, viewTypes: viewTypesProp, fileTypes: fileTypesProp, jointFileTypes: jointFileTypesProp, coordinationTypes: coordinationTypesProp, asyncFunctions: asyncFunctionsProp, warning, pageMode = false, children, debugMode = DEFAULT_DEBUG_MODE, logLevel = DEFAULT_LOG_LEVEL, } = props;
|
|
60
|
+
const { config, stores: storesProp, rowHeight, height, theme, onWarn, onConfigChange, onLoaderChange, validateConfig = true, validateOnConfigChange = false, isBounded = false, uid = null, styleContainer, remountOnUidChange = true, viewTypes: viewTypesProp, fileTypes: fileTypesProp, jointFileTypes: jointFileTypesProp, coordinationTypes: coordinationTypesProp, asyncFunctions: asyncFunctionsProp, warning, pageMode = false, children, debugMode = DEFAULT_DEBUG_MODE, logLevel = DEFAULT_LOG_LEVEL, } = props;
|
|
58
61
|
// eslint-disable-next-line no-unused-vars
|
|
59
62
|
const [debugErrors, setDebugErrors] = useState([]);
|
|
60
63
|
const viewTypes = useMemo(() => (viewTypesProp || []), [viewTypesProp]);
|
|
@@ -81,6 +84,41 @@ export function VitS(props) {
|
|
|
81
84
|
return JSON.stringify(config);
|
|
82
85
|
}, [config]);
|
|
83
86
|
const pluginSpecificConfigSchema = useMemo(() => buildConfigSchema(fileTypes, jointFileTypes, coordinationTypes, viewTypes), [viewTypes, fileTypes, jointFileTypes, coordinationTypes]);
|
|
87
|
+
// Pre-create and cache ZipFileStore instances for all zip URLs
|
|
88
|
+
// This ensures that multiple loaders pointing to the same zip URL
|
|
89
|
+
// share the same zip store, preserving HTTP2 multiplexing.
|
|
90
|
+
const mergedStores = useMemo(() => {
|
|
91
|
+
// Note: this logic could alternatively be located inside createLoaders,
|
|
92
|
+
// and could initialize all stores (not only zip stores).
|
|
93
|
+
const result = storesProp ?? {};
|
|
94
|
+
// Collect unique zip URLs and their requestInit from the config
|
|
95
|
+
// Maps URL -> requestInit for store creation with authentication headers
|
|
96
|
+
const urlMap = new Map();
|
|
97
|
+
if (Array.isArray(config.datasets)) {
|
|
98
|
+
config.datasets.forEach((dataset) => {
|
|
99
|
+
dataset.files?.forEach((file) => {
|
|
100
|
+
if (file.fileType?.endsWith('.zip') && file.url) {
|
|
101
|
+
// Use the first requestInit encountered for each URL.
|
|
102
|
+
if (!urlMap.has(file.url)) {
|
|
103
|
+
urlMap.set(file.url, file.requestInit);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
// Create stores for new zip URLs with their requestInit
|
|
110
|
+
urlMap.forEach((requestInit, url) => {
|
|
111
|
+
// Only create a new store if one does not already exist for this URL.
|
|
112
|
+
if (!result[url]) {
|
|
113
|
+
result[url] = ZipFileStore.fromUrl(url, {
|
|
114
|
+
overrides: requestInit,
|
|
115
|
+
transformEntries: transformEntriesForZipFileStore,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
return result;
|
|
120
|
+
// TODO: also depend on storesProp here?
|
|
121
|
+
}, [configKey]);
|
|
84
122
|
// Process the view config and memoize the result:
|
|
85
123
|
// - Validate.
|
|
86
124
|
// - Upgrade, if legacy schema.
|
|
@@ -176,7 +214,7 @@ export function VitS(props) {
|
|
|
176
214
|
// Initialize the view config and loaders in the global state.
|
|
177
215
|
const createViewConfigStoreClosure = useCallback(() => {
|
|
178
216
|
if (success) {
|
|
179
|
-
const loaders = createLoaders(configOrWarning.datasets, configOrWarning.description, fileTypes, coordinationTypes,
|
|
217
|
+
const loaders = createLoaders(configOrWarning.datasets, configOrWarning.description, fileTypes, coordinationTypes, mergedStores, queryClient);
|
|
180
218
|
return createViewConfigStore(loaders, configOrWarning);
|
|
181
219
|
}
|
|
182
220
|
// No config found, so clear the loaders.
|
|
@@ -189,5 +227,5 @@ export function VitS(props) {
|
|
|
189
227
|
if (debugMode && debugErrors.length > 0) {
|
|
190
228
|
return (_jsx(CacheProvider, { value: muiCache, children: _jsx(ThemeProvider, { theme: muiTheme[theme], children: _jsx(DebugWindow, { debugErrors: debugErrors }) }) }));
|
|
191
229
|
}
|
|
192
|
-
return success ? (_jsx(CacheProvider, { value: muiCache, children: _jsx(ThemeProvider, { theme: muiTheme[theme], children: _jsx(QueryClientProvider, { client: queryClient, children: _jsx(ViewConfigProvider, { createStore: createViewConfigStoreClosure, children: _jsx(AuxiliaryProvider, { createStore: createAuxiliaryStore, children: _jsxs(AsyncFunctionsContext.Provider, { value: asyncFunctions, children: [_jsx(VitessceGrid, { pageMode: pageMode, success: success, configKey: configKey, viewTypes: viewTypes, fileTypes: fileTypes, coordinationTypes: coordinationTypes, config: configOrWarning, rowHeight: rowHeight, height: height, theme: theme, isBounded: isBounded, stores:
|
|
230
|
+
return success ? (_jsx(CacheProvider, { value: muiCache, children: _jsx(ThemeProvider, { theme: muiTheme[theme], children: _jsx(QueryClientProvider, { client: queryClient, children: _jsx(ViewConfigProvider, { createStore: createViewConfigStoreClosure, children: _jsx(AuxiliaryProvider, { createStore: createAuxiliaryStore, children: _jsxs(AsyncFunctionsContext.Provider, { value: asyncFunctions, children: [_jsx(VitessceGrid, { pageMode: pageMode, success: success, configKey: configKey, viewTypes: viewTypes, fileTypes: fileTypes, coordinationTypes: coordinationTypes, config: configOrWarning, rowHeight: rowHeight, height: height, theme: theme, isBounded: isBounded, stores: mergedStores, queryClient: queryClient, children: children }), _jsx(CallbackPublisher, { onWarn: onWarn, onConfigChange: onConfigChange, onLoaderChange: onLoaderChange, validateOnConfigChange: validateOnConfigChange, pluginSpecificConfigSchema: pluginSpecificConfigSchema })] }) }) }, (remountOnUidChange ? configKey : undefined)) }) }) })) : (_jsx(CacheProvider, { value: muiCache, children: _jsx(ThemeProvider, { theme: muiTheme[theme], children: _jsx(Warning, { ...configOrWarning }) }) }));
|
|
193
231
|
}
|
package/dist-tsc/Warning.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export function Warning(props: any): import("
|
|
1
|
+
export function Warning(props: any): import("react").JSX.Element;
|
|
2
2
|
//# sourceMappingURL=Warning.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Warning.d.ts","sourceRoot":"","sources":["../src/Warning.js"],"names":[],"mappings":"AAIA
|
|
1
|
+
{"version":3,"file":"Warning.d.ts","sourceRoot":"","sources":["../src/Warning.js"],"names":[],"mappings":"AAIA,iEAoBC"}
|
|
@@ -96,7 +96,7 @@ const gridLayoutStyles = {
|
|
|
96
96
|
},
|
|
97
97
|
'.react-grid-item > .react-resizable-handle.react-resizable-handle-se': {
|
|
98
98
|
bottom: '0',
|
|
99
|
-
right: '
|
|
99
|
+
right: '10px',
|
|
100
100
|
cursor: 'se-resize',
|
|
101
101
|
},
|
|
102
102
|
'.react-grid-item > .react-resizable-handle.react-resizable-handle-nw': {
|
|
@@ -75,6 +75,7 @@ const lightPalette = {
|
|
|
75
75
|
gridLayoutBackground: '#FFFFFF',
|
|
76
76
|
paperBackground: '#FFFFFF',
|
|
77
77
|
cardBorder: 'rgba(241, 241, 241, 0.125)',
|
|
78
|
+
cardInfoBorder: '#ccc',
|
|
78
79
|
tooltipText: 'rgba(0, 0, 0, 0.87)',
|
|
79
80
|
};
|
|
80
81
|
export const muiTheme = {
|
|
@@ -100,6 +101,7 @@ export const muiTheme = {
|
|
|
100
101
|
gridLayoutBackground: '#333333',
|
|
101
102
|
paperBackground: '#2b2b2b',
|
|
102
103
|
cardBorder: 'rgba(0, 0, 0, 0.125)',
|
|
104
|
+
cardInfoBorder: '#222222',
|
|
103
105
|
tooltipText: '#FFFFFF',
|
|
104
106
|
...globalColors,
|
|
105
107
|
},
|
|
@@ -109,6 +111,7 @@ export const muiTheme = {
|
|
|
109
111
|
light: createTheme({
|
|
110
112
|
palette: {
|
|
111
113
|
...lightPalette,
|
|
114
|
+
cardInfoBorder: '#F1F1F1',
|
|
112
115
|
...globalColors,
|
|
113
116
|
},
|
|
114
117
|
...sharedThemeOptions,
|
|
@@ -126,6 +129,6 @@ export const muiTheme = {
|
|
|
126
129
|
...globalColors,
|
|
127
130
|
},
|
|
128
131
|
...sharedThemeOptions,
|
|
129
|
-
cardBorderSize: '
|
|
132
|
+
cardBorderSize: '1px',
|
|
130
133
|
}),
|
|
131
134
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"title-styles.d.ts","sourceRoot":"","sources":["../src/title-styles.js"],"names":[],"mappings":"AAEA;;
|
|
1
|
+
{"version":3,"file":"title-styles.d.ts","sourceRoot":"","sources":["../src/title-styles.js"],"names":[],"mappings":"AAEA;;cAyBO,CAAC;;;kBAE+B,eACvC;gBAAyB,WAAU;eAAsB,WACpD;EAyDD"}
|
package/dist-tsc/title-styles.js
CHANGED
|
@@ -13,18 +13,23 @@ export const useTitleStyles = makeStyles()(theme => ({
|
|
|
13
13
|
textOverflow: 'ellipsis',
|
|
14
14
|
whiteSpace: 'nowrap',
|
|
15
15
|
},
|
|
16
|
-
|
|
16
|
+
infoText: {
|
|
17
|
+
color: theme.palette.primaryForeground,
|
|
17
18
|
width: '100%',
|
|
18
19
|
textOverflow: 'ellipsis',
|
|
19
20
|
whiteSpace: 'nowrap',
|
|
20
21
|
overflow: 'hidden',
|
|
21
|
-
fontSize: '
|
|
22
|
+
fontSize: '60% !important',
|
|
22
23
|
opacity: '.8',
|
|
23
|
-
padding: '0
|
|
24
|
+
padding: '0',
|
|
24
25
|
justifyContent: 'center',
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
textAlign: 'center !important',
|
|
27
|
+
borderTop: '0px',
|
|
28
|
+
borderBottom: `1px solid ${theme.palette.cardInfoBorder}`,
|
|
29
|
+
borderLeft: `1px solid ${theme.palette.cardInfoBorder}`,
|
|
30
|
+
borderRight: `1px solid ${theme.palette.cardInfoBorder}`,
|
|
31
|
+
borderBottomLeftRadius: '4px',
|
|
32
|
+
borderBottomRightRadius: '4px',
|
|
28
33
|
},
|
|
29
34
|
titleButtons: {
|
|
30
35
|
display: 'flex',
|
|
@@ -40,15 +45,20 @@ export const useTitleStyles = makeStyles()(theme => ({
|
|
|
40
45
|
border: `${theme.cardBorderSize} solid ${theme.palette.cardBorder}`,
|
|
41
46
|
flex: '1 1 auto',
|
|
42
47
|
minHeight: '1px',
|
|
43
|
-
marginTop: '
|
|
44
|
-
marginBottom: '
|
|
48
|
+
marginTop: '0',
|
|
49
|
+
marginBottom: '0',
|
|
45
50
|
position: 'relative',
|
|
46
51
|
display: 'flex',
|
|
47
52
|
flexDirection: 'column',
|
|
48
53
|
minWidth: '0',
|
|
49
54
|
wordWrap: 'break-word',
|
|
50
55
|
backgroundClip: 'border-box',
|
|
51
|
-
|
|
56
|
+
borderTopLeftRadius: '4px',
|
|
57
|
+
borderTopRightRadius: '4px',
|
|
58
|
+
},
|
|
59
|
+
cardWithoutInfoText: {
|
|
60
|
+
borderBottomLeftRadius: '4px',
|
|
61
|
+
borderBottomRightRadius: '4px',
|
|
52
62
|
},
|
|
53
63
|
paddingCard: {
|
|
54
64
|
padding: '12px',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vitessce/vit-s",
|
|
3
|
-
"version": "3.9.
|
|
3
|
+
"version": "3.9.2",
|
|
4
4
|
"author": "HIDIVE Lab at HMS",
|
|
5
5
|
"homepage": "http://vitessce.io",
|
|
6
6
|
"repository": {
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
],
|
|
18
18
|
"dependencies": {
|
|
19
19
|
"@tanstack/react-query": "^5.80.2",
|
|
20
|
+
"@zarrita/storage": "0.1.3",
|
|
20
21
|
"clsx": "^1.1.1",
|
|
21
22
|
"d3-array": "^2.4.0",
|
|
22
23
|
"fast-deep-equal": "^3.1.3",
|
|
@@ -30,16 +31,17 @@
|
|
|
30
31
|
"react-error-boundary": "^5.0.0",
|
|
31
32
|
"@placemarkio/flat-drop-files": "^1.0.2",
|
|
32
33
|
"zarrita": "0.5.4",
|
|
33
|
-
"@vitessce/styles": "3.9.
|
|
34
|
-
"@vitessce/
|
|
35
|
-
"@vitessce/
|
|
36
|
-
"@vitessce/
|
|
37
|
-
"@vitessce/
|
|
38
|
-
"@vitessce/schemas": "3.9.
|
|
39
|
-
"@vitessce/sets-utils": "3.9.
|
|
40
|
-
"@vitessce/
|
|
41
|
-
"@vitessce/config": "3.9.
|
|
42
|
-
"@vitessce/
|
|
34
|
+
"@vitessce/styles": "3.9.2",
|
|
35
|
+
"@vitessce/abstract": "3.9.2",
|
|
36
|
+
"@vitessce/error": "3.9.2",
|
|
37
|
+
"@vitessce/constants-internal": "3.9.2",
|
|
38
|
+
"@vitessce/plugins": "3.9.2",
|
|
39
|
+
"@vitessce/schemas": "3.9.2",
|
|
40
|
+
"@vitessce/sets-utils": "3.9.2",
|
|
41
|
+
"@vitessce/zarr-utils": "3.9.2",
|
|
42
|
+
"@vitessce/config": "3.9.2",
|
|
43
|
+
"@vitessce/utils": "3.9.2",
|
|
44
|
+
"@vitessce/globals": "3.9.2"
|
|
43
45
|
},
|
|
44
46
|
"devDependencies": {
|
|
45
47
|
"@testing-library/jest-dom": "^6.6.3",
|
|
@@ -48,7 +50,7 @@
|
|
|
48
50
|
"react-dom": "18.3.1",
|
|
49
51
|
"vite": "^7.0.0",
|
|
50
52
|
"vitest": "^3.1.4",
|
|
51
|
-
"@vitessce/types": "3.9.
|
|
53
|
+
"@vitessce/types": "3.9.2"
|
|
52
54
|
},
|
|
53
55
|
"peerDependencies": {
|
|
54
56
|
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
package/src/TitleInfo.js
CHANGED
|
@@ -219,6 +219,7 @@ export function TitleInfo(props) {
|
|
|
219
219
|
const errors = errorsProp?.filter(Boolean);
|
|
220
220
|
|
|
221
221
|
const { classes } = useTitleStyles();
|
|
222
|
+
const hasInfoText = Boolean(info);
|
|
222
223
|
|
|
223
224
|
return (
|
|
224
225
|
// d-flex without wrapping div is not always full height; I don't understand the root cause.
|
|
@@ -227,9 +228,6 @@ export function TitleInfo(props) {
|
|
|
227
228
|
<div className={classes.titleLeft} role="heading" aria-level="1">
|
|
228
229
|
{title}
|
|
229
230
|
</div>
|
|
230
|
-
<div className={classes.titleInfo} title={info} role="note">
|
|
231
|
-
{info}
|
|
232
|
-
</div>
|
|
233
231
|
<div className={classes.titleButtons} role="toolbar" aria-label="Plot options and controls">
|
|
234
232
|
<PlotOptions
|
|
235
233
|
options={options}
|
|
@@ -266,6 +264,7 @@ export function TitleInfo(props) {
|
|
|
266
264
|
[classes.noScrollCard]: !isScroll && !isSpatial,
|
|
267
265
|
[classes.noPaddingCard]: !withPadding,
|
|
268
266
|
[classes.paddingCard]: withPadding,
|
|
267
|
+
[classes.cardWithoutInfoText]: !hasInfoText,
|
|
269
268
|
},
|
|
270
269
|
)}
|
|
271
270
|
aria-busy={!isReady}
|
|
@@ -274,6 +273,11 @@ export function TitleInfo(props) {
|
|
|
274
273
|
{ !isReady ? <LoadingIndicator /> : null }
|
|
275
274
|
{children}
|
|
276
275
|
</div>
|
|
276
|
+
{hasInfoText ? (
|
|
277
|
+
<div className={classes.infoText} title={info} role="note">
|
|
278
|
+
{info}
|
|
279
|
+
</div>
|
|
280
|
+
) : null}
|
|
277
281
|
</>
|
|
278
282
|
// "pl-2" only matters when the window is very narrow.
|
|
279
283
|
);
|
package/src/VitS.js
CHANGED
|
@@ -4,6 +4,9 @@ import {
|
|
|
4
4
|
CacheProvider,
|
|
5
5
|
createCache,
|
|
6
6
|
} from '@vitessce/styles';
|
|
7
|
+
// eslint-disable-next-line import/no-unresolved
|
|
8
|
+
import ZipFileStore from '@zarrita/storage/zip';
|
|
9
|
+
import { transformEntriesForZipFileStore } from '@vitessce/zarr-utils';
|
|
7
10
|
import {
|
|
8
11
|
QueryCache,
|
|
9
12
|
QueryClient,
|
|
@@ -77,7 +80,7 @@ import { AsyncFunctionsContext } from './contexts.js';
|
|
|
77
80
|
export function VitS(props) {
|
|
78
81
|
const {
|
|
79
82
|
config,
|
|
80
|
-
stores,
|
|
83
|
+
stores: storesProp,
|
|
81
84
|
rowHeight,
|
|
82
85
|
height,
|
|
83
86
|
theme,
|
|
@@ -104,6 +107,7 @@ export function VitS(props) {
|
|
|
104
107
|
|
|
105
108
|
// eslint-disable-next-line no-unused-vars
|
|
106
109
|
const [debugErrors, setDebugErrors] = useState([]);
|
|
110
|
+
|
|
107
111
|
const viewTypes = useMemo(() => (viewTypesProp || []), [viewTypesProp]);
|
|
108
112
|
const fileTypes = useMemo(() => (fileTypesProp || []), [fileTypesProp]);
|
|
109
113
|
const jointFileTypes = useMemo(
|
|
@@ -143,6 +147,46 @@ export function VitS(props) {
|
|
|
143
147
|
viewTypes,
|
|
144
148
|
), [viewTypes, fileTypes, jointFileTypes, coordinationTypes]);
|
|
145
149
|
|
|
150
|
+
|
|
151
|
+
// Pre-create and cache ZipFileStore instances for all zip URLs
|
|
152
|
+
// This ensures that multiple loaders pointing to the same zip URL
|
|
153
|
+
// share the same zip store, preserving HTTP2 multiplexing.
|
|
154
|
+
const mergedStores = useMemo(() => {
|
|
155
|
+
// Note: this logic could alternatively be located inside createLoaders,
|
|
156
|
+
// and could initialize all stores (not only zip stores).
|
|
157
|
+
const result = storesProp ?? {};
|
|
158
|
+
|
|
159
|
+
// Collect unique zip URLs and their requestInit from the config
|
|
160
|
+
// Maps URL -> requestInit for store creation with authentication headers
|
|
161
|
+
const urlMap = new Map();
|
|
162
|
+
if (Array.isArray(config.datasets)) {
|
|
163
|
+
config.datasets.forEach((dataset) => {
|
|
164
|
+
dataset.files?.forEach((file) => {
|
|
165
|
+
if (file.fileType?.endsWith('.zip') && file.url) {
|
|
166
|
+
// Use the first requestInit encountered for each URL.
|
|
167
|
+
if (!urlMap.has(file.url)) {
|
|
168
|
+
urlMap.set(file.url, file.requestInit);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Create stores for new zip URLs with their requestInit
|
|
176
|
+
urlMap.forEach((requestInit, url) => {
|
|
177
|
+
// Only create a new store if one does not already exist for this URL.
|
|
178
|
+
if (!result[url]) {
|
|
179
|
+
result[url] = ZipFileStore.fromUrl(url, {
|
|
180
|
+
overrides: requestInit,
|
|
181
|
+
transformEntries: transformEntriesForZipFileStore,
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
return result;
|
|
187
|
+
// TODO: also depend on storesProp here?
|
|
188
|
+
}, [configKey]);
|
|
189
|
+
|
|
146
190
|
// Process the view config and memoize the result:
|
|
147
191
|
// - Validate.
|
|
148
192
|
// - Upgrade, if legacy schema.
|
|
@@ -233,6 +277,7 @@ export function VitS(props) {
|
|
|
233
277
|
[asyncFunctionsProp, queryClient],
|
|
234
278
|
);
|
|
235
279
|
|
|
280
|
+
|
|
236
281
|
const muiCache = useMemo(() => createCache({
|
|
237
282
|
key: uid || 'vit',
|
|
238
283
|
prepend: true,
|
|
@@ -256,7 +301,7 @@ export function VitS(props) {
|
|
|
256
301
|
configOrWarning.description,
|
|
257
302
|
fileTypes,
|
|
258
303
|
coordinationTypes,
|
|
259
|
-
|
|
304
|
+
mergedStores,
|
|
260
305
|
queryClient,
|
|
261
306
|
);
|
|
262
307
|
return createViewConfigStore(loaders, configOrWarning);
|
|
@@ -300,7 +345,7 @@ export function VitS(props) {
|
|
|
300
345
|
height={height}
|
|
301
346
|
theme={theme}
|
|
302
347
|
isBounded={isBounded}
|
|
303
|
-
stores={
|
|
348
|
+
stores={mergedStores}
|
|
304
349
|
queryClient={queryClient}
|
|
305
350
|
>
|
|
306
351
|
{children}
|
|
@@ -97,7 +97,7 @@ const gridLayoutStyles = {
|
|
|
97
97
|
},
|
|
98
98
|
'.react-grid-item > .react-resizable-handle.react-resizable-handle-se': {
|
|
99
99
|
bottom: '0',
|
|
100
|
-
right: '
|
|
100
|
+
right: '10px',
|
|
101
101
|
cursor: 'se-resize',
|
|
102
102
|
},
|
|
103
103
|
'.react-grid-item > .react-resizable-handle.react-resizable-handle-nw': {
|
package/src/shared-mui/styles.js
CHANGED
|
@@ -78,6 +78,7 @@ const lightPalette = {
|
|
|
78
78
|
gridLayoutBackground: '#FFFFFF',
|
|
79
79
|
paperBackground: '#FFFFFF',
|
|
80
80
|
cardBorder: 'rgba(241, 241, 241, 0.125)',
|
|
81
|
+
cardInfoBorder: '#ccc',
|
|
81
82
|
tooltipText: 'rgba(0, 0, 0, 0.87)',
|
|
82
83
|
};
|
|
83
84
|
|
|
@@ -104,6 +105,7 @@ export const muiTheme = {
|
|
|
104
105
|
gridLayoutBackground: '#333333',
|
|
105
106
|
paperBackground: '#2b2b2b',
|
|
106
107
|
cardBorder: 'rgba(0, 0, 0, 0.125)',
|
|
108
|
+
cardInfoBorder: '#222222',
|
|
107
109
|
tooltipText: '#FFFFFF',
|
|
108
110
|
...globalColors,
|
|
109
111
|
},
|
|
@@ -113,6 +115,7 @@ export const muiTheme = {
|
|
|
113
115
|
light: createTheme({
|
|
114
116
|
palette: {
|
|
115
117
|
...lightPalette,
|
|
118
|
+
cardInfoBorder: '#F1F1F1',
|
|
116
119
|
...globalColors,
|
|
117
120
|
},
|
|
118
121
|
...sharedThemeOptions,
|
|
@@ -130,6 +133,6 @@ export const muiTheme = {
|
|
|
130
133
|
...globalColors,
|
|
131
134
|
},
|
|
132
135
|
...sharedThemeOptions,
|
|
133
|
-
cardBorderSize: '
|
|
136
|
+
cardBorderSize: '1px',
|
|
134
137
|
}),
|
|
135
138
|
};
|
package/src/title-styles.js
CHANGED
|
@@ -14,18 +14,23 @@ export const useTitleStyles = makeStyles()(theme => ({
|
|
|
14
14
|
textOverflow: 'ellipsis',
|
|
15
15
|
whiteSpace: 'nowrap',
|
|
16
16
|
},
|
|
17
|
-
|
|
17
|
+
infoText: {
|
|
18
|
+
color: theme.palette.primaryForeground,
|
|
18
19
|
width: '100%',
|
|
19
20
|
textOverflow: 'ellipsis',
|
|
20
21
|
whiteSpace: 'nowrap',
|
|
21
22
|
overflow: 'hidden',
|
|
22
|
-
fontSize: '
|
|
23
|
+
fontSize: '60% !important',
|
|
23
24
|
opacity: '.8',
|
|
24
|
-
padding: '0
|
|
25
|
+
padding: '0',
|
|
25
26
|
justifyContent: 'center',
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
textAlign: 'center !important',
|
|
28
|
+
borderTop: '0px',
|
|
29
|
+
borderBottom: `1px solid ${theme.palette.cardInfoBorder}`,
|
|
30
|
+
borderLeft: `1px solid ${theme.palette.cardInfoBorder}`,
|
|
31
|
+
borderRight: `1px solid ${theme.palette.cardInfoBorder}`,
|
|
32
|
+
borderBottomLeftRadius: '4px',
|
|
33
|
+
borderBottomRightRadius: '4px',
|
|
29
34
|
},
|
|
30
35
|
titleButtons: {
|
|
31
36
|
display: 'flex',
|
|
@@ -41,15 +46,20 @@ export const useTitleStyles = makeStyles()(theme => ({
|
|
|
41
46
|
border: `${theme.cardBorderSize} solid ${theme.palette.cardBorder}`,
|
|
42
47
|
flex: '1 1 auto',
|
|
43
48
|
minHeight: '1px',
|
|
44
|
-
marginTop: '
|
|
45
|
-
marginBottom: '
|
|
49
|
+
marginTop: '0',
|
|
50
|
+
marginBottom: '0',
|
|
46
51
|
position: 'relative',
|
|
47
52
|
display: 'flex',
|
|
48
53
|
flexDirection: 'column',
|
|
49
54
|
minWidth: '0',
|
|
50
55
|
wordWrap: 'break-word',
|
|
51
56
|
backgroundClip: 'border-box',
|
|
52
|
-
|
|
57
|
+
borderTopLeftRadius: '4px',
|
|
58
|
+
borderTopRightRadius: '4px',
|
|
59
|
+
},
|
|
60
|
+
cardWithoutInfoText: {
|
|
61
|
+
borderBottomLeftRadius: '4px',
|
|
62
|
+
borderBottomRightRadius: '4px',
|
|
53
63
|
},
|
|
54
64
|
paddingCard: {
|
|
55
65
|
padding: '12px',
|