• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

CBIIT / bento-c3dc-frontend / 24211815732

09 Apr 2026 08:29PM UTC coverage: 0.115% (-0.04%) from 0.153%
24211815732

Pull #504

github

web-flow
Merge 0d7e2c537 into 850690c82
Pull Request #504: C3DC 2146

6 of 5909 branches covered (0.1%)

Branch coverage included in aggregate %.

0 of 2221 new or added lines in 69 files covered. (0.0%)

31 existing lines in 7 files now uncovered.

10 of 7992 relevant lines covered (0.13%)

0.06 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/pages/CohortAnalyzer/HistogramPanel/hooks/useHistogramPanelBootstrap.js
NEW
1
import { useCallback, useEffect, useState } from 'react';
×
NEW
2
import { useDispatch, useSelector } from 'react-redux';
×
NEW
3
import { ADD_CHART_DATA_TYPES } from '../../config/cohortAnalyzerChartCatalog';
×
NEW
4
import {
×
5
  setStripOrder,
6
  setBesideStripPanelId,
7
  setSurvivalBesideFromSelection,
8
  upsertPanelRegistry,
9
  patchChartVisuals,
10
} from '../../store/cohortAnalyzerLayoutActions';
NEW
11
import { CA_PANEL_KIND } from '../../store/cohortAnalyzerLayoutConstants';
×
NEW
12
import {
×
13
  COHORT_ANALYZER_HISTOGRAM_TITLES as titles,
14
  buildDefaultCohortAnalyzerPanelRegistry,
15
} from '../../store/cohortAnalyzerDefaultPanelRegistry';
16

17
/**
18
 * Inline add-chart flow, strip/beside sync with selection, chart-type menu and download dropdown UX.
19
 */
