@aics/vole-app 3.5.0 → 3.6.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.
Files changed (38) hide show
  1. package/es/aics-image-viewer/components/App/index.js +10 -0
  2. package/es/aics-image-viewer/components/ChannelsWidget.js +3 -1
  3. package/es/aics-image-viewer/components/ChannelsWidgetRow.js +29 -16
  4. package/es/aics-image-viewer/components/ControlPanel/CopySettingsButton.js +177 -147
  5. package/es/aics-image-viewer/components/ControlPanel/index.js +4 -1
  6. package/es/aics-image-viewer/components/Toolbar/styles.css +0 -10
  7. package/es/aics-image-viewer/components/ViewerCanvasWrapper/index.js +2 -1
  8. package/es/aics-image-viewer/components/dimension_sliders/AxisClipSliders.js +21 -8
  9. package/es/aics-image-viewer/components/dimension_sliders/RotationSliders.js +5 -7
  10. package/es/aics-image-viewer/components/dimension_sliders/SliderRows.js +8 -6
  11. package/es/aics-image-viewer/components/shared/ControlPanelRow/index.js +4 -2
  12. package/es/aics-image-viewer/components/shared/ControlPanelRow/styles.css +4 -3
  13. package/es/aics-image-viewer/components/useVolume.js +58 -24
  14. package/es/aics-image-viewer/shared/constants.js +24 -0
  15. package/es/aics-image-viewer/shared/utils/parseSnapshot.js +28 -2
  16. package/es/aics-image-viewer/shared/utils/parseUrl.js +41 -139
  17. package/es/aics-image-viewer/shared/utils/test/camera.test.js +1 -1
  18. package/es/aics-image-viewer/shared/utils/test/parseUrl.test.js +20 -20
  19. package/es/aics-image-viewer/shared/utils/test/storage.test.js +2 -2
  20. package/es/aics-image-viewer/shared/utils/test/viewerChannelSettings.test.js +1 -1
  21. package/es/aics-image-viewer/state/test/deserialize.test.js +1 -1
  22. package/es/aics-image-viewer/state/test/reset.test.js +1 -1
  23. package/es/aics-image-viewer/state/test/serialize.test.js +1 -0
  24. package/package.json +26 -44
  25. package/type-declarations/aics-image-viewer/components/ChannelsWidget.d.ts +3 -0
  26. package/type-declarations/aics-image-viewer/components/ChannelsWidgetRow.d.ts +3 -0
  27. package/type-declarations/aics-image-viewer/components/ControlPanel/CopySettingsButton.d.ts +2 -0
  28. package/type-declarations/aics-image-viewer/components/ViewerCanvasWrapper/index.d.ts +1 -0
  29. package/type-declarations/aics-image-viewer/components/dimension_sliders/AxisClipSliders.d.ts +1 -0
  30. package/type-declarations/aics-image-viewer/components/dimension_sliders/SliderRows.d.ts +1 -2
  31. package/type-declarations/aics-image-viewer/components/shared/ControlPanelRow/index.d.ts +1 -0
  32. package/type-declarations/aics-image-viewer/components/useVolume.d.ts +3 -0
  33. package/type-declarations/aics-image-viewer/shared/constants.d.ts +1 -0
  34. package/type-declarations/aics-image-viewer/shared/utils/parseSnapshot.d.ts +2 -0
  35. package/type-declarations/aics-image-viewer/shared/utils/parseUrl.d.ts +1 -8
  36. package/es/Globals.d.js +0 -0
  37. package/es/aics-image-viewer/shared/utils/firebase/index.js +0 -109
  38. package/type-declarations/aics-image-viewer/shared/utils/firebase/index.d.ts +0 -69
