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

CBIIT / bento-c3dc-frontend / 25557662953

08 May 2026 01:15PM UTC coverage: 0.112% (-0.04%) from 0.153%
25557662953

push

github

web-flow
Merge pull request #504 from CBIIT/C3DC-2146

C3DC 2146

6 of 6162 branches covered (0.1%)

Branch coverage included in aggregate %.

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

31 existing lines in 7 files now uncovered.

10 of 8158 relevant lines covered (0.12%)

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
  setTopRowOrder,
7
  setBesideStripPanelId,
8
  setSurvivalBesideFromSelection,
9
  upsertPanelRegistry,
10
  patchChartVisuals,
11
} from '../../store/cohortAnalyzerLayoutActions';
NEW
12
import { CA_PANEL_KIND } from '../../store/cohortAnalyzerLayoutConstants';
×
NEW
13
import {
×
14
  COHORT_ANALYZER_HISTOGRAM_TITLES as titles,
15
  buildDefaultCohortAnalyzerPanelRegistry,
16
} from '../../store/cohortAnalyzerDefaultPanelRegistry';
17

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

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

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

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

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

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

NEW
83
      const datasetKey = selectedEntry.datasetKey;
×
NEW
84
      const label = selectedEntry.label;
×
85

NEW
86
      if (datasetKey === 'survivalAnalysis') {
×
NEW
87
        if (selectedDatasets.includes('survivalAnalysis')) {
×
NEW
88
          if (typeof onInlineAddChartClose === 'function') onInlineAddChartClose();
×
NEW
89
          return;
×
90
        }
NEW
91
        dispatch(
×
92
          upsertPanelRegistry({
93
            [datasetKey]: {
94
              kind: CA_PANEL_KIND.SURVIVAL,
95
              chartKey: datasetKey,
96
              label: label || titles[datasetKey] || datasetKey,
×
97
            },
98
          }),
99
        );
100
        // Show survival only in the lower histogram strip (last), not beside Venn in the upper row.
NEW
101
        const stripWithoutSurvival = stripOrder.filter((id) => id !== 'survivalAnalysis');
×
NEW
102
        dispatch(setStripOrder([...stripWithoutSurvival, 'survivalAnalysis']));
×
NEW
103
        let nextTopRow = (topRowOrder || []).filter((p) => p !== 'survival');
×
NEW
104
        if (nextTopRow.length === 0) {
×
NEW
105
          nextTopRow = ['venn'];
×
106
        }
NEW
107
        dispatch(setTopRowOrder(nextTopRow));
×
NEW
108
        setSelectedDatasets((prev) => (prev.includes(datasetKey) ? prev : [...prev, datasetKey]));
×
109
        // Keep focus on a histogram tab — do not jump to survival (it stays last in expanded modal tabs).
NEW
110
        setActiveTab((tab) => {
×
NEW
111
          if (tab && tab !== 'survivalAnalysis') return tab;
×
NEW
112
          const histo = selectedDatasets.filter((d) => d !== 'survivalAnalysis');
×
NEW
113
          return histo.length > 0 ? histo[histo.length - 1] : 'sexAtBirth';
×
114
        });
NEW
115
        if (typeof onInlineAddChartClose === 'function') {
×
NEW
116
          onInlineAddChartClose();
×
117
        }
NEW
118
        return;
×
119
      }
120

NEW
121
      if (stripOrder.includes(datasetKey)) {
×
NEW
122
        if (typeof onInlineAddChartClose === 'function') onInlineAddChartClose();
×
NEW
123
        return;
×
124
      }
NEW
125
      dispatch(
×
126
        upsertPanelRegistry({
127
          [datasetKey]: {
128
            kind: CA_PANEL_KIND.HISTOGRAM,
129
            chartKey: datasetKey,
130
            label: label || titles[datasetKey] || datasetKey,
×
131
          },
132
        }),
133
      );
NEW
134
      dispatch(patchChartVisuals({ [datasetKey]: chartTypeSelected }));
×
NEW
135
      const nextOrder = stripOrder.includes(datasetKey)
×
136
        ? stripOrder
×
137
        : [...stripOrder, datasetKey];
NEW
138
      dispatch(setStripOrder(nextOrder));
×
NEW
139
      setSelectedDatasets((prev) => (prev.includes(datasetKey) ? prev : [...prev, datasetKey]));
×
NEW
140
      setActiveTab(datasetKey);
×
NEW
141
      if (typeof onInlineAddChartClose === 'function') {
×
NEW
142
        onInlineAddChartClose();
×
143
      }
144
    },
145
    [
146
      inlineSelectedCatalogId,
147
      selectedDatasets,
148
      dispatch,
149
      stripOrder,
150
      topRowOrder,
151
      onInlineAddChartClose,
152
      setSelectedDatasets,
153
      setActiveTab,
154
    ],
155
  );
156

NEW
157
  const handleRemoveHistogramDataset = useCallback((dataset) => {
×
NEW
158
    if (!dataset) return;
×
NEW
159
    setShowDownloadDropdown(false);
×
NEW
160
    setChartTypeMenuDataset((prev) => (prev === dataset ? null : prev));
×
NEW
161
    setExpandedChart((prev) => (prev === dataset ? null : prev));
×
NEW
162
    setSelectedDatasets((prev) => {
×
NEW
163
      const next = prev.filter((d) => d !== dataset);
×
NEW
164
      setActiveTab((tab) => {
×
NEW
165
        if (tab !== dataset) return tab;
×
NEW
166
        const remainingHisto = next.filter((d) => d !== 'survivalAnalysis');
×
NEW
167
        if (remainingHisto.length > 0) return remainingHisto[0];
×
NEW
168
        if (next.length > 0) return next[0];
×
NEW
169
        return 'sexAtBirth';
×
170
      });
NEW
171
      return next;
×
172
    });
173
  }, [setSelectedDatasets, setActiveTab, setExpandedChart, setShowDownloadDropdown, setChartTypeMenuDataset]);