20
export function useHistogramPanelBootstrap({
21
  selectedDatasets,
22
  setSelectedDatasets,
23
  setActiveTab,
24
  setExpandedChart,
25
  inlineAddChartOpen,
26
  inlineAddChartNonce,
27
  onInlineAddChartClose,
28
  reduxHistogramSizes,
29
  reduxSurvivalSize,
30
  chartTypeMenuDataset,
31
  setChartTypeMenuDataset,
32
  chartTypeMenuRef,
33
  showDownloadDropdown,
34
  setShowDownloadDropdown,
35
  dropdownRef,
36
  histogramCardSizes,
37
  setHistogramCardSizes,
38
  setSurvivalCardSize,
39
}) {
NEW
40
  const dispatch = useDispatch();
×
NEW
41
  const stripOrder = useSelector((state) => state.cohortAnalyzerLayout.stripOrder);
×
NEW
42
  const besideStripPanelId = useSelector((state) => state.cohortAnalyzerLayout.besideStripPanelId);
×
43

NEW
44
  const [inlineAddStep, setInlineAddStep] = useState(1);
×
NEW
45
  const [inlineSelectedCatalogId, setInlineSelectedCatalogId] = useState(null);
×
46

NEW
47
  useEffect(() => {
×
NEW
48
    if (!inlineAddChartOpen) return;
×
NEW
49
    setInlineAddStep(1);
×
NEW
50
    setInlineSelectedCatalogId(null);
×
51
  }, [inlineAddChartOpen, inlineAddChartNonce]);
52

NEW
53
  useEffect(() => {
×
NEW
54
    const handleClickOutside = (event) => {
×
NEW
55
      if (
×
56
        chartTypeMenuDataset
×
57
        && chartTypeMenuRef.current
58
        && !chartTypeMenuRef.current.contains(event.target)
59
      ) {
NEW
60
        setChartTypeMenuDataset(null);
×
61
      }
62
    };
NEW
63
    if (chartTypeMenuDataset) {
×
NEW
64
      document.addEventListener('mousedown', handleClickOutside);
×
65
    }
NEW
66
    return () => document.removeEventListener('mousedown', handleClickOutside);
×
67
  }, [chartTypeMenuDataset, chartTypeMenuRef, setChartTypeMenuDataset]);
68

NEW
69
  useEffect(() => {
×
NEW
70
    dispatch(upsertPanelRegistry(buildDefaultCohortAnalyzerPanelRegistry()));
×
71
  }, [dispatch]);
72

NEW
73
  const finalizeInlineAddChart = useCallback(
×
74
    (chartTypeSelected, catalogEntryId) => {
NEW
75
      const catalogId = catalogEntryId != null ? catalogEntryId : inlineSelectedCatalogId;
×
NEW
76
      const selectedEntry = ADD_CHART_DATA_TYPES.find((e) => e.id === catalogId);
×
NEW
77
      if (!selectedEntry || !selectedEntry.datasetKey) return;
×
NEW
78
      const skipChartType = Boolean(selectedEntry.skipChartTypeStep);
×
NEW
79
      if (!skipChartType && chartTypeSelected == null) return;
×
80

NEW
81
      const datasetKey = selectedEntry.datasetKey;
×
NEW
82
      const label = selectedEntry.label;
×
83

NEW
84
      if (datasetKey === 'survivalAnalysis') {
×
NEW
85
        if (selectedDatasets.includes('survivalAnalysis')) {
×
NEW
86
          if (typeof onInlineAddChartClose === 'function') onInlineAddChartClose();
×
NEW
87
          return;
×
88
        }
NEW
89
        dispatch(
×
90
          upsertPanelRegistry({
91
            [datasetKey]: {
92
              kind: CA_PANEL_KIND.SURVIVAL,
93
              chartKey: datasetKey,
94
              label: label || titles[datasetKey] || datasetKey,
×
95
            },
96
          }),
97
        );
NEW
98
        setSelectedDatasets((prev) => (prev.includes(datasetKey) ? prev : [...prev, datasetKey]));
×
NEW
99
        setActiveTab(datasetKey);
×
NEW
100
        if (typeof onInlineAddChartClose === 'function') {
×
NEW
101
          onInlineAddChartClose();
×
102
        }
NEW
103
        return;
×
104
      }
105

NEW
106
      if (stripOrder.includes(datasetKey)) {
×
NEW
107
        if (typeof onInlineAddChartClose === 'function') onInlineAddChartClose();
×
NEW
108
        return;
×
109
      }
NEW
110
      dispatch(
×
111
        upsertPanelRegistry({
112
          [datasetKey]: {
113
            kind: CA_PANEL_KIND.HISTOGRAM,
114
            chartKey: datasetKey,
115
            label: label || titles[datasetKey] || datasetKey,
×
116
          },
117
        }),
118
      );
NEW
119
      dispatch(patchChartVisuals({ [datasetKey]: chartTypeSelected }));
×
NEW
120
      const nextOrder = stripOrder.includes(datasetKey)
×
121
        ? stripOrder
×
122
        : [...stripOrder, datasetKey];
NEW
123
      dispatch(setStripOrder(nextOrder));
×
NEW
124
      setSelectedDatasets((prev) => (prev.includes(datasetKey) ? prev : [...prev, datasetKey]));
×
NEW
125
      setActiveTab(datasetKey);
×
NEW
126
      if (typeof onInlineAddChartClose === 'function') {
×
NEW
127
        onInlineAddChartClose();
×
128
      }
129
    },
130
    [
131
      inlineSelectedCatalogId,
132
      selectedDatasets,
133
      dispatch,
134
      stripOrder,
135
      onInlineAddChartClose,
136
      setSelectedDatasets,
137
      setActiveTab,
138
    ],
139
  );
140

NEW
141
  const handleRemoveHistogramDataset = useCallback((dataset) => {
×
NEW
142
    if (!dataset) return;
×
NEW
143
    setShowDownloadDropdown(false);
×
NEW
144
    setChartTypeMenuDataset((prev) => (prev === dataset ? null : prev));
×
NEW
145
    setExpandedChart((prev) => (prev === dataset ? null : prev));
×
NEW
146
    setSelectedDatasets((prev) => {
×
NEW
147
      const next = prev.filter((d) => d !== dataset);
×
NEW
148
      setActiveTab((tab) => {
×
NEW
149
        if (tab !== dataset) return tab;
×
NEW
150
        const remainingHisto = next.filter((d) => d !== 'survivalAnalysis');
×
NEW
151
        if (remainingHisto.length > 0) return remainingHisto[0];
×
NEW
152
        if (next.length > 0) return next[0];
×
NEW
153
        return 'sexAtBirth';
×
154
      });
NEW
155
      return next;
×
156
    });
157
  }, [setSelectedDatasets, setActiveTab, setExpandedChart, setShowDownloadDropdown, setChartTypeMenuDataset]);
158

NEW
159
  useEffect(() => {
×
NEW
160
    setHistogramCardSizes(reduxHistogramSizes);
×
161
  }, [reduxHistogramSizes, setHistogramCardSizes]);
162

NEW
163
  useEffect(() => {
×
NEW
164
    if (reduxSurvivalSize == null) return;
×
NEW
165
    setSurvivalCardSize((prev) => ({ ...(prev || {}), ...reduxSurvivalSize }));
×
166
  }, [reduxSurvivalSize, setSurvivalCardSize]);
167

NEW
168
  useEffect(() => {
×
NEW
169
    const handleClickOutside = (event) => {
×
NEW
170
      if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
×
NEW
171
        setShowDownloadDropdown(false);
×
172
      }
173
    };
174

NEW
175
    if (showDownloadDropdown) {
×
NEW
176
      document.addEventListener('mousedown', handleClickOutside);
×
177
    }
178

NEW
179
    return () => {
×
NEW
180
      document.removeEventListener('mousedown', handleClickOutside);
×
181
    };
182
  }, [showDownloadDropdown, dropdownRef, setShowDownloadDropdown]);
