@vitessce/vit-s 3.5.6 → 3.5.7

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 CHANGED
@@ -25125,6 +25125,291 @@ function createPrefixedGetNextScopeNumeric(prefix2) {
25125
25125
  function getInitialCoordinationScopePrefix(datasetUid, dataType) {
25126
25126
  return `init_${datasetUid}_${dataType}_`;
25127
25127
  }
25128
+ var loglevel = { exports: {} };
25129
+ (function(module2) {
25130
+ (function(root2, definition) {
25131
+ if (module2.exports) {
25132
+ module2.exports = definition();
25133
+ } else {
25134
+ root2.log = definition();
25135
+ }
25136
+ })(commonjsGlobal, function() {
25137
+ var noop3 = function() {
25138
+ };
25139
+ var undefinedType2 = "undefined";
25140
+ var isIE2 = typeof window !== undefinedType2 && typeof window.navigator !== undefinedType2 && /Trident\/|MSIE /.test(window.navigator.userAgent);
25141
+ var logMethods = [
25142
+ "trace",
25143
+ "debug",
25144
+ "info",
25145
+ "warn",
25146
+ "error"
25147
+ ];
25148
+ var _loggersByName = {};
25149
+ var defaultLogger2 = null;
25150
+ function bindMethod(obj, methodName) {
25151
+ var method = obj[methodName];
25152
+ if (typeof method.bind === "function") {
25153
+ return method.bind(obj);
25154
+ } else {
25155
+ try {
25156
+ return Function.prototype.bind.call(method, obj);
25157
+ } catch (e) {
25158
+ return function() {
25159
+ return Function.prototype.apply.apply(method, [obj, arguments]);
25160
+ };
25161
+ }
25162
+ }
25163
+ }
25164
+ function traceForIE() {
25165
+ if (console.log) {
25166
+ if (console.log.apply) {
25167
+ console.log.apply(console, arguments);
25168
+ } else {
25169
+ Function.prototype.apply.apply(console.log, [console, arguments]);
25170
+ }
25171
+ }
25172
+ if (console.trace)
25173
+ console.trace();
25174
+ }
25175
+ function realMethod(methodName) {
25176
+ if (methodName === "debug") {
25177
+ methodName = "log";
25178
+ }
25179
+ if (typeof console === undefinedType2) {
25180
+ return false;
25181
+ } else if (methodName === "trace" && isIE2) {
25182
+ return traceForIE;
25183
+ } else if (console[methodName] !== void 0) {
25184
+ return bindMethod(console, methodName);
25185
+ } else if (console.log !== void 0) {
25186
+ return bindMethod(console, "log");
25187
+ } else {
25188
+ return noop3;
25189
+ }
25190
+ }
25191
+ function replaceLoggingMethods() {
25192
+ var level = this.getLevel();
25193
+ for (var i = 0; i < logMethods.length; i++) {
25194
+ var methodName = logMethods[i];
25195
+ this[methodName] = i < level ? noop3 : this.methodFactory(methodName, level, this.name);
25196
+ }
25197
+ this.log = this.debug;
25198
+ if (typeof console === undefinedType2 && level < this.levels.SILENT) {
25199
+ return "No console available for logging";
25200
+ }
25201
+ }
25202
+ function enableLoggingWhenConsoleArrives(methodName) {
25203
+ return function() {
25204
+ if (typeof console !== undefinedType2) {
25205
+ replaceLoggingMethods.call(this);
25206
+ this[methodName].apply(this, arguments);
25207
+ }
25208
+ };
25209
+ }
25210
+ function defaultMethodFactory(methodName, _level, _loggerName) {
25211
+ return realMethod(methodName) || enableLoggingWhenConsoleArrives.apply(this, arguments);
25212
+ }
25213
+ function Logger(name, factory) {
25214
+ var self2 = this;
25215
+ var inheritedLevel;
25216
+ var defaultLevel;
25217
+ var userLevel;
25218
+ var storageKey = "loglevel";
25219
+ if (typeof name === "string") {
25220
+ storageKey += ":" + name;
25221
+ } else if (typeof name === "symbol") {
25222
+ storageKey = void 0;
25223
+ }
25224
+ function persistLevelIfPossible(levelNum) {
25225
+ var levelName = (logMethods[levelNum] || "silent").toUpperCase();
25226
+ if (typeof window === undefinedType2 || !storageKey)
25227
+ return;
25228
+ try {
25229
+ window.localStorage[storageKey] = levelName;
25230
+ return;
25231
+ } catch (ignore) {
25232
+ }
25233
+ try {
25234
+ window.document.cookie = encodeURIComponent(storageKey) + "=" + levelName + ";";
25235
+ } catch (ignore) {
25236
+ }
25237
+ }
25238
+ function getPersistedLevel() {
25239
+ var storedLevel;
25240
+ if (typeof window === undefinedType2 || !storageKey)
25241
+ return;
25242
+ try {
25243
+ storedLevel = window.localStorage[storageKey];
25244
+ } catch (ignore) {
25245
+ }
25246
+ if (typeof storedLevel === undefinedType2) {
25247
+ try {
25248
+ var cookie = window.document.cookie;
25249
+ var cookieName = encodeURIComponent(storageKey);
25250
+ var location = cookie.indexOf(cookieName + "=");
25251
+ if (location !== -1) {
25252
+ storedLevel = /^([^;]+)/.exec(
25253
+ cookie.slice(location + cookieName.length + 1)
25254
+ )[1];
25255
+ }
25256
+ } catch (ignore) {
25257
+ }
25258
+ }
25259
+ if (self2.levels[storedLevel] === void 0) {
25260
+ storedLevel = void 0;
25261
+ }
25262
+ return storedLevel;
25263
+ }
25264
+ function clearPersistedLevel() {
25265
+ if (typeof window === undefinedType2 || !storageKey)
25266
+ return;
25267
+ try {
25268
+ window.localStorage.removeItem(storageKey);
25269
+ } catch (ignore) {
25270
+ }
25271
+ try {
25272
+ window.document.cookie = encodeURIComponent(storageKey) + "=; expires=Thu, 01 Jan 1970 00:00:00 UTC";
25273
+ } catch (ignore) {
25274
+ }
25275
+ }
25276
+ function normalizeLevel(input) {
25277
+ var level = input;
25278
+ if (typeof level === "string" && self2.levels[level.toUpperCase()] !== void 0) {
25279
+ level = self2.levels[level.toUpperCase()];
25280
+ }
25281
+ if (typeof level === "number" && level >= 0 && level <= self2.levels.SILENT) {
25282
+ return level;
25283
+ } else {
25284
+ throw new TypeError("log.setLevel() called with invalid level: " + input);
25285
+ }
25286
+ }
25287
+ self2.name = name;
25288
+ self2.levels = {
25289
+ "TRACE": 0,
25290
+ "DEBUG": 1,
25291
+ "INFO": 2,
25292
+ "WARN": 3,
25293
+ "ERROR": 4,
25294
+ "SILENT": 5
25295
+ };
25296
+ self2.methodFactory = factory || defaultMethodFactory;
25297
+ self2.getLevel = function() {
25298
+ if (userLevel != null) {
25299
+ return userLevel;
25300
+ } else if (defaultLevel != null) {
25301
+ return defaultLevel;
25302
+ } else {
25303
+ return inheritedLevel;
25304
+ }
25305
+ };
25306
+ self2.setLevel = function(level, persist) {
25307
+ userLevel = normalizeLevel(level);
25308
+ if (persist !== false) {
25309
+ persistLevelIfPossible(userLevel);
25310
+ }
25311
+ return replaceLoggingMethods.call(self2);
25312
+ };
25313
+ self2.setDefaultLevel = function(level) {
25314
+ defaultLevel = normalizeLevel(level);
25315
+ if (!getPersistedLevel()) {
25316
+ self2.setLevel(level, false);
25317
+ }
25318
+ };
25319
+ self2.resetLevel = function() {
25320
+ userLevel = null;
25321
+ clearPersistedLevel();
25322
+ replaceLoggingMethods.call(self2);
25323
+ };
25324
+ self2.enableAll = function(persist) {
25325
+ self2.setLevel(self2.levels.TRACE, persist);
25326
+ };
25327
+ self2.disableAll = function(persist) {
25328
+ self2.setLevel(self2.levels.SILENT, persist);
25329
+ };
25330
+ self2.rebuild = function() {
25331
+ if (defaultLogger2 !== self2) {
25332
+ inheritedLevel = normalizeLevel(defaultLogger2.getLevel());
25333
+ }
25334
+ replaceLoggingMethods.call(self2);
25335
+ if (defaultLogger2 === self2) {
25336
+ for (var childName in _loggersByName) {
25337
+ _loggersByName[childName].rebuild();
25338
+ }
25339
+ }
25340
+ };
25341
+ inheritedLevel = normalizeLevel(
25342
+ defaultLogger2 ? defaultLogger2.getLevel() : "WARN"
25343
+ );
25344
+ var initialLevel = getPersistedLevel();
25345
+ if (initialLevel != null) {
25346
+ userLevel = normalizeLevel(initialLevel);
25347
+ }
25348
+ replaceLoggingMethods.call(self2);
25349
+ }
25350
+ defaultLogger2 = new Logger();
25351
+ defaultLogger2.getLogger = function getLogger(name) {
25352
+ if (typeof name !== "symbol" && typeof name !== "string" || name === "") {
25353
+ throw new TypeError("You must supply a name when creating a logger.");
25354
+ }
25355
+ var logger = _loggersByName[name];
25356
+ if (!logger) {
25357
+ logger = _loggersByName[name] = new Logger(
25358
+ name,
25359
+ defaultLogger2.methodFactory
25360
+ );
25361
+ }
25362
+ return logger;
25363
+ };
25364
+ var _log2 = typeof window !== undefinedType2 ? window.log : void 0;
25365
+ defaultLogger2.noConflict = function() {
25366
+ if (typeof window !== undefinedType2 && window.log === defaultLogger2) {
25367
+ window.log = _log2;
25368
+ }
25369
+ return defaultLogger2;
25370
+ };
25371
+ defaultLogger2.getLoggers = function getLoggers() {
25372
+ return _loggersByName;
25373
+ };
25374
+ defaultLogger2["default"] = defaultLogger2;
25375
+ return defaultLogger2;
25376
+ });
25377
+ })(loglevel);
25378
+ var loglevelExports = loglevel.exports;
25379
+ const log$3 = /* @__PURE__ */ getDefaultExportFromCjs(loglevelExports);
25380
+ const LogLevel = {
25381
+ SILENT: "silent",
25382
+ INFO: "info",
25383
+ WARN: "warn",
25384
+ ERROR: "error",
25385
+ DEBUG: "debug",
25386
+ TRACE: "trace"
25387
+ // default value
25388
+ };
25389
+ const OrderedLogLevels = [
25390
+ LogLevel.TRACE,
25391
+ LogLevel.DEBUG,
25392
+ LogLevel.INFO,
25393
+ LogLevel.WARN,
25394
+ LogLevel.ERROR
25395
+ ];
25396
+ const DEFAULT_DEBUG_MODE = false;
25397
+ const DEFAULT_LOG_LEVEL = LogLevel.TRACE;
25398
+ function getLogLevel() {
25399
+ return log$3.getLevel();
25400
+ }
25401
+ function setLogLevel(level) {
25402
+ if (Object.values(LogLevel).includes(level)) {
25403
+ log$3.setLevel(level);
25404
+ } else {
25405
+ log$3.warn("Log level is not valid");
25406
+ }
25407
+ }
25408
+ function atLeastLogLevel(someLevel) {
25409
+ const currLevel = getLogLevel();
25410
+ const numericTarget = OrderedLogLevels.indexOf(someLevel);
25411
+ return currLevel <= numericTarget;
25412
+ }
25128
25413
  configSchema1_0_0.shape.coordinationSpace.unwrap();
25129
25414
  configSchema1_0_0.shape.layout.element.shape.coordinationScopes.unwrap();
25130
25415
  function upgradeReplaceViewProp(prefix2, view, coordinationSpace) {
@@ -25542,7 +25827,7 @@ function upgradeFrom1_0_14(config2) {
25542
25827
  Object.entries(propAnalogies).forEach(([oldProp, newType]) => {
25543
25828
  var _a;
25544
25829
  if ((_a = viewDef.props) == null ? void 0 : _a[oldProp]) {
25545
- console.warn(`Warning: the '${oldProp}' prop on the ${viewDef.component} view is deprecated. Please use the '${newType}' coordination type instead.`);
25830
+ log$3.warn(`Warning: the '${oldProp}' prop on the ${viewDef.component} view is deprecated. Please use the '${newType}' coordination type instead.`);
25546
25831
  }
25547
25832
  });
25548
25833
  });
@@ -25565,7 +25850,7 @@ function upgradeFrom1_0_15(config2) {
25565
25850
  Object.entries(coordinationScopes).forEach(([coordinationType, coordinationScope]) => {
25566
25851
  if (!Array.isArray(coordinationScope) && typeof coordinationScope === "object") {
25567
25852
  if (coordinationType === "dataset") {
25568
- console.error("Expected coordinationScopes.dataset value to be either string or string[], but got object.");
25853
+ log$3.error("Expected coordinationScopes.dataset value to be either string or string[], but got object.");
25569
25854
  }
25570
25855
  coordinationScopesBy.dataset[coordinationType] = coordinationScope;
25571
25856
  } else if (Array.isArray(coordinationScope) || typeof coordinationScope === "string") {
@@ -27778,7 +28063,8 @@ const ViewType$1 = {
27778
28063
  FEATURE_BAR_PLOT: "featureBarPlot",
27779
28064
  BIOMARKER_SELECT: "biomarkerSelect",
27780
28065
  LINK_CONTROLLER: "linkController",
27781
- DUAL_SCATTERPLOT: "dualScatterplot"
28066
+ DUAL_SCATTERPLOT: "dualScatterplot",
28067
+ TREEMAP: "treemap"
27782
28068
  };
27783
28069
  const DataType$1 = {
27784
28070
  OBS_LABELS: "obsLabels",
@@ -27854,6 +28140,7 @@ const FileType$1 = {
27854
28140
  OBS_LABELS_ANNDATA_ZARR: "obsLabels.anndata.zarr",
27855
28141
  FEATURE_LABELS_ANNDATA_ZARR: "featureLabels.anndata.zarr",
27856
28142
  SAMPLE_EDGES_ANNDATA_ZARR: "sampleEdges.anndata.zarr",
28143
+ SAMPLE_SETS_ANNDATA_ZARR: "sampleSets.anndata.zarr",
27857
28144
  // AnnData - zipped
27858
28145
  OBS_FEATURE_MATRIX_ANNDATA_ZARR_ZIP: "obsFeatureMatrix.anndata.zarr.zip",
27859
28146
  OBS_FEATURE_COLUMNS_ANNDATA_ZARR_ZIP: "obsFeatureColumns.anndata.zarr.zip",
@@ -27866,6 +28153,7 @@ const FileType$1 = {
27866
28153
  OBS_LABELS_ANNDATA_ZARR_ZIP: "obsLabels.anndata.zarr.zip",
27867
28154
  FEATURE_LABELS_ANNDATA_ZARR_ZIP: "featureLabels.anndata.zarr.zip",
27868
28155
  SAMPLE_EDGES_ANNDATA_ZARR_ZIP: "sampleEdges.anndata.zarr.zip",
28156
+ SAMPLE_SETS_ANNDATA_ZARR_ZIP: "sampleSets.anndata.zarr.zip",
27869
28157
  // AnnData - h5ad via reference spec
27870
28158
  OBS_FEATURE_MATRIX_ANNDATA_H5AD: "obsFeatureMatrix.anndata.h5ad",
27871
28159
  OBS_FEATURE_COLUMNS_ANNDATA_H5AD: "obsFeatureColumns.anndata.h5ad",
@@ -27878,6 +28166,7 @@ const FileType$1 = {
27878
28166
  OBS_LABELS_ANNDATA_H5AD: "obsLabels.anndata.h5ad",
27879
28167
  FEATURE_LABELS_ANNDATA_H5AD: "featureLabels.anndata.h5ad",
27880
28168
  SAMPLE_EDGES_ANNDATA_H5AD: "sampleEdges.anndata.h5ad",
28169
+ SAMPLE_SETS_ANNDATA_H5AD: "sampleSets.anndata.h5ad",
27881
28170
  // SpatialData
27882
28171
  IMAGE_SPATIALDATA_ZARR: "image.spatialdata.zarr",
27883
28172
  LABELS_SPATIALDATA_ZARR: "labels.spatialdata.zarr",
@@ -28069,12 +28358,15 @@ const CoordinationType$1 = {
28069
28358
  SAMPLE_SET_FILTER: "sampleSetFilter",
28070
28359
  SAMPLE_FILTER_MODE: "sampleFilterMode",
28071
28360
  SAMPLE_SET_COLOR: "sampleSetColor",
28361
+ SAMPLE_HIGHLIGHT: "sampleHighlight",
28072
28362
  EMBEDDING_POINTS_VISIBLE: "embeddingPointsVisible",
28073
28363
  EMBEDDING_CONTOURS_VISIBLE: "embeddingContoursVisible",
28074
28364
  EMBEDDING_CONTOURS_FILLED: "embeddingContoursFilled",
28075
28365
  EMBEDDING_CONTOUR_PERCENTILES: "embeddingContourPercentiles",
28076
28366
  CONTOUR_COLOR_ENCODING: "contourColorEncoding",
28077
- CONTOUR_COLOR: "contourColor"
28367
+ CONTOUR_COLOR: "contourColor",
28368
+ // Treemap
28369
+ HIERARCHY_LEVELS: "hierarchyLevels"
28078
28370
  };
28079
28371
  const STATUS = {
28080
28372
  LOADING: "loading",
@@ -28143,10 +28435,10 @@ const AUTO_INDEPENDENT_COORDINATION_TYPES = [
28143
28435
  CoordinationType$1.EMBEDDING_OBS_OPACITY
28144
28436
  ];
28145
28437
  const note = "This file is autogenerated by .changeset/post-changelog.mjs.";
28146
- const version = "3.5.6";
28147
- const date = "2025-01-29";
28438
+ const version = "3.5.7";
28439
+ const date = "2025-02-19";
28148
28440
  const branch = "changeset-release/main";
28149
- const hash = "c8eedf07";
28441
+ const hash = "a4bc3a6a";
28150
28442
  const META_VERSION = {
28151
28443
  note,
28152
28444
  version,
@@ -28320,7 +28612,7 @@ function makeConstantWithDeprecationMessage(currObj, oldObj) {
28320
28612
  const oldKeys = Object.keys(oldObj);
28321
28613
  const propKey = String(prop);
28322
28614
  if (oldKeys.includes(propKey)) {
28323
- console.warn(`Notice about the constant mapping ${propKey}: '${oldObj[propKey][0]}':
28615
+ log$3.warn(`Notice about the constant mapping ${propKey}: '${oldObj[propKey][0]}':
28324
28616
  ${oldObj[propKey][1]}`);
28325
28617
  return oldObj[propKey];
28326
28618
  }
@@ -28489,6 +28781,9 @@ const annDataObsSetsArr = z.array(z.object({
28489
28781
  z.object({
28490
28782
  obsSets: annDataObsSetsArr
28491
28783
  });
28784
+ z.object({
28785
+ sampleSets: annDataObsSetsArr
28786
+ });
28492
28787
  const annDataObsFeatureColumnsArr = z.array(z.object({
28493
28788
  path: z.string()
28494
28789
  }));
@@ -36896,14 +37191,11 @@ class LoaderNotFoundError extends AbstractLoaderError {
36896
37191
  this.dataset = dataset;
36897
37192
  this.fileType = fileType;
36898
37193
  this.viewCoordinationValues = viewCoordinationValues;
37194
+ this.message = `Expected to match on { ${Object.entries(viewCoordinationValues || {}).map(([k, v]) => `${k}: ${v ?? "null"}`).join(", ")} }`;
36899
37195
  }
36900
37196
  warnInConsole() {
36901
- const { loaders, viewCoordinationValues } = this;
36902
- console.warn(
36903
- // eslint-disable-next-line prefer-template
36904
- `Expected to match on { ${Object.entries(viewCoordinationValues).map(([k, v]) => k + ": " + v).join(", ")} }`,
36905
- loaders
36906
- );
37197
+ const { loaders, message } = this;
37198
+ log$3.warn(message, loaders);
36907
37199
  }
36908
37200
  }
36909
37201
  function getSourceAndLoaderFromFileType(type3, fileTypes) {
@@ -36980,7 +37272,7 @@ function withDefaults(coordinationValues, dataType, fileType, datasetUid, defaul
36980
37272
  ...coordinationValues
36981
37273
  };
36982
37274
  if (!isEqual$1(coordinationValues, coordinationValuesWithDefaults)) {
36983
- console.warn(`Using coordination value defaults for file type ${fileType} in dataset ${datasetUid}
37275
+ log$3.warn(`Using coordination value defaults for file type ${fileType} in dataset ${datasetUid}
36984
37276
  Before: ${JSON.stringify(coordinationValues)}
36985
37277
  After: ${JSON.stringify(coordinationValuesWithDefaults)}`);
36986
37278
  }
@@ -37763,11 +38055,33 @@ function Warning(props) {
37763
38055
  /* @__PURE__ */ jsxRuntimeExports.jsx("p", { children: unformatted })
37764
38056
  ] }) }) }) });
37765
38057
  }
38058
+ function DebugWindow({ debugErrors }) {
38059
+ const classes = useStyles$4();
38060
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: VITESSCE_CONTAINER, children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: clsx(classes.warningLayout, classes.containerFluid), children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: classes.row, children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: classes.warningCard, children: debugErrors.map((error, index) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
38061
+ index === 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
38062
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("h1", { children: [
38063
+ "Error Type: ",
38064
+ error.name
38065
+ ] }),
38066
+ Object.keys(error).map(
38067
+ (key) => key !== "name" && key !== "message" && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [
38068
+ key.charAt(0).toUpperCase() + key.slice(1),
38069
+ ": ",
38070
+ error[key]
38071
+ ] }, key)
38072
+ )
38073
+ ] }),
38074
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [
38075
+ "Error: ",
38076
+ error.message
38077
+ ] })
38078
+ ] }, error.message || index)) }) }) }) });
38079
+ }
37766
38080
  function validateViewConfig(viewConfig, pluginSpecificConfigSchema) {
37767
38081
  try {
37768
38082
  pluginSpecificConfigSchema.parse(viewConfig);
37769
38083
  } catch (e) {
37770
- console.error(e);
38084
+ log$3.error(e);
37771
38085
  }
37772
38086
  }