174

NEW
175
  useEffect(() => {
×
NEW
176
    setHistogramCardSizes(reduxHistogramSizes);
×
177
  }, [reduxHistogramSizes, setHistogramCardSizes]);
178

NEW
179
  useEffect(() => {
×
NEW
180
    if (reduxSurvivalSize == null) return;
×
NEW
181
    setSurvivalCardSize((prev) => ({ ...(prev || {}), ...reduxSurvivalSize }));
×
182
  }, [reduxSurvivalSize, setSurvivalCardSize]);
183

NEW
184
  useEffect(() => {
×
NEW
185
    const handleClickOutside = (event) => {
×
NEW
186
      if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
×
NEW
187
        setShowDownloadDropdown(false);
×
188
      }
189
    };
190

NEW
191
    if (showDownloadDropdown) {
×
NEW
192
      document.addEventListener('mousedown', handleClickOutside);
×
193
    }
194

NEW
195
    return () => {
×
NEW
196
      document.removeEventListener('mousedown', handleClickOutside);
×
197
    };
198
  }, [showDownloadDropdown, dropdownRef, setShowDownloadDropdown]);
199

NEW
200
  useEffect(() => {
×
NEW
201
    const visibleDatasets = selectedDatasets.filter((dataset) => dataset !== 'survivalAnalysis');
×
NEW
202
    const hasTopRowTokensInStrip = stripOrder.some(
×
NEW
203
      (id) => id === 'venn' || id === 'survivalAnalysis',
×
204
    );
205

NEW
206
    if (stripOrder.length === 0 && visibleDatasets.length > 0) {
×
NEW
207
      let initial = [...visibleDatasets];
×
NEW
208
      if (besideStripPanelId != null && visibleDatasets.includes(besideStripPanelId)) {
×
NEW
209
        initial = [
×
210
          besideStripPanelId,
NEW
211
          ...visibleDatasets.filter((d) => d !== besideStripPanelId),
×
212
        ];
213
      }
NEW
214
      dispatch(setStripOrder(initial));
×
NEW
215
      return;
×
216
    }
217

NEW
218
    if (hasTopRowTokensInStrip) {
×
NEW
219
      const missing = visibleDatasets.filter((dataset) => !stripOrder.includes(dataset));
×
NEW
220
      if (missing.length > 0) {
×
221
        const survivalInStrip =
NEW
222
          stripOrder.includes('survivalAnalysis')
×
223
          && selectedDatasets.includes('survivalAnalysis');
NEW
224
        if (survivalInStrip) {
×
NEW
225
          const core = stripOrder.filter((id) => id !== 'survivalAnalysis');
×
NEW
226
          dispatch(setStripOrder([...core, ...missing, 'survivalAnalysis']));
×
227
        } else {
NEW
228
          dispatch(setStripOrder([...stripOrder, ...missing]));
×
229
        }
230
      }
NEW
231
      return;
×
232
    }
233

NEW
234
    const prevVisible = stripOrder.filter((dataset) => visibleDatasets.includes(dataset));
×
NEW
235
    const missing = visibleDatasets.filter((dataset) => !prevVisible.includes(dataset));
×
NEW
236
    const next = [...prevVisible, ...missing];
×
237
    const unchanged =
NEW
238
      next.length === stripOrder.length &&
×
NEW
239
      next.every((d, i) => d === stripOrder[i]);
×
NEW
240
    if (!unchanged) {
×
NEW
241
      dispatch(setStripOrder(next));
×
242
    }
243
  }, [selectedDatasets, stripOrder, besideStripPanelId, dispatch]);
244

NEW
245
  const survivalSelected = selectedDatasets.includes('survivalAnalysis');
×
246

NEW
247
  useEffect(() => {
×
NEW
248
    dispatch(setSurvivalBesideFromSelection(survivalSelected));
×
249
  }, [survivalSelected, dispatch]);
250

NEW
251
  useEffect(() => {
×
NEW
252
    if (survivalSelected) return;
×
NEW
253
    const visible = selectedDatasets.filter((d) => d !== 'survivalAnalysis');
×
NEW
254
    if (visible.length === 0) {
×
NEW
255
      if (besideStripPanelId != null) {
×
NEW
256
        dispatch(setBesideStripPanelId(null));
×
257
      }
NEW
258
      return;
×
259
    }
NEW
260
    if (besideStripPanelId != null && visible.includes(besideStripPanelId)) {
×
NEW
261
      return;
×
262
    }
NEW
263
    const order = stripOrder.filter((d) => visible.includes(d));
×
NEW
264
    const first = order[0] || visible[0];
×
NEW
265
    if (first) {
×
NEW
266
      dispatch(setBesideStripPanelId(first));
×
267
    }
268
  }, [
269
    survivalSelected,
270
    selectedDatasets,
271
    stripOrder,
272
    besideStripPanelId,
273
    dispatch,
274
  ]);
275

NEW
276
  return {
×
277
    stripOrder,
278
    inlineAddStep,
279
    setInlineAddStep,
280
    inlineSelectedCatalogId,
281
    setInlineSelectedCatalogId,
282
    finalizeInlineAddChart,
283
    handleRemoveHistogramDataset,
284
    survivalSelected,
285
  };
286
}
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