183

NEW
184
  useEffect(() => {
×
NEW
185
    const visibleDatasets = selectedDatasets.filter((dataset) => dataset !== 'survivalAnalysis');
×
NEW
186
    const hasTopRowTokensInStrip = stripOrder.some(
×
NEW
187
      (id) => id === 'venn' || id === 'survivalAnalysis',
×
188
    );
189

NEW
190
    if (stripOrder.length === 0 && visibleDatasets.length > 0) {
×
NEW
191
      let initial = [...visibleDatasets];
×
NEW
192
      if (besideStripPanelId != null && visibleDatasets.includes(besideStripPanelId)) {
×
NEW
193
        initial = [
×
194
          besideStripPanelId,
NEW
195
          ...visibleDatasets.filter((d) => d !== besideStripPanelId),
×
196
        ];
197
      }
NEW
198
      dispatch(setStripOrder(initial));
×
NEW
199
      return;
×
200
    }
201

NEW
202
    if (hasTopRowTokensInStrip) {
×
NEW
203
      const missing = visibleDatasets.filter((dataset) => !stripOrder.includes(dataset));
×
NEW
204
      if (missing.length > 0) {
×
NEW
205
        dispatch(setStripOrder([...stripOrder, ...missing]));
×
206
      }
NEW
207
      return;
×
208
    }
209

NEW
210
    const prevVisible = stripOrder.filter((dataset) => visibleDatasets.includes(dataset));
×
NEW
211
    const missing = visibleDatasets.filter((dataset) => !prevVisible.includes(dataset));
×
NEW
212
    const next = [...prevVisible, ...missing];
×
213
    const unchanged =
NEW
214
      next.length === stripOrder.length &&
×
NEW
215
      next.every((d, i) => d === stripOrder[i]);
×
NEW
216
    if (!unchanged) {
×
NEW
217
      dispatch(setStripOrder(next));
×
218
    }
219
  }, [selectedDatasets, stripOrder, besideStripPanelId, dispatch]);
220

NEW
221
  const survivalSelected = selectedDatasets.includes('survivalAnalysis');
×
222

NEW
223
  useEffect(() => {
×
NEW
224
    dispatch(setSurvivalBesideFromSelection(survivalSelected));
×
225
  }, [survivalSelected, dispatch]);
226

NEW
227
  useEffect(() => {
×
NEW
228
    if (survivalSelected) return;
×
NEW
229
    const visible = selectedDatasets.filter((d) => d !== 'survivalAnalysis');
×
NEW
230
    if (visible.length === 0) {
×
NEW
231
      if (besideStripPanelId != null) {
×
NEW
232
        dispatch(setBesideStripPanelId(null));
×
233
      }
NEW
234
      return;
×
235
    }
NEW
236
    if (besideStripPanelId != null && visible.includes(besideStripPanelId)) {
×
NEW
237
      return;
×
238
    }
NEW
239
    const order = stripOrder.filter((d) => visible.includes(d));
×
NEW
240
    const first = order[0] || visible[0];
×
NEW
241
    if (first) {
×
NEW
242
      dispatch(setBesideStripPanelId(first));
×
243
    }
244
  }, [
245
    survivalSelected,
246
    selectedDatasets,
247
    stripOrder,
248
    besideStripPanelId,
249
    dispatch,
250
  ]);
251

NEW
252
  return {
×
253
    stripOrder,
254
    inlineAddStep,
255
    setInlineAddStep,
256
    inlineSelectedCatalogId,
257
    setInlineSelectedCatalogId,
258
    finalizeInlineAddChart,
259
    handleRemoveHistogramDataset,
260
    survivalSelected,
261
  };
262
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc