@aics/vole-app 3.2.3 → 3.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -25
- package/es/aics-image-viewer/components/App/index.js +18 -12
- package/es/aics-image-viewer/components/AxisClipSliders/index.js +2 -1
- package/es/aics-image-viewer/components/ChannelsWidget.js +2 -2
- package/es/aics-image-viewer/components/ControlPanel/index.js +15 -11
- package/es/aics-image-viewer/components/ControlPanel/styles.css +5 -5
- package/es/aics-image-viewer/components/ErrorAlert/index.js +102 -65
- package/es/aics-image-viewer/components/ErrorAlert/styles.css +40 -7
- package/es/aics-image-viewer/components/StyleProvider/index.js +65 -27
- package/es/aics-image-viewer/components/TfEditor/index.js +8 -1
- package/es/aics-image-viewer/components/Toolbar/index.js +65 -7
- package/es/aics-image-viewer/components/Toolbar/styles.css +22 -110
- package/es/aics-image-viewer/components/shared/ControlPanelRow/styles.css +1 -1
- package/es/aics-image-viewer/components/useVolume.js +45 -40
- package/es/aics-image-viewer/shared/constants.js +3 -1
- package/es/aics-image-viewer/shared/utils/playControls.js +12 -1
- package/es/aics-image-viewer/shared/utils/sceneStore.js +26 -7
- package/es/aics-image-viewer/shared/utils/test/urlParsing.test.js +10 -2
- package/es/aics-image-viewer/shared/utils/urlParsing.js +17 -3
- package/es/aics-image-viewer/shared/utils/viewerChannelSettings.js +3 -4
- package/es/aics-image-viewer/state/store.js +24 -6
- package/es/aics-image-viewer/state/subscribers.js +22 -1
- package/es/aics-image-viewer/state/test/reset.test.js +3 -1
- package/package.json +5 -5
- package/type-declarations/aics-image-viewer/components/App/types.d.ts +2 -2
- package/type-declarations/aics-image-viewer/components/ControlPanel/index.d.ts +4 -5
- package/type-declarations/aics-image-viewer/components/ErrorAlert/index.d.ts +8 -5
- package/type-declarations/aics-image-viewer/components/Toolbar/index.d.ts +4 -0
- package/type-declarations/aics-image-viewer/components/useVolume.d.ts +3 -3
- package/type-declarations/aics-image-viewer/shared/constants.d.ts +1 -1
- package/type-declarations/aics-image-viewer/shared/utils/playControls.d.ts +1 -0
- package/type-declarations/aics-image-viewer/shared/utils/sceneStore.d.ts +3 -2
- package/type-declarations/aics-image-viewer/shared/utils/urlParsing.d.ts +7 -1
- package/type-declarations/aics-image-viewer/state/store.d.ts +2 -0
- package/type-declarations/aics-image-viewer/state/types.d.ts +2 -0
- package/LICENSE.txt +0 -26
package/LICENSE
CHANGED
|
@@ -1,33 +1,29 @@
|
|
|
1
|
-
|
|
2
|
-
license plus clause a third clause that prohibits redistribution and use for
|
|
3
|
-
commercial purposes without further permission.
|
|
1
|
+
BSD 3-Clause License
|
|
4
2
|
|
|
5
|
-
Copyright
|
|
3
|
+
Copyright (c) 2017-2026, Allen Institute
|
|
4
|
+
All rights reserved.
|
|
6
5
|
|
|
7
|
-
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
Redistribution and use in source and binary forms, with or without
|
|
8
7
|
modification, are permitted provided that the following conditions are met:
|
|
9
8
|
|
|
10
|
-
1. Redistributions of source code must retain the above copyright notice, this
|
|
11
|
-
list of conditions and the following disclaimer.
|
|
9
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
10
|
+
list of conditions and the following disclaimer.
|
|
12
11
|
|
|
13
|
-
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
14
|
-
this list of conditions and the following disclaimer in the documentation
|
|
15
|
-
and/or other materials provided with the distribution.
|
|
12
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
13
|
+
this list of conditions and the following disclaimer in the documentation
|
|
14
|
+
and/or other materials provided with the distribution.
|
|
16
15
|
|
|
17
|
-
3.
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
into anything for which you will charge fees or other compensation or use of
|
|
21
|
-
the software to perform a commercial service for a third party. Contact
|
|
22
|
-
terms@alleninstitute.org for commercial licensing opportunities.
|
|
16
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
17
|
+
contributors may be used to endorse or promote products derived from
|
|
18
|
+
this software without specific prior written permission.
|
|
23
19
|
|
|
24
|
-
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
25
|
-
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
26
|
-
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
27
|
-
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
28
|
-
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
29
|
-
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
30
|
-
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
31
|
-
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
32
|
-
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
20
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
21
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
22
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
23
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
24
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
25
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
26
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
27
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
28
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
33
29
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@@ -54,7 +54,8 @@ var defaultVisibleControls = {
|
|
|
54
54
|
resetCameraButton: true,
|
|
55
55
|
showAxesButton: true,
|
|
56
56
|
showBoundingBoxButton: true,
|
|
57
|
-
metadataViewer: true
|
|
57
|
+
metadataViewer: true,
|
|
58
|
+
scaleLevelControls: true
|
|
58
59
|
};
|
|
59
60
|
var defaultProps = {
|
|
60
61
|
// rawData has a "dtype" which is expected to be "uint8", a "shape":[c,z,y,x] and a "buffer" which is a DataView
|
|
@@ -113,6 +114,7 @@ var App = function App(props) {
|
|
|
113
114
|
var time = useViewerState(select("time"));
|
|
114
115
|
var showAxes = useViewerState(select("showAxes"));
|
|
115
116
|
var channelSettings = useViewerState(select("channelSettings"));
|
|
117
|
+
var changeViewerSetting = useViewerState(select("changeViewerSetting"));
|
|
116
118
|
var changeChannelSetting = useViewerState(select("changeChannelSetting"));
|
|
117
119
|
var applyColorPresets = useViewerState(select("applyColorPresets"));
|
|
118
120
|
var resetToSavedState = useViewerState(select("resetToSavedViewerState"));
|
|
@@ -150,8 +152,8 @@ var App = function App(props) {
|
|
|
150
152
|
var showError = (_props$showError = props.showError) !== null && _props$showError !== void 0 ? _props$showError : _showError;
|
|
151
153
|
useEffect(function () {
|
|
152
154
|
// Get notifications of loading errors which occur after the initial load, e.g. on time change or new channel load
|
|
153
|
-
view3d.setLoadErrorHandler(function (
|
|
154
|
-
return showError(e);
|
|
155
|
+
view3d.setLoadErrorHandler(function (vol, e) {
|
|
156
|
+
return showError(e, vol);
|
|
155
157
|
});
|
|
156
158
|
return function () {
|
|
157
159
|
return view3d.setLoadErrorHandler(undefined);
|
|
@@ -264,10 +266,12 @@ var App = function App(props) {
|
|
|
264
266
|
_useState2 = _slicedToArray(_useState, 2),
|
|
265
267
|
loadedScene = _useState2[0],
|
|
266
268
|
setLoadedScene = _useState2[1];
|
|
267
|
-
var onChangeScene = useCallback(function (image, sceneIndex) {
|
|
269
|
+
var onChangeScene = useCallback(function (image, sceneIndex, loadSpec) {
|
|
270
|
+
changeViewerSetting("time", loadSpec.time);
|
|
268
271
|
onImageTitleChange === null || onImageTitleChange === void 0 || onImageTitleChange(image.imageInfo.imageInfo.name);
|
|
269
272
|
setLoadedScene(sceneIndex);
|
|
270
|
-
|
|
273
|
+
changeViewerSetting("scaleLevelIndex", image.imageInfo.multiscaleLevel);
|
|
274
|
+
}, [onImageTitleChange, changeViewerSetting]);
|
|
271
275
|
var onChannelLoaded = useCallback(function (image, channelIndex, isInitialLoad) {
|
|
272
276
|
// TODO this was once a search by name - is that still necessary or will
|
|
273
277
|
// the index always be correct?
|
|
@@ -320,17 +324,17 @@ var App = function App(props) {
|
|
|
320
324
|
|
|
321
325
|
// save the channel's new range for remapping next time
|
|
322
326
|
channelRangesRef.current[channelIndex] = [thisChannel.rawMin, thisChannel.rawMax];
|
|
323
|
-
|
|
327
|
+
|
|
328
|
+
// Note: updateLuts and updateActiveChannels are not called here because the
|
|
329
|
+
// channelVersion bump (via onChannelDataLoaded) will trigger ChannelUpdater
|
|
330
|
+
// effects that apply LUT/color settings and call updateLuts with the final state.
|
|
324
331
|
view3d.onVolumeData(image, [channelIndex]);
|
|
325
332
|
if (image.channelNames[channelIndex] === maskChannelName) {
|
|
326
333
|
view3d.setVolumeChannelAsMask(image, channelIndex);
|
|
327
334
|
}
|
|
328
|
-
if (image.isLoaded()) {
|
|
329
|
-
view3d.updateActiveChannels(image);
|
|
330
|
-
}
|
|
331
335
|
}, [view3d, changeChannelSetting, maskChannelName, props.viewerChannelSettings]);
|
|
332
|
-
var onError = useCallback(function (error) {
|
|
333
|
-
showError(error);
|
|
336
|
+
var onError = useCallback(function (error, image) {
|
|
337
|
+
showError(error, image);
|
|
334
338
|
onImageTitleChange === null || onImageTitleChange === void 0 || onImageTitleChange(undefined);
|
|
335
339
|
}, [showError, onImageTitleChange]);
|
|
336
340
|
var volume = useVolume(scenes, {
|
|
@@ -585,7 +589,9 @@ var App = function App(props) {
|
|
|
585
589
|
resetCamera: resetCamera,
|
|
586
590
|
downloadScreenshot: saveScreenshot,
|
|
587
591
|
resetToSavedViewerState: resetToSavedViewerState,
|
|
588
|
-
visibleControls: visibleControls
|
|
592
|
+
visibleControls: visibleControls,
|
|
593
|
+
multiscaleDims: image === null || image === void 0 ? void 0 : image.imageInfo.imageInfo.multiscaleLevelDims,
|
|
594
|
+
multiscaleIndex: image === null || image === void 0 ? void 0 : image.imageInfo.multiscaleLevel
|
|
589
595
|
}), /*#__PURE__*/React.createElement(CellViewerCanvasWrapper, {
|
|
590
596
|
view3d: view3d,
|
|
591
597
|
image: image,
|
|
@@ -287,7 +287,8 @@ var AxisClipSliders = function AxisClipSliders(props) {
|
|
|
287
287
|
onChange: function onChange(_ref6) {
|
|
288
288
|
var _ref7 = _slicedToArray(_ref6, 1),
|
|
289
289
|
scene = _ref7[0];
|
|
290
|
-
|
|
290
|
+
props.changeViewerSetting("scene", scene);
|
|
291
|
+
props.changeViewerSetting("useExactScaleLevel", false);
|
|
291
292
|
}
|
|
292
293
|
})))));
|
|
293
294
|
};
|
|
@@ -139,14 +139,14 @@ var ChannelsWidget = function ChannelsWidget(props) {
|
|
|
139
139
|
};
|
|
140
140
|
var renderChannelRow = function renderChannelRow(channelIndex) {
|
|
141
141
|
var channelName = channelNames[channelIndex];
|
|
142
|
-
return
|
|
142
|
+
return /*#__PURE__*/React.createElement(ChannelsWidgetRow, {
|
|
143
143
|
key: channelIndex,
|
|
144
144
|
index: channelIndex,
|
|
145
145
|
channelDataForChannel: channelDataChannels[channelIndex],
|
|
146
146
|
name: getDisplayName(channelName, channelIndex, viewerChannelSettings),
|
|
147
147
|
onColorChangeComplete: props.onColorChangeComplete,
|
|
148
148
|
saveIsosurface: props.saveIsosurface
|
|
149
|
-
})
|
|
149
|
+
});
|
|
150
150
|
};
|
|
151
151
|
var rows = channelDataChannels && Object.entries(channelGroupedByType).filter(function (_ref3) {
|
|
152
152
|
var _ref4 = _slicedToArray(_ref3, 2),
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
|
2
1
|
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
|
|
3
2
|
function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }
|
|
4
3
|
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
@@ -38,10 +37,11 @@ function ControlPanel(props) {
|
|
|
38
37
|
var resetToDefaultViewerState = useViewerState(select("resetToDefaultViewerState"));
|
|
39
38
|
var singleChannelMode = useViewerState(select("singleChannelMode"));
|
|
40
39
|
var changeViewerSetting = useViewerState(select("changeViewerSetting"));
|
|
41
|
-
var
|
|
42
|
-
var getDropdownContainer =
|
|
43
|
-
|
|
44
|
-
|
|
40
|
+
var containerRef = React.useRef(null);
|
|
41
|
+
var getDropdownContainer = function getDropdownContainer() {
|
|
42
|
+
var _containerRef$current;
|
|
43
|
+
return (_containerRef$current = containerRef.current) !== null && _containerRef$current !== void 0 ? _containerRef$current : document.body;
|
|
44
|
+
};
|
|
45
45
|
var viewerChannelSettings = props.viewerChannelSettings,
|
|
46
46
|
visibleControls = props.visibleControls,
|
|
47
47
|
hasImage = props.hasImage;
|
|
@@ -98,12 +98,11 @@ function ControlPanel(props) {
|
|
|
98
98
|
}, "Single channel mode"))));
|
|
99
99
|
};
|
|
100
100
|
var renderTab = function renderTab(thisTab, icon) {
|
|
101
|
-
return /*#__PURE__*/React.createElement(Tooltip,
|
|
101
|
+
return /*#__PURE__*/React.createElement(Tooltip, {
|
|
102
102
|
title: ControlTabNames[thisTab],
|
|
103
103
|
placement: "right"
|
|
104
|
-
},
|
|
105
|
-
|
|
106
|
-
}), /*#__PURE__*/React.createElement(Button, {
|
|
104
|
+
}, /*#__PURE__*/React.createElement(Button, {
|
|
105
|
+
"aria-label": ControlTabNames[thisTab],
|
|
107
106
|
className: tab === thisTab ? "ant-btn-icon-only btn-tabactive" : "ant-btn-icon-only",
|
|
108
107
|
onClick: function onClick() {
|
|
109
108
|
return setTab(thisTab);
|
|
@@ -151,22 +150,27 @@ function ControlPanel(props) {
|
|
|
151
150
|
onClick: resetToDefaultViewerState
|
|
152
151
|
}, "Clear all settings"))));
|
|
153
152
|
};
|
|
153
|
+
var collapseLabel = props.collapsed ? "Show panel" : "Hide panel";
|
|
154
154
|
return /*#__PURE__*/React.createElement("div", {
|
|
155
155
|
className: "control-panel-col-container",
|
|
156
|
-
ref:
|
|
156
|
+
ref: containerRef
|
|
157
157
|
}, /*#__PURE__*/React.createElement("div", {
|
|
158
158
|
className: "control-panel-tab-col",
|
|
159
159
|
style: {
|
|
160
160
|
flex: "0 0 50px"
|
|
161
161
|
}
|
|
162
|
+
}, /*#__PURE__*/React.createElement(Tooltip, {
|
|
163
|
+
title: collapseLabel,
|
|
164
|
+
placement: "right"
|
|
162
165
|
}, /*#__PURE__*/React.createElement(Button, {
|
|
166
|
+
"aria-label": collapseLabel,
|
|
163
167
|
className: "ant-btn-icon-only btn-collapse" + (props.collapsed ? " btn-collapse-collapsed" : ""),
|
|
164
168
|
onClick: function onClick() {
|
|
165
169
|
return props.setCollapsed(!props.collapsed);
|
|
166
170
|
}
|
|
167
171
|
}, /*#__PURE__*/React.createElement(ViewerIcon, {
|
|
168
172
|
type: "closePanel"
|
|
169
|
-
})), /*#__PURE__*/React.createElement("div", {
|
|
173
|
+
}))), /*#__PURE__*/React.createElement("div", {
|
|
170
174
|
className: "tab-divider"
|
|
171
175
|
}), renderTab(ControlTab.Channels, /*#__PURE__*/React.createElement(ViewerIcon, {
|
|
172
176
|
type: "channels"
|
|
@@ -20,16 +20,16 @@
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
.control-panel-col-container .control-panel-tab-col .ant-btn:not([disabled]).btn-tabactive{
|
|
23
|
-
color:var(--color-button-icon-
|
|
24
|
-
background-color:var(--color-button-icon-
|
|
25
|
-
border-color:var(--color-button-icon-
|
|
23
|
+
color:var(--color-button-icon-active-text);
|
|
24
|
+
background-color:var(--color-button-icon-active-bg);
|
|
25
|
+
border-color:var(--color-button-icon-active-outline);
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
.control-panel-col-container .control-panel-tab-col .ant-btn:not([disabled]):hover,
|
|
29
29
|
.control-panel-col-container .control-panel-tab-col .ant-btn:not([disabled]):focus-visible{
|
|
30
|
-
color:var(--color-button-icon-
|
|
30
|
+
color:var(--color-button-icon-active-text);
|
|
31
31
|
background-color:var(--color-button-primary-hover-bg);
|
|
32
|
-
border-color:var(--color-button-icon-
|
|
32
|
+
border-color:var(--color-button-icon-active-outline);
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
.control-panel-col-container .control-panel-tab-col .btn-collapse svg{
|
|
@@ -13,10 +13,11 @@ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object
|
|
|
13
13
|
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
|
|
14
14
|
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
15
15
|
import { VolumeLoadErrorType } from "@aics/vole-core";
|
|
16
|
-
import { RightOutlined } from "@ant-design/icons";
|
|
16
|
+
import { LeftOutlined, RightOutlined, WarningOutlined } from "@ant-design/icons";
|
|
17
17
|
import { Alert, Button } from "antd";
|
|
18
18
|
import React from "react";
|
|
19
19
|
import { useConstructor } from "../../shared/utils/hooks";
|
|
20
|
+
import { useViewerState } from "../../state/store";
|
|
20
21
|
import "./styles.css";
|
|
21
22
|
var IssueLink = function IssueLink(_ref) {
|
|
22
23
|
var bug = _ref.bug,
|
|
@@ -32,113 +33,149 @@ var UNKNOWN_ERROR_DESCRIPTION = /*#__PURE__*/React.createElement(React.Fragment,
|
|
|
32
33
|
}, "send us a bug report here"), ".");
|
|
33
34
|
var ERROR_TYPE_DESCRIPTIONS = _defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty({}, VolumeLoadErrorType.UNKNOWN, /*#__PURE__*/React.createElement(React.Fragment, null, "An unknown error occurred while loading volume data. Check the browser console (F12) for more details. If this looks like a bug, ", /*#__PURE__*/React.createElement(IssueLink, {
|
|
34
35
|
bug: true
|
|
35
|
-
}, "send us a bug report here"), ".")), VolumeLoadErrorType.NOT_FOUND, /*#__PURE__*/React.createElement(React.Fragment, null, "The viewer was unable to find any volume data at the specified location. Check that the provided URL is correct and try again.")), VolumeLoadErrorType.TOO_LARGE, /*#__PURE__*/React.createElement(React.Fragment, null, "No
|
|
36
|
+
}, "send us a bug report here"), ".")), VolumeLoadErrorType.NOT_FOUND, /*#__PURE__*/React.createElement(React.Fragment, null, "The viewer was unable to find any volume data at the specified location. Check that the provided URL is correct and try again.")), VolumeLoadErrorType.TOO_LARGE, /*#__PURE__*/React.createElement(React.Fragment, null, "No resolution level is available for this volume which fits within our maximum memory footprint. This maximum is tuned to ensure compatibility with the majority of browsers. If you're trying to load your own OME-Zarr dataset, you may be able to open this volume by including a lower resolution level.")), VolumeLoadErrorType.LOAD_DATA_FAILED, /*#__PURE__*/React.createElement(React.Fragment, null, "The viewer was able to find a source of volume data at the specified location, but encountered an error while trying to load it. Check that your dataset is complete and properly formatted. You can also check the browser console (F12) for more details about this error. If it looks like a problem on our end,", " ", /*#__PURE__*/React.createElement(IssueLink, {
|
|
36
37
|
bug: true
|
|
37
38
|
}, "start a bug report here"), ".")), VolumeLoadErrorType.INVALID_METADATA, /*#__PURE__*/React.createElement(React.Fragment, null, "The viewer was unable to read all necessary information from this volume's metadata. Check that your dataset's metadata is complete and properly formatted. If you believe your data is valid and should be supported by our viewer, let us know by ", /*#__PURE__*/React.createElement(IssueLink, null, "opening a GitHub issue"), ".")), VolumeLoadErrorType.INVALID_MULTI_SOURCE_ZARR, /*#__PURE__*/React.createElement(React.Fragment, null, "The viewer is currently configured to consolidate multiple OME-Zarr datasets into a single volume, but the provided datasets can't all be matched up. Ensure that all dataset URLs are correct and that at least one equivalently-sized scale level exists in all datasets."));
|
|
38
39
|
var getErrorTitle = function getErrorTitle(error) {
|
|
39
40
|
var _error$toString;
|
|
40
41
|
return error instanceof Error && ((_error$toString = error.toString) === null || _error$toString === void 0 ? void 0 : _error$toString.call(error)) || typeof error === "string" && error || _typeof(error) === "object" && error !== null && error.title || "Unknown error";
|
|
41
42
|
};
|
|
42
|
-
var getErrorDescription = function getErrorDescription(
|
|
43
|
+
var getErrorDescription = function getErrorDescription(_ref2) {
|
|
43
44
|
var _ERROR_TYPE_DESCRIPTI2;
|
|
45
|
+
var error = _ref2.error,
|
|
46
|
+
dims = _ref2.dims;
|
|
44
47
|
var type = error.type;
|
|
45
48
|
if (!type) {
|
|
46
49
|
return _typeof(error) === "object" && error !== null && error.description || UNKNOWN_ERROR_DESCRIPTION;
|
|
47
50
|
}
|
|
51
|
+
if (type === VolumeLoadErrorType.TOO_LARGE && useViewerState.getState().useExactScaleLevel) {
|
|
52
|
+
var dimsDetail = "";
|
|
53
|
+
if (Array.isArray(dims)) {
|
|
54
|
+
var _dims = _slicedToArray(dims, 5),
|
|
55
|
+
_t = _dims[0],
|
|
56
|
+
_c = _dims[1],
|
|
57
|
+
z = _dims[2],
|
|
58
|
+
y = _dims[3],
|
|
59
|
+
x = _dims[4];
|
|
60
|
+
dimsDetail = " (".concat(x, " x ").concat(y, " x ").concat(z, ")");
|
|
61
|
+
}
|
|
62
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, "The viewer cannot load this resolution level", dimsDetail, " within memory limits. Try again with a smaller resolution level.");
|
|
63
|
+
}
|
|
48
64
|
return (_ERROR_TYPE_DESCRIPTI2 = ERROR_TYPE_DESCRIPTIONS[type]) !== null && _ERROR_TYPE_DESCRIPTI2 !== void 0 ? _ERROR_TYPE_DESCRIPTI2 : UNKNOWN_ERROR_DESCRIPTION;
|
|
49
65
|
};
|
|
50
|
-
var ErrorAlert = function ErrorAlert(
|
|
51
|
-
var errors =
|
|
52
|
-
|
|
53
|
-
firstErrorCount = _ref2$firstErrorCount === void 0 ? 0 : _ref2$firstErrorCount,
|
|
54
|
-
_afterClose = _ref2.afterClose,
|
|
55
|
-
onSkipError = _ref2.onSkipError;
|
|
66
|
+
var ErrorAlert = function ErrorAlert(_ref3) {
|
|
67
|
+
var errors = _ref3.errors,
|
|
68
|
+
afterClose = _ref3.afterClose;
|
|
56
69
|
var _React$useState = React.useState(false),
|
|
57
70
|
_React$useState2 = _slicedToArray(_React$useState, 2),
|
|
58
71
|
showDetails = _React$useState2[0],
|
|
59
72
|
setShowDetails = _React$useState2[1];
|
|
60
73
|
var _React$useState3 = React.useState(0),
|
|
61
74
|
_React$useState4 = _slicedToArray(_React$useState3, 2),
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
var
|
|
65
|
-
|
|
75
|
+
errorIndex = _React$useState4[0],
|
|
76
|
+
setErrorIndex = _React$useState4[1];
|
|
77
|
+
var _React$useState5 = React.useState(false),
|
|
78
|
+
_React$useState6 = _slicedToArray(_React$useState5, 2),
|
|
79
|
+
flash = _React$useState6[0],
|
|
80
|
+
setFlash = _React$useState6[1];
|
|
81
|
+
var error = errors[errorIndex];
|
|
82
|
+
var infoStyle = {
|
|
83
|
+
display: showDetails ? undefined : "none"
|
|
84
|
+
};
|
|
85
|
+
React.useEffect(function () {
|
|
86
|
+
setErrorIndex(errors.length - 1);
|
|
87
|
+
setFlash(errors.length > 1);
|
|
88
|
+
window.setTimeout(function () {
|
|
89
|
+
return setFlash(false);
|
|
90
|
+
}, 100);
|
|
91
|
+
}, [errors]);
|
|
92
|
+
var cause = error.error.cause;
|
|
93
|
+
var msg = /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
|
|
94
|
+
className: "error-title"
|
|
95
|
+
}, getErrorTitle(error.error) + (error.count > 1 ? " (".concat(error.count, ")") : ""), " ", /*#__PURE__*/React.createElement(Button, {
|
|
66
96
|
type: "text",
|
|
67
97
|
onClick: function onClick() {
|
|
68
98
|
return setShowDetails(!showDetails);
|
|
69
99
|
}
|
|
70
100
|
}, showDetails ? "Show less info" : "Show more info")), /*#__PURE__*/React.createElement("div", {
|
|
71
|
-
style:
|
|
72
|
-
|
|
101
|
+
style: infoStyle
|
|
102
|
+
}, getErrorDescription(error)), cause !== undefined && /*#__PURE__*/React.createElement("div", {
|
|
103
|
+
className: "error-cause",
|
|
104
|
+
style: infoStyle
|
|
105
|
+
}, "Caused by ", getErrorTitle(cause)));
|
|
106
|
+
var pageButton = undefined;
|
|
107
|
+
if (errors.length > 1) {
|
|
108
|
+
if (errorIndex === errors.length - 1) {
|
|
109
|
+
pageButton = /*#__PURE__*/React.createElement(Button, {
|
|
110
|
+
type: "text",
|
|
111
|
+
onClick: function onClick() {
|
|
112
|
+
return setErrorIndex(function (i) {
|
|
113
|
+
return i - 1;
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
}, /*#__PURE__*/React.createElement(LeftOutlined, null), " ", errors.length - 1, " previous error", errors.length > 2 ? "s" : "");
|
|
117
|
+
} else {
|
|
118
|
+
pageButton = /*#__PURE__*/React.createElement(React.Fragment, null, errorIndex > 0 && /*#__PURE__*/React.createElement(Button, {
|
|
119
|
+
type: "text",
|
|
120
|
+
onClick: function onClick() {
|
|
121
|
+
return setErrorIndex(function (i) {
|
|
122
|
+
return i - 1;
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
}, /*#__PURE__*/React.createElement(LeftOutlined, null)), "Error ", errorIndex + 1, " of ", errors.length, /*#__PURE__*/React.createElement(Button, {
|
|
126
|
+
type: "text",
|
|
127
|
+
onClick: function onClick() {
|
|
128
|
+
return setErrorIndex(function (i) {
|
|
129
|
+
return i + 1;
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
}, /*#__PURE__*/React.createElement(RightOutlined, null)));
|
|
73
133
|
}
|
|
74
|
-
}
|
|
75
|
-
var
|
|
76
|
-
type: "text",
|
|
77
|
-
onClick: function onClick() {
|
|
78
|
-
setErrorsSeenCount(function (count) {
|
|
79
|
-
return count + 1;
|
|
80
|
-
});
|
|
81
|
-
onSkipError === null || onSkipError === void 0 || onSkipError();
|
|
82
|
-
}
|
|
83
|
-
}, "Error ", errorsSeenCount + 1, " of ", errors.length + errorsSeenCount, " ", /*#__PURE__*/React.createElement(RightOutlined, null));
|
|
134
|
+
}
|
|
135
|
+
var alertClass = flash ? "load-error-alert error-flash" : "load-error-alert";
|
|
84
136
|
return /*#__PURE__*/React.createElement(Alert, {
|
|
85
137
|
showIcon: true,
|
|
86
|
-
type: "error",
|
|
87
|
-
className: "load-error-alert",
|
|
88
|
-
message: errorMessage,
|
|
89
138
|
closable: true,
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
139
|
+
type: "error",
|
|
140
|
+
icon: /*#__PURE__*/React.createElement(WarningOutlined, null),
|
|
141
|
+
className: alertClass,
|
|
142
|
+
message: msg,
|
|
143
|
+
afterClose: afterClose,
|
|
144
|
+
action: pageButton
|
|
95
145
|
});
|
|
96
146
|
};
|
|
97
147
|
export var useErrorAlert = function useErrorAlert() {
|
|
98
|
-
var _React$
|
|
99
|
-
_React$
|
|
100
|
-
|
|
101
|
-
|
|
148
|
+
var _React$useState7 = React.useState([]),
|
|
149
|
+
_React$useState8 = _slicedToArray(_React$useState7, 2),
|
|
150
|
+
errors = _React$useState8[0],
|
|
151
|
+
setErrors = _React$useState8[1];
|
|
102
152
|
// Keep track of which errors have been seen and how many times
|
|
103
153
|
var seenErrors = useConstructor(function () {
|
|
104
154
|
return new Map();
|
|
105
155
|
});
|
|
106
|
-
var
|
|
107
|
-
_React$useState8 = _slicedToArray(_React$useState7, 2),
|
|
108
|
-
errorCounts = _React$useState8[0],
|
|
109
|
-
setErrorCounts = _React$useState8[1];
|
|
110
|
-
var addError = React.useCallback(function (error) {
|
|
156
|
+
var addError = React.useCallback(function (error, image) {
|
|
111
157
|
var _seenErrors$get;
|
|
112
158
|
var errorTitle = getErrorTitle(error);
|
|
113
159
|
console.error(error instanceof Error ? error : errorTitle);
|
|
114
|
-
var
|
|
115
|
-
|
|
116
|
-
|
|
160
|
+
var count = ((_seenErrors$get = seenErrors.get(errorTitle)) !== null && _seenErrors$get !== void 0 ? _seenErrors$get : 0) + 1;
|
|
161
|
+
var imageInfo = image === null || image === void 0 ? void 0 : image.imageInfo.imageInfo;
|
|
162
|
+
var dims = imageInfo && imageInfo.multiscaleLevelDims[imageInfo.multiscaleLevel].shape;
|
|
163
|
+
setErrors(function (prev) {
|
|
164
|
+
return [].concat(_toConsumableArray(prev), [{
|
|
165
|
+
error: error,
|
|
166
|
+
count: count,
|
|
167
|
+
dims: dims
|
|
168
|
+
}]);
|
|
117
169
|
});
|
|
118
|
-
|
|
119
|
-
return [].concat(_toConsumableArray(prev), [errorSeenCount]);
|
|
120
|
-
});
|
|
121
|
-
seenErrors.set(errorTitle, errorSeenCount);
|
|
170
|
+
seenErrors.set(errorTitle, count);
|
|
122
171
|
}, [seenErrors]);
|
|
123
|
-
var onSkipError = React.useCallback(function () {
|
|
124
|
-
setErrorList(function (prev) {
|
|
125
|
-
return prev.slice(1);
|
|
126
|
-
});
|
|
127
|
-
setErrorCounts(function (prev) {
|
|
128
|
-
return prev.slice(1);
|
|
129
|
-
});
|
|
130
|
-
}, []);
|
|
131
172
|
var afterClose = React.useCallback(function () {
|
|
132
|
-
|
|
133
|
-
setErrorCounts([]);
|
|
173
|
+
return setErrors([]);
|
|
134
174
|
}, []);
|
|
135
|
-
var
|
|
136
|
-
|
|
137
|
-
errors: errorList,
|
|
138
|
-
firstErrorCount: errCount,
|
|
139
|
-
onSkipError: onSkipError,
|
|
175
|
+
var alertNode = errors.length > 0 && /*#__PURE__*/React.createElement(ErrorAlert, {
|
|
176
|
+
errors: errors,
|
|
140
177
|
afterClose: afterClose
|
|
141
178
|
});
|
|
142
|
-
return [
|
|
179
|
+
return [alertNode, addError];
|
|
143
180
|
};
|
|
144
181
|
export default ErrorAlert;
|
|
@@ -5,21 +5,54 @@
|
|
|
5
5
|
width:40vw;
|
|
6
6
|
align-items:start;
|
|
7
7
|
z-index:5000;
|
|
8
|
-
border-color
|
|
8
|
+
border-color:var(--color-text-error);
|
|
9
9
|
padding:12px 30px;
|
|
10
|
+
color:var(--color-text-section);
|
|
10
11
|
}
|
|
12
|
+
|
|
13
|
+
.load-error-alert.error-flash{
|
|
14
|
+
background-color:var(--color-text-error);
|
|
15
|
+
}
|
|
16
|
+
|
|
11
17
|
.load-error-alert .ant-alert-icon,
|
|
12
18
|
.load-error-alert .ant-alert-close-icon,
|
|
13
19
|
.load-error-alert .ant-alert-message div{
|
|
14
20
|
min-height:24px;
|
|
15
21
|
}
|
|
16
|
-
|
|
22
|
+
|
|
23
|
+
.load-error-alert .ant-alert-close-icon{
|
|
24
|
+
margin-inline-start:14px;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.load-error-alert .ant-alert-action{
|
|
28
|
+
display:inline-flex;
|
|
29
|
+
align-items:center;
|
|
30
|
+
gap:4px;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.load-error-alert .ant-alert-action > button{
|
|
34
|
+
gap:4px;
|
|
35
|
+
border:none !important;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.load-error-alert .ant-btn-text,
|
|
39
|
+
.load-error-alert .ant-alert-action{
|
|
17
40
|
color:var(--color-text-link);
|
|
18
41
|
}
|
|
42
|
+
|
|
19
43
|
.load-error-alert .ant-btn-text:hover{
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
font-
|
|
44
|
+
color:#25affe !important;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.load-error-alert .anticon{
|
|
48
|
+
font-size:21px;
|
|
25
49
|
}
|
|
50
|
+
|
|
51
|
+
.load-error-alert .ant-alert-message > div.error-title{
|
|
52
|
+
font-weight:600;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.load-error-alert .ant-alert-message > div.error-cause{
|
|
56
|
+
font-style:italic;
|
|
57
|
+
color:var(--color-text-body);
|
|
58
|
+
}
|