@vitessce/biomarker-select 3.5.6 → 3.5.8

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
@@ -1,6 +1,6 @@
1
1
  import * as React from "react";
2
2
  import React__default, { Children, isValidElement, cloneElement, createElement, PureComponent, useRef, useEffect, useMemo, useState, useCallback } from "react";
3
- import { useCoordination, useViewConfigStoreApi, useViewConfig, useSetViewConfig, useAsyncFunction } from "@vitessce/vit-s";
3
+ import { useLoaders, useCoordination, useViewConfigStoreApi, useViewConfig, useSetViewConfig, useMatchingLoader, useColumnNameMapping, useAsyncFunction, useComparisonMetadata } from "@vitessce/vit-s";
4
4
  import * as ReactDOM from "react-dom";
5
5
  import ReactDOM__default from "react-dom";
6
6
  function getDefaultExportFromCjs(x) {
@@ -909,9 +909,35 @@ const ViewType = {
909
909
  FEATURE_VALUE_HISTOGRAM: "featureValueHistogram",
910
910
  DOT_PLOT: "dotPlot",
911
911
  FEATURE_BAR_PLOT: "featureBarPlot",
912
+ VOLCANO_PLOT: "volcanoPlot",
913
+ OBS_SET_COMPOSITION_BAR_PLOT: "obsSetCompositionBarPlot",
914
+ FEATURE_SET_ENRICHMENT_BAR_PLOT: "featureSetEnrichmentBarPlot",
912
915
  BIOMARKER_SELECT: "biomarkerSelect",
916
+ COMPARATIVE_HEADING: "comparativeHeading",
913
917
  LINK_CONTROLLER: "linkController",
914
- DUAL_SCATTERPLOT: "dualScatterplot"
918
+ NEUROGLANCER: "neuroglancer",
919
+ DUAL_SCATTERPLOT: "dualScatterplot",
920
+ TREEMAP: "treemap"
921
+ };
922
+ const DataType = {
923
+ OBS_LABELS: "obsLabels",
924
+ OBS_EMBEDDING: "obsEmbedding",
925
+ OBS_FEATURE_MATRIX: "obsFeatureMatrix",
926
+ OBS_SETS: "obsSets",
927
+ FEATURE_LABELS: "featureLabels",
928
+ IMAGE: "image",
929
+ OBS_SEGMENTATIONS: "obsSegmentations",
930
+ NEIGHBORHOODS: "neighborhoods",
931
+ GENOMIC_PROFILES: "genomic-profiles",
932
+ OBS_SPOTS: "obsSpots",
933
+ OBS_POINTS: "obsPoints",
934
+ OBS_LOCATIONS: "obsLocations",
935
+ SAMPLE_SETS: "sampleSets",
936
+ SAMPLE_EDGES: "sampleEdges",
937
+ COMPARISON_METADATA: "comparisonMetadata",
938
+ FEATURE_STATS: "featureStats",
939
+ FEATURE_SET_STATS: "featureSetStats",
940
+ OBS_SET_STATS: "obsSetStats"
915
941
  };
916
942
  const AsyncFunctionType = {
917
943
  // String input (rather than Node input)
@@ -1065,14 +1091,25 @@ const CoordinationType = {
1065
1091
  SAMPLE_SET_FILTER: "sampleSetFilter",
1066
1092
  SAMPLE_FILTER_MODE: "sampleFilterMode",
1067
1093
  SAMPLE_SET_COLOR: "sampleSetColor",
1094
+ SAMPLE_HIGHLIGHT: "sampleHighlight",
1068
1095
  EMBEDDING_POINTS_VISIBLE: "embeddingPointsVisible",
1069
1096
  EMBEDDING_CONTOURS_VISIBLE: "embeddingContoursVisible",
1070
1097
  EMBEDDING_CONTOURS_FILLED: "embeddingContoursFilled",
1071
1098
  EMBEDDING_CONTOUR_PERCENTILES: "embeddingContourPercentiles",
1072
1099
  CONTOUR_COLOR_ENCODING: "contourColorEncoding",
1073
- CONTOUR_COLOR: "contourColor"
1100
+ CONTOUR_COLOR: "contourColor",
1101
+ // For volcano plot:
1102
+ FEATURE_POINT_SIGNIFICANCE_THRESHOLD: "featurePointSignificanceThreshold",
1103
+ FEATURE_LABEL_SIGNIFICANCE_THRESHOLD: "featureLabelSignificanceThreshold",
1104
+ FEATURE_POINT_FOLD_CHANGE_THRESHOLD: "featurePointFoldChangeThreshold",
1105
+ FEATURE_LABEL_FOLD_CHANGE_THRESHOLD: "featureLabelFoldChangeThreshold",
1106
+ // Treemap
1107
+ HIERARCHY_LEVELS: "hierarchyLevels"
1074
1108
  };
1075
1109
  const COMPONENT_COORDINATION_TYPES = {
1110
+ [ViewType.NEUROGLANCER]: [
1111
+ CoordinationType.DATASET
1112
+ ],
1076
1113
  [ViewType.SCATTERPLOT]: [
1077
1114
  CoordinationType.DATASET,
1078
1115
  CoordinationType.OBS_TYPE,
@@ -1542,14 +1579,106 @@ const COMPONENT_COORDINATION_TYPES = {
1542
1579
  CoordinationType.OBS_COLOR_ENCODING,
1543
1580
  CoordinationType.ADDITIONAL_OBS_SETS
1544
1581
  ],
1582
+ [ViewType.VOLCANO_PLOT]: [
1583
+ CoordinationType.DATASET,
1584
+ CoordinationType.OBS_TYPE,
1585
+ CoordinationType.FEATURE_TYPE,
1586
+ CoordinationType.SAMPLE_TYPE,
1587
+ // For selection of case-control sets of samples:
1588
+ CoordinationType.SAMPLE_SET_SELECTION,
1589
+ // For selection of one-vs-others sets of observations:
1590
+ CoordinationType.OBS_SET_SELECTION,
1591
+ // TODO: CoordinationType.FEATURE_SET_SELECTION,
1592
+ // TODO: CoordinationType.FEATURE_SET_HIGHLIGHT,
1593
+ // TODO: CoordinationType.FEATURE_SET_COLOR,
1594
+ CoordinationType.FEATURE_HIGHLIGHT,
1595
+ CoordinationType.FEATURE_SELECTION,
1596
+ CoordinationType.FEATURE_VALUE_COLORMAP,
1597
+ CoordinationType.FEATURE_VALUE_COLORMAP_RANGE,
1598
+ // TODO: CoordinationType.FEATURE_COLOR_ENCODING,
1599
+ // TODO: CoordinationType.ADDITIONAL_FEATURE_SETS,
1600
+ CoordinationType.TOOLTIPS_VISIBLE,
1601
+ CoordinationType.ADDITIONAL_OBS_SETS,
1602
+ CoordinationType.OBS_SET_COLOR,
1603
+ CoordinationType.SAMPLE_SET_COLOR,
1604
+ CoordinationType.FEATURE_POINT_SIGNIFICANCE_THRESHOLD,
1605
+ CoordinationType.FEATURE_LABEL_SIGNIFICANCE_THRESHOLD,
1606
+ CoordinationType.FEATURE_POINT_FOLD_CHANGE_THRESHOLD,
1607
+ CoordinationType.FEATURE_LABEL_FOLD_CHANGE_THRESHOLD
1608
+ ],
1609
+ [ViewType.OBS_SET_COMPOSITION_BAR_PLOT]: [
1610
+ CoordinationType.DATASET,
1611
+ CoordinationType.OBS_TYPE,
1612
+ CoordinationType.SAMPLE_TYPE,
1613
+ // For selection of case-control sets of samples:
1614
+ CoordinationType.SAMPLE_SET_SELECTION,
1615
+ // For selection of one-vs-others sets of observations:
1616
+ CoordinationType.OBS_SET_SELECTION,
1617
+ CoordinationType.ADDITIONAL_OBS_SETS,
1618
+ CoordinationType.OBS_SET_COLOR,
1619
+ CoordinationType.SAMPLE_SET_COLOR
1620
+ ],
1621
+ [ViewType.FEATURE_SET_ENRICHMENT_BAR_PLOT]: [
1622
+ CoordinationType.DATASET,
1623
+ CoordinationType.OBS_TYPE,
1624
+ CoordinationType.FEATURE_TYPE,
1625
+ CoordinationType.SAMPLE_TYPE,
1626
+ // For selection of case-control sets of samples:
1627
+ CoordinationType.SAMPLE_SET_SELECTION,
1628
+ // For selection of one-vs-others sets of observations:
1629
+ CoordinationType.OBS_SET_SELECTION,
1630
+ CoordinationType.ADDITIONAL_OBS_SETS,
1631
+ CoordinationType.OBS_SET_COLOR,
1632
+ CoordinationType.SAMPLE_SET_COLOR,
1633
+ CoordinationType.FEATURE_SELECTION
1634
+ ],
1545
1635
  [ViewType.LINK_CONTROLLER]: [],
1546
1636
  [ViewType.BIOMARKER_SELECT]: [
1637
+ CoordinationType.DATASET,
1638
+ CoordinationType.OBS_TYPE,
1639
+ CoordinationType.SAMPLE_TYPE,
1547
1640
  CoordinationType.FEATURE_SELECTION,
1548
1641
  CoordinationType.SAMPLE_SET_SELECTION,
1549
1642
  CoordinationType.SAMPLE_SET_FILTER,
1550
1643
  CoordinationType.OBS_SET_SELECTION,
1551
1644
  CoordinationType.OBS_SET_FILTER
1552
1645
  // TODO: create coordination types for internal state of the biomarker selection view?
1646
+ ],
1647
+ [ViewType.COMPARATIVE_HEADING]: [
1648
+ CoordinationType.DATASET,
1649
+ CoordinationType.OBS_TYPE,
1650
+ CoordinationType.SAMPLE_TYPE,
1651
+ CoordinationType.FEATURE_SELECTION,
1652
+ CoordinationType.SAMPLE_SET_SELECTION,
1653
+ CoordinationType.SAMPLE_SET_FILTER,
1654
+ CoordinationType.OBS_SET_SELECTION,
1655
+ CoordinationType.OBS_SET_FILTER
1656
+ ],
1657
+ [ViewType.TREEMAP]: [
1658
+ CoordinationType.DATASET,
1659
+ CoordinationType.OBS_TYPE,
1660
+ CoordinationType.FEATURE_TYPE,
1661
+ CoordinationType.FEATURE_VALUE_TYPE,
1662
+ CoordinationType.OBS_FILTER,
1663
+ CoordinationType.OBS_HIGHLIGHT,
1664
+ CoordinationType.OBS_SET_SELECTION,
1665
+ CoordinationType.OBS_SET_FILTER,
1666
+ CoordinationType.OBS_SELECTION,
1667
+ CoordinationType.OBS_SELECTION_MODE,
1668
+ CoordinationType.OBS_SET_HIGHLIGHT,
1669
+ CoordinationType.OBS_SET_COLOR,
1670
+ CoordinationType.OBS_COLOR_ENCODING,
1671
+ CoordinationType.ADDITIONAL_OBS_SETS,
1672
+ CoordinationType.SAMPLE_TYPE,
1673
+ CoordinationType.SAMPLE_SET_SELECTION,
1674
+ CoordinationType.SAMPLE_SET_FILTER,
1675
+ CoordinationType.SAMPLE_SET_COLOR,
1676
+ CoordinationType.SAMPLE_SELECTION,
1677
+ CoordinationType.SAMPLE_SELECTION_MODE,
1678
+ CoordinationType.SAMPLE_FILTER,
1679
+ CoordinationType.SAMPLE_FILTER_MODE,
1680
+ CoordinationType.SAMPLE_HIGHLIGHT,
1681
+ CoordinationType.HIERARCHY_LEVELS
1553
1682
  ]
1554
1683
  };
1555
1684
  var common = {
@@ -30739,7 +30868,7 @@ function SelectStratification(props) {
30739
30868
  ) })
30740
30869
  ] });
