@vitessce/vit-s 2.0.3 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +41348 -0
- package/dist-tsc/CallbackPublisher.d.ts +18 -0
- package/dist-tsc/CallbackPublisher.d.ts.map +1 -0
- package/dist-tsc/CallbackPublisher.js +62 -0
- package/dist-tsc/LoadingIndicator.d.ts +2 -0
- package/dist-tsc/LoadingIndicator.d.ts.map +1 -0
- package/dist-tsc/LoadingIndicator.js +26 -0
- package/dist-tsc/TitleInfo.d.ts +2 -0
- package/dist-tsc/TitleInfo.d.ts.map +1 -0
- package/dist-tsc/TitleInfo.js +74 -0
- package/dist-tsc/VitS.d.ts +45 -0
- package/dist-tsc/VitS.d.ts.map +1 -0
- package/dist-tsc/VitS.js +119 -0
- package/dist-tsc/VitessceGrid.d.ts +23 -0
- package/dist-tsc/VitessceGrid.d.ts.map +1 -0
- package/dist-tsc/VitessceGrid.js +60 -0
- package/dist-tsc/VitessceGrid.test.d.ts +2 -0
- package/dist-tsc/VitessceGrid.test.d.ts.map +1 -0
- package/dist-tsc/VitessceGrid.test.js +40 -0
- package/dist-tsc/Warning.d.ts +2 -0
- package/dist-tsc/Warning.d.ts.map +1 -0
- package/dist-tsc/Warning.js +45 -0
- package/dist-tsc/classNames.d.ts +8 -0
- package/dist-tsc/classNames.d.ts.map +1 -0
- package/dist-tsc/classNames.js +8 -0
- package/dist-tsc/data/AbstractLoader.d.ts +22 -0
- package/dist-tsc/data/AbstractLoader.d.ts.map +1 -0
- package/dist-tsc/data/AbstractLoader.js +18 -0
- package/dist-tsc/data/AbstractTwoStepLoader.d.ts +6 -0
- package/dist-tsc/data/AbstractTwoStepLoader.d.ts.map +1 -0
- package/dist-tsc/data/AbstractTwoStepLoader.js +7 -0
- package/dist-tsc/data/LoaderResult.d.ts +7 -0
- package/dist-tsc/data/LoaderResult.d.ts.map +1 -0
- package/dist-tsc/data/LoaderResult.js +7 -0
- package/dist-tsc/data/index.d.ts +4 -0
- package/dist-tsc/data/index.d.ts.map +1 -0
- package/dist-tsc/data/index.js +3 -0
- package/dist-tsc/data/loader-registry.d.ts +9 -0
- package/dist-tsc/data/loader-registry.d.ts.map +1 -0
- package/dist-tsc/data/loader-registry.js +27 -0
- package/dist-tsc/data-hook-utils.d.ts +69 -0
- package/dist-tsc/data-hook-utils.d.ts.map +1 -0
- package/dist-tsc/data-hook-utils.js +173 -0
- package/dist-tsc/data-hooks.d.ts +77 -0
- package/dist-tsc/data-hooks.d.ts.map +1 -0
- package/dist-tsc/data-hooks.js +241 -0
- package/dist-tsc/errors/AbstractLoaderError.d.ts +10 -0
- package/dist-tsc/errors/AbstractLoaderError.d.ts.map +1 -0
- package/dist-tsc/errors/AbstractLoaderError.js +13 -0
- package/dist-tsc/errors/DataSourceFetchError.d.ts +8 -0
- package/dist-tsc/errors/DataSourceFetchError.d.ts.map +1 -0
- package/dist-tsc/errors/DataSourceFetchError.js +13 -0
- package/dist-tsc/errors/DatasetNotFoundError.d.ts +6 -0
- package/dist-tsc/errors/DatasetNotFoundError.d.ts.map +1 -0
- package/dist-tsc/errors/DatasetNotFoundError.js +17 -0
- package/dist-tsc/errors/LoaderNotFoundError.d.ts +10 -0
- package/dist-tsc/errors/LoaderNotFoundError.d.ts.map +1 -0
- package/dist-tsc/errors/LoaderNotFoundError.js +17 -0
- package/dist-tsc/errors/LoaderValidationError.d.ts +10 -0
- package/dist-tsc/errors/LoaderValidationError.d.ts.map +1 -0
- package/dist-tsc/errors/LoaderValidationError.js +15 -0
- package/dist-tsc/errors/index.d.ts +6 -0
- package/dist-tsc/errors/index.d.ts.map +1 -0
- package/dist-tsc/errors/index.js +5 -0
- package/dist-tsc/hooks.d.ts +80 -0
- package/dist-tsc/hooks.d.ts.map +1 -0
- package/dist-tsc/hooks.js +271 -0
- package/dist-tsc/index.d.ts +11 -0
- package/dist-tsc/index.d.ts.map +1 -0
- package/dist-tsc/index.js +10 -17
- package/dist-tsc/plugins.test.fixtures.d.ts +61 -0
- package/dist-tsc/plugins.test.fixtures.d.ts.map +1 -0
- package/dist-tsc/plugins.test.fixtures.js +76 -0
- package/dist-tsc/schemas/config-0.1.0.schema.json +84 -0
- package/dist-tsc/schemas/config-1.0.0.schema.json +733 -0
- package/dist-tsc/schemas/config-1.0.1.schema.json +909 -0
- package/dist-tsc/schemas/config-1.0.10.schema.json +969 -0
- package/dist-tsc/schemas/config-1.0.11.schema.json +990 -0
- package/dist-tsc/schemas/config-1.0.12.schema.json +997 -0
- package/dist-tsc/schemas/config-1.0.13.schema.json +1013 -0
- package/dist-tsc/schemas/config-1.0.14.schema.json +1048 -0
- package/dist-tsc/schemas/config-1.0.15.schema.json +1048 -0
- package/dist-tsc/schemas/config-1.0.16.schema.json +1089 -0
- package/dist-tsc/schemas/config-1.0.2.schema.json +910 -0
- package/dist-tsc/schemas/config-1.0.3.schema.json +910 -0
- package/dist-tsc/schemas/config-1.0.4.schema.json +949 -0
- package/dist-tsc/schemas/config-1.0.5.schema.json +949 -0
- package/dist-tsc/schemas/config-1.0.6.schema.json +949 -0
- package/dist-tsc/schemas/config-1.0.7.schema.json +949 -0
- package/dist-tsc/schemas/config-1.0.8.schema.json +965 -0
- package/dist-tsc/schemas/config-1.0.9.schema.json +965 -0
- package/dist-tsc/schemas/obsSets.schema.d.ts +179 -0
- package/dist-tsc/schemas/obsSets.schema.d.ts.map +1 -0
- package/dist-tsc/schemas/obsSets.schema.js +195 -0
- package/dist-tsc/schemas/obsSetsTabular.schema.d.ts +57 -0
- package/dist-tsc/schemas/obsSetsTabular.schema.d.ts.map +1 -0
- package/dist-tsc/schemas/obsSetsTabular.schema.js +38 -0
- package/dist-tsc/schemas/raster.schema.d.ts +239 -0
- package/dist-tsc/schemas/raster.schema.d.ts.map +1 -0
- package/dist-tsc/schemas/raster.schema.js +120 -0
- package/dist-tsc/shared-mui/components.d.ts +2 -0
- package/dist-tsc/shared-mui/components.d.ts.map +1 -0
- package/dist-tsc/shared-mui/components.js +29 -0
- package/dist-tsc/shared-mui/container.d.ts +2 -0
- package/dist-tsc/shared-mui/container.d.ts.map +1 -0
- package/dist-tsc/shared-mui/container.js +211 -0
- package/dist-tsc/shared-mui/styles.d.ts +5 -0
- package/dist-tsc/shared-mui/styles.d.ts.map +1 -0
- package/dist-tsc/shared-mui/styles.js +109 -0
- package/dist-tsc/shared-plot-options/CellColorEncodingOption.d.ts +2 -0
- package/dist-tsc/shared-plot-options/CellColorEncodingOption.d.ts.map +1 -0
- package/dist-tsc/shared-plot-options/CellColorEncodingOption.js +17 -0
- package/dist-tsc/shared-plot-options/OptionSelect.d.ts +2 -0
- package/dist-tsc/shared-plot-options/OptionSelect.d.ts.map +1 -0
- package/dist-tsc/shared-plot-options/OptionSelect.js +12 -0
- package/dist-tsc/shared-plot-options/OptionsContainer.d.ts +2 -0
- package/dist-tsc/shared-plot-options/OptionsContainer.d.ts.map +1 -0
- package/dist-tsc/shared-plot-options/OptionsContainer.js +9 -0
- package/dist-tsc/shared-plot-options/index.d.ts +5 -0
- package/dist-tsc/shared-plot-options/index.d.ts.map +1 -0
- package/dist-tsc/shared-plot-options/index.js +4 -0
- package/dist-tsc/shared-plot-options/styles.d.ts +2 -0
- package/dist-tsc/shared-plot-options/styles.d.ts.map +1 -0
- package/dist-tsc/shared-plot-options/styles.js +48 -0
- package/dist-tsc/state/hooks.d.ts +216 -0
- package/dist-tsc/state/hooks.d.ts.map +1 -0
- package/dist-tsc/state/hooks.js +575 -0
- package/dist-tsc/title-styles.d.ts +2 -0
- package/dist-tsc/title-styles.d.ts.map +1 -0
- package/dist-tsc/title-styles.js +72 -0
- package/dist-tsc/view-config-utils.d.ts +30 -0
- package/dist-tsc/view-config-utils.d.ts.map +1 -0
- package/dist-tsc/view-config-utils.js +234 -0
- package/dist-tsc/view-config-utils.test.d.ts +2 -0
- package/dist-tsc/view-config-utils.test.d.ts.map +1 -0
- package/dist-tsc/view-config-utils.test.fixtures.d.ts +1049 -0
- package/dist-tsc/view-config-utils.test.fixtures.d.ts.map +1 -0
- package/dist-tsc/view-config-utils.test.fixtures.js +883 -0
- package/dist-tsc/view-config-utils.test.js +209 -0
- package/dist-tsc/vitessce-grid-layout/VitessceGridLayout.d.ts +8 -0
- package/dist-tsc/vitessce-grid-layout/VitessceGridLayout.d.ts.map +1 -0
- package/dist-tsc/vitessce-grid-layout/VitessceGridLayout.js +114 -0
- package/dist-tsc/vitessce-grid-layout/VitessceGridLayout.test.d.ts +2 -0
- package/dist-tsc/vitessce-grid-layout/VitessceGridLayout.test.d.ts.map +1 -0
- package/dist-tsc/vitessce-grid-layout/VitessceGridLayout.test.js +48 -0
- package/dist-tsc/vitessce-grid-layout/index.d.ts +2 -0
- package/dist-tsc/vitessce-grid-layout/index.d.ts.map +1 -0
- package/dist-tsc/vitessce-grid-layout/index.js +1 -0
- package/dist-tsc/vitessce-grid-layout/layout-utils.d.ts +15 -0
- package/dist-tsc/vitessce-grid-layout/layout-utils.d.ts.map +1 -0
- package/dist-tsc/vitessce-grid-layout/layout-utils.js +61 -0
- package/dist-tsc/vitessce-grid-layout/layout-utils.test.d.ts +2 -0
- package/dist-tsc/vitessce-grid-layout/layout-utils.test.d.ts.map +1 -0
- package/dist-tsc/vitessce-grid-layout/layout-utils.test.js +148 -0
- package/dist-tsc/vitessce-grid-utils.d.ts +13 -0
- package/dist-tsc/vitessce-grid-utils.d.ts.map +1 -0
- package/dist-tsc/vitessce-grid-utils.js +141 -0
- package/package.json +23 -10
- package/src/CallbackPublisher.js +7 -11
- package/src/LoadingIndicator.js +1 -2
- package/src/TitleInfo.js +12 -85
- package/src/VitS.js +72 -50
- package/src/VitessceGrid.js +21 -13
- package/src/VitessceGrid.test.jsx +16 -7
- package/src/Warning.js +2 -2
- package/src/data/AbstractLoader.js +2 -25
- package/src/data/AbstractTwoStepLoader.js +1 -1
- package/src/data/index.js +3 -3
- package/src/data/loader-registry.js +22 -13
- package/src/data-hook-utils.js +4 -6
- package/src/data-hooks.js +4 -4
- package/src/errors/DataSourceFetchError.js +1 -1
- package/src/errors/DatasetNotFoundError.js +1 -1
- package/src/errors/LoaderNotFoundError.js +1 -1
- package/src/errors/LoaderValidationError.js +1 -1
- package/src/errors/index.js +5 -6
- package/src/hooks.js +70 -5
- package/src/index.js +21 -46
- package/src/schemas/config-1.0.16.schema.json +21 -1
- package/src/shared-mui/components.js +10 -8
- package/src/shared-mui/container.js +1 -1
- package/src/shared-mui/styles.js +5 -2
- package/src/shared-plot-options/CellColorEncodingOption.js +3 -4
- package/src/shared-plot-options/OptionSelect.js +2 -2
- package/src/shared-plot-options/OptionsContainer.js +2 -5
- package/src/shared-plot-options/index.js +4 -4
- package/src/shared-plot-options/styles.js +1 -1
- package/src/state/hooks.js +10 -3
- package/src/title-styles.js +73 -0
- package/src/view-config-utils.js +46 -98
- package/src/view-config-utils.test.jsx +222 -0
- package/src/vitessce-grid-layout/VitessceGridLayout.js +51 -30
- package/src/vitessce-grid-layout/VitessceGridLayout.test.jsx +17 -9
- package/src/vitessce-grid-layout/index.js +1 -1
- package/src/vitessce-grid-layout/layout-utils.js +1 -1
- package/src/vitessce-grid-layout/layout-utils.test.js +1 -1
- package/src/vitessce-grid-utils.js +27 -15
- package/dist/index.mjs +0 -84801
- package/src/component-registry.js +0 -21
- package/src/errors/OptionsValidationError.js +0 -25
- package/src/file-options-schemas-legacy.js +0 -139
- package/src/file-options-schemas-legacy.test.js +0 -138
- package/src/file-options-schemas.js +0 -327
- package/src/file-options-schemas.test.js +0 -26
- package/src/joint-file-types-legacy.js +0 -298
- package/src/joint-file-types-legacy.test.js +0 -412
- package/src/joint-file-types.js +0 -171
- package/src/joint-file-types.test.js +0 -144
- package/src/json-schemas.js +0 -9
- package/src/plugins.js +0 -186
- package/src/plugins.test.js +0 -42
- package/src/schemas/config-1.0.16.schema.test.js +0 -32
- package/src/schemas/schema.test-old.js +0 -49
- package/src/view-config-upgraders.js +0 -628
- package/src/view-config-utils.test.js +0 -95
- package/src/view-config-versions.js +0 -68
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { makeStyles } from '@material-ui/core';
|
|
2
|
+
|
|
3
|
+
export const useTitleStyles = makeStyles(theme => ({
|
|
4
|
+
title: {
|
|
5
|
+
color: theme.palette.primaryForeground,
|
|
6
|
+
overflowX: 'hidden',
|
|
7
|
+
display: 'flex',
|
|
8
|
+
flexDirection: 'row',
|
|
9
|
+
flexShrink: '0',
|
|
10
|
+
},
|
|
11
|
+
titleLeft: {
|
|
12
|
+
flexShrink: '1',
|
|
13
|
+
textOverflow: 'ellipsis',
|
|
14
|
+
whiteSpace: 'nowrap',
|
|
15
|
+
},
|
|
16
|
+
titleInfo: {
|
|
17
|
+
width: '100%',
|
|
18
|
+
textOverflow: 'ellipsis',
|
|
19
|
+
whiteSpace: 'nowrap',
|
|
20
|
+
overflow: 'hidden',
|
|
21
|
+
fontSize: '80% !important',
|
|
22
|
+
opacity: '.8',
|
|
23
|
+
padding: '0 4px',
|
|
24
|
+
justifyContent: 'center',
|
|
25
|
+
lineHeight: '25px !important',
|
|
26
|
+
flexShrink: '1',
|
|
27
|
+
textAlign: 'right !important',
|
|
28
|
+
},
|
|
29
|
+
titleButtons: {
|
|
30
|
+
display: 'flex',
|
|
31
|
+
flexDirection: 'row',
|
|
32
|
+
flexGrow: '1',
|
|
33
|
+
flexShrink: '0',
|
|
34
|
+
justifyContent: 'right',
|
|
35
|
+
'& div': {
|
|
36
|
+
display: 'inline-block',
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
card: {
|
|
40
|
+
border: `1px solid ${theme.palette.cardBorder}`,
|
|
41
|
+
flex: '1 1 auto',
|
|
42
|
+
minHeight: '1px',
|
|
43
|
+
padding: '12px',
|
|
44
|
+
marginTop: '8px',
|
|
45
|
+
marginBottom: '8px',
|
|
46
|
+
position: 'relative',
|
|
47
|
+
display: 'flex',
|
|
48
|
+
flexDirection: 'column',
|
|
49
|
+
minWidth: '0',
|
|
50
|
+
wordWrap: 'break-word',
|
|
51
|
+
backgroundClip: 'border-box',
|
|
52
|
+
borderRadius: '4px',
|
|
53
|
+
},
|
|
54
|
+
noScrollCard: {
|
|
55
|
+
backgroundColor: theme.palette.secondaryBackground,
|
|
56
|
+
color: theme.palette.secondaryForeground,
|
|
57
|
+
},
|
|
58
|
+
scrollCard: {
|
|
59
|
+
backgroundColor: theme.palette.primaryBackground,
|
|
60
|
+
color: theme.palette.primaryForeground,
|
|
61
|
+
'& a': {
|
|
62
|
+
color: theme.palette.primaryForegroundActive,
|
|
63
|
+
},
|
|
64
|
+
overflowY: 'auto',
|
|
65
|
+
},
|
|
66
|
+
spatialCard: {
|
|
67
|
+
backgroundColor: theme.palette.black,
|
|
68
|
+
color: theme.palette.white,
|
|
69
|
+
'& a': {
|
|
70
|
+
color: theme.palette.white,
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
}));
|
package/src/view-config-utils.js
CHANGED
|
@@ -1,20 +1,10 @@
|
|
|
1
1
|
/* eslint-disable no-plusplus */
|
|
2
2
|
/* eslint-disable camelcase */
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import { getNextScope } from '@vitessce/utils';
|
|
3
|
+
import { cloneDeep } from 'lodash-es';
|
|
4
|
+
import { fromEntries, getNextScope } from '@vitessce/utils';
|
|
6
5
|
import {
|
|
7
6
|
AUTO_INDEPENDENT_COORDINATION_TYPES,
|
|
8
7
|
} from '@vitessce/constants-internal';
|
|
9
|
-
import { getViewTypes } from './component-registry';
|
|
10
|
-
import {
|
|
11
|
-
getComponentCoordinationTypes,
|
|
12
|
-
getDefaultCoordinationValues,
|
|
13
|
-
getCoordinationTypes,
|
|
14
|
-
getFileTypes,
|
|
15
|
-
getJointFileTypes,
|
|
16
|
-
} from './plugins';
|
|
17
|
-
import { SCHEMA_HANDLERS } from './view-config-versions';
|
|
18
8
|
|
|
19
9
|
/**
|
|
20
10
|
* Get a list of all unique scope names for a
|
|
@@ -40,8 +30,10 @@ export function getExistingScopesForCoordinationType(config, coordinationType) {
|
|
|
40
30
|
* to set in the coordination space.
|
|
41
31
|
* @returns {object} The new view config.
|
|
42
32
|
*/
|
|
43
|
-
function coordinateComponentsTogether(config, coordinationType, scopeValue) {
|
|
44
|
-
const componentCoordinationTypes =
|
|
33
|
+
function coordinateComponentsTogether(config, coordinationType, scopeValue, viewTypes) {
|
|
34
|
+
const componentCoordinationTypes = fromEntries(
|
|
35
|
+
viewTypes.map(vt => ([vt.name, vt.coordinationTypes])),
|
|
36
|
+
);
|
|
45
37
|
const scopeName = getNextScope(getExistingScopesForCoordinationType(config, coordinationType));
|
|
46
38
|
const newConfig = {
|
|
47
39
|
...config,
|
|
@@ -82,8 +74,10 @@ function coordinateComponentsTogether(config, coordinationType, scopeValue) {
|
|
|
82
74
|
* to set in the coordination space.
|
|
83
75
|
* @returns {object} The new view config.
|
|
84
76
|
*/
|
|
85
|
-
function coordinateComponentsIndependent(config, coordinationType, scopeValue) {
|
|
86
|
-
const componentCoordinationTypes =
|
|
77
|
+
function coordinateComponentsIndependent(config, coordinationType, scopeValue, viewTypes) {
|
|
78
|
+
const componentCoordinationTypes = fromEntries(
|
|
79
|
+
viewTypes.map(vt => ([vt.name, vt.coordinationTypes])),
|
|
80
|
+
);
|
|
87
81
|
const newConfig = {
|
|
88
82
|
...config,
|
|
89
83
|
layout: [...config.layout],
|
|
@@ -120,13 +114,24 @@ function coordinateComponentsIndependent(config, coordinationType, scopeValue) {
|
|
|
120
114
|
return newConfig;
|
|
121
115
|
}
|
|
122
116
|
|
|
123
|
-
|
|
117
|
+
/**
|
|
118
|
+
* Perform initialization using initStrategy: "auto".
|
|
119
|
+
* @param {object} config The view config.
|
|
120
|
+
* @param {PluginCoordinationType[]} coordinationTypeObjs
|
|
121
|
+
* @param {PluginViewType[]} viewTypeObjs
|
|
122
|
+
* @returns {object} The config.
|
|
123
|
+
*/
|
|
124
|
+
function initializeAuto(config, coordinationTypeObjs, viewTypeObjs) {
|
|
124
125
|
let newConfig = config;
|
|
125
126
|
const { layout, datasets } = newConfig;
|
|
126
127
|
|
|
127
|
-
const componentCoordinationTypes =
|
|
128
|
-
|
|
129
|
-
|
|
128
|
+
const componentCoordinationTypes = fromEntries(
|
|
129
|
+
viewTypeObjs.map(vt => ([vt.name, vt.coordinationTypes])),
|
|
130
|
+
);
|
|
131
|
+
const defaultCoordinationValues = fromEntries(
|
|
132
|
+
coordinationTypeObjs.map(ct => ([ct.name, ct.defaultValue])),
|
|
133
|
+
);
|
|
134
|
+
const coordinationTypes = coordinationTypeObjs.map(ct => ct.name);
|
|
130
135
|
|
|
131
136
|
// For each coordination type, check whether it requires initialization.
|
|
132
137
|
coordinationTypes.forEach((coordinationType) => {
|
|
@@ -153,9 +158,13 @@ function initializeAuto(config) {
|
|
|
153
158
|
// a unique scope for every component ("independent")
|
|
154
159
|
// vs. the same scope for every component ("together").
|
|
155
160
|
if (AUTO_INDEPENDENT_COORDINATION_TYPES.includes(coordinationType)) {
|
|
156
|
-
newConfig = coordinateComponentsIndependent(
|
|
161
|
+
newConfig = coordinateComponentsIndependent(
|
|
162
|
+
newConfig, coordinationType, defaultValue, viewTypeObjs,
|
|
163
|
+
);
|
|
157
164
|
} else {
|
|
158
|
-
newConfig = coordinateComponentsTogether(
|
|
165
|
+
newConfig = coordinateComponentsTogether(
|
|
166
|
+
newConfig, coordinationType, defaultValue, viewTypeObjs,
|
|
167
|
+
);
|
|
159
168
|
}
|
|
160
169
|
}
|
|
161
170
|
});
|
|
@@ -163,35 +172,6 @@ function initializeAuto(config) {
|
|
|
163
172
|
return newConfig;
|
|
164
173
|
}
|
|
165
174
|
|
|
166
|
-
export function checkTypes(config) {
|
|
167
|
-
// Add a log message when there are additionalProperties in the coordination space that
|
|
168
|
-
// do not appear in the view config JSON schema,
|
|
169
|
-
// with a note that this indicates either a mistake or custom coordination type usage.
|
|
170
|
-
const coordinationTypesInConfig = Object.keys(config.coordinationSpace || {});
|
|
171
|
-
const allCoordinationTypes = getCoordinationTypes();
|
|
172
|
-
const unknownCoordinationTypes = difference(coordinationTypesInConfig, allCoordinationTypes);
|
|
173
|
-
if (unknownCoordinationTypes.length > 0) {
|
|
174
|
-
return [false, `The following coordination types are not recognized: [${unknownCoordinationTypes}].\nIf these are plugin coordination types, ensure that they have been properly registered.`];
|
|
175
|
-
}
|
|
176
|
-
// Add a log message when there are views in the layout that are neither
|
|
177
|
-
// core views nor registered plugin views.
|
|
178
|
-
const viewTypesInConfig = config.layout.map(c => c.component);
|
|
179
|
-
const allViewTypes = getViewTypes();
|
|
180
|
-
const unknownViewTypes = difference(viewTypesInConfig, allViewTypes);
|
|
181
|
-
if (unknownViewTypes.length > 0) {
|
|
182
|
-
return [false, `The following view types are not recognized: [${unknownViewTypes}].\nIf these are plugin view types, ensure that they have been properly registered.`];
|
|
183
|
-
}
|
|
184
|
-
// Add a log message when there are file definitions with neither
|
|
185
|
-
// core nor registered plugin file types.
|
|
186
|
-
const fileTypesInConfig = config.datasets.flatMap(d => d.files.map(f => f.fileType));
|
|
187
|
-
const allFileTypes = getFileTypes();
|
|
188
|
-
const unknownFileTypes = difference(fileTypesInConfig, allFileTypes);
|
|
189
|
-
if (unknownFileTypes.length > 0) {
|
|
190
|
-
return [false, `The following file types are not recognized: [${unknownFileTypes}].\nIf these are plugin file types, ensure that they have been properly registered.`];
|
|
191
|
-
}
|
|
192
|
-
return [true, 'All view types, coordination types, and file types that appear in the view config are recognized.'];
|
|
193
|
-
}
|
|
194
|
-
|
|
195
175
|
/**
|
|
196
176
|
* Assign unique ids for view definitions where
|
|
197
177
|
* they are missing a value for the uid property
|
|
@@ -200,7 +180,7 @@ export function checkTypes(config) {
|
|
|
200
180
|
* @returns The updated view config.
|
|
201
181
|
*/
|
|
202
182
|
function assignViewUids(config) {
|
|
203
|
-
const { layout } = config;
|
|
183
|
+
const { uid, layout } = config;
|
|
204
184
|
const usedIds = layout.map(view => view.uid);
|
|
205
185
|
layout.forEach((view, i) => {
|
|
206
186
|
// Assign uids for views where they are not present.
|
|
@@ -210,8 +190,10 @@ function assignViewUids(config) {
|
|
|
210
190
|
usedIds.push(nextUid);
|
|
211
191
|
}
|
|
212
192
|
});
|
|
193
|
+
const newUid = uid || getNextScope([]);
|
|
213
194
|
return {
|
|
214
195
|
...config,
|
|
196
|
+
uid: newUid,
|
|
215
197
|
layout,
|
|
216
198
|
};
|
|
217
199
|
}
|
|
@@ -224,8 +206,10 @@ function assignViewUids(config) {
|
|
|
224
206
|
* convenience file types.
|
|
225
207
|
* @returns The view config containing expanded minimal file types.
|
|
226
208
|
*/
|
|
227
|
-
function expandConvenienceFileDefs(config) {
|
|
228
|
-
const convenienceFileTypes =
|
|
209
|
+
function expandConvenienceFileDefs(config, jointFileTypes) {
|
|
210
|
+
const convenienceFileTypes = fromEntries(
|
|
211
|
+
jointFileTypes.map(ft => ([ft.name, ft.expandFunction])),
|
|
212
|
+
);
|
|
229
213
|
const { datasets: currDatasets } = config;
|
|
230
214
|
const datasets = cloneDeep(currDatasets);
|
|
231
215
|
currDatasets.forEach((dataset, i) => {
|
|
@@ -262,54 +246,18 @@ function expandConvenienceFileDefs(config) {
|
|
|
262
246
|
* Should be "stable": if run on the same view config twice, the return value the second
|
|
263
247
|
* time should be identical to the return value the first time.
|
|
264
248
|
* @param {object} config The view config prop.
|
|
249
|
+
* @param {PluginJointFileType[]} jointFileTypes
|
|
250
|
+
* @param {PluginCoordinationType[]} coordinationTypes
|
|
251
|
+
* @param {PluginViewType[]} viewTypes
|
|
265
252
|
* @returns The initialized view config.
|
|
266
253
|
*/
|
|
267
|
-
export function initialize(config) {
|
|
254
|
+
export function initialize(config, jointFileTypes, coordinationTypes, viewTypes) {
|
|
268
255
|
let newConfig = cloneDeep(config);
|
|
269
256
|
if (newConfig.initStrategy === 'auto') {
|
|
270
|
-
|
|
257
|
+
// TODO: pass coordination types with defaults
|
|
258
|
+
// TODO: pass view types with per-view coordination type lists
|
|
259
|
+
newConfig = initializeAuto(config, coordinationTypes, viewTypes);
|
|
271
260
|
}
|
|
272
|
-
newConfig = expandConvenienceFileDefs(newConfig);
|
|
261
|
+
newConfig = expandConvenienceFileDefs(newConfig, jointFileTypes);
|
|
273
262
|
return assignViewUids(newConfig);
|
|
274
263
|
}
|
|
275
|
-
|
|
276
|
-
export function upgradeAndValidate(oldConfig, onConfigUpgrade = null) {
|
|
277
|
-
// oldConfig object must have a `version` property.
|
|
278
|
-
let nextConfig = oldConfig;
|
|
279
|
-
let fromVersion;
|
|
280
|
-
let upgradeFunction; let
|
|
281
|
-
validateFunction;
|
|
282
|
-
|
|
283
|
-
do {
|
|
284
|
-
fromVersion = nextConfig.version;
|
|
285
|
-
|
|
286
|
-
if (!Object.keys(SCHEMA_HANDLERS).includes(fromVersion)) {
|
|
287
|
-
return [{
|
|
288
|
-
title: 'Config validation failed',
|
|
289
|
-
preformatted: 'Unknown config version.',
|
|
290
|
-
}, false];
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
[validateFunction, upgradeFunction] = SCHEMA_HANDLERS[fromVersion];
|
|
294
|
-
|
|
295
|
-
// Validate under the legacy schema before upgrading.
|
|
296
|
-
const validLegacy = validateFunction(nextConfig);
|
|
297
|
-
if (!validLegacy) {
|
|
298
|
-
const failureReason = JSON.stringify(validateFunction.errors, null, 2);
|
|
299
|
-
return [{
|
|
300
|
-
title: 'Config validation failed',
|
|
301
|
-
preformatted: failureReason,
|
|
302
|
-
}, false];
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
if (upgradeFunction) {
|
|
306
|
-
const prevConfig = nextConfig;
|
|
307
|
-
nextConfig = upgradeFunction(nextConfig);
|
|
308
|
-
if (onConfigUpgrade) {
|
|
309
|
-
onConfigUpgrade(prevConfig, nextConfig);
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
} while (upgradeFunction);
|
|
313
|
-
|
|
314
|
-
return [nextConfig, true];
|
|
315
|
-
}
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
/* eslint-disable camelcase */
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { z } from '@vitessce/schemas';
|
|
4
|
+
import { PluginViewType, PluginCoordinationType } from '@vitessce/plugins';
|
|
5
|
+
import {
|
|
6
|
+
getExistingScopesForCoordinationType,
|
|
7
|
+
initialize,
|
|
8
|
+
} from './view-config-utils.js';
|
|
9
|
+
|
|
10
|
+
function FakeComponent(props) {
|
|
11
|
+
const { text } = props;
|
|
12
|
+
return <span>{text}</span>;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const jointFileTypes = [];
|
|
16
|
+
const coordinationTypes = [
|
|
17
|
+
new PluginCoordinationType('dataset', null, z.string().nullable()),
|
|
18
|
+
new PluginCoordinationType('embeddingTargetX', 0, z.number()),
|
|
19
|
+
new PluginCoordinationType('embeddingTargetY', 0, z.number()),
|
|
20
|
+
new PluginCoordinationType('embeddingZoom', 3, z.number()),
|
|
21
|
+
new PluginCoordinationType('embeddingType', null, z.string().nullable()),
|
|
22
|
+
];
|
|
23
|
+
const viewTypes = [
|
|
24
|
+
new PluginViewType('description', FakeComponent, ['dataset']),
|
|
25
|
+
new PluginViewType('scatterplot', FakeComponent, ['dataset', 'embeddingType', 'embeddingZoom', 'embeddingTargetX', 'embeddingTargetY']),
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
describe('src/app/view-config-utils.js', () => {
|
|
29
|
+
describe('getExistingScopesForCoordinationType', () => {
|
|
30
|
+
it('gets all scope names for a particular coordination type', () => {
|
|
31
|
+
const config = {
|
|
32
|
+
coordinationSpace: {
|
|
33
|
+
dataset: {
|
|
34
|
+
A: 'my-dataset-1',
|
|
35
|
+
B: 'my-dataset-2',
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
layout: [
|
|
39
|
+
{
|
|
40
|
+
coordinationScopes: {
|
|
41
|
+
dataset: 'A',
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
coordinationScopes: {
|
|
46
|
+
dataset: 'C',
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
],
|
|
50
|
+
};
|
|
51
|
+
expect(getExistingScopesForCoordinationType(config, 'dataset')).toEqual(['A', 'B', 'C']);
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
describe('initialize', () => {
|
|
56
|
+
it('initializes coordination space and component coordination scopes when initStrategy is auto', () => {
|
|
57
|
+
const preInitializationConfig = {
|
|
58
|
+
version: '1.0.16',
|
|
59
|
+
name: 'My config name',
|
|
60
|
+
description: 'My config description',
|
|
61
|
+
initStrategy: 'auto',
|
|
62
|
+
coordinationSpace: {
|
|
63
|
+
embeddingTargetX: {
|
|
64
|
+
A: 0,
|
|
65
|
+
},
|
|
66
|
+
embeddingTargetY: {
|
|
67
|
+
A: 0,
|
|
68
|
+
},
|
|
69
|
+
embeddingType: {
|
|
70
|
+
't-SNE': 't-SNE',
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
datasets: [
|
|
74
|
+
{
|
|
75
|
+
files: [],
|
|
76
|
+
name: 'A',
|
|
77
|
+
uid: 'A',
|
|
78
|
+
},
|
|
79
|
+
],
|
|
80
|
+
layout: [
|
|
81
|
+
{
|
|
82
|
+
component: 'description',
|
|
83
|
+
coordinationScopes: {},
|
|
84
|
+
h: 2,
|
|
85
|
+
w: 3,
|
|
86
|
+
x: 9,
|
|
87
|
+
y: 0,
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
component: 'scatterplot',
|
|
91
|
+
coordinationScopes: {
|
|
92
|
+
embeddingTargetX: 'A',
|
|
93
|
+
embeddingTargetY: 'A',
|
|
94
|
+
embeddingType: 't-SNE',
|
|
95
|
+
},
|
|
96
|
+
h: 4,
|
|
97
|
+
w: 5,
|
|
98
|
+
x: 0,
|
|
99
|
+
y: 2,
|
|
100
|
+
},
|
|
101
|
+
],
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const initializedViewConfig = {
|
|
105
|
+
version: '1.0.16',
|
|
106
|
+
uid: 'A',
|
|
107
|
+
name: 'My config name',
|
|
108
|
+
description: 'My config description',
|
|
109
|
+
initStrategy: 'auto',
|
|
110
|
+
coordinationSpace: {
|
|
111
|
+
dataset: {
|
|
112
|
+
A: 'A',
|
|
113
|
+
},
|
|
114
|
+
embeddingTargetX: {
|
|
115
|
+
A: 0,
|
|
116
|
+
},
|
|
117
|
+
embeddingTargetY: {
|
|
118
|
+
A: 0,
|
|
119
|
+
},
|
|
120
|
+
embeddingType: {
|
|
121
|
+
't-SNE': 't-SNE',
|
|
122
|
+
},
|
|
123
|
+
embeddingZoom: {
|
|
124
|
+
A: 3,
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
datasets: [
|
|
128
|
+
{
|
|
129
|
+
files: [],
|
|
130
|
+
name: 'A',
|
|
131
|
+
uid: 'A',
|
|
132
|
+
},
|
|
133
|
+
],
|
|
134
|
+
layout: [
|
|
135
|
+
{
|
|
136
|
+
component: 'description',
|
|
137
|
+
coordinationScopes: {
|
|
138
|
+
dataset: 'A',
|
|
139
|
+
},
|
|
140
|
+
h: 2,
|
|
141
|
+
uid: 'A',
|
|
142
|
+
w: 3,
|
|
143
|
+
x: 9,
|
|
144
|
+
y: 0,
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
component: 'scatterplot',
|
|
148
|
+
coordinationScopes: {
|
|
149
|
+
dataset: 'A',
|
|
150
|
+
embeddingTargetX: 'A',
|
|
151
|
+
embeddingTargetY: 'A',
|
|
152
|
+
embeddingType: 't-SNE',
|
|
153
|
+
embeddingZoom: 'A',
|
|
154
|
+
},
|
|
155
|
+
h: 4,
|
|
156
|
+
uid: 'B',
|
|
157
|
+
w: 5,
|
|
158
|
+
x: 0,
|
|
159
|
+
y: 2,
|
|
160
|
+
},
|
|
161
|
+
],
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
expect(initialize(preInitializationConfig, jointFileTypes, coordinationTypes, viewTypes))
|
|
165
|
+
.toEqual(initializedViewConfig);
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
it('does not initialize when initStrategy is none', () => {
|
|
169
|
+
const preInitializationConfig = {
|
|
170
|
+
version: '1.0.16',
|
|
171
|
+
name: 'My config name',
|
|
172
|
+
description: 'My config description',
|
|
173
|
+
initStrategy: 'none', // initStrategy is none
|
|
174
|
+
coordinationSpace: {
|
|
175
|
+
embeddingTargetX: {
|
|
176
|
+
A: 0,
|
|
177
|
+
},
|
|
178
|
+
embeddingTargetY: {
|
|
179
|
+
A: 0,
|
|
180
|
+
},
|
|
181
|
+
embeddingType: {
|
|
182
|
+
't-SNE': 't-SNE',
|
|
183
|
+
},
|
|
184
|
+
},
|
|
185
|
+
datasets: [
|
|
186
|
+
{
|
|
187
|
+
files: [],
|
|
188
|
+
name: 'A',
|
|
189
|
+
uid: 'A',
|
|
190
|
+
},
|
|
191
|
+
],
|
|
192
|
+
layout: [
|
|
193
|
+
{
|
|
194
|
+
component: 'description',
|
|
195
|
+
coordinationScopes: {},
|
|
196
|
+
h: 2,
|
|
197
|
+
w: 3,
|
|
198
|
+
x: 9,
|
|
199
|
+
y: 0,
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
component: 'scatterplot',
|
|
203
|
+
coordinationScopes: {
|
|
204
|
+
embeddingTargetX: 'A',
|
|
205
|
+
embeddingTargetY: 'A',
|
|
206
|
+
embeddingType: 't-SNE',
|
|
207
|
+
},
|
|
208
|
+
h: 4,
|
|
209
|
+
w: 5,
|
|
210
|
+
x: 0,
|
|
211
|
+
y: 2,
|
|
212
|
+
},
|
|
213
|
+
],
|
|
214
|
+
};
|
|
215
|
+
expect(
|
|
216
|
+
initialize(
|
|
217
|
+
preInitializationConfig, jointFileTypes, coordinationTypes, viewTypes,
|
|
218
|
+
).coordinationSpace,
|
|
219
|
+
).toEqual(preInitializationConfig.coordinationSpace);
|
|
220
|
+
});
|
|
221
|
+
});
|
|
222
|
+
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import React, { useState } from 'react';
|
|
1
|
+
import React, { useState, useMemo, useCallback } from 'react';
|
|
2
2
|
import { Responsive, WidthProvider } from 'react-grid-layout-with-lodash';
|
|
3
|
-
import isEqual from 'lodash
|
|
4
|
-
import { getMaxRows, resolveLayout } from './layout-utils';
|
|
3
|
+
import { isEqual } from 'lodash-es';
|
|
4
|
+
import { getMaxRows, resolveLayout } from './layout-utils.js';
|
|
5
5
|
|
|
6
6
|
const ResponsiveGridLayout = WidthProvider(Responsive);
|
|
7
7
|
|
|
@@ -16,18 +16,31 @@ class ResponsiveHeightGridLayout extends ResponsiveGridLayout {
|
|
|
16
16
|
export function VitessceGridLayout(props) {
|
|
17
17
|
const {
|
|
18
18
|
layout,
|
|
19
|
-
|
|
19
|
+
viewTypes, padding, margin: marginProp, draggableHandle: draggableHandleClass,
|
|
20
20
|
onResize, onResizeStop, rowHeight, theme, height,
|
|
21
21
|
onRemoveComponent, onLayoutChange: onLayoutChangeProp,
|
|
22
22
|
isBounded,
|
|
23
23
|
} = props;
|
|
24
24
|
|
|
25
|
+
const getComponent = useCallback((viewType) => {
|
|
26
|
+
if (Array.isArray(viewTypes)) {
|
|
27
|
+
const matchingViewType = viewTypes.find(v => v.name === viewType);
|
|
28
|
+
if (matchingViewType) {
|
|
29
|
+
return matchingViewType.component;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return () => null;
|
|
33
|
+
}, [viewTypes]);
|
|
34
|
+
|
|
25
35
|
const draggableHandle = `.${draggableHandleClass}`;
|
|
26
36
|
|
|
27
37
|
// If layout changes, update grid components.
|
|
28
38
|
const {
|
|
29
39
|
cols: gridCols, layouts: gridLayouts, breakpoints: gridBreakpoints, components: gridComponents,
|
|
30
|
-
} = resolveLayout(layout);
|
|
40
|
+
} = useMemo(() => resolveLayout(layout), [layout]);
|
|
41
|
+
|
|
42
|
+
const containerPadding = useMemo(() => ([padding, padding]), [padding]);
|
|
43
|
+
const margin = useMemo(() => ([marginProp, marginProp]), [marginProp]);
|
|
31
44
|
|
|
32
45
|
const maxRows = getMaxRows(gridLayouts);
|
|
33
46
|
|
|
@@ -53,16 +66,16 @@ export function VitessceGridLayout(props) {
|
|
|
53
66
|
//
|
|
54
67
|
// Additionally, react-grid-layout doesn't revert if you don't save a new/changed layouts. If you
|
|
55
68
|
// wish to do this, first you have to save the new layouts and render the grid with it, and then
|
|
56
|
-
// you can revert to the original layouts. Thus, we need one state for
|
|
69
|
+
// you can revert to the original layouts. Thus, we need one state for a temporary grid layout,
|
|
57
70
|
// which gets called on every onLayoutChange. If the grid height is still valid, we then call
|
|
58
|
-
// onValidLayoutChange, otherwise we
|
|
71
|
+
// onValidLayoutChange, otherwise we call onValidLayoutChange with lastValidGridLayouts.
|
|
59
72
|
//
|
|
60
73
|
// See the following GitHub issue for more information.
|
|
61
74
|
// https://github.com/react-grid-layout/react-grid-layout/issues/1104#issuecomment-827785217
|
|
62
|
-
const [
|
|
75
|
+
const [tempGridLayouts, setTempGridLayouts] = useState(null);
|
|
63
76
|
const [lastValidGridLayouts, setLastValidGridLayouts] = useState(gridLayouts);
|
|
64
77
|
|
|
65
|
-
const onValidLayoutChange = (newLayout) => {
|
|
78
|
+
const onValidLayoutChange = useCallback((newLayout) => {
|
|
66
79
|
if (newLayout.length === Object.entries(gridComponents).length) {
|
|
67
80
|
const newComponentProps = {};
|
|
68
81
|
newLayout.forEach((nextC) => {
|
|
@@ -84,24 +97,31 @@ export function VitessceGridLayout(props) {
|
|
|
84
97
|
onLayoutChangeProp(newComponentProps);
|
|
85
98
|
}
|
|
86
99
|
}
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
const onLayoutChange = (newLayout, allLayouts) => {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
100
|
+
}, [gridComponents, onLayoutChangeProp]);
|
|
101
|
+
|
|
102
|
+
const onLayoutChange = useCallback((newLayout, allLayouts) => {
|
|
103
|
+
// We first need to set the new layout to the potentially-invalid allLayouts
|
|
104
|
+
// (see comments above about react-grid-layout limitations).
|
|
105
|
+
setTempGridLayouts(allLayouts);
|
|
106
|
+
// Then we wait 50ms and validate/set the new layout.
|
|
107
|
+
setTimeout(() => {
|
|
108
|
+
if (!isBounded || getMaxRows({ ID: newLayout }) <= maxRows) {
|
|
109
|
+
// Good, new layout was valid with respect to isBounded, so set in parent.
|
|
110
|
+
onValidLayoutChange(newLayout);
|
|
111
|
+
setLastValidGridLayouts(allLayouts);
|
|
112
|
+
} else {
|
|
113
|
+
// Bad, new layout was not valid with respect to isBounded.
|
|
114
|
+
onValidLayoutChange(lastValidGridLayouts);
|
|
115
|
+
}
|
|
116
|
+
setTempGridLayouts(null);
|
|
117
|
+
}, 50);
|
|
118
|
+
}, [isBounded, lastValidGridLayouts, maxRows, onValidLayoutChange]);
|
|
102
119
|
|
|
120
|
+
const saveCurrentLayouts = useCallback(() => {
|
|
121
|
+
setLastValidGridLayouts(gridLayouts);
|
|
122
|
+
}, [gridLayouts]);
|
|
103
123
|
|
|
104
|
-
const layoutChildren = Object.values(gridComponents).map((v) => {
|
|
124
|
+
const layoutChildren = useMemo(() => Object.values(gridComponents).map((v) => {
|
|
105
125
|
const Component = getComponent(v.component);
|
|
106
126
|
|
|
107
127
|
const removeGridComponent = () => {
|
|
@@ -120,14 +140,15 @@ export function VitessceGridLayout(props) {
|
|
|
120
140
|
/>
|
|
121
141
|
</div>
|
|
122
142
|
);
|
|
123
|
-
});
|
|
124
|
-
|
|
143
|
+
}), [gridComponents, getComponent, onRemoveComponent, theme]);
|
|
144
|
+
|
|
145
|
+
return (gridLayouts && gridComponents && gridBreakpoints && gridCols) && (
|
|
125
146
|
<>
|
|
126
147
|
{style}
|
|
127
148
|
<ResponsiveHeightGridLayout
|
|
128
149
|
className="layout"
|
|
129
150
|
cols={gridCols}
|
|
130
|
-
layouts={
|
|
151
|
+
layouts={tempGridLayouts || gridLayouts}
|
|
131
152
|
breakpoints={gridBreakpoints}
|
|
132
153
|
height={height}
|
|
133
154
|
rowHeight={
|
|
@@ -136,8 +157,8 @@ export function VitessceGridLayout(props) {
|
|
|
136
157
|
(window.innerHeight - 2 * padding - (maxRows - 1) * margin)
|
|
137
158
|
/ maxRows
|
|
138
159
|
)}
|
|
139
|
-
containerPadding={
|
|
140
|
-
margin={
|
|
160
|
+
containerPadding={containerPadding}
|
|
161
|
+
margin={margin}
|
|
141
162
|
draggableHandle={draggableHandle}
|
|
142
163
|
onLayoutChange={onLayoutChange}
|
|
143
164
|
isBounded={isBounded}
|