@vitessce/vit-s 3.3.1 → 3.3.3
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 +983 -220
- package/dist-tsc/TitleInfo.d.ts.map +1 -1
- package/dist-tsc/TitleInfo.js +7 -5
- package/dist-tsc/VitS.d.ts.map +1 -1
- package/dist-tsc/VitS.js +1 -1
- package/dist-tsc/VitessceGrid.d.ts.map +1 -1
- package/dist-tsc/VitessceGrid.js +2 -2
- package/dist-tsc/data-hook-utils.d.ts +1 -1
- package/dist-tsc/data-hook-utils.d.ts.map +1 -1
- package/dist-tsc/data-hook-utils.js +14 -7
- package/dist-tsc/data-hooks-multilevel-utils.d.ts.map +1 -1
- package/dist-tsc/data-hooks-multilevel-utils.js +5 -3
- package/dist-tsc/data-hooks-multilevel.d.ts.map +1 -1
- package/dist-tsc/data-hooks-multilevel.js +5 -2
- package/dist-tsc/data-hooks.d.ts +4 -4
- package/dist-tsc/data-hooks.d.ts.map +1 -1
- package/dist-tsc/data-hooks.js +9 -9
- package/dist-tsc/index.d.ts +1 -1
- package/dist-tsc/index.js +1 -1
- package/dist-tsc/state/hooks.d.ts +7 -0
- package/dist-tsc/state/hooks.d.ts.map +1 -1
- package/dist-tsc/state/hooks.js +122 -3
- package/dist-tsc/state/spatial-reducers.js +1 -1
- package/dist-tsc/vitessce-grid-utils.js +1 -1
- package/package.json +6 -5
- package/src/TitleInfo.js +18 -11
- package/src/VitS.js +1 -0
- package/src/VitessceGrid.js +2 -0
- package/src/data-hook-utils.js +24 -10
- package/src/data-hooks-multilevel-utils.js +5 -3
- package/src/data-hooks-multilevel.js +5 -2
- package/src/data-hooks.js +9 -5
- package/src/index.js +1 -0
- package/src/state/hooks.js +125 -3
- package/src/state/spatial-reducers.js +1 -1
- package/src/vitessce-grid-utils.js +1 -1
package/src/TitleInfo.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useState } from 'react';
|
|
1
|
+
import React, { useState, useMemo } from 'react';
|
|
2
2
|
import clsx from 'clsx';
|
|
3
3
|
import { makeStyles, MenuItem, IconButton, Link } from '@material-ui/core';
|
|
4
4
|
import {
|
|
@@ -57,11 +57,13 @@ function PlotOptions(props) {
|
|
|
57
57
|
const { options } = props;
|
|
58
58
|
const [open, setOpen] = useState(false);
|
|
59
59
|
const classes = useStyles();
|
|
60
|
+
|
|
61
|
+
const buttonIcon = useMemo(() => (<SettingsIconWithArrow open={open} />), [open]);
|
|
60
62
|
return (options ? (
|
|
61
63
|
<PopperMenu
|
|
62
64
|
open={open}
|
|
63
65
|
setOpen={setOpen}
|
|
64
|
-
buttonIcon={
|
|
66
|
+
buttonIcon={buttonIcon}
|
|
65
67
|
buttonClassName={classes.iconButton}
|
|
66
68
|
placement="bottom-end"
|
|
67
69
|
aria-label="Open plot options menu"
|
|
@@ -84,17 +86,18 @@ function DownloadOptions(props) {
|
|
|
84
86
|
const { urls } = props;
|
|
85
87
|
const [open, setOpen] = useState(false);
|
|
86
88
|
const classes = useStyles();
|
|
89
|
+
const buttonIcon = useMemo(() => (<CloudDownloadIconWithArrow open={open} />), [open]);
|
|
87
90
|
return (urls && urls.length ? (
|
|
88
91
|
<PopperMenu
|
|
89
92
|
open={open}
|
|
90
93
|
setOpen={setOpen}
|
|
91
|
-
buttonIcon={
|
|
94
|
+
buttonIcon={buttonIcon}
|
|
92
95
|
buttonClassName={classes.iconButton}
|
|
93
96
|
placement="bottom-end"
|
|
94
97
|
aria-label="Open download options menu"
|
|
95
98
|
>
|
|
96
99
|
{urls.map(({ url, name }) => (
|
|
97
|
-
<MenuItem dense key={`${url}_${name}`}
|
|
100
|
+
<MenuItem dense key={`${url}_${name}`} aria-label={`Click to download ${name}`}>
|
|
98
101
|
<Link underline="always" href={url} target="_blank" rel="noopener" className={classes.downloadLink}>
|
|
99
102
|
Download {name}
|
|
100
103
|
</Link>
|
|
@@ -123,7 +126,7 @@ function ClosePaneButton(props) {
|
|
|
123
126
|
export function TitleInfo(props) {
|
|
124
127
|
const {
|
|
125
128
|
title, info, children, isScroll, isSpatial, removeGridComponent, urls,
|
|
126
|
-
isReady, options,
|
|
129
|
+
isReady, options, closeButtonVisible = true, downloadButtonVisible = true,
|
|
127
130
|
} = props;
|
|
128
131
|
|
|
129
132
|
const classes = useTitleStyles();
|
|
@@ -142,12 +145,16 @@ export function TitleInfo(props) {
|
|
|
142
145
|
<PlotOptions
|
|
143
146
|
options={options}
|
|
144
147
|
/>
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
148
|
+
{downloadButtonVisible ? (
|
|
149
|
+
<DownloadOptions
|
|
150
|
+
urls={urls}
|
|
151
|
+
/>
|
|
152
|
+
) : null}
|
|
153
|
+
{closeButtonVisible ? (
|
|
154
|
+
<ClosePaneButton
|
|
155
|
+
removeGridComponent={removeGridComponent}
|
|
156
|
+
/>
|
|
157
|
+
) : null}
|
|
151
158
|
</div>
|
|
152
159
|
</div>
|
|
153
160
|
<div
|
package/src/VitS.js
CHANGED
package/src/VitessceGrid.js
CHANGED
|
@@ -50,6 +50,7 @@ export default function VitessceGrid(props) {
|
|
|
50
50
|
viewTypes,
|
|
51
51
|
fileTypes,
|
|
52
52
|
coordinationTypes,
|
|
53
|
+
stores,
|
|
53
54
|
} = props;
|
|
54
55
|
|
|
55
56
|
const [rowHeight, containerRef] = useRowHeight(config, initialRowHeight, height, margin, padding);
|
|
@@ -93,6 +94,7 @@ export default function VitessceGrid(props) {
|
|
|
93
94
|
config.description,
|
|
94
95
|
fileTypes,
|
|
95
96
|
coordinationTypes,
|
|
97
|
+
stores,
|
|
96
98
|
);
|
|
97
99
|
newConfig = config;
|
|
98
100
|
}
|
package/src/data-hook-utils.js
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { useEffect, useMemo } from 'react';
|
|
2
2
|
import { useQuery, useQueries } from '@tanstack/react-query';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
capitalize,
|
|
5
|
+
fromEntries,
|
|
6
|
+
getInitialCoordinationScopePrefix,
|
|
7
|
+
} from '@vitessce/utils';
|
|
4
8
|
import { STATUS } from '@vitessce/constants-internal';
|
|
5
9
|
import {
|
|
6
10
|
getMatchingLoader,
|
|
@@ -66,7 +70,7 @@ export async function dataQueryFn(ctx) {
|
|
|
66
70
|
const { data, url, coordinationValues } = payload;
|
|
67
71
|
// Status: success
|
|
68
72
|
// Array of objects like { url, name }.
|
|
69
|
-
const urls = Array.isArray(url) ? url : [{ url, name: dataType }];
|
|
73
|
+
const urls = (Array.isArray(url) ? url : [{ url, name: dataType }]).filter(d => d.url);
|
|
70
74
|
return { data, coordinationValues, urls };
|
|
71
75
|
}
|
|
72
76
|
// No loader was found.
|
|
@@ -169,6 +173,7 @@ export function useDataType(
|
|
|
169
173
|
export function useDataTypeMulti(
|
|
170
174
|
dataType, loaders, dataset, isRequired,
|
|
171
175
|
coordinationSetters, initialCoordinationValues, matchOnObj,
|
|
176
|
+
mergeCoordination, viewUid,
|
|
172
177
|
) {
|
|
173
178
|
const placeholderObject = useMemo(() => ({}), []);
|
|
174
179
|
const setWarning = useSetWarning();
|
|
@@ -200,14 +205,23 @@ export function useDataTypeMulti(
|
|
|
200
205
|
|
|
201
206
|
useEffect(() => {
|
|
202
207
|
dataQueries
|
|
203
|
-
.
|
|
204
|
-
.
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
208
|
+
.filter(q => Boolean(q.data?.coordinationValues))
|
|
209
|
+
.forEach((q) => {
|
|
210
|
+
const { coordinationValues } = q.data;
|
|
211
|
+
if (mergeCoordination) {
|
|
212
|
+
mergeCoordination(
|
|
213
|
+
coordinationValues,
|
|
214
|
+
// Auto-generate based on the dataset and data type.
|
|
215
|
+
getInitialCoordinationScopePrefix(dataset, dataType),
|
|
216
|
+
viewUid,
|
|
217
|
+
);
|
|
218
|
+
} else {
|
|
219
|
+
initCoordinationSpace(
|
|
220
|
+
coordinationValues,
|
|
221
|
+
coordinationSetters,
|
|
222
|
+
initialCoordinationValues,
|
|
223
|
+
);
|
|
224
|
+
}
|
|
211
225
|
});
|
|
212
226
|
// Deliberate dependency omissions: use indirect dependencies for efficiency.
|
|
213
227
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
@@ -388,7 +388,7 @@ export function useFeatureSelectionMultiLevel(
|
|
|
388
388
|
// (i.e., a single number, despite possibly different numbers of queries).
|
|
389
389
|
// Reference: https://github.com/TanStack/query/issues/3049#issuecomment-1253201068
|
|
390
390
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
391
|
-
}, [featureQueries.reduce((a, h) => a + h.dataUpdatedAt, 0)]);
|
|
391
|
+
}, [featureQueries.reduce((a, h) => a + h.dataUpdatedAt, 0), queryKeyScopeTuples]);
|
|
392
392
|
|
|
393
393
|
return [geneData, loadedGeneName, extents, normData, dataStatus];
|
|
394
394
|
}
|
|
@@ -479,8 +479,10 @@ export function useObsFeatureMatrixIndicesMultiLevel(
|
|
|
479
479
|
// We use .reduce to ensure the number of dependencies is stable
|
|
480
480
|
// (i.e., a single number, despite possibly different numbers of queries).
|
|
481
481
|
// Reference: https://github.com/TanStack/query/issues/3049#issuecomment-1253201068
|
|
482
|
+
// We also want to re-compute if any of the keys within the matchOnObj change,
|
|
483
|
+
// so we also use queryKeyScopeTuples as a dependency.
|
|
482
484
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
483
|
-
}, [indicesQueries.reduce((a, h) => a + h.dataUpdatedAt, 0)]);
|
|
485
|
+
}, [indicesQueries.reduce((a, h) => a + h.dataUpdatedAt, 0), queryKeyScopeTuples]);
|
|
484
486
|
|
|
485
487
|
return [indicesData, dataStatus];
|
|
486
488
|
}
|
|
@@ -535,7 +537,7 @@ function useDataTypeMultiLevel(
|
|
|
535
537
|
// (i.e., a single number, despite possibly different numbers of queries).
|
|
536
538
|
// Reference: https://github.com/TanStack/query/issues/3049#issuecomment-1253201068
|
|
537
539
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
538
|
-
}, [locationsQueries.reduce((a, h) => a + h.dataUpdatedAt, 0)]);
|
|
540
|
+
}, [locationsQueries.reduce((a, h) => a + h.dataUpdatedAt, 0), queryKeyScopeTuples]);
|
|
539
541
|
|
|
540
542
|
return [locationsData, dataStatus];
|
|
541
543
|
}
|
|
@@ -42,6 +42,8 @@ export function useSegmentationMultiFeatureSelection(
|
|
|
42
42
|
// use coordinationScopes and coordinationScopesBy which are
|
|
43
43
|
// indirect dependencies here.
|
|
44
44
|
[coordinationScopes, coordinationScopesBy]);
|
|
45
|
+
const useMemoDependency = Object.values(featureSelectionCoordination[0] || {})
|
|
46
|
+
.flatMap(layerVal => Object.values(layerVal).map(cVal => cVal.featureSelection));
|
|
45
47
|
const selections = useMemo(() => fromEntries(Object.entries(featureSelectionCoordination[0])
|
|
46
48
|
.map(([layerScope, layerVal]) => ([
|
|
47
49
|
layerScope,
|
|
@@ -52,8 +54,9 @@ export function useSegmentationMultiFeatureSelection(
|
|
|
52
54
|
]))),
|
|
53
55
|
// Need to execute this more frequently, whenever the featureSelections update.
|
|
54
56
|
[coordinationScopes, coordinationScopesBy,
|
|
55
|
-
|
|
56
|
-
|
|
57
|
+
// We need to ensure there are always the same number of
|
|
58
|
+
// entries in the full dependency array.
|
|
59
|
+
JSON.stringify(useMemoDependency.length > 0 ? useMemoDependency : [null]),
|
|
57
60
|
]);
|
|
58
61
|
const [
|
|
59
62
|
featureData, loadedSelections, extents, normData, featureStatus,
|
package/src/data-hooks.js
CHANGED
|
@@ -334,7 +334,7 @@ export function useObsFeatureMatrixIndices(
|
|
|
334
334
|
obsIndex: payloadData.rows,
|
|
335
335
|
featureIndex: payloadData.cols,
|
|
336
336
|
},
|
|
337
|
-
urls: [{ url, name: DataType.OBS_FEATURE_MATRIX }],
|
|
337
|
+
urls: (url ? [{ url, name: DataType.OBS_FEATURE_MATRIX }] : null),
|
|
338
338
|
};
|
|
339
339
|
}
|
|
340
340
|
// No loadAttrs function.
|
|
@@ -377,6 +377,7 @@ export function useObsFeatureMatrixIndices(
|
|
|
377
377
|
|
|
378
378
|
export function useMultiObsPoints(
|
|
379
379
|
coordinationScopes, coordinationScopesBy, loaders, dataset,
|
|
380
|
+
mergeCoordination, viewUid,
|
|
380
381
|
) {
|
|
381
382
|
const obsTypeCoordination = useComplexCoordination(
|
|
382
383
|
[
|
|
@@ -394,13 +395,14 @@ export function useMultiObsPoints(
|
|
|
394
395
|
const [obsPointsData, obsPointsDataStatus, obsPointsUrls] = useDataTypeMulti(
|
|
395
396
|
DataType.OBS_POINTS, loaders, dataset,
|
|
396
397
|
false, {}, {},
|
|
397
|
-
matchOnObj,
|
|
398
|
+
matchOnObj, mergeCoordination, viewUid,
|
|
398
399
|
);
|
|
399
400
|
return [obsPointsData, obsPointsDataStatus, obsPointsUrls];
|
|
400
401
|
}
|
|
401
402
|
|
|
402
403
|
export function useMultiObsSpots(
|
|
403
404
|
coordinationScopes, coordinationScopesBy, loaders, dataset,
|
|
405
|
+
mergeCoordination, viewUid,
|
|
404
406
|
) {
|
|
405
407
|
const obsTypeCoordination = useComplexCoordination(
|
|
406
408
|
[
|
|
@@ -418,7 +420,7 @@ export function useMultiObsSpots(
|
|
|
418
420
|
const [obsSpotsData, obsSpotsDataStatus, obsSpotsUrls] = useDataTypeMulti(
|
|
419
421
|
DataType.OBS_SPOTS, loaders, dataset,
|
|
420
422
|
false, {}, {},
|
|
421
|
-
matchOnObj,
|
|
423
|
+
matchOnObj, mergeCoordination, viewUid,
|
|
422
424
|
);
|
|
423
425
|
return [obsSpotsData, obsSpotsDataStatus, obsSpotsUrls];
|
|
424
426
|
}
|
|
@@ -470,6 +472,7 @@ export function useMultiObsLabels(
|
|
|
470
472
|
|
|
471
473
|
export function useMultiObsSegmentations(
|
|
472
474
|
coordinationScopes, coordinationScopesBy, loaders, dataset,
|
|
475
|
+
mergeCoordination, viewUid,
|
|
473
476
|
) {
|
|
474
477
|
const imageCoordination = useComplexCoordination(
|
|
475
478
|
[
|
|
@@ -491,13 +494,14 @@ export function useMultiObsSegmentations(
|
|
|
491
494
|
] = useDataTypeMulti(
|
|
492
495
|
DataType.OBS_SEGMENTATIONS, loaders, dataset,
|
|
493
496
|
false, {}, {},
|
|
494
|
-
matchOnObj,
|
|
497
|
+
matchOnObj, mergeCoordination, viewUid,
|
|
495
498
|
);
|
|
496
499
|
return [obsSegmentationsData, obsSegmentationsDataStatus, obsSegmentationsUrls];
|
|
497
500
|
}
|
|
498
501
|
|
|
499
502
|
export function useMultiImages(
|
|
500
503
|
coordinationScopes, coordinationScopesBy, loaders, dataset,
|
|
504
|
+
mergeCoordination, viewUid,
|
|
501
505
|
) {
|
|
502
506
|
// TODO: delegate the generation of matchOnObj to a different hoook and pass as a parameter?
|
|
503
507
|
// (in all of the useMulti data hooks)?
|
|
@@ -517,7 +521,7 @@ export function useMultiImages(
|
|
|
517
521
|
const [imageData, imageDataStatus, imageUrls] = useDataTypeMulti(
|
|
518
522
|
DataType.IMAGE, loaders, dataset,
|
|
519
523
|
false, {}, {},
|
|
520
|
-
matchOnObj,
|
|
524
|
+
matchOnObj, mergeCoordination, viewUid,
|
|
521
525
|
);
|
|
522
526
|
return [imageData, imageDataStatus, imageUrls];
|
|
523
527
|
}
|
package/src/index.js
CHANGED
package/src/state/hooks.js
CHANGED
|
@@ -4,9 +4,10 @@ import { useRef, useCallback, useMemo } from 'react';
|
|
|
4
4
|
import create from 'zustand';
|
|
5
5
|
import createContext from 'zustand/context';
|
|
6
6
|
import shallow from 'zustand/shallow';
|
|
7
|
-
import { isMatch,
|
|
7
|
+
import { isMatch, cloneDeep } from 'lodash-es';
|
|
8
8
|
import { CoordinationType } from '@vitessce/constants-internal';
|
|
9
9
|
import { fromEntries, capitalize } from '@vitessce/utils';
|
|
10
|
+
import { getCoordinationSpaceAndScopes } from '@vitessce/config';
|
|
10
11
|
import {
|
|
11
12
|
removeImageChannelInMetaCoordinationScopesHelper,
|
|
12
13
|
addImageChannelInMetaCoordinationScopesHelper,
|
|
@@ -52,7 +53,15 @@ export function getScopes(coordinationScopes, metaSpace) {
|
|
|
52
53
|
metaScopesArr.forEach((metaScope) => {
|
|
53
54
|
// Merge the original coordinationScopes with the matching meta-coordinationScopes
|
|
54
55
|
// from the coordinationSpace.
|
|
55
|
-
|
|
56
|
+
let o1 = result;
|
|
57
|
+
const o2 = metaSpace[metaScope] || {};
|
|
58
|
+
Object.entries(o2).forEach(([cType, cScope]) => {
|
|
59
|
+
o1 = {
|
|
60
|
+
...o1,
|
|
61
|
+
[cType]: cScope,
|
|
62
|
+
};
|
|
63
|
+
});
|
|
64
|
+
result = o1;
|
|
56
65
|
});
|
|
57
66
|
}
|
|
58
67
|
}
|
|
@@ -80,7 +89,29 @@ export function getScopesBy(coordinationScopes, coordinationScopesBy, metaSpaceB
|
|
|
80
89
|
metaScopesArr.forEach((metaScope) => {
|
|
81
90
|
// Merge the original coordinationScopesBy with the matching meta-coordinationScopesBy
|
|
82
91
|
// from the coordinationSpace.
|
|
83
|
-
|
|
92
|
+
let o1 = result;
|
|
93
|
+
const o2 = metaSpaceBy[metaScope] || {};
|
|
94
|
+
// Cannot simply use lodash merge(o1, o2)
|
|
95
|
+
// because we do not want to merge (objects/arrays) at the leaf
|
|
96
|
+
// (i.e., secondaryScopeVal) level.
|
|
97
|
+
// We want the values in o2 to take precedence over the values in o1.
|
|
98
|
+
Object.entries(o2).forEach(([primaryType, primaryObj]) => {
|
|
99
|
+
Object.entries(primaryObj).forEach(([secondaryType, secondaryObj]) => {
|
|
100
|
+
Object.entries(secondaryObj).forEach(([primaryScope, secondaryScopeVal]) => {
|
|
101
|
+
o1 = {
|
|
102
|
+
...o1,
|
|
103
|
+
[primaryType]: {
|
|
104
|
+
...(o1?.[primaryType] || {}),
|
|
105
|
+
[secondaryType]: {
|
|
106
|
+
...(o1?.[primaryType]?.[secondaryType] || {}),
|
|
107
|
+
[primaryScope]: secondaryScopeVal,
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
};
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
result = o1;
|
|
84
115
|
});
|
|
85
116
|
}
|
|
86
117
|
}
|
|
@@ -173,6 +204,87 @@ export const createViewConfigStore = (initialLoaders, initialConfig) => create(s
|
|
|
173
204
|
},
|
|
174
205
|
};
|
|
175
206
|
}),
|
|
207
|
+
mergeCoordination: (newCoordinationValues, scopePrefix, viewUid) => set((state) => {
|
|
208
|
+
const { coordinationSpace, layout } = state.viewConfig;
|
|
209
|
+
const {
|
|
210
|
+
coordinationSpace: newCoordinationSpace,
|
|
211
|
+
coordinationScopes,
|
|
212
|
+
} = getCoordinationSpaceAndScopes(newCoordinationValues, scopePrefix);
|
|
213
|
+
// Merge coordination objects in coordination space
|
|
214
|
+
Object.entries(newCoordinationSpace).forEach(([coordinationType, coordinationObj]) => {
|
|
215
|
+
if (coordinationType === CoordinationType.META_COORDINATION_SCOPES) {
|
|
216
|
+
// Perform an extra level of merging for meta-coordination scopes.
|
|
217
|
+
Object.entries(coordinationObj).forEach(([coordinationScope, coordinationValue]) => {
|
|
218
|
+
coordinationSpace[coordinationType] = {
|
|
219
|
+
...coordinationSpace[coordinationType],
|
|
220
|
+
[coordinationScope]: {
|
|
221
|
+
...coordinationValue,
|
|
222
|
+
...(coordinationSpace[coordinationType]?.[coordinationScope] || {}),
|
|
223
|
+
},
|
|
224
|
+
};
|
|
225
|
+
});
|
|
226
|
+
} else if (coordinationType === CoordinationType.META_COORDINATION_SCOPES_BY) {
|
|
227
|
+
// Perform two extra levels of merging for meta-coordination scopesBy.
|
|
228
|
+
Object.entries(coordinationObj).forEach(([coordinationScope, coordinationValue]) => {
|
|
229
|
+
Object.entries(coordinationValue).forEach(([primaryType, primaryObj]) => {
|
|
230
|
+
Object.entries(primaryObj).forEach(([secondaryType, secondaryObj]) => {
|
|
231
|
+
coordinationSpace[coordinationType] = {
|
|
232
|
+
...coordinationSpace[coordinationType],
|
|
233
|
+
[coordinationScope]: {
|
|
234
|
+
...(coordinationSpace[coordinationType]?.[coordinationScope] || {}),
|
|
235
|
+
[primaryType]: {
|
|
236
|
+
...(coordinationSpace[coordinationType]?.[coordinationScope]?.[primaryType] || {}),
|
|
237
|
+
[secondaryType]: {
|
|
238
|
+
...secondaryObj,
|
|
239
|
+
...(coordinationSpace[coordinationType]?.[coordinationScope]?.[primaryType]?.[secondaryType] || {}),
|
|
240
|
+
},
|
|
241
|
+
},
|
|
242
|
+
},
|
|
243
|
+
};
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
});
|
|
247
|
+
} else {
|
|
248
|
+
coordinationSpace[coordinationType] = {
|
|
249
|
+
...coordinationObj,
|
|
250
|
+
// Existing coordination values should be preserved,
|
|
251
|
+
// so that user-defined values take precedence over auto-initialization values.
|
|
252
|
+
...(coordinationSpace[coordinationType] || {}),
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
const newViewConfig = {
|
|
258
|
+
...state.viewConfig,
|
|
259
|
+
coordinationSpace: {
|
|
260
|
+
...coordinationSpace,
|
|
261
|
+
},
|
|
262
|
+
layout: layout.map((viewObj) => {
|
|
263
|
+
if (viewObj.uid === viewUid) {
|
|
264
|
+
// Merge coordination scopes for views
|
|
265
|
+
return {
|
|
266
|
+
...viewObj,
|
|
267
|
+
coordinationScopes: {
|
|
268
|
+
...viewObj.coordinationScopes,
|
|
269
|
+
[CoordinationType.META_COORDINATION_SCOPES]: [
|
|
270
|
+
...(coordinationScopes[CoordinationType.META_COORDINATION_SCOPES] || []),
|
|
271
|
+
...(viewObj.coordinationScopes[CoordinationType.META_COORDINATION_SCOPES] || []),
|
|
272
|
+
],
|
|
273
|
+
[CoordinationType.META_COORDINATION_SCOPES_BY]: [
|
|
274
|
+
...(coordinationScopes[CoordinationType.META_COORDINATION_SCOPES_BY] || []),
|
|
275
|
+
...(viewObj.coordinationScopes[CoordinationType.META_COORDINATION_SCOPES_BY] || []),
|
|
276
|
+
],
|
|
277
|
+
},
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
return viewObj;
|
|
281
|
+
}),
|
|
282
|
+
};
|
|
283
|
+
// console.log('newViewConfig', newViewConfig);
|
|
284
|
+
return {
|
|
285
|
+
viewConfig: newViewConfig,
|
|
286
|
+
};
|
|
287
|
+
}),
|
|
176
288
|
removeImageChannelInMetaCoordinationScopes: (coordinationScopesRaw, layerScope, channelScope) => set((state) => {
|
|
177
289
|
const { coordinationSpace } = state.viewConfig;
|
|
178
290
|
return {
|
|
@@ -969,6 +1081,16 @@ export function useSetLoaders() {
|
|
|
969
1081
|
return useViewConfigStore(state => state.setLoaders);
|
|
970
1082
|
}
|
|
971
1083
|
|
|
1084
|
+
/**
|
|
1085
|
+
* Obtain the loaders setter function from
|
|
1086
|
+
* the global app state.
|
|
1087
|
+
* @returns {function} The loaders setter function
|
|
1088
|
+
* in the `useViewConfigStore` store.
|
|
1089
|
+
*/
|
|
1090
|
+
export function useMergeCoordination() {
|
|
1091
|
+
return useViewConfigStore(state => state.mergeCoordination);
|
|
1092
|
+
}
|
|
1093
|
+
|
|
972
1094
|
/**
|
|
973
1095
|
* Obtain the view config setter function from
|
|
974
1096
|
* the global app state.
|
|
@@ -25,7 +25,7 @@ export function getMetaScope(coordinationScopes, coordinationSpace, parameter) {
|
|
|
25
25
|
metaScopesArr.forEach((metaScope) => {
|
|
26
26
|
// Merge the original coordinationScopes with the matching meta-coordinationScopes
|
|
27
27
|
// from the coordinationSpace.
|
|
28
|
-
if (metaSpace[metaScope][parameter]) {
|
|
28
|
+
if (metaSpace[metaScope]?.[parameter]) {
|
|
29
29
|
latestMetaScope = metaScope;
|
|
30
30
|
}
|
|
31
31
|
});
|
|
@@ -97,7 +97,7 @@ function withDefaults(
|
|
|
97
97
|
const defaultKeys = DATA_TYPE_COORDINATION_VALUE_USAGE[dataType]
|
|
98
98
|
.filter(k => (
|
|
99
99
|
Object.keys(defaultCoordinationValues).includes(k)
|
|
100
|
-
&& defaultCoordinationValues[k]
|
|
100
|
+
// && defaultCoordinationValues[k]
|
|
101
101
|
&& !Object.keys(coordinationValues).includes(k)
|
|
102
102
|
));
|
|
103
103
|
const defaultValues = pick(defaultCoordinationValues, defaultKeys);
|