30741
30870
  }
30742
- const steps = [
30871
+ const steps$1 = [
30743
30872
  "Select biomarkers (modality-agnostic)",
30744
30873
  "Derive modality-specific biomarker signature",
30745
30874
  "Define case-control stratification"
@@ -30789,12 +30918,12 @@ function ConfirmatoryStepper(props) {
30789
30918
  setActiveStep(0);
30790
30919
  };
30791
30920
  useEffect(() => {
30792
- if (activeStep === steps.length) {
30921
+ if (activeStep === steps$1.length) {
30793
30922
  onFinish();
30794
30923
  }
30795
- }, [activeStep, steps]);
30924
+ }, [activeStep, steps$1]);
30796
30925
  return /* @__PURE__ */ jsxRuntimeExports.jsxs(Grid$1, { item: true, container: true, xs: 12, children: [
30797
- /* @__PURE__ */ jsxRuntimeExports.jsx(Grid$1, { item: true, container: true, xs: 12, children: /* @__PURE__ */ jsxRuntimeExports.jsx(Box$1, { className: classes.fullWidthBox, children: /* @__PURE__ */ jsxRuntimeExports.jsx(Stepper$1, { activeStep, children: steps.map((label, index) => {
30926
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Grid$1, { item: true, container: true, xs: 12, children: /* @__PURE__ */ jsxRuntimeExports.jsx(Box$1, { className: classes.fullWidthBox, children: /* @__PURE__ */ jsxRuntimeExports.jsx(Stepper$1, { activeStep, children: steps$1.map((label, index) => {
30798
30927
  const stepProps = {};
30799
30928
  const labelProps = {};
30800
30929
  if (isStepOptional(index)) {
@@ -30806,7 +30935,7 @@ function ConfirmatoryStepper(props) {
30806
30935
  return /* @__PURE__ */ jsxRuntimeExports.jsx(Step$1, { ...stepProps, children: /* @__PURE__ */ jsxRuntimeExports.jsx(StepLabel$1, { ...labelProps, children: label }) }, label);
30807
30936
  }) }) }) }),
30808
30937
  /* @__PURE__ */ jsxRuntimeExports.jsxs(Grid$1, { item: true, container: true, xs: 12, style: { marginTop: "20px" }, alignItems: "flex-start", children: [
30809
- /* @__PURE__ */ jsxRuntimeExports.jsx(Grid$1, { item: true, container: true, xs: 8, children: activeStep === steps.length ? /* @__PURE__ */ jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(Typography$1, { style: { marginTop: "20px", marginBottom: "10px" }, children: "All steps completed - you're finished" }) }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
30938
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Grid$1, { item: true, container: true, xs: 8, children: activeStep === steps$1.length ? /* @__PURE__ */ jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(Typography$1, { style: { marginTop: "20px", marginBottom: "10px" }, children: "All steps completed - you're finished" }) }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
30810
30939
  activeStep === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx(
30811
30940
  SelectAgnostic,
30812
30941
  {
@@ -30862,6 +30991,118 @@ function ConfirmatoryStepper(props) {
30862
30991
  stratifications
30863
30992
  }
30864
30993
  ) }),
30994
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Box$1, { className: classes.fullWidthBox, children: activeStep === steps$1.length ? /* @__PURE__ */ jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Box$1, { style: { display: "flex", flexDirection: "row", paddingTop: "20px" }, children: [
30995
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Box$1, { style: { flex: "1 1 auto" } }),
30996
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Button$1, { onClick: handleReset, children: "Reset" })
30997
+ ] }) }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(Box$1, { style: { display: "flex", flexDirection: "row", paddingTop: "20px" }, children: [
30998
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
30999
+ Button$1,
31000
+ {
31001
+ color: "inherit",
31002
+ disabled: activeStep === 0,
31003
+ onClick: handleBack,
31004
+ style: { mr: 1 },
31005
+ children: "Back"
31006
+ }
31007
+ ),
31008
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Box$1, { style: { flex: "1 1 auto" } }),
31009
+ isStepOptional(activeStep) && /* @__PURE__ */ jsxRuntimeExports.jsx(Button$1, { color: "inherit", onClick: handleSkip, style: { marginRight: "10px" }, children: "Skip" }),
31010
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Button$1, { onClick: handleNext, children: activeStep === steps$1.length - 1 ? "Finish" : "Next" })
31011
+ ] }) })
31012
+ ] })
31013
+ ] });
31014
+ }
31015
+ const steps = [
31016
+ "Define case-control stratification"
31017
+ ];
31018
+ function ExploratoryStepper(props) {
31019
+ const {
31020
+ autocompleteNode,
31021
+ currentModalityAgnosticSelection,
31022
+ setCurrentModalityAgnosticSelection,
31023
+ currentModalitySpecificSelection,
31024
+ setCurrentModalitySpecificSelection,
31025
+ currentStratificationSelection,
31026
+ setCurrentStratificationSelection,
31027
+ getEdges,
31028
+ stratifications,
31029
+ onFinish
31030
+ } = props;
31031
+ const classes = useStyles();
31032
+ const [activeStep, setActiveStep] = React__default.useState(0);
31033
+ const [skipped, setSkipped] = React__default.useState(/* @__PURE__ */ new Set());
31034
+ const isStepOptional = (step) => step === 2;
31035
+ const isStepSkipped = (step) => skipped.has(step);
31036
+ const handleNext = () => {
31037
+ let newSkipped = skipped;
31038
+ if (isStepSkipped(activeStep)) {
31039
+ newSkipped = new Set(newSkipped.values());
31040
+ newSkipped.delete(activeStep);
31041
+ }
31042
+ setActiveStep((prevActiveStep) => prevActiveStep + 1);
31043
+ setSkipped(newSkipped);
31044
+ };
31045
+ const handleBack = () => {
31046
+ setActiveStep((prevActiveStep) => prevActiveStep - 1);
31047
+ };
31048
+ const handleSkip = () => {
31049
+ if (!isStepOptional(activeStep)) {
31050
+ throw new Error("You can't skip a step that isn't optional.");
31051
+ }
31052
+ setActiveStep((prevActiveStep) => prevActiveStep + 1);
31053
+ setSkipped((prevSkipped) => {
31054
+ const newSkipped = new Set(prevSkipped.values());
31055
+ newSkipped.add(activeStep);
31056
+ return newSkipped;
31057
+ });
31058
+ };
31059
+ const handleReset = () => {
31060
+ setActiveStep(0);
31061
+ };
31062
+ useEffect(() => {
31063
+ if (activeStep === steps.length) {
31064
+ onFinish();
31065
+ }
31066
+ }, [activeStep, steps]);
31067
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(Grid$1, { item: true, container: true, xs: 12, children: [
31068
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Grid$1, { item: true, container: true, xs: 12, children: /* @__PURE__ */ jsxRuntimeExports.jsx(Box$1, { className: classes.fullWidthBox, children: /* @__PURE__ */ jsxRuntimeExports.jsx(Stepper$1, { activeStep, children: steps.map((label, index) => {
31069
+ const stepProps = {};
31070
+ const labelProps = {};
31071
+ if (isStepOptional(index)) {
31072
+ labelProps.optional = /* @__PURE__ */ jsxRuntimeExports.jsx(Typography$1, { variant: "caption", children: "Optional" });
31073
+ }
31074
+ if (isStepSkipped(index)) {
31075
+ stepProps.completed = false;
31076
+ }
31077
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(Step$1, { ...stepProps, children: /* @__PURE__ */ jsxRuntimeExports.jsx(StepLabel$1, { ...labelProps, children: label }) }, label);
31078
+ }) }) }) }),
31079
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(Grid$1, { item: true, container: true, xs: 12, style: { marginTop: "20px" }, alignItems: "flex-start", children: [
31080
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Grid$1, { item: true, container: true, xs: 8, children: activeStep === steps.length ? /* @__PURE__ */ jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(Typography$1, { style: { marginTop: "20px", marginBottom: "10px" }, children: "All steps completed - you're finished" }) }) : /* @__PURE__ */ jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, { children: activeStep === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx(
31081
+ SelectStratification,
31082
+ {
31083
+ autocompleteNode,
31084
+ currentModalityAgnosticSelection,
31085
+ setCurrentModalityAgnosticSelection,
31086
+ currentModalitySpecificSelection,
31087
+ setCurrentModalitySpecificSelection,
31088
+ currentStratificationSelection,
31089
+ setCurrentStratificationSelection,
31090
+ getEdges,
31091
+ stratifications
31092
+ }
31093
+ ) : null }) }),
31094
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Grid$1, { item: true, container: true, xs: 4, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
31095
+ ConfirmatoryCart,
31096
+ {
31097
+ currentModalityAgnosticSelection,
31098
+ setCurrentModalityAgnosticSelection,
31099
+ currentModalitySpecificSelection,
31100
+ setCurrentModalitySpecificSelection,
31101
+ currentStratificationSelection,
31102
+ setCurrentStratificationSelection,
31103
+ stratifications
31104
+ }
31105
+ ) }),
30865
31106
  /* @__PURE__ */ jsxRuntimeExports.jsx(Box$1, { className: classes.fullWidthBox, children: activeStep === steps.length ? /* @__PURE__ */ jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Box$1, { style: { display: "flex", flexDirection: "row", paddingTop: "20px" }, children: [
30866
31107
  /* @__PURE__ */ jsxRuntimeExports.jsx(Box$1, { style: { flex: "1 1 auto" } }),
30867
31108
  /* @__PURE__ */ jsxRuntimeExports.jsx(Button$1, { onClick: handleReset, children: "Reset" })
@@ -30928,22 +31169,60 @@ function ScmdUi(props) {
30928
31169
  onFinish
30929
31170
  }
30930
31171
  ) : null,
30931
- mode === "exploratory" ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "TODO" }) : null
31172
+ mode === "exploratory" ? /* @__PURE__ */ jsxRuntimeExports.jsx(
31173
+ ExploratoryStepper,
31174
+ {
31175
+ autocompleteNode,
31176
+ currentModalityAgnosticSelection,
31177
+ setCurrentModalityAgnosticSelection,
31178
+ currentModalitySpecificSelection,
31179
+ setCurrentModalitySpecificSelection,
31180
+ currentStratificationSelection,
31181
+ setCurrentStratificationSelection,
31182
+ getEdges,
31183
+ stratifications,
31184
+ onFinish
31185
+ }
31186
+ ) : null
30932
31187
  ] }) : null