@@ -33,7 +33,6 @@ import { parseKeyValueList, stringSnapshotToViewerChannelSetting, stringSnapshot
33
33
  import { channelStateToStringSnapshot, objectToKeyValueList, viewerStateToStringSnapshot } from "../../state/serialize";
34
34
  import { ViewerStateSnapshotKeys } from "../../state/types";
35
35
  import { removeUndefinedProperties } from "./datatypes";
36
- import FirebaseRequest from "./firebase";
37
36
  import { readStoredMetadata, readStoredScenes } from "./storage";
38
37
  var CHANNEL_STATE_KEY_REGEX = /^c[0-9]+$/;
39
38
 
@@ -65,10 +64,6 @@ var DataParams = /*#__PURE__*/_createClass(function DataParams() {
65
64
  * See `ManifestJson` for the type definition.
66
65
  */
67
66
  _defineProperty(this, "manifest", undefined);
68
- /** The name of a dataset in the Cell Feature Explorer database. Used with `id`. */
69
- _defineProperty(this, "dataset", undefined);
70
- /** The ID of a cell within the loaded dataset. Used with `dataset`. */
71
- _defineProperty(this, "id", undefined);
72
67
  /** The key of a collection of scenes stored in local storage. Overrides `url`. */
73
68
  _defineProperty(this, "collectionid", undefined);
74
69
  /**
@@ -264,86 +259,7 @@ function parseChannelSettings(params) {
264
259
  }
265
260
 
266
261
  //// FULL URL PARSING //////////////////////
267
- function loadDataset(_x, _x2, _x3) {
268
- return _loadDataset.apply(this, arguments);
269
- }
270
- function _loadDataset() {
271
- _loadDataset = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee(firestore, dataset, id) {
272
- var db, args, datasets, datasetMeta, _iterator2, _step2, d, innerDatasets, names, matchingName, datasetData, baseUrl, fileInfo;
273
- return _regeneratorRuntime().wrap(function _callee$(_context) {
274
- while (1) switch (_context.prev = _context.next) {
275
- case 0:
276
- db = new FirebaseRequest(firestore);
277
- args = {};
278
- _context.next = 4;
279
- return db.getAvailableDatasets();
280
- case 4:
281
- datasets = _context.sent;
282
- datasetMeta = undefined;
283
- _iterator2 = _createForOfIteratorHelper(datasets);
284
- _context.prev = 7;
285
- _iterator2.s();
286
- case 9:
287
- if ((_step2 = _iterator2.n()).done) {
288
- _context.next = 19;
289
- break;
290
- }
291
- d = _step2.value;
292
- innerDatasets = d.datasets;
293
- names = Object.keys(innerDatasets);
294
- matchingName = names.find(function (name) {
295
- return name === dataset;
296
- });
297
- if (!matchingName) {
298
- _context.next = 17;
299
- break;
300
- }
301
- datasetMeta = innerDatasets[matchingName];
302
- return _context.abrupt("break", 19);
303
- case 17:
304
- _context.next = 9;
305
- break;
306
- case 19:
307
- _context.next = 24;
308
- break;
309
- case 21:
310
- _context.prev = 21;
311
- _context.t0 = _context["catch"](7);
312
- _iterator2.e(_context.t0);
313
- case 24:
314
- _context.prev = 24;
315
- _iterator2.f();
316
- return _context.finish(24);
317
- case 27:
318
- if (!(datasetMeta === undefined)) {
319
- _context.next = 30;
320
- break;
321
- }
322
- console.error("No matching dataset: ".concat(dataset));
323
- return _context.abrupt("return", {});
324
- case 30:
325
- _context.next = 32;
326
- return db.selectDataset(datasetMeta.manifest);
327
- case 32:
328
- datasetData = _context.sent;
329
- baseUrl = datasetData.volumeViewerDataRoot + "/";
330
- args.imageDownloadHref = datasetData.downloadRoot + "/" + id;
331
- // args.fovDownloadHref = datasetData.downloadRoot + "/" + id;
332
- _context.next = 37;
333
- return db.getFileInfoByCellId(id);
334
- case 37:
335
- fileInfo = _context.sent;
336
- args.imageUrl = baseUrl + fileInfo.volumeviewerPath;
337
- args.parentImageUrl = baseUrl + fileInfo.fovVolumeviewerPath;
338
- return _context.abrupt("return", args);
339
- case 41:
340
- case "end":
341
- return _context.stop();
342
- }
343
- }, _callee, null, [[7, 21, 24, 27]]);
344
- }));
345
- return _loadDataset.apply(this, arguments);
346
- }
262
+
347
263
  function isStringArray(arr) {
348
264
  return Array.isArray(arr) && arr.every(function (item) {
349
265
  return typeof item === "string";
@@ -354,15 +270,13 @@ function isValidScenesArray(arr) {
354
270
  return typeof item === "string" || isStringArray(item);
355
271
  });
356
272
  }
357
- export function loadFromManifest(_x4) {
273
+ export function loadFromManifest(_x) {
358
274
  return _loadFromManifest.apply(this, arguments);
359
275
  }
360
276
 
361
277
  /**
362
278
  * Parses a set of URL search parameters into props for the viewer.
363
279
  * @param search The query string to parse, which must be valid in the `URLSearchParams constructor
364
- * @param firestore Optional Firestore instance. If provided, the function can load data from a
365
- * Firestore dataset if the `dataset` and `id` parameters are provided.
366
280
  * @returns An object containing:
367
281
  * - `args`: Partial AppProps object.
368
282
  * - `viewerSettings`: Partial ViewerState object.
@@ -370,46 +284,46 @@ export function loadFromManifest(_x4) {
370
284
  * `args` can be passed as props to the `ImageViewerApp`, and `viewerSettings` can be passed to `ViewerStateProvider`.
371
285
  */
372
286
  function _loadFromManifest() {
373
- _loadFromManifest = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee2(manifestUrl) {
287
+ _loadFromManifest = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee(manifestUrl) {
374
288
  var response, manifestJson, scenes, metadata;
375
- return _regeneratorRuntime().wrap(function _callee2$(_context2) {
376
- while (1) switch (_context2.prev = _context2.next) {
289
+ return _regeneratorRuntime().wrap(function _callee$(_context) {
290
+ while (1) switch (_context.prev = _context.next) {
377
291
  case 0:
378
- _context2.prev = 0;
379
- _context2.next = 3;
292
+ _context.prev = 0;
293
+ _context.next = 3;
380
294
  return fetch(manifestUrl);
381
295
  case 3:
382
- response = _context2.sent;
383
- _context2.next = 10;
296
+ response = _context.sent;
297
+ _context.next = 10;
384
298
  break;
385
299
  case 6:
386
- _context2.prev = 6;
387
- _context2.t0 = _context2["catch"](0);
388
- console.error(_context2.t0);
389
- throw new Error("JSON manifest could not be fetched from URL '".concat(manifestUrl, "': ").concat(_context2.t0));
300
+ _context.prev = 6;
301
+ _context.t0 = _context["catch"](0);
302
+ console.error(_context.t0);
303
+ throw new Error("JSON manifest could not be fetched from URL '".concat(manifestUrl, "': ").concat(_context.t0));
390
304
  case 10:
391
305
  if (response.ok) {
392
- _context2.next = 12;
306
+ _context.next = 12;
393
307
  break;
394
308
  }
395
309
  throw new Error("JSON manifest could not be fetched from URL '".concat(manifestUrl, "': Received ").concat(response.status, " ").concat(response.statusText));
396
310
  case 12:
397
- _context2.prev = 12;
398
- _context2.next = 15;
311
+ _context.prev = 12;
312
+ _context.next = 15;
399
313
  return response.json();
400
314
  case 15:
401
- manifestJson = _context2.sent;
402
- _context2.next = 21;
315
+ manifestJson = _context.sent;
316
+ _context.next = 21;
403
317
  break;
404
318
  case 18:
405
- _context2.prev = 18;
406
- _context2.t1 = _context2["catch"](12);
407
- throw new Error("Could not parse JSON manifest from URL '".concat(manifestUrl, "': ").concat(_context2.t1));
319
+ _context.prev = 18;
320
+ _context.t1 = _context["catch"](12);
321
+ throw new Error("Could not parse JSON manifest from URL '".concat(manifestUrl, "': ").concat(_context.t1));
408
322
  case 21:
409
323
  // Parse scenes
410
324
  scenes = manifestJson.scenes;
411
325
  if (!(scenes === undefined)) {
412
- _context2.next = 24;
326
+ _context.next = 24;
413
327
  break;
414
328
  }
415
329
  throw new Error("No 'scenes' property was found in JSON manifest from URL '".concat(manifestUrl, "'"));
@@ -418,7 +332,7 @@ function _loadFromManifest() {
418
332
  scenes = [scenes];
419
333
  }
420
334
  if (!(!Array.isArray(scenes) || scenes.length === 0 || !isValidScenesArray(scenes))) {
421
- _context2.next = 27;
335
+ _context.next = 27;
422
336
  break;
423
337
  }
424
338
  throw new Error("Invalid 'scenes' property found in JSON manifest from URL '".concat(manifestUrl, "'. 'scenes' must be a non-empty array of strings or string arrays."));
@@ -428,19 +342,19 @@ function _loadFromManifest() {
428
342
  if (manifestJson.meta !== undefined && Array.isArray(manifestJson.meta)) {
429
343
  metadata = manifestJson.meta;
430
344
  }
431
- return _context2.abrupt("return", {
345
+ return _context.abrupt("return", {
432
346
  scenes: scenes,
433
347
  metadata: metadata
434
348
  });
435
349
  case 30:
436
350
  case "end":
437
- return _context2.stop();
351
+ return _context.stop();
438
352
  }
439
- }, _callee2, null, [[0, 6], [12, 18]]);
353
+ }, _callee, null, [[0, 6], [12, 18]]);
440
354
  }));
441
355
  return _loadFromManifest.apply(this, arguments);
442
356
  }
443
- export function parseViewerUrlParams(_x5, _x6) {
357
+ export function parseViewerUrlParams(_x2) {
444
358
  return _parseViewerUrlParams.apply(this, arguments);
445
359
  }
446
360
 
@@ -451,10 +365,10 @@ export function parseViewerUrlParams(_x5, _x6) {
451
365
  * This includes the output of GET_DEFAULT_VIEWER_STATE and GET_DEFAULT_CHANNEL_STATE.
452
366
  */
453
367
  function _parseViewerUrlParams() {
454
- _parseViewerUrlParams = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee3(search, firestore) {
455
- var searchParams, params, args, viewerSettings, deprecatedChannelSettings, channelSettings, scenes, _yield$loadFromManife, manifestScenes, manifestMetadata, collectionid, msgorigin, getFromStorage, urlParamFromStorage, urlParam, firstScene, firstUrl, imageUrls, datasetArgs;
456
- return _regeneratorRuntime().wrap(function _callee3$(_context3) {
457
- while (1) switch (_context3.prev = _context3.next) {
368
+ _parseViewerUrlParams = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee2(search) {
369
+ var searchParams, params, args, viewerSettings, deprecatedChannelSettings, channelSettings, scenes, _yield$loadFromManife, manifestScenes, manifestMetadata, collectionid, msgorigin, getFromStorage, urlParamFromStorage, urlParam, firstScene, firstUrl, imageUrls;
370
+ return _regeneratorRuntime().wrap(function _callee2$(_context2) {
371
+ while (1) switch (_context2.prev = _context2.next) {
458
372
  case 0:
459
373
  searchParams = new URLSearchParams(search);
460
374
  params = getAllowedParams(searchParams);
@@ -467,22 +381,22 @@ function _parseViewerUrlParams() {
467
381
 
468
382
  // Parse data sources (URL or dataset/id pair)
469
383
  if (!(params.manifest !== undefined || params.url !== undefined || params.collectionid !== undefined)) {
470
- _context3.next = 35;
384
+ _context2.next = 33;
471
385
  break;
472
386
  }
473
387
  if (!params.manifest) {
474
- _context3.next = 18;
388
+ _context2.next = 18;
475
389
  break;
476
390
  }
477
- _context3.next = 11;
391
+ _context2.next = 11;
478
392
  return loadFromManifest(params.manifest);
479
393
  case 11:
480
- _yield$loadFromManife = _context3.sent;
394
+ _yield$loadFromManife = _context2.sent;
481
395
  manifestScenes = _yield$loadFromManife.scenes;
482
396
  manifestMetadata = _yield$loadFromManife.metadata;
483
397
  scenes = manifestScenes;
484
398
  args.metadata = manifestMetadata !== null && manifestMetadata !== void 0 ? manifestMetadata : undefined;
485
- _context3.next = 24;
399
+ _context2.next = 24;
486
400
  break;
487
401
  case 18:
488
402
  // Load from URL or storage
@@ -523,28 +437,16 @@ function _parseViewerUrlParams() {
523
437
  }]
524
438
  };
525
439
  }
526
- _context3.next = 40;
527
- break;
528
- case 35:
529
- if (!(params.dataset && params.id && firestore)) {
530
- _context3.next = 40;
531
- break;
532
- }
533
- _context3.next = 38;
534
- return loadDataset(firestore, params.dataset, params.id);
535
- case 38:
536
- datasetArgs = _context3.sent;
537
- args = _objectSpread(_objectSpread({}, args), datasetArgs);
538
- case 40:
539
- return _context3.abrupt("return", {
440
+ case 33:
441
+ return _context2.abrupt("return", {
540
442
  args: removeUndefinedProperties(args),
541
443
  viewerSettings: removeUndefinedProperties(viewerSettings)
542
444
  });
543
- case 41:
445
+ case 34:
544
446
  case "end":
545
- return _context3.stop();
447
+ return _context2.stop();
546
448
  }
547
- }, _callee3);
449
+ }, _callee2);
548
450
  }));
549
451
  return _parseViewerUrlParams.apply(this, arguments);
550
452
  }
@@ -4,8 +4,8 @@ function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r)
4
4
  function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
5
5
  function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
6
6
  function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
7
- import { describe, expect, it } from "@jest/globals";
8
7
  import { mat3 } from "gl-matrix";
8
+ import { describe, expect, it } from "vitest";
9
9
  import { applyMatrix, defaultOrientedCamera, getRotationAngles, rotationMatrix } from "../camera";
10
10
  var expectCameraStateToBe = function expectCameraStateToBe(actual, expected, precision) {
11
11
  var _actual$position = _slicedToArray(actual.position, 3),
@@ -22,7 +22,7 @@ function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" !=
22
22
  function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
23
23
  function asyncGeneratorStep(n, t, e, r, o, a, c) { try { var i = n[a](c), u = i.value; } catch (n) { return void e(n); } i.done ? t(u) : Promise.resolve(u).then(r, o); }
24
24
  function _asyncToGenerator(n) { return function () { var t = this, e = arguments; return new Promise(function (r, o) { var a = n.apply(t, e); function _next(n) { asyncGeneratorStep(a, r, o, _next, _throw, "next", n); } function _throw(n) { asyncGeneratorStep(a, r, o, _next, _throw, "throw", n); } _next(void 0); }); }; }
25
- import { describe, expect, it } from "@jest/globals";
25
+ import { describe, expect, it } from "vitest";
26
26
  import { parseKeyValueList } from "../../../state/deserialize";
27
27
  import { DEFAULT_TEST_VIEWER_CHANNEL_SETTING } from "../../../state/test/test_data";
28
28
  import { ViewMode } from "../../../state/types";
@@ -399,46 +399,46 @@ describe("parseViewerUrlParams", function () {
399
399
  }
400
400
  }, _callee9, null, [[4, 17, 20, 23]]);
401
401
  })));
402
- it("parses viewer settings", /*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee10() {
403
- var queryString, _yield$parseViewerUrl10, viewerSettings;
404
- return _regeneratorRuntime().wrap(function _callee10$(_context10) {
405
- while (1) switch (_context10.prev = _context10.next) {
402
+ it("parses viewer settings", /*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee0() {
403
+ var queryString, _yield$parseViewerUrl0, viewerSettings;
404
+ return _regeneratorRuntime().wrap(function _callee0$(_context0) {
405
+ while (1) switch (_context0.prev = _context0.next) {
406
406
  case 0:
407
407
  queryString = "mask=30&view=X";
408
- _context10.next = 3;
408
+ _context0.next = 3;
409
409
  return parseViewerUrlParams(queryString);
410
410
  case 3:
411
- _yield$parseViewerUrl10 = _context10.sent;
412
- viewerSettings = _yield$parseViewerUrl10.viewerSettings;
411
+ _yield$parseViewerUrl0 = _context0.sent;
412
+ viewerSettings = _yield$parseViewerUrl0.viewerSettings;
413
413
  expect(viewerSettings.viewMode).toEqual(ViewMode.yz);
414
414
  expect(viewerSettings.maskAlpha).toEqual(30);
415
415
  case 7:
416
416
  case "end":
417
- return _context10.stop();
417
+ return _context0.stop();
418
418
  }
419
- }, _callee10);
419
+ }, _callee0);
420
420
  })));
421
- it("returns an empty object when no params are passed in", /*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee11() {
422
- var queryString, _yield$parseViewerUrl11, args, viewerSettings;
423
- return _regeneratorRuntime().wrap(function _callee11$(_context11) {
424
- while (1) switch (_context11.prev = _context11.next) {
421
+ it("returns an empty object when no params are passed in", /*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee1() {
422
+ var queryString, _yield$parseViewerUrl1, args, viewerSettings;
423
+ return _regeneratorRuntime().wrap(function _callee1$(_context1) {
424
+ while (1) switch (_context1.prev = _context1.next) {
425
425
  case 0:
426
426
  queryString = "";
427
- _context11.next = 3;
427
+ _context1.next = 3;
428
428
  return parseViewerUrlParams(queryString);
429
429
  case 3:
430
- _yield$parseViewerUrl11 = _context11.sent;
431
- args = _yield$parseViewerUrl11.args;
432
- viewerSettings = _yield$parseViewerUrl11.viewerSettings;
430
+ _yield$parseViewerUrl1 = _context1.sent;
431
+ args = _yield$parseViewerUrl1.args;
432
+ viewerSettings = _yield$parseViewerUrl1.viewerSettings;
433
433
  expect(Object.keys(args).length === 0);
434
434
  expect(args).toEqual({});
435
435
  expect(Object.keys(viewerSettings).length === 0);
436
436
  expect(viewerSettings).toEqual({});
437
437
  case 10:
438
438
  case "end":
439
- return _context11.stop();
439
+ return _context1.stop();
440
440
  }
441
- }, _callee11);
441
+ }, _callee1);
442
442
  })));
443
443
  });
444
444
  describe("serializeViewerUrlParams", function () {
@@ -1,6 +1,6 @@
1
- import { describe, expect, it } from "@jest/globals";
1
+ import { describe, expect, it } from "vitest";
2
2
  import { readStoredMetadata, readStoredScenes, writeMetadata, writeScenes } from "../storage";
3
- var LONG_STRING = "This is a very long string, long enough that it dwarfs the size of other example data used in this test. Its purpose is to test how the functions in the \"storage\" module evict data from local storage when the quota for local storage size is exceeded. The local storage quota is set to five thousand in this test environment, which is much smaller than most browsers will provide. At one thousand two hundred and thirty-four characters, this string represents a little less than a quarter of the total size of local storage in this test environment. Therefore, the tests below can reliably predict that up to three objects containing this string in one of its properties will fit in local storage, and that inserting a fourth one will trigger an eviction. They can also predict that a single object containing four or more copies of this string will not be allowed in local storage at all. This is slightly imprecise because adding items to local storage using the functions tested in this module incurs some additional storage penalties for the storage key, the stringified JSON surrounding the value, and the key and value of the least-recently-used queue. The size of local storage in this test environment is set in jest.config.js.";
3
+ var LONG_STRING = "This is a very long string, long enough that it dwarfs the size of other example data used in this test. Its purpose is to test how the functions in the \"storage\" module evict data from local storage when the quota for local storage size is exceeded. The local storage quota is set to five thousand in this test environment, which is much smaller than most browsers will provide. At one thousand two hundred and thirty-four characters, this string represents a little less than a quarter of the total size of local storage in this test environment. Therefore, the tests below can reliably predict that up to three objects containing this string in one of its properties will fit in local storage, and that inserting a fourth one will trigger an eviction. They can also predict that a single object containing four or more copies of this string will not be allowed in local storage at all. This is slightly imprecise because adding items to local storage using the functions tested in this module incurs some additional storage penalties for the storage key, the stringified JSON surrounding the value, and the key and value of the least-recently-used queue. The size of local storage in this test environment is set in vitest.config.ts.";
4
4
  var LARGE_ENTRY = {
5
5
  data: LONG_STRING
6
6
  };
@@ -1,4 +1,4 @@
1
- import { describe, expect, it } from "@jest/globals";
1
+ import { describe, expect, it } from "vitest";
2
2
  import { makeChannelIndexGrouping, matchChannel } from "../viewerChannelSettings";
3
3
  describe("viewer settings", function () {
4
4
  describe("matching names", function () {
@@ -10,7 +10,7 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
10
10
  function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
11
11
  function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
12
12
  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); }
13
- import { describe, expect, it } from "@jest/globals";
13
+ import { describe, expect, it } from "vitest";
14
14
  import { CONTROL_POINTS_REGEX, enumParser, LEGACY_CONTROL_POINTS_REGEX, parseHexColorAsColorArray, parseKeyValueList, stringSnapshotToChannelState, stringSnapshotToViewerChannelSetting, stringSnapshotToViewerState, validateInt, validateNumber } from "../deserialize";
15
15
  import { viewerStateToStringSnapshot } from "../serialize";
16
16
  import { RenderMode, ViewMode } from "../types";
@@ -7,7 +7,7 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
7
7
  function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
8
8
  function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
9
9
  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); }
10
- import { describe, expect, it } from "@jest/globals";
10
+ import { describe, expect, it } from "vitest";
11
11
  import { getDefaultCameraState, getDefaultChannelState, getDefaultViewerState } from "../../shared/constants";
12
12
  import { useViewerState } from "../store";
13
13
  import { ImageType, RenderMode, ViewMode } from "../types";
@@ -4,6 +4,7 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
4
4
  function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
5
5
  function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
6
6
  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); }
7
+ import { describe, expect, it } from "vitest";
7
8
  import { getDefaultCameraState } from "../../shared/constants";
8
9
  import { cameraStateToSnapshot, channelStateToSnapshot, channelStateToStringSnapshot, objectToKeyValueList, stringifyCameraStateSnapshot, viewerStateToSnapshot, viewerStateToStringSnapshot } from "../serialize";
9
10
  import { CUSTOM_TEST_CHANNEL_STATE, CUSTOM_TEST_VIEWER_STATE, DEFAULT_TEST_CHANNEL_STATE, DEFAULT_TEST_VIEWER_STATE, SERIALIZED_CUSTOM_TEST_CHANNEL_STATE, SERIALIZED_CUSTOM_TEST_VIEWER_STATE, SERIALIZED_DEFAULT_TEST_CHANNEL_STATE, SERIALIZED_DEFAULT_TEST_VIEWER_STATE, STRINGIFIED_CUSTOM_TEST_CHANNEL_STATE, STRINGIFIED_CUSTOM_TEST_VIEWER_STATE, STRINGIFIED_DEFAULT_TEST_CHANNEL_STATE, STRINGIFIED_DEFAULT_TEST_VIEWER_STATE } from "./test_data";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aics/vole-app",
3
- "version": "3.5.0",
3
+ "version": "3.6.0",
4
4
  "description": "web view of cell volume images",
5
5
  "main": "es/index.js",
6
6
  "module": "es/index.js",
@@ -21,32 +21,30 @@
21
21
  "url": "git+https://github.com/allen-cell-animated/vole-app.git"
22
22
  },
23
23
  "scripts": {
24
- "start": "webpack serve --config webpack.dev.js --env env=dev",
25
- "gh-build-nightly": "webpack --config webpack.dev.js --env env=production basename=/vole-app/",
26
- "gh-build-release": "webpack --config webpack.dev.js --env env=production basename=/website-3d-cell-viewer-release/",
27
- "s3-build": "webpack --config webpack.dev.js --env env=production",
28
- "release-build": "webpack --config webpack.dev.js --env env=production",
29
- "docker-build": "webpack --config webpack.common.js --env env=production",
30
- "dev": "webpack --config webpack.dev.js --env env=dev",
24
+ "start": "vite dev",
25
+ "gh-build-nightly": "vite build --base=/vole-app/",
26
+ "s3-build": "vite build",
27
+ "release-build": "vite build",
28
+ "docker-build": "vite build",
29
+ "dev": "vite dev",
31
30
  "lint": "eslint --config ./.eslintrc --ignore-path ./.eslintignore --ext .jsx --ext .js --ext .ts --ext .tsx ./",
32
- "test": "jest --coverage --passWithNoTests",
33
- "test:github-action": "jest --silent --passWithNoTests --ci --coverage --coverageReporters=\"text\" --coverageReporters=\"text-summary\" --outputFile=\"report.json\"",
31
+ "test": "vitest run --passWithNoTests",
34
32
  "typeCheck": "tsc -p tsconfig.json --noEmit",
35
33
  "generateTypes": "tsc -p tsconfig.base.json --emitDeclarationOnly",
36
- "transpileES": "cross-env TS_NODE_PROJECT=tsconfig.es.json BABEL_ENV=es babel src --out-dir es --extensions \".js,.jsx,.ts,.tsx,.svg\" --ignore src/**/*.test.*",
34
+ "transpileES": "cross-env TS_NODE_PROJECT=tsconfig.es.json BABEL_ENV=es VOLEAPP_VERSION=$npm_package_version babel src --out-dir es --extensions \".js,.jsx,.ts,.tsx,.svg\" --ignore src/**/*.test.*",
37
35
  "build": "npm-run-all generateTypes postcss transpileES",
38
36
  "postcss": "postcss src/**/*.css --base src --dir es",
39
37
  "publish-patch": "npm version patch | xargs -I {} sh -c 'git push origin {}'",
40
38
  "postpublish-patch": "git push origin main",
41
39
  "prepare": "cross-env DEPLOYMENT_ENV=production npm run build",
42
- "predeploy": "cross-env DEPLOYMENT_ENV=production npm run dev",
40
+ "predeploy": "cross-env DEPLOYMENT_ENV=production npm run release-build",
43
41
  "deploy": "gh-pages -d imageviewer -t true",
44
42
  "checks": "npm run lint && npm run typeCheck && npm run test"
45
43
  },
46
44
  "author": "Allen Institute, Cell Science",
47
45
  "license": "BSD-3-Clause",
48
46
  "dependencies": {
49
- "@aics/vole-core": "^4.9.2",
47
+ "@aics/vole-core": "^4.10.1",
50
48
  "@ant-design/icons": "^5.2.5",
51
49
  "@fortawesome/fontawesome-svg-core": "^6.5.2",
52
50
  "@fortawesome/free-solid-svg-icons": "^6.5.2",
@@ -81,60 +79,44 @@
81
79
  "@trivago/prettier-plugin-sort-imports": "^4.3.0",
82
80
  "@types/color-string": "^1.5.2",
83
81
  "@types/d3": "^7.4.3",
84
- "@types/jest": "^29.5.14",
85
82
  "@types/lodash": "^4.14.185",
83
+ "@types/node": "^26.5.0",
86
84
  "@types/react": "^18.x",
87
85
  "@types/react-color": "^3.0.12",
88
86
  "@types/react-dom": "^18.x",
89
87
  "@types/three": "0.184.0",
90
- "@typescript-eslint/eslint-plugin": "^8.46.2",
91
- "@typescript-eslint/parser": "^8.46.2",
88
+ "@typescript-eslint/eslint-plugin": "^8.70.0",
89
+ "@typescript-eslint/parser": "^8.70.0",
90
+ "@vitejs/plugin-react": "^6.1.1",
92
91
  "antd": "^5.16.2",
93
- "axios": "^0.21.1",
94
- "babel-loader": "^8.2.2",
95
92
  "babel-plugin-replace-import-extension": "^1.1.3",
96
- "clean-webpack-plugin": "^4.0.0-alpha.0",
97
- "command-line-args": "^5.1.1",
98
- "copy-webpack-plugin": "^11.0.0",
93
+ "babel-plugin-transform-inline-environment-variables": "^0.4.4",
99
94
  "cross-env": "^7.0.3",
100
- "css-loader": "^6.2.0",
101
- "esbuild": "^0.14.50",
102
- "esbuild-jest": "^0.5.0",
95
+ "esbuild": "^0.28.2",
103
96
  "eslint": "^8.20.0",
97
+ "eslint-import-resolver-typescript": "^4.4.5",
98
+ "eslint-plugin-import": "^2.32.0",
104
99
  "eslint-plugin-react": "^7.37.5",
105
100
  "eslint-plugin-react-hooks": "^5.2.0",
106
- "file-loader": "^6.2.0",
107
- "firebase": "^7.x",
108
101
  "gh-pages": "^4.0.0",
109
- "html-webpack-plugin": "^5.3.2",
110
- "jest": "^29.7.0",
111
- "jest-environment-jsdom": "^30.2.0",
112
- "mini-css-extract-plugin": "^2.9.1",
113
- "morgan": "^1.9.1",
102
+ "jsdom": "^30.0.1",
114
103
  "npm-run-all": "^4.1.5",
115
- "postcss": "^8.4.47",
104
+ "postcss": "^8.5.26",
116
105
  "postcss-cli": "^11.0.0",
117
106
  "postcss-discard-comments": "^7.0.3",
118
107
  "postcss-extend-rule": "^4.0.0",
119
108
  "postcss-import": "^16.1.0",
120
- "postcss-loader": "^8.1.1",
121
- "postcss-mixins": "^11.0.3",
109
+ "postcss-mixins": "^12.1.2",
122
110
  "postcss-nested": "^6.2.0",
123
111
  "postcss-simple-vars": "^7.0.1",
124
112
  "postcss-url": "^10.1.3",
125
113
  "prettier": "^3.3.3",
126
- "prop-types": "^15.5.10",
127
114
  "react": "^18.3.1",
128
115
  "react-dom": "^18.3.1",
129
- "resolve-url-loader": "^5.0.0",
130
- "style-loader": "^4.0.0",
131
- "ts-jest": "^29.4.6",
132
116
  "typescript": "^5.9.3",
133
- "url-loader": "^4.1.1",
134
- "webpack": "^5.89.0",
135
- "webpack-cli": "^4.7.2",
136
- "webpack-dev-server": "^4.9.3",
137
- "webpack-merge": "^5.8.0",
138
- "webpack-shell-plugin": "^0.5.0"
117
+ "vite": "^8.2.2",
118
+ "vite-plugin-glsl": "^1.6.1",
119
+ "vite-plugin-svgr": "^5.2.0",
120
+ "vitest": "^4.1.11"
139
121
  }
140
122
  }
@@ -7,6 +7,9 @@ export type ChannelsWidgetProps = {
7
7
  channelDataChannels: Channel[] | undefined;
8
8
  channelGroupedByType: ChannelGrouping;
9
9
  viewerChannelSettings?: ViewerChannelSettings;
10
+ scrollContainer?: HTMLElement | null;
11
+ getDropdownContainer?: () => HTMLElement;
12
+ controlPanelCollapsed?: boolean;
10
13
  saveIsosurface: (channelIndex: number, type: IsosurfaceFormat) => void;
11
14
  onApplyColorPresets: (presets: ColorArray[]) => void;
12
15
  filterFunc?: (key: string) => boolean;
@@ -8,6 +8,9 @@ interface ChannelsWidgetRowProps {
8
8
  channelDataForChannel: Channel;
9
9
  saveIsosurface: (channelIndex: number, type: IsosurfaceFormat) => void;
10
10
  onColorChangeComplete?: (newRGB: ColorObject, oldRGB?: ColorObject, index?: number) => void;
11
+ getDropdownContainer?: () => HTMLElement;
12
+ scrollContainer?: HTMLElement | null;
13
+ controlPanelCollapsed?: boolean;
11
14
  }
12
15
  declare const ChannelsWidgetRow: React.FC<ChannelsWidgetRowProps>;
13
16
  export default ChannelsWidgetRow;
@@ -4,6 +4,8 @@ export type CopySettingsButtonProps = {
4
4
  scrollContainer?: HTMLElement | null;
5
5
  hide?: boolean;
6
6
  getDropdownContainer?: () => HTMLElement;
7
+ hideImportExport?: boolean;
8
+ channelIndex?: number;
7
9
  };
8
10
  declare const CopySettingsButton: React.FC<CopySettingsButtonProps>;
9
11
  export default CopySettingsButton;
@@ -12,6 +12,7 @@ type ViewerWrapperProps = {
12
12
  numSlicesLoaded: XYZ<number>;
13
13
  playControls: PlayControls;
14
14
  playingAxis: AxisName | "t" | null;
15
+ setScrubbingAxis: (axis: AxisName | "t" | null) => void;
15
16
  numTimesteps: number;
16
17
  numScenes: number;
17
18
  visibleControls: {
@@ -18,6 +18,7 @@ type AxisClipSlidersProps = {
18
18
  scene: number;
19
19
  playingAxis: AxisName | "t" | null;
20
20
  playControls: PlayControls;
21
+ setScrubbingAxis: (axis: AxisName | "t" | null) => void;
21
22
  };
22
23
  export declare const AxisClipSliders: React.FC<AxisClipSlidersProps>;
23
24
  export {};
@@ -17,9 +17,8 @@ type DimensionSliderRowProps = SharedSliderRowProps<number[]> & {
17
17
  unitSymbol?: string;
18
18
  };
19
19
  type IndexSliderRowProps = Omit<SharedSliderRowProps, "min">;
20
- type PlaySliderRowProps = Omit<SharedSliderRowProps, "valReadout" | "min" | "onSlide"> & {
20
+ type PlaySliderRowProps = Omit<SharedSliderRowProps, "valReadout" | "min"> & {
21
21
  playing: boolean;
22
- updateWhileSliding?: boolean;
23
22
  onTogglePlayback: (play: boolean) => void;
24
23
  };
25
24
  /** A single slider row, with a slider, one or two spinbox inputs, and a max value. */
@@ -6,6 +6,7 @@ export type ControlPanelRowProps = React.PropsWithChildren<ColorPickerPropPassth
6
6
  verticalMargin?: number;
7
7
  showColorPicker?: boolean;
8
8
  title?: React.ReactNode;
9
+ icon?: React.ReactNode;
9
10
  onClick?: React.MouseEventHandler;
10
11
  className?: string;
11
12
  highlight?: boolean;