37773
38087
  function CallbackPublisher(props) {
@@ -37808,10 +38122,12 @@ function CallbackPublisher(props) {
37808
38122
  return null;
37809
38123
  }
37810
38124
  function logConfig(config2, name) {
37811
- console.groupCollapsed(`🚄 VitS (${META_VERSION.version}) ${name}`);
37812
- console.info(`data:,${JSON.stringify(config2)}`);
37813
- console.info(JSON.stringify(config2, null, 2));
37814
- console.groupEnd();
38125
+ if (atLeastLogLevel(LogLevel.INFO)) {
38126
+ console.groupCollapsed(`🚄 VitS (${META_VERSION.version}) ${name}`);
38127
+ console.info(`data:,${JSON.stringify(config2)}`);
38128
+ console.info(JSON.stringify(config2, null, 2));
38129
+ console.groupEnd();
38130
+ }
37815
38131
  }
37816
38132
  function getExistingScopesForCoordinationType(config2, coordinationType) {
37817
38133
  var _a;
@@ -38038,8 +38354,11 @@ function VitS(props) {
38038
38354
  asyncFunctions: asyncFunctionsProp,
38039
38355
  warning: warning2,
38040
38356
  pageMode = false,
38041
- children: children2
38357
+ children: children2,
38358
+ debugMode = DEFAULT_DEBUG_MODE,
38359
+ logLevel = DEFAULT_LOG_LEVEL
38042
38360
  } = props;
38361
+ const [debugErrors, setDebugErrors] = useState([]);
38043
38362
  const viewTypes = useMemo(() => viewTypesProp || [], [viewTypesProp]);
38044
38363
  const fileTypes = useMemo(() => fileTypesProp || [], [fileTypesProp]);
38045
38364
  const jointFileTypes = useMemo(
@@ -38051,6 +38370,11 @@ function VitS(props) {
38051
38370
  [coordinationTypesProp]
38052
38371
  );
38053
38372
  const generateClassName2 = useMemo(() => createGenerateClassName(uid), [uid]);
38373
+ useLayoutEffect(() => {
38374
+ setLogLevel(logLevel);
38375
+ }, [logLevel]);
38376
+ useLayoutEffect(() => {
38377
+ }, [debugMode]);
38054
38378
  const configVersion = config2 == null ? void 0 : config2.version;
38055
38379
  const configKey = useMemo(() => {
38056
38380
  if (config2 == null ? void 0 : config2.uid) {
@@ -38151,6 +38475,9 @@ function VitS(props) {
38151
38475
  }
38152
38476
  return createViewConfigStore(null, null);
38153
38477
  }, [success, configKey]);
38478
+ if (debugMode && debugErrors.length > 0) {
38479
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(StylesProvider, { generateClassName: generateClassName2, children: /* @__PURE__ */ jsxRuntimeExports.jsx(ThemeProvider, { theme: muiTheme[theme], children: /* @__PURE__ */ jsxRuntimeExports.jsx(DebugWindow, { debugErrors }) }) });
38480
+ }
38154
38481
  return success ? /* @__PURE__ */ jsxRuntimeExports.jsx(StylesProvider, { generateClassName: generateClassName2, children: /* @__PURE__ */ jsxRuntimeExports.jsx(ThemeProvider, { theme: muiTheme[theme], children: /* @__PURE__ */ jsxRuntimeExports.jsx(QueryClientProvider, { client: queryClient, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
38155
38482
  ViewConfigProvider,
38156
38483
  {
@@ -38501,8 +38828,8 @@ function TitleInfo(props) {
38501
38828
  }
38502
38829
  function warn(error, setWarning) {
38503
38830
  setWarning(error.message);
38504
- console.warn(error.message);
38505
- console.error(error.stack);
38831
+ log$3.warn(error.message);
38832
+ log$3.error(error.stack);
38506
38833
  if (error instanceof AbstractLoaderError) {
38507
38834
  error.warnInConsole();
38508
38835
  }
@@ -1,4 +1,5 @@
1
1
  import { useEffect } from 'react';
2
+ import { log } from '@vitessce/globals';
2
3
  import { useViewConfigStoreApi, useLoaders, useWarning } from './state/hooks.js';
3
4
  function validateViewConfig(viewConfig, pluginSpecificConfigSchema) {
4
5
  // Need the try-catch here since Zustand will actually
@@ -7,7 +8,7 @@ function validateViewConfig(viewConfig, pluginSpecificConfigSchema) {
7
8
  pluginSpecificConfigSchema.parse(viewConfig);
8
9
  }
9
10
  catch (e) {
10
- console.error(e);
11
+ log.error(e);
11
12
  }
12
13
  // Do nothing if successful.
13
14
  }
@@ -0,0 +1,4 @@
1
+ export function DebugWindow({ debugErrors }: {
2
+ debugErrors: any;
3
+ }): import("react").JSX.Element;
4
+ //# sourceMappingURL=DebugWindow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DebugWindow.d.ts","sourceRoot":"","sources":["../src/DebugWindow.js"],"names":[],"mappings":"AAIA;;gCA8BC"}
@@ -0,0 +1,9 @@
1
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
+ import clsx from 'clsx';
3
+ import { useStyles } from './shared-warning-styles.js';
4
+ import { VITESSCE_CONTAINER } from './classNames.js';
5
+ export function DebugWindow({ debugErrors }) {
6
+ const classes = useStyles();
7
+ return (_jsx("div", { className: VITESSCE_CONTAINER, children: _jsx("div", { className: clsx(classes.warningLayout, classes.containerFluid), children: _jsx("div", { className: classes.row, children: _jsx("div", { className: classes.warningCard, children: debugErrors.map((error, index) => (_jsxs("div", { children: [index === 0 && (_jsxs("div", { children: [_jsxs("h1", { children: ["Error Type: ", error.name] }), Object.keys(error).map(key => key !== 'name'
8
+ && key !== 'message' && (_jsxs("p", { children: [key.charAt(0).toUpperCase() + key.slice(1), ": ", error[key]] }, key)))] })), _jsxs("p", { children: ["Error: ", error.message] })] }, error.message || index))) }) }) }) }));
9
+ }
@@ -31,6 +31,8 @@
31
31
  * @param {array} props.coordinationTypes Plugin coordination types.
32
32
  * @param {null|object} props.warning A warning to render within the Vitessce grid,
33
33
  * @param {boolean} props.pageMode Whether to render in page mode. By default, false.
34
+ * @param {boolean} props.debugMode Whether to display the debugWindow. By default, false.
35
+ * @param {null|string} props.logLevel To set the log level in the console.
34
36
  * provided by the parent.
35
37
  */
36
38
  export function VitS(props: {
@@ -51,5 +53,7 @@ export function VitS(props: {
51
53
  coordinationTypes: array;
52
54
  warning: null | object;
53
55
  pageMode: boolean;
56
+ debugMode: boolean;
57
+ logLevel: null | string;
54
58
  }): JSX.Element;
55
59
  //# sourceMappingURL=VitS.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"VitS.d.ts","sourceRoot":"","sources":["../src/VitS.js"],"names":[],"mappings":"AA+BA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,4BAhCG;IAAsB,MAAM,EAApB,MAAM;IAGkB,SAAS,EAAjC,SAAS,GAAC,MAAM;IACF,MAAM,EAApB,MAAM;IACQ,KAAK,EAAnB,MAAM;IAEU,MAAM;IACN,cAAc;IAEd,cAAc;IAEf,cAAc,EAA7B,OAAO;IAIQ,sBAAsB,EAArC,OAAO;IAGY,GAAG,EAAtB,IAAI,GAAC,MAAM;IAGI,kBAAkB,EAAjC,OAAO;IAEM,SAAS,EAAtB,KAAK;IACQ,SAAS,EAAtB,KAAK;IACQ,cAAc,EAA3B,KAAK;IACQ,iBAAiB,EAA9B,KAAK;IACc,OAAO,EAA1B,IAAI,GAAC,MAAM;IACI,QAAQ,EAAvB,OAAO;CAEjB,eAqNA"}
1
+ {"version":3,"file":"VitS.d.ts","sourceRoot":"","sources":["../src/VitS.js"],"names":[],"mappings":"AAoCA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,4BAlCG;IAAsB,MAAM,EAApB,MAAM;IAGkB,SAAS,EAAjC,SAAS,GAAC,MAAM;IACF,MAAM,EAApB,MAAM;IACQ,KAAK,EAAnB,MAAM;IAEU,MAAM;IACN,cAAc;IAEd,cAAc;IAEf,cAAc,EAA7B,OAAO;IAIQ,sBAAsB,EAArC,OAAO;IAGY,GAAG,EAAtB,IAAI,GAAC,MAAM;IAGI,kBAAkB,EAAjC,OAAO;IAEM,SAAS,EAAtB,KAAK;IACQ,SAAS,EAAtB,KAAK;IACQ,cAAc,EAA3B,KAAK;IACQ,iBAAiB,EAA9B,KAAK;IACc,OAAO,EAA1B,IAAI,GAAC,MAAM;IACI,QAAQ,EAAvB,OAAO;IACQ,SAAS,EAAxB,OAAO;IACY,QAAQ,EAA3B,IAAI,GAAC,MAAM;CAErB,eA2OA"}
package/dist-tsc/VitS.js CHANGED
@@ -1,13 +1,15 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import React, { useEffect, useMemo, useCallback } from 'react';
2
+ import React, { useState, useEffect, useMemo, useCallback, useLayoutEffect } from 'react';
3
3
  import { ThemeProvider, StylesProvider, } from '@material-ui/core';
4
4
  import { QueryClient, QueryClientProvider, } from '@tanstack/react-query';
5
5
  import { isEqual } from 'lodash-es';
6
6
  import { buildConfigSchema, latestConfigSchema } from '@vitessce/schemas';
7
+ import { setLogLevel, setDebugMode, DEFAULT_LOG_LEVEL, DEFAULT_DEBUG_MODE, } from '@vitessce/globals';
7
8
  import { muiTheme } from './shared-mui/styles.js';
8
9
  import { ViewConfigProvider, createViewConfigStore, AuxiliaryProvider, createAuxiliaryStore, } from './state/hooks.js';
9
10
  import VitessceGrid from './VitessceGrid.js';
10
11
  import { Warning } from './Warning.js';
12
+ import { DebugWindow } from './DebugWindow.js';
11
13
  import CallbackPublisher from './CallbackPublisher.js';
12
14
  import { initialize, logConfig, } from './view-config-utils.js';
13
15
  import { createLoaders } from './vitessce-grid-utils.js';
@@ -46,15 +48,26 @@ import { AsyncFunctionsContext } from './contexts.js';
46
48
  * @param {array} props.coordinationTypes Plugin coordination types.
47
49
  * @param {null|object} props.warning A warning to render within the Vitessce grid,
48
50
  * @param {boolean} props.pageMode Whether to render in page mode. By default, false.
51
+ * @param {boolean} props.debugMode Whether to display the debugWindow. By default, false.
52
+ * @param {null|string} props.logLevel To set the log level in the console.
49
53
  * provided by the parent.
50
54
  */
51
55
  export function VitS(props) {
52
- const { config, stores, rowHeight, height, theme, onWarn, onConfigChange, onLoaderChange, validateConfig = true, validateOnConfigChange = false, isBounded = false, uid = null, remountOnUidChange = true, viewTypes: viewTypesProp, fileTypes: fileTypesProp, jointFileTypes: jointFileTypesProp, coordinationTypes: coordinationTypesProp, asyncFunctions: asyncFunctionsProp, warning, pageMode = false, children, } = props;
56
+ const { config, stores, rowHeight, height, theme, onWarn, onConfigChange, onLoaderChange, validateConfig = true, validateOnConfigChange = false, isBounded = false, uid = null, remountOnUidChange = true, viewTypes: viewTypesProp, fileTypes: fileTypesProp, jointFileTypes: jointFileTypesProp, coordinationTypes: coordinationTypesProp, asyncFunctions: asyncFunctionsProp, warning, pageMode = false, children, debugMode = DEFAULT_DEBUG_MODE, logLevel = DEFAULT_LOG_LEVEL, } = props;
57
+ // eslint-disable-next-line no-unused-vars
58
+ const [debugErrors, setDebugErrors] = useState([]);
53
59
  const viewTypes = useMemo(() => (viewTypesProp || []), [viewTypesProp]);
54
60
  const fileTypes = useMemo(() => (fileTypesProp || []), [fileTypesProp]);
55
61
  const jointFileTypes = useMemo(() => (jointFileTypesProp || []), [jointFileTypesProp]);
56
62
  const coordinationTypes = useMemo(() => (coordinationTypesProp || []), [coordinationTypesProp]);
57
63
  const generateClassName = useMemo(() => createGenerateClassName(uid), [uid]);
64
+ // Set error handling-related globals.
65
+ useLayoutEffect(() => {
66
+ setLogLevel(logLevel);
67
+ }, [logLevel]);
68
+ useLayoutEffect(() => {
69
+ setDebugMode(debugMode);
70
+ }, [debugMode]);
58
71
  const configVersion = config?.version;
59
72
  // If config.uid exists, then use it for hook dependencies to detect changes
60
73
  // (controlled component case). If not, then use the config object itself
@@ -156,5 +169,11 @@ export function VitS(props) {
156
169
  return createViewConfigStore(null, null);
157
170
  // eslint-disable-next-line react-hooks/exhaustive-deps
158
171
  }, [success, configKey]);
172
+ // TODO: use in ErrorBoundary fallback.
173
+ // Will probably need to move a lot to a child of VitS
174
+ // so that when the child throws errors the parent can catch.
175
+ if (debugMode && debugErrors.length > 0) {
176
+ return (_jsx(StylesProvider, { generateClassName: generateClassName, children: _jsx(ThemeProvider, { theme: muiTheme[theme], children: _jsx(DebugWindow, { debugErrors: debugErrors }) }) }));
177
+ }
159
178
  return success ? (_jsx(StylesProvider, { generateClassName: generateClassName, children: _jsx(ThemeProvider, { theme: muiTheme[theme], children: _jsx(QueryClientProvider, { client: queryClient, children: _jsx(ViewConfigProvider, { createStore: createViewConfigStoreClosure, ...(remountOnUidChange ? ({ key: configKey }) : {}), children: _jsx(AuxiliaryProvider, { createStore: createAuxiliaryStore, children: _jsxs(AsyncFunctionsContext.Provider, { value: asyncFunctions, children: [_jsx(VitessceGrid, { pageMode: pageMode, success: success, configKey: configKey, viewTypes: viewTypes, fileTypes: fileTypes, coordinationTypes: coordinationTypes, config: configOrWarning, rowHeight: rowHeight, height: height, theme: theme, isBounded: isBounded, stores: stores, children: children }), _jsx(CallbackPublisher, { onWarn: onWarn, onConfigChange: onConfigChange, onLoaderChange: onLoaderChange, validateOnConfigChange: validateOnConfigChange, pluginSpecificConfigSchema: pluginSpecificConfigSchema })] }) }) }) }) }) })) : (_jsx(StylesProvider, { generateClassName: generateClassName, children: _jsx(ThemeProvider, { theme: muiTheme[theme], children: _jsx(Warning, { ...configOrWarning }) }) }));
160
179
  }
@@ -1 +1 @@
1
- {"version":3,"file":"Warning.d.ts","sourceRoot":"","sources":["../src/Warning.js"],"names":[],"mappings":"AAyCA,iEAoBC"}
1
+ {"version":3,"file":"Warning.d.ts","sourceRoot":"","sources":["../src/Warning.js"],"names":[],"mappings":"AAIA,iEAoBC"}
@@ -1,43 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import clsx from 'clsx';
3
- import { makeStyles } from '@material-ui/core';
3
+ import { useStyles } from './shared-warning-styles.js';
4
4
  import { VITESSCE_CONTAINER } from './classNames.js';
5
- const useStyles = makeStyles(theme => ({
6
- warningLayout: {
7
- backgroundColor: theme.palette.gridLayoutBackground,
8
- position: 'absolute',
9
- width: '100%',
10
- height: '100vh',
11
- },
12
- containerFluid: {
13
- width: '100%',
14
- padding: '15px',
15
- marginRight: 'auto',
16
- marginLeft: 'auto',
17
- boxSizing: 'border-box',
18
- display: 'flex',
19
- },
20
- row: {
21
- flexGrow: '1',
22
- },
23
- warningCard: {
24
- border: `1px solid ${theme.palette.cardBorder}`,
25
- flex: '1 1 auto',
26
- minHeight: '1px',
27
- padding: '12px',
28
- marginTop: '8px',
29
- marginBottom: '8px',
30
- position: 'relative',
31
- display: 'flex',
32
- flexDirection: 'column',
33
- minWidth: '0',
34
- wordWrap: 'break-word',
35
- backgroundClip: 'border-box',
36
- borderRadius: '4px',
37
- backgroundColor: theme.palette.primaryBackground,
38
- color: theme.palette.primaryForeground,
39
- },
40
- }));
41
5
  export function Warning(props) {
42
6
  const { title, preformatted, unformatted, } = props;
43
7
  const classes = useStyles();
@@ -1 +1 @@
1
- {"version":3,"file":"data-hook-utils.d.ts","sourceRoot":"","sources":["../src/data-hook-utils.js"],"names":[],"mappings":"AAiBA;;;;GAIG;AACH,4BAFW,mBAAmB,yBAS7B;AAED;;;;;;;;;;GAUG;AACH,8CATW,MAAM,WAGN,MAAM,iBAGN,MAAM,QAiBhB;AAGD,oDAuBC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,oDAhBW,MAAM,WAEN,MAAM,cAEN,OAAO,uBAEP,MAAM,6BAGN,MAAM,iBAGJ,KAAK,CAiDjB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,yDAhBW,MAAM,WAEN,MAAM,cAEN,OAAO,uBAEP,MAAM,6BAGN,MAAM,0DAGJ,KAAK,CAsFjB;AAED,+FAGC;oCA1PM,oBAAoB"}
1
+ {"version":3,"file":"data-hook-utils.d.ts","sourceRoot":"","sources":["../src/data-hook-utils.js"],"names":[],"mappings":"AAkBA;;;;GAIG;AACH,4BAFW,mBAAmB,yBAS7B;AAED;;;;;;;;;;GAUG;AACH,8CATW,MAAM,WAGN,MAAM,iBAGN,MAAM,QAiBhB;AAGD,oDAuBC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,oDAhBW,MAAM,WAEN,MAAM,cAEN,OAAO,uBAEP,MAAM,6BAGN,MAAM,iBAGJ,KAAK,CAiDjB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,yDAhBW,MAAM,WAEN,MAAM,cAEN,OAAO,uBAEP,MAAM,6BAGN,MAAM,0DAGJ,KAAK,CAsFjB;AAED,+FAGC;oCA1PM,oBAAoB"}
@@ -1,6 +1,7 @@
1
1
  import { useEffect, useMemo } from 'react';
2
2
  import { useQuery, useQueries } from '@tanstack/react-query';
3
3
  import { capitalize, getInitialCoordinationScopePrefix, } from '@vitessce/utils';
4
+ import { log } from '@vitessce/globals';
4
5
  import { STATUS } from '@vitessce/constants-internal';
5
6
  import { AbstractLoaderError, LoaderNotFoundError, } from '@vitessce/abstract';
6
7
  import { getMatchingLoader, useMatchingLoader, useSetWarning, } from './state/hooks.js';
@@ -11,8 +12,8 @@ import { getMatchingLoader, useMatchingLoader, useSetWarning, } from './state/ho
11
12
  */
12
13
  export function warn(error, setWarning) {
13
14
  setWarning(error.message);
14
- console.warn(error.message);
15
- console.error(error.stack);
15
+ log.warn(error.message);
16
+ log.error(error.stack);
16
17
  if (error instanceof AbstractLoaderError) {
17
18
  error.warnInConsole();
18
19
  }
package/dist-tsc/hooks.js CHANGED
@@ -4,8 +4,8 @@ import { extent } from 'd3-array';
4
4
  import { useQuery } from '@tanstack/react-query';
5
5
  import { capitalize } from '@vitessce/utils';
6
6
  import { STATUS, AsyncFunctionType } from '@vitessce/constants-internal';
7
- import { useGridResize, useEmitGridResize } from './state/hooks.js';
8
7
  import { VITESSCE_CONTAINER } from './classNames.js';
8
+ import { useGridResize, useEmitGridResize } from './state/hooks.js';
9
9
  import { useAsyncFunction } from './contexts.js';
10
10
  function getWindowDimensions() {
11
11
  const { innerWidth: width, innerHeight: height } = window;
@@ -0,0 +1,2 @@
1
+ export const useStyles: (props?: any) => import("@material-ui/core/styles/withStyles").ClassNameMap<never>;
2
+ //# sourceMappingURL=shared-warning-styles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared-warning-styles.d.ts","sourceRoot":"","sources":["../src/shared-warning-styles.js"],"names":[],"mappings":"AAEA,2GAmCI"}
@@ -0,0 +1,37 @@
1
+ import { makeStyles } from '@material-ui/core';
2
+ export const useStyles = makeStyles(theme => ({
3
+ warningLayout: {
4
+ backgroundColor: theme.palette.gridLayoutBackground,
5
+ position: 'absolute',
6
+ width: '100%',
7
+ height: '100vh',
8
+ },
9
+ containerFluid: {
10
+ width: '100%',
11
+ padding: '15px',
12
+ marginRight: 'auto',
13
+ marginLeft: 'auto',
14
+ boxSizing: 'border-box',
15
+ display: 'flex',
16
+ },
17
+ row: {
18
+ flexGrow: '1',
19
+ },
20
+ warningCard: {
21
+ border: `1px solid ${theme.palette.cardBorder}`,
22
+ flex: '1 1 auto',
23
+ minHeight: '1px',
24
+ padding: '12px',
25
+ marginTop: '8px',
26
+ marginBottom: '8px',
27
+ position: 'relative',
28
+ display: 'flex',
29
+ flexDirection: 'column',
30
+ minWidth: '0',
31
+ wordWrap: 'break-word',
32
+ backgroundClip: 'border-box',
33
+ borderRadius: '4px',
34
+ backgroundColor: theme.palette.primaryBackground,
35
+ color: theme.palette.primaryForeground,
36
+ },
37
+ }));
@@ -1 +1 @@
1
- {"version":3,"file":"view-config-utils.d.ts","sourceRoot":"","sources":["../src/view-config-utils.js"],"names":[],"mappings":"AASA,wDAKC;AAED;;;;;;;;GAQG;AACH,6DALW,MAAM,oBACN,MAAM,GAEJ,MAAM,EAAE,CAMpB;AAyND;;;;;;;;;;;;;;GAcG;AACH,mCANW,MAAM,kBACN,mBAAmB,EAAE,qBACrB,sBAAsB,EAAE,aACxB,cAAc,EAAE;;;EAY1B"}
1
+ {"version":3,"file":"view-config-utils.d.ts","sourceRoot":"","sources":["../src/view-config-utils.js"],"names":[],"mappings":"AAUA,wDAOC;AAED;;;;;;;;GAQG;AACH,6DALW,MAAM,oBACN,MAAM,GAEJ,MAAM,EAAE,CAMpB;AAyND;;;;;;;;;;;;;;GAcG;AACH,mCANW,MAAM,kBACN,mBAAmB,EAAE,qBACrB,sBAAsB,EAAE,aACxB,cAAc,EAAE;;;EAY1B"}
@@ -2,12 +2,15 @@
2
2
  /* eslint-disable camelcase */
3
3
  import { cloneDeep } from 'lodash-es';
4
4
  import { getNextScope } from '@vitessce/utils';
5
+ import { atLeastLogLevel, LogLevel } from '@vitessce/globals';
5
6
  import { AUTO_INDEPENDENT_COORDINATION_TYPES, META_VERSION, } from '@vitessce/constants-internal';
6
7
  export function logConfig(config, name) {
7
- console.groupCollapsed(`🚄 VitS (${META_VERSION.version}) ${name}`);
8
- console.info(`data:,${JSON.stringify(config)}`);
9
- console.info(JSON.stringify(config, null, 2));
10
- console.groupEnd();
8
+ if (atLeastLogLevel(LogLevel.INFO)) {
9
+ console.groupCollapsed(`🚄 VitS (${META_VERSION.version}) ${name}`);
10
+ console.info(`data:,${JSON.stringify(config)}`);
11
+ console.info(JSON.stringify(config, null, 2));
12
+ console.groupEnd();
13
+ }
11
14
  }
12
15
  /**
13
16
  * Get a list of all unique scope names for a
@@ -3,6 +3,7 @@ import { InternMap } from 'internmap';
3
3
  import { isEqual, pick } from 'lodash-es';
4
4
  import { DATA_TYPE_COORDINATION_VALUE_USAGE } from '@vitessce/constants-internal';
5
5
  import { getSourceAndLoaderFromFileType, getDataTypeFromFileType } from '@vitessce/abstract';
6
+ import { log } from '@vitessce/globals';
6
7
  /**
7
8
  * Return the bottom coordinate of the layout.
8
9
  * https://github.com/STRML/react-grid-layout/blob/20dac73f91274526034c00968b5bedb9c2ed36b9/lib/utils.js#L82
@@ -90,7 +91,7 @@ function withDefaults(coordinationValues, dataType, fileType, datasetUid, defaul
90
91
  };
91
92
  if (!isEqual(coordinationValues, coordinationValuesWithDefaults)) {
92
93
  // eslint-disable-next-line max-len
93
- console.warn(`Using coordination value defaults for file type ${fileType} in dataset ${datasetUid}\nBefore: ${JSON.stringify(coordinationValues)}\nAfter: ${JSON.stringify(coordinationValuesWithDefaults)}`);
94
+ log.warn(`Using coordination value defaults for file type ${fileType} in dataset ${datasetUid}\nBefore: ${JSON.stringify(coordinationValues)}\nAfter: ${JSON.stringify(coordinationValuesWithDefaults)}`);
94
95
  }
95
96
  return coordinationValuesWithDefaults;
96
97
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vitessce/vit-s",
3
- "version": "3.5.6",
3
+ "version": "3.5.7",
4
4
  "author": "HIDIVE Lab at HMS",
5
5
  "homepage": "http://vitessce.io",
6
6
  "repository": {
@@ -29,13 +29,14 @@
29
29
  "uuid": "^9.0.0",
30
30
  "zustand": "^3.5.10",
31
31
  "react-aria": "^3.28.0",
32
- "@vitessce/abstract": "3.5.6",
33
- "@vitessce/constants-internal": "3.5.6",
34
- "@vitessce/plugins": "3.5.6",
35
- "@vitessce/schemas": "3.5.6",
36
- "@vitessce/utils": "3.5.6",
37
- "@vitessce/sets-utils": "3.5.6",
38
- "@vitessce/config": "3.5.6"
32
+ "@vitessce/abstract": "3.5.7",
33
+ "@vitessce/constants-internal": "3.5.7",
34
+ "@vitessce/plugins": "3.5.7",
35
+ "@vitessce/schemas": "3.5.7",
36
+ "@vitessce/utils": "3.5.7",
37
+ "@vitessce/sets-utils": "3.5.7",
38
+ "@vitessce/config": "3.5.7",
39
+ "@vitessce/globals": "3.5.7"
39
40
  },
40
41
  "devDependencies": {
41
42
  "@testing-library/jest-dom": "^5.16.4",
@@ -43,7 +44,7 @@
43
44
  "react": "^18.0.0",
44
45
  "vite": "^4.3.0",
45
46
  "vitest": "^0.32.2",
46
- "@vitessce/types": "3.5.6"
47
+ "@vitessce/types": "3.5.7"
47
48
  },
48
49
  "peerDependencies": {
49
50
  "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
@@ -1,14 +1,14 @@
1
1
  import { useEffect } from 'react';
2
+ import { log } from '@vitessce/globals';
2
3
  import { useViewConfigStoreApi, useLoaders, useWarning } from './state/hooks.js';
3
4
 
4
-
5
5
  function validateViewConfig(viewConfig, pluginSpecificConfigSchema) {
6
6
  // Need the try-catch here since Zustand will actually
7
7
  // just catch and ignore errors in its subscription callbacks.
8
8
  try {
9
9
  pluginSpecificConfigSchema.parse(viewConfig);
10
10
  } catch (e) {
11
- console.error(e);
11
+ log.error(e);
12
12
  }
13
13
  // Do nothing if successful.
14
14
  }
@@ -0,0 +1,35 @@
1
+ import clsx from 'clsx';
2
+ import { useStyles } from './shared-warning-styles.js';
3
+ import { VITESSCE_CONTAINER } from './classNames.js';
4
+
5
+ export function DebugWindow({ debugErrors }) {
6
+ const classes = useStyles();
7
+ return (
8
+ <div className={VITESSCE_CONTAINER}>
9
+ <div className={clsx(classes.warningLayout, classes.containerFluid)}>
10
+ <div className={classes.row}>
11
+ <div className={classes.warningCard}>
12
+ {debugErrors.map((error, index) => (
13
+ <div key={error.message || index}>
14
+ {index === 0 && (
15
+ <div>
16
+ <h1>Error Type: {error.name}</h1>
17
+ {Object.keys(error).map(
18
+ key => key !== 'name'
19
+ && key !== 'message' && (
20
+ <p key={key}>
21
+ {key.charAt(0).toUpperCase() + key.slice(1)}: {error[key]}
22
+ </p>
23
+ ),
24
+ )}
25
+ </div>
26
+ )}
27
+ <p>Error: {error.message}</p>
28
+ </div>
29
+ ))}
30
+ </div>
31
+ </div>
32
+ </div>
33
+ </div>
34
+ );
35
+ }
package/src/VitS.js CHANGED
@@ -1,4 +1,4 @@
1
- import React, { useEffect, useMemo, useCallback } from 'react';
1
+ import React, { useState, useEffect, useMemo, useCallback, useLayoutEffect } from 'react';
2
2
  import {
3
3
  ThemeProvider,
4
4
  StylesProvider,
@@ -9,6 +9,10 @@ import {
9
9
  } from '@tanstack/react-query';
10
10
  import { isEqual } from 'lodash-es';
11
11
  import { buildConfigSchema, latestConfigSchema } from '@vitessce/schemas';
12
+ import {
13
+ setLogLevel, setDebugMode,
14
+ DEFAULT_LOG_LEVEL, DEFAULT_DEBUG_MODE,
15
+ } from '@vitessce/globals';
12
16
  import { muiTheme } from './shared-mui/styles.js';
13
17
  import {
14
18
  ViewConfigProvider,
@@ -19,6 +23,7 @@ import {
19
23
 
20
24
  import VitessceGrid from './VitessceGrid.js';
21
25
  import { Warning } from './Warning.js';
26
+ import { DebugWindow } from './DebugWindow.js';
22
27
  import CallbackPublisher from './CallbackPublisher.js';
23
28
  import {
24
29
  initialize,
@@ -62,6 +67,8 @@ import { AsyncFunctionsContext } from './contexts.js';
62
67
  * @param {array} props.coordinationTypes Plugin coordination types.
63
68
  * @param {null|object} props.warning A warning to render within the Vitessce grid,
64
69
  * @param {boolean} props.pageMode Whether to render in page mode. By default, false.
70
+ * @param {boolean} props.debugMode Whether to display the debugWindow. By default, false.
71
+ * @param {null|string} props.logLevel To set the log level in the console.
65
72
  * provided by the parent.
66
73
  */
67
74
  export function VitS(props) {
@@ -87,8 +94,12 @@ export function VitS(props) {
87
94
  warning,
88
95
  pageMode = false,
89
96
  children,
97
+ debugMode = DEFAULT_DEBUG_MODE,
98
+ logLevel = DEFAULT_LOG_LEVEL,
90
99
  } = props;
91
100
 
101
+ // eslint-disable-next-line no-unused-vars
102
+ const [debugErrors, setDebugErrors] = useState([]);
92
103
  const viewTypes = useMemo(() => (viewTypesProp || []), [viewTypesProp]);
93
104
  const fileTypes = useMemo(() => (fileTypesProp || []), [fileTypesProp]);
94
105
  const jointFileTypes = useMemo(
@@ -99,9 +110,15 @@ export function VitS(props) {
99
110
  () => (coordinationTypesProp || []),
100
111
  [coordinationTypesProp],
101
112
  );
102
-
103
113
  const generateClassName = useMemo(() => createGenerateClassName(uid), [uid]);
104
114
 
115
+ // Set error handling-related globals.
116
+ useLayoutEffect(() => {
117
+ setLogLevel(logLevel);
118
+ }, [logLevel]);
119
+ useLayoutEffect(() => {
120
+ setDebugMode(debugMode);
121
+ }, [debugMode]);
105
122
  const configVersion = config?.version;
106
123
 
107
124
  // If config.uid exists, then use it for hook dependencies to detect changes
@@ -230,6 +247,18 @@ export function VitS(props) {
230
247
  // eslint-disable-next-line react-hooks/exhaustive-deps
231
248
  }, [success, configKey]);
232
249
 
250
+ // TODO: use in ErrorBoundary fallback.
251
+ // Will probably need to move a lot to a child of VitS
252
+ // so that when the child throws errors the parent can catch.
253
+ if (debugMode && debugErrors.length > 0) {
254
+ return (
255
+ <StylesProvider generateClassName={generateClassName}>
256
+ <ThemeProvider theme={muiTheme[theme]}>
257
+ <DebugWindow debugErrors={debugErrors} />
258
+ </ThemeProvider>
259
+ </StylesProvider>
260
+ );
261
+ }
233
262
  return success ? (
234
263
  <StylesProvider generateClassName={generateClassName}>
235
264
  <ThemeProvider theme={muiTheme[theme]}>
package/src/Warning.js CHANGED
@@ -1,44 +1,7 @@
1
1
  import clsx from 'clsx';
2
- import { makeStyles } from '@material-ui/core';
2
+ import { useStyles } from './shared-warning-styles.js';
3
3
  import { VITESSCE_CONTAINER } from './classNames.js';
4
4
 
5
- const useStyles = makeStyles(theme => ({
6
- warningLayout: {
7
- backgroundColor: theme.palette.gridLayoutBackground,
8
- position: 'absolute',
9
- width: '100%',
10
- height: '100vh',
11
- },
12
- containerFluid: {
13
- width: '100%',
14
- padding: '15px',
15
- marginRight: 'auto',
16
- marginLeft: 'auto',
17
- boxSizing: 'border-box',
18
- display: 'flex',
19
- },
20
- row: {
21
- flexGrow: '1',
22
- },
23
- warningCard: {
24
- border: `1px solid ${theme.palette.cardBorder}`,
25
- flex: '1 1 auto',
26
- minHeight: '1px',
27
- padding: '12px',
28
- marginTop: '8px',
29
- marginBottom: '8px',
30
- position: 'relative',
31
- display: 'flex',
32
- flexDirection: 'column',
33
- minWidth: '0',
34
- wordWrap: 'break-word',
35
- backgroundClip: 'border-box',
36
- borderRadius: '4px',
37
- backgroundColor: theme.palette.primaryBackground,
38
- color: theme.palette.primaryForeground,
39
- },
40
- }));
41
-
42
5
  export function Warning(props) {
43
6
  const {
44
7
  title,
@@ -4,6 +4,7 @@ import {
4
4
  capitalize,
5
5
  getInitialCoordinationScopePrefix,
6
6
  } from '@vitessce/utils';
7
+ import { log } from '@vitessce/globals';
7
8
  import { STATUS } from '@vitessce/constants-internal';
8
9
  import {
9
10
  AbstractLoaderError,
@@ -22,8 +23,8 @@ import {
22
23
  */
23
24
  export function warn(error, setWarning) {
24
25
  setWarning(error.message);
25
- console.warn(error.message);
26
- console.error(error.stack);
26
+ log.warn(error.message);
27
+ log.error(error.stack);
27
28
  if (error instanceof AbstractLoaderError) {
28
29
  error.warnInConsole();
29
30
  }
package/src/hooks.js CHANGED
@@ -6,8 +6,8 @@ import { extent } from 'd3-array';
6
6
  import { useQuery } from '@tanstack/react-query';
7
7
  import { capitalize } from '@vitessce/utils';
8
8
  import { STATUS, AsyncFunctionType } from '@vitessce/constants-internal';
9
- import { useGridResize, useEmitGridResize } from './state/hooks.js';
10
9
  import { VITESSCE_CONTAINER } from './classNames.js';
10
+ import { useGridResize, useEmitGridResize } from './state/hooks.js';
11
11
  import { useAsyncFunction } from './contexts.js';
12
12
 
13
13
 
@@ -0,0 +1,38 @@
1
+ import { makeStyles } from '@material-ui/core';
2
+
3
+ export const useStyles = makeStyles(theme => ({
4
+ warningLayout: {
5
+ backgroundColor: theme.palette.gridLayoutBackground,
6
+ position: 'absolute',
7
+ width: '100%',
8
+ height: '100vh',
9
+ },
10
+ containerFluid: {
11
+ width: '100%',
12
+ padding: '15px',
13
+ marginRight: 'auto',
14
+ marginLeft: 'auto',
15
+ boxSizing: 'border-box',
16
+ display: 'flex',
17
+ },
18
+ row: {
19
+ flexGrow: '1',
20
+ },
21
+ warningCard: {
22
+ border: `1px solid ${theme.palette.cardBorder}`,
23
+ flex: '1 1 auto',
24
+ minHeight: '1px',
25
+ padding: '12px',
26
+ marginTop: '8px',
27
+ marginBottom: '8px',
28
+ position: 'relative',
29
+ display: 'flex',
30
+ flexDirection: 'column',
31
+ minWidth: '0',
32
+ wordWrap: 'break-word',
33
+ backgroundClip: 'border-box',
34
+ borderRadius: '4px',
35
+ backgroundColor: theme.palette.primaryBackground,
36
+ color: theme.palette.primaryForeground,
37
+ },
38
+ }));
@@ -2,16 +2,19 @@
2
2
  /* eslint-disable camelcase */
3
3
  import { cloneDeep } from 'lodash-es';
4
4
  import { getNextScope } from '@vitessce/utils';
5
+ import { atLeastLogLevel, LogLevel } from '@vitessce/globals';
5
6
  import {
6
7
  AUTO_INDEPENDENT_COORDINATION_TYPES,
7
8
  META_VERSION,
8
9
  } from '@vitessce/constants-internal';
9
10
 
10
11
  export function logConfig(config, name) {
11
- console.groupCollapsed(`🚄 VitS (${META_VERSION.version}) ${name}`);
12
- console.info(`data:,${JSON.stringify(config)}`);
13
- console.info(JSON.stringify(config, null, 2));
14
- console.groupEnd();
12
+ if (atLeastLogLevel(LogLevel.INFO)) {
13
+ console.groupCollapsed(`🚄 VitS (${META_VERSION.version}) ${name}`);
14
+ console.info(`data:,${JSON.stringify(config)}`);
15
+ console.info(JSON.stringify(config, null, 2));
16
+ console.groupEnd();
17
+ }
15
18
  }
16
19
 
17
20
  /**
@@ -5,7 +5,7 @@ import { InternMap } from 'internmap';
5
5
  import { isEqual, pick } from 'lodash-es';
6
6
  import { DATA_TYPE_COORDINATION_VALUE_USAGE } from '@vitessce/constants-internal';
7
7
  import { getSourceAndLoaderFromFileType, getDataTypeFromFileType } from '@vitessce/abstract';
8
-
8
+ import { log } from '@vitessce/globals';
9
9
  /**
10
10
  * Return the bottom coordinate of the layout.
11
11
  * https://github.com/STRML/react-grid-layout/blob/20dac73f91274526034c00968b5bedb9c2ed36b9/lib/utils.js#L82
@@ -107,7 +107,7 @@ function withDefaults(
107
107
  };
108
108
  if (!isEqual(coordinationValues, coordinationValuesWithDefaults)) {
109
109
  // eslint-disable-next-line max-len
110
- console.warn(`Using coordination value defaults for file type ${fileType} in dataset ${datasetUid}\nBefore: ${JSON.stringify(coordinationValues)}\nAfter: ${JSON.stringify(coordinationValuesWithDefaults)}`);
110
+ log.warn(`Using coordination value defaults for file type ${fileType} in dataset ${datasetUid}\nBefore: ${JSON.stringify(coordinationValues)}\nAfter: ${JSON.stringify(coordinationValuesWithDefaults)}`);
111
111
  }
112
112
  return coordinationValuesWithDefaults;
113
113
  }