30933
31188
  ] });
30934
31189
  }
30935
31190
  function BiomarkerSelectSubscriber(props) {
30936
31191
  const {
30937
31192
  coordinationScopes,
30938
- stratificationOptions
31193
+ stratificationOptions: stratificationOptionsProp
31194
+ // TODO: Remove; Get from comparisonMetadata instead
30939
31195
  } = props;
30940
- useCoordination(
31196
+ const loaders = useLoaders();
31197
+ const [{
31198
+ dataset,
31199
+ obsType,
31200
+ sampleType,
31201
+ sampleSetSelection,
31202
+ featureSelection
31203
+ }, {
31204
+ setSampleSetSelection,
31205
+ setFeatureSelection
31206
+ }] = useCoordination(
30941
31207
  COMPONENT_COORDINATION_TYPES[ViewType.BIOMARKER_SELECT],
30942
31208
  coordinationScopes
30943
31209
  );
30944
31210
  const viewConfigStoreApi = useViewConfigStoreApi();
30945
31211
  const viewConfig = useViewConfig();
30946
31212
  const setViewConfig = useSetViewConfig(viewConfigStoreApi);
31213
+ useMatchingLoader(
31214
+ loaders,
31215
+ dataset,
31216
+ DataType.OBS_SETS,
31217
+ { obsType }
31218
+ );
31219
+ const sampleSetsLoader = useMatchingLoader(
31220
+ loaders,
31221
+ dataset,
31222
+ DataType.SAMPLE_SETS,
31223
+ { sampleType }
31224
+ );
31225
+ const sampleSetsColumnNameMappingReversed = useColumnNameMapping(sampleSetsLoader, true);
30947
31226
  const [isSelecting, setIsSelecting] = useState(true);
30948
31227
  const [mode, setMode] = useState(null);
30949
31228
  const [step, setStep] = useState(null);
@@ -30960,6 +31239,36 @@ function BiomarkerSelectSubscriber(props) {
30960
31239
  async (node, targetModality) => transformFeature2(node, targetModality),
30961
31240
  [transformFeature2]
30962
31241
  );
31242
+ const [{ comparisonMetadata }, cmpMetadataStatus, cmpMetadataUrls] = useComparisonMetadata(
31243
+ loaders,
31244
+ dataset,
31245
+ false,
31246
+ {},
31247
+ {},
31248
+ { obsType, sampleType }
31249
+ );
31250
+ const stratificationOptions = useMemo(() => {
31251
+ if (comparisonMetadata == null ? void 0 : comparisonMetadata.sample_group_pairs) {
31252
+ return comparisonMetadata.sample_group_pairs.map((sampleGroupPair) => {
31253
+ const [sampleGroupCol, sampleGroupValues] = sampleGroupPair;
31254
+ const [sampleGroupCtrl, sampleGroupCase] = sampleGroupValues;
31255
+ const groupName = sampleSetsColumnNameMappingReversed == null ? void 0 : sampleSetsColumnNameMappingReversed[sampleGroupCol];
31256
+ return {
31257
+ stratificationId: `${sampleGroupCol}_${sampleGroupCtrl}-vs-${sampleGroupCase}`,
31258
+ name: `${groupName}: ${sampleGroupCtrl} vs. ${sampleGroupCase}`,
31259
+ stratificationType: "sampleSet",
31260
+ sampleSets: [
31261
+ // With sampleSets coming from the comparison_metadata,
31262
+ // need to use loader options from obsSets and sampleSets to get mapping
31263
+ // from column name to group name.
31264
+ [groupName, sampleGroupCtrl],
31265
+ [groupName, sampleGroupCase]
31266
+ ]
31267
+ };
31268
+ });
31269
+ }
31270
+ return null;
31271
+ }, [comparisonMetadata, sampleSetsColumnNameMappingReversed]);
30963
31272
  return /* @__PURE__ */ jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, { children: isSelecting ? /* @__PURE__ */ jsxRuntimeExports.jsx(
30964
31273
  ScmdUi,
30965
31274
  {
@@ -30977,24 +31286,46 @@ function BiomarkerSelectSubscriber(props) {
30977
31286
  getEdges,
30978
31287
  stratifications: stratificationOptions,
30979
31288
  onFinish: () => {
30980
- setViewConfig({
31289
+ const newViewConfig = {
30981
31290
  ...viewConfig,
30982
31291
  coordinationSpace: {
30983
31292
  ...viewConfig.coordinationSpace,
30984
31293
  sampleSetFilter: {
30985
31294
  ...viewConfig.coordinationSpace.sampleSetFilter,
30986
- "case-control": currentStratificationSelection == null ? void 0 : currentStratificationSelection.sampleSets
31295
+ __comparison__: currentStratificationSelection == null ? void 0 : currentStratificationSelection.sampleSets
30987
31296
  },
30988
31297
  sampleSetSelection: {
30989
31298
  ...viewConfig.coordinationSpace.sampleSetSelection,
30990
- "case-control": currentStratificationSelection == null ? void 0 : currentStratificationSelection.sampleSets
31299
+ __comparison__: currentStratificationSelection == null ? void 0 : currentStratificationSelection.sampleSets
31300
+ },
31301
+ featureSelection: {
31302
+ ...viewConfig.coordinationSpace.featureSelection,
31303
+ __comparison__: currentModalitySpecificSelection ? currentModalitySpecificSelection.map((d) => d.label) : null
30991
31304
  }
30992
31305
  }
30993
- });
31306
+ };
31307
+ setViewConfig(newViewConfig);
30994
31308
  }
30995
31309
  }
30996
31310
  ) : null });
30997
31311
  }
31312
+ function ComparativeHeadingSubscriber(props) {
31313
+ var _a2, _b;
31314
+ const {
31315
+ coordinationScopes
31316
+ } = props;
31317
+ const [{
31318
+ sampleSetSelection
31319
+ }] = useCoordination(
31320
+ COMPONENT_COORDINATION_TYPES[ViewType.COMPARATIVE_HEADING],
31321
+ coordinationScopes
31322
+ );
31323
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, { children: sampleSetSelection && sampleSetSelection.length === 2 ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { width: "100%", display: "flex", flexDirection: "row" }, children: [
31324
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { style: { width: "45%" }, children: /* @__PURE__ */ jsxRuntimeExports.jsx("h2", { children: (_a2 = sampleSetSelection == null ? void 0 : sampleSetSelection[0]) == null ? void 0 : _a2.at(-1) }) }),
31325
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { style: { width: "5%" }, children: /* @__PURE__ */ jsxRuntimeExports.jsx("h2", { style: { textAlign: "right" }, children: "vs. " }) }),
31326
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { style: { width: "50%" }, children: /* @__PURE__ */ jsxRuntimeExports.jsx("h2", { children: (_b = sampleSetSelection == null ? void 0 : sampleSetSelection[1]) == null ? void 0 : _b.at(-1) }) })
31327
+ ] }) : null });
31328
+ }
30998
31329
  var EOL = {}, EOF = {}, QUOTE = 34, NEWLINE = 10, RETURN = 13;
30999
31330
  function objectConverter(columns2) {
31000
31331
  return new Function("d", "return {" + columns2.map(function(name, i) {
@@ -32193,6 +32524,7 @@ async function getTermMapping({ queryClient }, keyCuriePrefix, valCuriePrefix) {
32193
32524
  }
32194
32525
  export {
32195
32526
  BiomarkerSelectSubscriber,
32527
+ ComparativeHeadingSubscriber,
32196
32528
  autocompleteFeature,
32197
32529
  getAlternativeTerms,
32198
32530
  getTermMapping,
@@ -1 +1 @@
1
- {"version":3,"file":"BiomarkerSelectSubscriber.d.ts","sourceRoot":"","sources":["../src/BiomarkerSelectSubscriber.js"],"names":[],"mappings":"AAcA;;;;;GAKG;AACH,iDAHG;IAA+F,qBAAqB,EAA5G;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,kBAAkB,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,CAAC,CAAA;KAAC,EAAE;CACvF,eAmFF"}
1
+ {"version":3,"file":"BiomarkerSelectSubscriber.d.ts","sourceRoot":"","sources":["../src/BiomarkerSelectSubscriber.js"],"names":[],"mappings":"AAiBA;;;;;GAKG;AACH,iDAHG;IAA+F,qBAAqB,EAA5G;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,kBAAkB,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,CAAC,CAAA;KAAC,EAAE;CACvF,eA0JF"}
@@ -1,9 +1,9 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  /* eslint-disable max-len */
3
3
  /* eslint-disable no-unused-vars */
4
- import React, { useState, useCallback } from 'react';
5
- import { useAsyncFunction, useViewConfigStoreApi, useSetViewConfig, useViewConfig, useCoordination, } from '@vitessce/vit-s';
6
- import { AsyncFunctionType, ViewType, COMPONENT_COORDINATION_TYPES } from '@vitessce/constants-internal';
4
+ import React, { useState, useCallback, useMemo } from 'react';
5
+ import { useAsyncFunction, useViewConfigStoreApi, useSetViewConfig, useViewConfig, useCoordination, useLoaders, useComparisonMetadata, useMatchingLoader, useColumnNameMapping, } from '@vitessce/vit-s';
6
+ import { AsyncFunctionType, ViewType, COMPONENT_COORDINATION_TYPES, DataType } from '@vitessce/constants-internal';
7
7
  import { ScmdUi } from './scmd-ui.js';
8
8
  /**
9
9
  *
@@ -12,11 +12,18 @@ import { ScmdUi } from './scmd-ui.js';
12
12
  * @returns
13
13
  */
14
14
  export function BiomarkerSelectSubscriber(props) {
15
- const { coordinationScopes, stratificationOptions, } = props;
16
- const [{ sampleSetSelection, featureSelection, }, { setSampleSetSelection, setFeatureSelection, }] = useCoordination(COMPONENT_COORDINATION_TYPES[ViewType.BIOMARKER_SELECT], coordinationScopes);
15
+ const { coordinationScopes, stratificationOptions: stratificationOptionsProp, // TODO: Remove; Get from comparisonMetadata instead
16
+ } = props;
17
+ const loaders = useLoaders();
18
+ const [{ dataset, obsType, sampleType, sampleSetSelection, featureSelection, }, { setSampleSetSelection, setFeatureSelection, }] = useCoordination(COMPONENT_COORDINATION_TYPES[ViewType.BIOMARKER_SELECT], coordinationScopes);
17
19
  const viewConfigStoreApi = useViewConfigStoreApi();
18
20
  const viewConfig = useViewConfig();
19
21
  const setViewConfig = useSetViewConfig(viewConfigStoreApi);
22
+ // Need obsSets and sampleSets options to obtain mapping between
23
+ // group names and column names.
24
+ const obsSetsLoader = useMatchingLoader(loaders, dataset, DataType.OBS_SETS, { obsType });
25
+ const sampleSetsLoader = useMatchingLoader(loaders, dataset, DataType.SAMPLE_SETS, { sampleType });
26
+ const sampleSetsColumnNameMappingReversed = useColumnNameMapping(sampleSetsLoader, true);
20
27
  // TODO: make isSelecting a coordination type plugin.
21
28
  // TODO: use store hooks from @vitessce/vit-s to update the view config based on the selections.
22
29
  const [isSelecting, setIsSelecting] = useState(true);
@@ -29,20 +36,69 @@ export function BiomarkerSelectSubscriber(props) {
29
36
  const transformFeature = useAsyncFunction(AsyncFunctionType.TRANSFORM_FEATURE);
30
37
  const autocompleteNode = useCallback(async (inputValue) => autocompleteFeature(inputValue), [autocompleteFeature]);
31
38
  const getEdges = useCallback(async (node, targetModality) => transformFeature(node, targetModality), [transformFeature]);
39
+ const [{ comparisonMetadata }, cmpMetadataStatus, cmpMetadataUrls] = useComparisonMetadata(loaders, dataset, false, {}, {}, { obsType, sampleType });
40
+ const stratificationOptions = useMemo(() => {
41
+ /*
42
+ return array of objects like {
43
+ stratificationId: 'aki-vs-hr',
44
+ name: 'Acute kidney injury (AKI) vs. Healthy reference',
45
+ stratificationType: 'sampleSet', // key changed from 'groupType'. value changed from 'clinical'
46
+ sampleSets: [
47
+ ['Disease Type', 'AKI'],
48
+ ['Disease Type', 'Reference'],
49
+ ],
50
+ },
51
+ */
52
+ if (comparisonMetadata?.sample_group_pairs) {
53
+ return comparisonMetadata.sample_group_pairs.map((sampleGroupPair) => {
54
+ const [sampleGroupCol, sampleGroupValues] = sampleGroupPair;
55
+ const [sampleGroupCtrl, sampleGroupCase] = sampleGroupValues;
56
+ const groupName = sampleSetsColumnNameMappingReversed?.[sampleGroupCol];
57
+ return {
58
+ stratificationId: `${sampleGroupCol}_${sampleGroupCtrl}-vs-${sampleGroupCase}`,
59
+ name: `${groupName}: ${sampleGroupCtrl} vs. ${sampleGroupCase}`,
60
+ stratificationType: 'sampleSet',
61
+ sampleSets: [
62
+ // With sampleSets coming from the comparison_metadata,
63
+ // need to use loader options from obsSets and sampleSets to get mapping
64
+ // from column name to group name.
65
+ [groupName, sampleGroupCtrl],
66
+ [groupName, sampleGroupCase],
67
+ ],
68
+ };
69
+ });
70
+ }
71
+ return null;
72
+ }, [comparisonMetadata, sampleSetsColumnNameMappingReversed]);
32
73
  return (_jsx(_Fragment, { children: isSelecting ? (_jsx(ScmdUi, { mode: mode, setMode: setMode, step: step, setStep: setStep, currentModalityAgnosticSelection: currentModalityAgnosticSelection, setCurrentModalityAgnosticSelection: setCurrentModalityAgnosticSelection, currentModalitySpecificSelection: currentModalitySpecificSelection, setCurrentModalitySpecificSelection: setCurrentModalitySpecificSelection, currentStratificationSelection: currentStratificationSelection, setCurrentStratificationSelection: setCurrentStratificationSelection, autocompleteNode: autocompleteNode, getEdges: getEdges, stratifications: stratificationOptions, onFinish: () => {
33
- setViewConfig({
74
+ if (mode === 'exploratory') {
75
+ // mode is exploratory, configure accordingly.
76
+ // TODO
77
+ }
78
+ else {
79
+ // mode is confirmatory, configure accordingly.
80
+ // TODO
81
+ }
82
+ const newViewConfig = {
34
83
  ...viewConfig,
35
84
  coordinationSpace: {
36
85
  ...viewConfig.coordinationSpace,
37
86
  sampleSetFilter: {
38
87
  ...viewConfig.coordinationSpace.sampleSetFilter,
39
- 'case-control': currentStratificationSelection?.sampleSets,
88
+ __comparison__: currentStratificationSelection?.sampleSets,
40
89
  },
41
90
  sampleSetSelection: {
42
91
  ...viewConfig.coordinationSpace.sampleSetSelection,
43
- 'case-control': currentStratificationSelection?.sampleSets,
92
+ __comparison__: currentStratificationSelection?.sampleSets,
93
+ },
94
+ featureSelection: {
95
+ ...viewConfig.coordinationSpace.featureSelection,
96
+ __comparison__: currentModalitySpecificSelection ? currentModalitySpecificSelection.map(d => d.label) : null,
44
97
  },
45
98
  },
46
- });
99
+ };
100
+ // TODO: can the normal coordination value setters be used instead?
101
+ // (e.g., setFeatureSelection, setSampleSetSelection)
102
+ setViewConfig(newViewConfig);
47
103
  } })) : null }));
48
104
  }
@@ -0,0 +1,2 @@
1
+ export function ComparativeHeadingSubscriber(props: any): JSX.Element;
2
+ //# sourceMappingURL=ComparativeHeadingSubscriber.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ComparativeHeadingSubscriber.d.ts","sourceRoot":"","sources":["../src/ComparativeHeadingSubscriber.js"],"names":[],"mappings":"AAOA,sEAuBC"}
@@ -0,0 +1,9 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import React from 'react';
3
+ import { useCoordination, } from '@vitessce/vit-s';
4
+ import { ViewType, COMPONENT_COORDINATION_TYPES } from '@vitessce/constants-internal';
5
+ export function ComparativeHeadingSubscriber(props) {
6
+ const { coordinationScopes, } = props;
7
+ const [{ sampleSetSelection, }] = useCoordination(COMPONENT_COORDINATION_TYPES[ViewType.COMPARATIVE_HEADING], coordinationScopes);
8
+ return (_jsx(_Fragment, { children: sampleSetSelection && sampleSetSelection.length === 2 ? (_jsxs("div", { style: { width: '100%', display: 'flex', flexDirection: 'row' }, children: [_jsx("div", { style: { width: '45%' }, children: _jsx("h2", { children: sampleSetSelection?.[0]?.at(-1) }) }), _jsx("div", { style: { width: '5%' }, children: _jsx("h2", { style: { textAlign: 'right' }, children: "vs.\u00A0" }) }), _jsx("div", { style: { width: '50%' }, children: _jsx("h2", { children: sampleSetSelection?.[1]?.at(-1) }) })] })) : null }));
9
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"default-async-functions.d.ts","sourceRoot":"","sources":["../src/default-async-functions.js"],"names":[],"mappings":"AAqHA;;;;;;;GAOG;AACH,qDALG;IAAyB,WAAW,EAA5B,WAAW;CACnB,WAAQ,MAAM,kBACN,IAAI,GAAG,kBAAkB,GACvB,OAAO,CAAC,MAAM,EAAE,CAAC,CAiB7B;AAeD;;;;;;;GAOG;AACH,kDALG;IAAyB,WAAW,EAA5B,WAAW;CACnB,QAAQ,MAAM,kBACN,kBAAkB,GAChB,OAAO,CAAC,MAAM,EAAE,CAAC,CAkC7B;AAED;;;;;;GAMG;AACH,qDAJG;IAAyB,WAAW,EAA5B,WAAW;CACnB,SAAQ,MAAM,GACJ,OAAO,CAAC,MAAM,EAAE,CAAC,CA2B7B;AAED;;;;;;;GAOG;AACH,gDALG;IAAyB,WAAW,EAA5B,WAAW;CACnB,kBAAQ,MAAM,kBACN,MAAM,GACJ,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAoBxC;iCAzPsD,uBAAuB;wCADsE,iBAAiB;4BAAjB,iBAAiB"}
1
+ {"version":3,"file":"default-async-functions.d.ts","sourceRoot":"","sources":["../src/default-async-functions.js"],"names":[],"mappings":"AAqHA;;;;;;;GAOG;AACH,qDALG;IAAyB,WAAW,EAA5B,WAAW;CACnB,WAAQ,MAAM,kBACN,IAAI,GAAG,kBAAkB,GACvB,OAAO,CAAC,MAAM,EAAE,CAAC,CAiB7B;AAeD;;;;;;;GAOG;AACH,kDALG;IAAyB,WAAW,EAA5B,WAAW;CACnB,QAAQ,MAAM,kBACN,kBAAkB,GAChB,OAAO,CAAC,MAAM,EAAE,CAAC,CAmC7B;AAED;;;;;;GAMG;AACH,qDAJG;IAAyB,WAAW,EAA5B,WAAW;CACnB,SAAQ,MAAM,GACJ,OAAO,CAAC,MAAM,EAAE,CAAC,CA2B7B;AAED;;;;;;;GAOG;AACH,gDALG;IAAyB,WAAW,EAA5B,WAAW;CACnB,kBAAQ,MAAM,kBACN,MAAM,GACJ,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAoBxC;iCA1PsD,uBAAuB;wCADsE,iBAAiB;4BAAjB,iBAAiB"}
@@ -161,6 +161,7 @@ export async function transformFeature({ queryClient }, node, targetModality) {
161
161
  staleTime: Infinity,
162
162
  queryFn: loadPathwayToGeneEdges,
163
163
  });
164
+ // TODO: support matching using ontology term (rather than requiring kgId)?
164
165
  const matchingEdges = pathwayGeneEdges.filter((/** @type {KgEdge} */ d) => d.source === node.kgId);
165
166
  const matchingGeneIds = matchingEdges.map((/** @type {KgEdge} */ d) => d.target);
166
167
  const matchingGenes = geneNodes.filter(d => matchingGeneIds.includes(d.kgId));
@@ -1,3 +1,4 @@
1
1
  export { BiomarkerSelectSubscriber } from "./BiomarkerSelectSubscriber.js";
2
+ export { ComparativeHeadingSubscriber } from "./ComparativeHeadingSubscriber.js";
2
3
  export { autocompleteFeature, transformFeature, getAlternativeTerms, getTermMapping } from "./default-async-functions.js";
3
4
  //# sourceMappingURL=index.d.ts.map
package/dist-tsc/index.js CHANGED
@@ -1,2 +1,3 @@
1
1
  export { BiomarkerSelectSubscriber } from './BiomarkerSelectSubscriber.js';
2
+ export { ComparativeHeadingSubscriber } from './ComparativeHeadingSubscriber.js';
2
3
  export { autocompleteFeature, transformFeature, getAlternativeTerms, getTermMapping, } from './default-async-functions.js';
@@ -1 +1 @@
1
- {"version":3,"file":"scmd-ui.d.ts","sourceRoot":"","sources":["../src/scmd-ui.js"],"names":[],"mappings":"AAOA,gDAmEC"}
1
+ {"version":3,"file":"scmd-ui.d.ts","sourceRoot":"","sources":["../src/scmd-ui.js"],"names":[],"mappings":"AAQA,gDAkFC"}
@@ -2,7 +2,8 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  /* eslint-disable no-unused-vars */
3
3
  import React, { useState } from 'react';
4
4
  import { Button, ButtonGroup, Grid, Tooltip } from '@material-ui/core';
5
- import { ConfirmatoryStepper } from './confirmatory-stepper.js';
5
+ import { ConfirmatoryStepper } from './stepper-confirmatory.js';
6
+ import { ExploratoryStepper } from './stepper-exploratory.js';
6
7
  import { useStyles } from './styles.js';
7
8
  export function ScmdUi(props) {
8
9
  const { mode: modeProp, setMode, step: stepProp, setStep, currentModalityAgnosticSelection, setCurrentModalityAgnosticSelection, currentModalitySpecificSelection, setCurrentModalitySpecificSelection, currentStratificationSelection, setCurrentStratificationSelection, autocompleteNode, getEdges, stratifications, onFinish, } = props;
@@ -11,5 +12,5 @@ export function ScmdUi(props) {
11
12
  const step = mode === 'confirmatory' ? (stepProp || 'select-biomarkers') : (stepProp || 'define-stratification');
12
13
  const [tempIsVisible, setTempIsVisible] = useState(true);
13
14
  const isConfirmatoryMode = mode === 'confirmatory';
14
- return (_jsxs(Grid, { container: true, style: { border: '0px solid red' }, children: [_jsxs(Grid, { item: true, container: true, xs: 12, className: classes.header, children: [_jsx(Grid, { item: true, xs: 8 }), _jsx(Grid, { item: true, container: true, xs: 4, justifyContent: "flex-end", children: _jsxs(ButtonGroup, { variant: "outlined", size: "small", color: "secondary", "aria-label": "Toggle between confirmatory and exploratory modes", children: [_jsx(Tooltip, { arrow: true, title: "Start from biomarker(s) of interest", children: _jsx(Button, { variant: isConfirmatoryMode ? 'contained' : 'outlined', onClick: () => setMode('confirmatory'), children: "Confirmatory (Hypothesis-driven)" }) }), _jsx(Tooltip, { arrow: true, title: "Lacking biomarker(s) of interest", children: _jsx(Button, { variant: !isConfirmatoryMode ? 'contained' : 'outlined', onClick: () => setMode('exploratory'), children: "Exploratory (Hypothesis-generating)" }) })] }) })] }), tempIsVisible ? (_jsxs("div", { style: { border: '2px solid #eee', borderRadius: '5px' }, children: [mode === 'confirmatory' ? (_jsx(ConfirmatoryStepper, { autocompleteNode: autocompleteNode, currentModalityAgnosticSelection: currentModalityAgnosticSelection, setCurrentModalityAgnosticSelection: setCurrentModalityAgnosticSelection, currentModalitySpecificSelection: currentModalitySpecificSelection, setCurrentModalitySpecificSelection: setCurrentModalitySpecificSelection, currentStratificationSelection: currentStratificationSelection, setCurrentStratificationSelection: setCurrentStratificationSelection, getEdges: getEdges, stratifications: stratifications, onFinish: onFinish })) : null, mode === 'exploratory' ? _jsx("span", { children: "TODO" }) : null] })) : null] }));
15
+ return (_jsxs(Grid, { container: true, style: { border: '0px solid red' }, children: [_jsxs(Grid, { item: true, container: true, xs: 12, className: classes.header, children: [_jsx(Grid, { item: true, xs: 8 }), _jsx(Grid, { item: true, container: true, xs: 4, justifyContent: "flex-end", children: _jsxs(ButtonGroup, { variant: "outlined", size: "small", color: "secondary", "aria-label": "Toggle between confirmatory and exploratory modes", children: [_jsx(Tooltip, { arrow: true, title: "Start from biomarker(s) of interest", children: _jsx(Button, { variant: isConfirmatoryMode ? 'contained' : 'outlined', onClick: () => setMode('confirmatory'), children: "Confirmatory (Hypothesis-driven)" }) }), _jsx(Tooltip, { arrow: true, title: "Lacking biomarker(s) of interest", children: _jsx(Button, { variant: !isConfirmatoryMode ? 'contained' : 'outlined', onClick: () => setMode('exploratory'), children: "Exploratory (Hypothesis-generating)" }) })] }) })] }), tempIsVisible ? (_jsxs("div", { style: { border: '2px solid #eee', borderRadius: '5px' }, children: [mode === 'confirmatory' ? (_jsx(ConfirmatoryStepper, { autocompleteNode: autocompleteNode, currentModalityAgnosticSelection: currentModalityAgnosticSelection, setCurrentModalityAgnosticSelection: setCurrentModalityAgnosticSelection, currentModalitySpecificSelection: currentModalitySpecificSelection, setCurrentModalitySpecificSelection: setCurrentModalitySpecificSelection, currentStratificationSelection: currentStratificationSelection, setCurrentStratificationSelection: setCurrentStratificationSelection, getEdges: getEdges, stratifications: stratifications, onFinish: onFinish })) : null, mode === 'exploratory' ? (_jsx(ExploratoryStepper, { autocompleteNode: autocompleteNode, currentModalityAgnosticSelection: currentModalityAgnosticSelection, setCurrentModalityAgnosticSelection: setCurrentModalityAgnosticSelection, currentModalitySpecificSelection: currentModalitySpecificSelection, setCurrentModalitySpecificSelection: setCurrentModalitySpecificSelection, currentStratificationSelection: currentStratificationSelection, setCurrentStratificationSelection: setCurrentStratificationSelection, getEdges: getEdges, stratifications: stratifications, onFinish: onFinish })) : null] })) : null] }));
15
16
  }
@@ -1,2 +1,2 @@
1
1
  export function ConfirmatoryStepper(props: any): JSX.Element;
2
- //# sourceMappingURL=confirmatory-stepper.d.ts.map
2
+ //# sourceMappingURL=stepper-confirmatory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stepper-confirmatory.d.ts","sourceRoot":"","sources":["../src/stepper-confirmatory.js"],"names":[],"mappings":"AAcA,6DAkMC"}
@@ -0,0 +1,2 @@
1
+ export function ExploratoryStepper(props: any): JSX.Element;
2
+ //# sourceMappingURL=stepper-exploratory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stepper-exploratory.d.ts","sourceRoot":"","sources":["../src/stepper-exploratory.js"],"names":[],"mappings":"AAUA,4DAoKC"}
@@ -0,0 +1,61 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import React, { useEffect } from 'react';
3
+ import { Stepper, Step, StepLabel, Button, Grid, Box, Typography } from '@material-ui/core';
4
+ import { ConfirmatoryCart } from './cart.js';
5
+ import { SelectStratification } from './select-stratification.js';
6
+ import { useStyles } from './styles.js';
7
+ const steps = [
8
+ 'Define case-control stratification',
9
+ ];
10
+ export function ExploratoryStepper(props) {
11
+ const { autocompleteNode, currentModalityAgnosticSelection, setCurrentModalityAgnosticSelection, currentModalitySpecificSelection, setCurrentModalitySpecificSelection, currentStratificationSelection, setCurrentStratificationSelection, getEdges, stratifications, onFinish, } = props;
12
+ const classes = useStyles();
13
+ const [activeStep, setActiveStep] = React.useState(0);
14
+ const [skipped, setSkipped] = React.useState(new Set());
15
+ const isStepOptional = step => step === 2;
16
+ const isStepSkipped = step => skipped.has(step);
17
+ const handleNext = () => {
18
+ let newSkipped = skipped;
19
+ if (isStepSkipped(activeStep)) {
20
+ newSkipped = new Set(newSkipped.values());
21
+ newSkipped.delete(activeStep);
22
+ }
23
+ setActiveStep(prevActiveStep => prevActiveStep + 1);
24
+ setSkipped(newSkipped);
25
+ };
26
+ const handleBack = () => {
27
+ setActiveStep(prevActiveStep => prevActiveStep - 1);
28
+ };
29
+ const handleSkip = () => {
30
+ if (!isStepOptional(activeStep)) {
31
+ // You probably want to guard against something like this,
32
+ // it should never occur unless someone's actively trying to break something.
33
+ throw new Error("You can't skip a step that isn't optional.");
34
+ }
35
+ setActiveStep(prevActiveStep => prevActiveStep + 1);
36
+ setSkipped((prevSkipped) => {
37
+ const newSkipped = new Set(prevSkipped.values());
38
+ newSkipped.add(activeStep);
39
+ return newSkipped;
40
+ });
41
+ };
42
+ const handleReset = () => {
43
+ setActiveStep(0);
44
+ };
45
+ useEffect(() => {
46
+ if (activeStep === steps.length) {
47
+ onFinish();
48
+ }
49
+ }, [activeStep, steps]);
50
+ return (_jsxs(Grid, { item: true, container: true, xs: 12, children: [_jsx(Grid, { item: true, container: true, xs: 12, children: _jsx(Box, { className: classes.fullWidthBox, children: _jsx(Stepper, { activeStep: activeStep, children: steps.map((label, index) => {
51
+ const stepProps = {};
52
+ const labelProps = {};
53
+ if (isStepOptional(index)) {
54
+ labelProps.optional = (_jsx(Typography, { variant: "caption", children: "Optional" }));
55
+ }
56
+ if (isStepSkipped(index)) {
57
+ stepProps.completed = false;
58
+ }
59
+ return (_jsx(Step, { ...stepProps, children: _jsx(StepLabel, { ...labelProps, children: label }) }, label));
60
+ }) }) }) }), _jsxs(Grid, { item: true, container: true, xs: 12, style: { marginTop: '20px' }, alignItems: "flex-start", children: [_jsx(Grid, { item: true, container: true, xs: 8, children: activeStep === steps.length ? (_jsx(_Fragment, { children: _jsx(Typography, { style: { marginTop: '20px', marginBottom: '10px' }, children: "All steps completed - you're finished" }) })) : (_jsx(_Fragment, { children: activeStep === 0 ? (_jsx(SelectStratification, { autocompleteNode: autocompleteNode, currentModalityAgnosticSelection: currentModalityAgnosticSelection, setCurrentModalityAgnosticSelection: setCurrentModalityAgnosticSelection, currentModalitySpecificSelection: currentModalitySpecificSelection, setCurrentModalitySpecificSelection: setCurrentModalitySpecificSelection, currentStratificationSelection: currentStratificationSelection, setCurrentStratificationSelection: setCurrentStratificationSelection, getEdges: getEdges, stratifications: stratifications })) : null })) }), _jsx(Grid, { item: true, container: true, xs: 4, children: _jsx(ConfirmatoryCart, { currentModalityAgnosticSelection: currentModalityAgnosticSelection, setCurrentModalityAgnosticSelection: setCurrentModalityAgnosticSelection, currentModalitySpecificSelection: currentModalitySpecificSelection, setCurrentModalitySpecificSelection: setCurrentModalitySpecificSelection, currentStratificationSelection: currentStratificationSelection, setCurrentStratificationSelection: setCurrentStratificationSelection, stratifications: stratifications }) }), _jsx(Box, { className: classes.fullWidthBox, children: activeStep === steps.length ? (_jsx(_Fragment, { children: _jsxs(Box, { style: { display: 'flex', flexDirection: 'row', paddingTop: '20px' }, children: [_jsx(Box, { style: { flex: '1 1 auto' } }), _jsx(Button, { onClick: handleReset, children: "Reset" })] }) })) : (_jsxs(Box, { style: { display: 'flex', flexDirection: 'row', paddingTop: '20px' }, children: [_jsx(Button, { color: "inherit", disabled: activeStep === 0, onClick: handleBack, style: { mr: 1 }, children: "Back" }), _jsx(Box, { style: { flex: '1 1 auto' } }), isStepOptional(activeStep) && (_jsx(Button, { color: "inherit", onClick: handleSkip, style: { marginRight: '10px' }, children: "Skip" })), _jsx(Button, { onClick: handleNext, children: activeStep === steps.length - 1 ? 'Finish' : 'Next' })] })) })] })] }));
61
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vitessce/biomarker-select",
3
- "version": "3.5.6",
3
+ "version": "3.5.8",
4
4
  "author": "Gehlenborg Lab",
5
5
  "homepage": "http://vitessce.io",
6
6
  "repository": {
@@ -24,9 +24,9 @@
24
24
  "react-window": "^1.8.10",
25
25
  "fuse.js": "^7.0.0",
26
26
  "d3-dsv": "^1.1.1",
27
- "@vitessce/constants-internal": "3.5.6",
28
- "@vitessce/vit-s": "3.5.6",
29
- "@vitessce/types": "3.5.6"
27
+ "@vitessce/constants-internal": "3.5.8",
28
+ "@vitessce/vit-s": "3.5.8",
29
+ "@vitessce/types": "3.5.8"
30
30
  },
31
31
  "devDependencies": {
32
32
  "@testing-library/jest-dom": "^5.16.4",
@@ -1,17 +1,20 @@
1
1
  /* eslint-disable max-len */
2
2
  /* eslint-disable no-unused-vars */
3
- import React, { useState, useCallback } from 'react';
3
+ import React, { useState, useCallback, useMemo } from 'react';
4
4
  import {
5
5
  useAsyncFunction,
6
6
  useViewConfigStoreApi,
7
7
  useSetViewConfig,
8
8
  useViewConfig,
9
9
  useCoordination,
10
+ useLoaders,
11
+ useComparisonMetadata,
12
+ useMatchingLoader,
13
+ useColumnNameMapping,
10
14
  } from '@vitessce/vit-s';
11
- import { AsyncFunctionType, ViewType, COMPONENT_COORDINATION_TYPES } from '@vitessce/constants-internal';
15
+ import { AsyncFunctionType, ViewType, COMPONENT_COORDINATION_TYPES, DataType } from '@vitessce/constants-internal';
12
16
  import { ScmdUi } from './scmd-ui.js';
13
17
 
14
-
15
18
  /**
16
19
  *
17
20
  * @param {object} props
@@ -21,10 +24,15 @@ import { ScmdUi } from './scmd-ui.js';
21
24
  export function BiomarkerSelectSubscriber(props) {
22
25
  const {
23
26
  coordinationScopes,
24
- stratificationOptions,
27
+ stratificationOptions: stratificationOptionsProp, // TODO: Remove; Get from comparisonMetadata instead
25
28
  } = props;
26
29
 
30
+ const loaders = useLoaders();
31
+
27
32
  const [{
33
+ dataset,
34
+ obsType,
35
+ sampleType,
28
36
  sampleSetSelection,
29
37
  featureSelection,
30
38
  }, {
@@ -40,6 +48,16 @@ export function BiomarkerSelectSubscriber(props) {
40
48
  const setViewConfig = useSetViewConfig(viewConfigStoreApi);
41
49
 
42
50
 
51
+ // Need obsSets and sampleSets options to obtain mapping between
52
+ // group names and column names.
53
+ const obsSetsLoader = useMatchingLoader(
54
+ loaders, dataset, DataType.OBS_SETS, { obsType },
55
+ );
56
+ const sampleSetsLoader = useMatchingLoader(
57
+ loaders, dataset, DataType.SAMPLE_SETS, { sampleType },
58
+ );
59
+ const sampleSetsColumnNameMappingReversed = useColumnNameMapping(sampleSetsLoader, true);
60
+
43
61
  // TODO: make isSelecting a coordination type plugin.
44
62
  // TODO: use store hooks from @vitessce/vit-s to update the view config based on the selections.
45
63
  const [isSelecting, setIsSelecting] = useState(true);
@@ -62,6 +80,43 @@ export function BiomarkerSelectSubscriber(props) {
62
80
  [transformFeature],
63
81
  );
64
82
 
83
+ const [{ comparisonMetadata }, cmpMetadataStatus, cmpMetadataUrls] = useComparisonMetadata(
84
+ loaders, dataset, false, {}, {}, { obsType, sampleType },
85
+ );
86
+ const stratificationOptions = useMemo(() => {
87
+ /*
88
+ return array of objects like {
89
+ stratificationId: 'aki-vs-hr',
90
+ name: 'Acute kidney injury (AKI) vs. Healthy reference',
91
+ stratificationType: 'sampleSet', // key changed from 'groupType'. value changed from 'clinical'
92
+ sampleSets: [
93
+ ['Disease Type', 'AKI'],
94
+ ['Disease Type', 'Reference'],
95
+ ],
96
+ },
97
+ */
98
+ if (comparisonMetadata?.sample_group_pairs) {
99
+ return comparisonMetadata.sample_group_pairs.map((sampleGroupPair) => {
100
+ const [sampleGroupCol, sampleGroupValues] = sampleGroupPair;
101
+ const [sampleGroupCtrl, sampleGroupCase] = sampleGroupValues;
102
+ const groupName = sampleSetsColumnNameMappingReversed?.[sampleGroupCol];
103
+ return {
104
+ stratificationId: `${sampleGroupCol}_${sampleGroupCtrl}-vs-${sampleGroupCase}`,
105
+ name: `${groupName}: ${sampleGroupCtrl} vs. ${sampleGroupCase}`,
106
+ stratificationType: 'sampleSet',
107
+ sampleSets: [
108
+ // With sampleSets coming from the comparison_metadata,
109
+ // need to use loader options from obsSets and sampleSets to get mapping
110
+ // from column name to group name.
111
+ [groupName, sampleGroupCtrl],
112
+ [groupName, sampleGroupCase],
113
+ ],
114
+ };
115
+ });
116
+ }
117
+ return null;
118
+ }, [comparisonMetadata, sampleSetsColumnNameMappingReversed]);
119
+
65
120
  return (
66
121
  <>
67
122
  {isSelecting ? (
@@ -80,20 +135,39 @@ export function BiomarkerSelectSubscriber(props) {
80
135
  getEdges={getEdges}
81
136
  stratifications={stratificationOptions}
82
137
  onFinish={() => {
83
- setViewConfig({
138
+ if (mode === 'exploratory') {
139
+ // mode is exploratory, configure accordingly.
140
+
141
+ // TODO
142
+
143
+ } else {
144
+ // mode is confirmatory, configure accordingly.
145
+
146
+ // TODO
147
+ }
148
+
149
+ const newViewConfig = {
84
150
  ...viewConfig,
85
151
  coordinationSpace: {
86
152
  ...viewConfig.coordinationSpace,
87
153
  sampleSetFilter: {
88
154
  ...viewConfig.coordinationSpace.sampleSetFilter,
89
- 'case-control': currentStratificationSelection?.sampleSets,
155
+ __comparison__: currentStratificationSelection?.sampleSets,
90
156
  },
91
157
  sampleSetSelection: {
92
158
  ...viewConfig.coordinationSpace.sampleSetSelection,
93
- 'case-control': currentStratificationSelection?.sampleSets,
159
+ __comparison__: currentStratificationSelection?.sampleSets,
160
+ },
161
+ featureSelection: {
162
+ ...viewConfig.coordinationSpace.featureSelection,
163
+ __comparison__: currentModalitySpecificSelection ? currentModalitySpecificSelection.map(d => d.label) : null,
94
164
  },
95
165
  },
96
- });
166
+ };
167
+
168
+ // TODO: can the normal coordination value setters be used instead?
169
+ // (e.g., setFeatureSelection, setSampleSetSelection)
170
+ setViewConfig(newViewConfig);
97
171
  }}
98
172
  />
99
173
  ) : null}
@@ -0,0 +1,31 @@
1
+ import React from 'react';
2
+ import {
3
+ useCoordination,
4
+ } from '@vitessce/vit-s';
5
+ import { ViewType, COMPONENT_COORDINATION_TYPES } from '@vitessce/constants-internal';
6
+
7
+
8
+ export function ComparativeHeadingSubscriber(props) {
9
+ const {
10
+ coordinationScopes,
11
+ } = props;
12
+
13
+ const [{
14
+ sampleSetSelection,
15
+ }] = useCoordination(
16
+ COMPONENT_COORDINATION_TYPES[ViewType.COMPARATIVE_HEADING],
17
+ coordinationScopes,
18
+ );
19
+
20
+ return (
21
+ <>
22
+ {sampleSetSelection && sampleSetSelection.length === 2 ? (
23
+ <div style={{ width: '100%', display: 'flex', flexDirection: 'row' }}>
24
+ <div style={{ width: '45%' }}><h2>{sampleSetSelection?.[0]?.at(-1)}</h2></div>
25
+ <div style={{ width: '5%' }}><h2 style={{ textAlign: 'right' }}>vs.&nbsp;</h2></div>
26
+ <div style={{ width: '50%' }}><h2>{sampleSetSelection?.[1]?.at(-1)}</h2></div>
27
+ </div>
28
+ ) : null}
29
+ </>
30
+ );
31
+ }
@@ -180,6 +180,7 @@ export async function transformFeature({ queryClient }, node, targetModality) {
180
180
  queryFn: loadPathwayToGeneEdges,
181
181
  });
182
182
 
183
+ // TODO: support matching using ontology term (rather than requiring kgId)?
183
184
  const matchingEdges = pathwayGeneEdges.filter((/** @type {KgEdge} */ d) => d.source === node.kgId);
184
185
  const matchingGeneIds = matchingEdges.map((/** @type {KgEdge} */ d) => d.target);
185
186
  const matchingGenes = geneNodes.filter(d => matchingGeneIds.includes(d.kgId));
package/src/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export { BiomarkerSelectSubscriber } from './BiomarkerSelectSubscriber.js';
2
+ export { ComparativeHeadingSubscriber } from './ComparativeHeadingSubscriber.js';
2
3
  export {
3
4
  autocompleteFeature,
4
5
  transformFeature,
package/src/scmd-ui.js CHANGED
@@ -1,7 +1,8 @@
1
1
  /* eslint-disable no-unused-vars */
2
2
  import React, { useState } from 'react';
3
3
  import { Button, ButtonGroup, Grid, Tooltip } from '@material-ui/core';
4
- import { ConfirmatoryStepper } from './confirmatory-stepper.js';
4
+ import { ConfirmatoryStepper } from './stepper-confirmatory.js';
5
+ import { ExploratoryStepper } from './stepper-exploratory.js';
5
6
  import { useStyles } from './styles.js';
6
7
 
7
8
 
@@ -67,7 +68,22 @@ export function ScmdUi(props) {
67
68
  onFinish={onFinish}
68
69
  />
69
70
  ) : null}
70
- {mode === 'exploratory' ? <span>TODO</span> : null}
71
+ {mode === 'exploratory' ? (
72
+ <ExploratoryStepper
73
+ autocompleteNode={autocompleteNode}
74
+
75
+ currentModalityAgnosticSelection={currentModalityAgnosticSelection}
76
+ setCurrentModalityAgnosticSelection={setCurrentModalityAgnosticSelection}
77
+ currentModalitySpecificSelection={currentModalitySpecificSelection}
78
+ setCurrentModalitySpecificSelection={setCurrentModalitySpecificSelection}
79
+ currentStratificationSelection={currentStratificationSelection}
80
+ setCurrentStratificationSelection={setCurrentStratificationSelection}
81
+
82
+ getEdges={getEdges}
83
+ stratifications={stratifications}
84
+ onFinish={onFinish}
85
+ />
86
+ ) : null}
71
87
  </div>
72
88
  ) : null}
73
89
  </Grid>
@@ -0,0 +1,175 @@
1
+ import React, { useEffect } from 'react';
2
+ import { Stepper, Step, StepLabel, Button, Grid, Box, Typography } from '@material-ui/core';
3
+ import { ConfirmatoryCart } from './cart.js';
4
+ import { SelectStratification } from './select-stratification.js';
5
+ import { useStyles } from './styles.js';
6
+
7
+ const steps = [
8
+ 'Define case-control stratification',
9
+ ];
10
+
11
+ export function ExploratoryStepper(props) {
12
+ const {
13
+ autocompleteNode,
14
+
15
+ currentModalityAgnosticSelection,
16
+ setCurrentModalityAgnosticSelection,
17
+ currentModalitySpecificSelection,
18
+ setCurrentModalitySpecificSelection,
19
+ currentStratificationSelection,
20
+ setCurrentStratificationSelection,
21
+
22
+ getEdges,
23
+ stratifications,
24
+ onFinish,
25
+ } = props;
26
+ const classes = useStyles();
27
+ const [activeStep, setActiveStep] = React.useState(0);
28
+ const [skipped, setSkipped] = React.useState(new Set());
29
+
30
+ const isStepOptional = step => step === 2;
31
+
32
+ const isStepSkipped = step => skipped.has(step);
33
+
34
+ const handleNext = () => {
35
+ let newSkipped = skipped;
36
+ if (isStepSkipped(activeStep)) {
37
+ newSkipped = new Set(newSkipped.values());
38
+ newSkipped.delete(activeStep);
39
+ }
40
+
41
+ setActiveStep(prevActiveStep => prevActiveStep + 1);
42
+ setSkipped(newSkipped);
43
+ };
44
+
45
+ const handleBack = () => {
46
+ setActiveStep(prevActiveStep => prevActiveStep - 1);
47
+ };
48
+
49
+ const handleSkip = () => {
50
+ if (!isStepOptional(activeStep)) {
51
+ // You probably want to guard against something like this,
52
+ // it should never occur unless someone's actively trying to break something.
53
+ throw new Error("You can't skip a step that isn't optional.");
54
+ }
55
+
56
+ setActiveStep(prevActiveStep => prevActiveStep + 1);
57
+ setSkipped((prevSkipped) => {
58
+ const newSkipped = new Set(prevSkipped.values());
59
+ newSkipped.add(activeStep);
60
+ return newSkipped;
61
+ });
62
+ };
63
+
64
+ const handleReset = () => {
65
+ setActiveStep(0);
66
+ };
67
+
68
+ useEffect(() => {
69
+ if (activeStep === steps.length) {
70
+ onFinish();
71
+ }
72
+ }, [activeStep, steps]);
73
+
74
+
75
+ return (
76
+ <Grid item container xs={12}>
77
+ <Grid item container xs={12}>
78
+ <Box className={classes.fullWidthBox}>
79
+ <Stepper activeStep={activeStep}>
80
+ {steps.map((label, index) => {
81
+ const stepProps = {};
82
+ const labelProps = {};
83
+ if (isStepOptional(index)) {
84
+ labelProps.optional = (
85
+ <Typography variant="caption">Optional</Typography>
86
+ );
87
+ }
88
+ if (isStepSkipped(index)) {
89
+ stepProps.completed = false;
90
+ }
91
+ return (
92
+ <Step key={label} {...stepProps}>
93
+ <StepLabel {...labelProps}>{label}</StepLabel>
94
+ </Step>
95
+ );
96
+ })}
97
+ </Stepper>
98
+ </Box>
99
+ </Grid>
100
+ <Grid item container xs={12} style={{ marginTop: '20px' }} alignItems="flex-start">
101
+ {/* Step contents to left of cart */}
102
+ <Grid item container xs={8}>
103
+ {activeStep === steps.length ? (
104
+ <>
105
+ <Typography style={{ marginTop: '20px', marginBottom: '10px' }}>
106
+ All steps completed - you&apos;re finished
107
+ </Typography>
108
+ </>
109
+ ) : (
110
+ <>
111
+ {activeStep === 0 ? (
112
+ <SelectStratification
113
+ autocompleteNode={autocompleteNode}
114
+
115
+ currentModalityAgnosticSelection={currentModalityAgnosticSelection}
116
+ setCurrentModalityAgnosticSelection={setCurrentModalityAgnosticSelection}
117
+ currentModalitySpecificSelection={currentModalitySpecificSelection}
118
+ setCurrentModalitySpecificSelection={setCurrentModalitySpecificSelection}
119
+ currentStratificationSelection={currentStratificationSelection}
120
+ setCurrentStratificationSelection={setCurrentStratificationSelection}
121
+
122
+ getEdges={getEdges}
123
+ stratifications={stratifications}
124
+ />
125
+ ) : null}
126
+ </>
127
+ )}
128
+ </Grid>
129
+ {/* Cart */}
130
+ <Grid item container xs={4}>
131
+ <ConfirmatoryCart
132
+ currentModalityAgnosticSelection={currentModalityAgnosticSelection}
133
+ setCurrentModalityAgnosticSelection={setCurrentModalityAgnosticSelection}
134
+ currentModalitySpecificSelection={currentModalitySpecificSelection}
135
+ setCurrentModalitySpecificSelection={setCurrentModalitySpecificSelection}
136
+ currentStratificationSelection={currentStratificationSelection}
137
+ setCurrentStratificationSelection={setCurrentStratificationSelection}
138
+ stratifications={stratifications}
139
+ />
140
+ </Grid>
141
+ {/* Step navigation button footer */}
142
+ <Box className={classes.fullWidthBox}>
143
+ {activeStep === steps.length ? (
144
+ <>
145
+ <Box style={{ display: 'flex', flexDirection: 'row', paddingTop: '20px' }}>
146
+ <Box style={{ flex: '1 1 auto' }} />
147
+ <Button onClick={handleReset}>Reset</Button>
148
+ </Box>
149
+ </>
150
+ ) : (
151
+ <Box style={{ display: 'flex', flexDirection: 'row', paddingTop: '20px' }}>
152
+ <Button
153
+ color="inherit"
154
+ disabled={activeStep === 0}
155
+ onClick={handleBack}
156
+ style={{ mr: 1 }}
157
+ >
158
+ Back
159
+ </Button>
160
+ <Box style={{ flex: '1 1 auto' }} />
161
+ {isStepOptional(activeStep) && (
162
+ <Button color="inherit" onClick={handleSkip} style={{ marginRight: '10px' }}>
163
+ Skip
164
+ </Button>
165
+ )}
166
+ <Button onClick={handleNext}>
167
+ {activeStep === steps.length - 1 ? 'Finish' : 'Next'}
168
+ </Button>
169
+ </Box>
170
+ )}
171
+ </Box>
172
+ </Grid>
173
+ </Grid>
174
+ );
175
+ }
@@ -1 +0,0 @@
1
- {"version":3,"file":"confirmatory-stepper.d.ts","sourceRoot":"","sources":["../src/confirmatory-stepper.js"],"names":[],"mappings":"AAcA,6DAkMC"}