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

CBIIT / crdc-datahub-ui / 26241948143

21 May 2026 05:23PM UTC coverage: 84.756% (+5.7%) from 79.008%
26241948143

push

github

web-flow
Merge pull request #998 from CBIIT/3.6.0

3.6.0 Release

6022 of 6644 branches covered (90.64%)

Branch coverage included in aggregate %.

3572 of 3715 new or added lines in 81 files covered. (96.15%)

15 existing lines in 6 files now uncovered.

35928 of 42851 relevant lines covered (83.84%)

243.57 hits per line

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

92.5
/src/hooks/useBuildReduxStore.ts
1
import { useLazyQuery } from "@apollo/client";
1✔
2
import {
1✔
3
  ddgraph,
4
  moduleReducers as submission,
5
  versionInfo,
6
  changelogInfo,
7
  iconMapInfo,
8
  getModelExploreData,
9
  getChangelog,
10
} from "data-model-navigator";
11
import { useState } from "react";
1✔
12
import { createStore, combineReducers, Store } from "redux";
1✔
13

14
import logo from "../assets/header/Logo.jpg";
1✔
15
import { baseConfiguration, defaultReadMeTitle, graphViewConfig } from "../config/ModelNavigator";
1✔
16
import {
1✔
17
  RETRIEVE_PVS_BY_PROPERTY_NAME,
18
  RetrievePVsByPropertyNameInput,
19
  RetrievePVsByPropertyNameResponse,
20
} from "../graphql";
21
import {
1✔
22
  buildAssetUrls,
23
  buildBaseFilterContainers,
24
  buildFilterOptionsList,
25
  extractModelProperties,
26
  Logger,
27
  populatePermissibleValues,
28
} from "../utils";
29

30
export type ReduxStoreStatus = "waiting" | "loading" | "error" | "success";
31

32
export type ReduxStoreData = {
33
  /**
34
   * The current status of the Redux store.
35
   */
36
  status: ReduxStoreStatus;
37
  /**
38
   * The Redux store instance.
39
   */
40
  store: Store;
41
};
42

43
export type ReduxStoreResult = [ReduxStoreData, (assets: DataCommon, modelVersion: string) => void];
44

45
const makeStore = (): Store => {
1✔
46
  const reducers = { ddgraph, versionInfo, submission, changelogInfo, iconMapInfo };
39✔
47
  const newStore = createStore(combineReducers(reducers));
39✔
48

49
  // @ts-ignore
50
  newStore.injectReducer = (key, reducer) => {
39✔
51
    reducers[key] = reducer;
×
52
    newStore.replaceReducer(combineReducers(reducers));
×
53
  };
×
54

55
  return newStore;
39✔
56
};
39✔
57

58
/**
59
 * A hook to build and populate the Redux store with DMN data
60
 *
61
 * @params {void}
62
 */
63
const useBuildReduxStore = (): ReduxStoreResult => {
1✔
64
  const [store] = useState<Store>(makeStore());
39✔
65
  const [status, setStatus] = useState<ReduxStoreStatus>("waiting");
39✔
66

67
  const [retrievePVs] = useLazyQuery<
39✔
68
    RetrievePVsByPropertyNameResponse,
69
    RetrievePVsByPropertyNameInput
70
  >(RETRIEVE_PVS_BY_PROPERTY_NAME, {
39✔
71
    context: { clientName: "backend" },
39✔
72
    fetchPolicy: "cache-first",
39✔
73
  });
39✔
74

75
  /**
76
   * Injects the Data Model into the store
77
   *
78
   * @param datacommon The Data Model to inject assets from
79
   * @param modelVersion The version of the Data Model to inject
80
   */
81
  const populateStore = async (datacommon: DataCommon, modelVersion: string) => {
39✔
82
    if (
9✔
83
      !datacommon?.name ||
9✔
84
      !datacommon?.assets ||
8✔
85
      !datacommon?.assets["current-version"] ||
8✔
86
      !datacommon?.assets["model-navigator-config"]
8✔
87
    ) {
9✔
88
      setStatus("error");
1✔
89
      return;
1✔
90
    }
1✔
91

92
    setStatus("loading");
8✔
93

94
    const assets = buildAssetUrls(datacommon, modelVersion);
8✔
95
    const dmnConfig = datacommon.assets["model-navigator-config"];
8✔
96

97
    const [changelogMD, modelData] = await Promise.allSettled([
8✔
98
      getChangelog(assets?.changelog),
9✔
99
      getModelExploreData(...assets.model_files),
9✔
100
    ]).then((results) =>
9✔
101
      results.map((result) => {
8✔
102
        if (result.status === "fulfilled") {
16✔
103
          return result.value;
16✔
104
        }
16!
105

NEW
106
        Logger.error("Received error during Model Navigator store building", result.reason);
×
NEW
107
        return null;
×
108
      })
8✔
109
    );
9✔
110

111
    const { data: dictionary, version: versionData } = modelData || {};
9✔
112
    if (!dictionary || !versionData) {
9✔
113
      setStatus("error");
1✔
114
      return;
1✔
115
    }
1✔
116

117
    const allProperties = extractModelProperties(dictionary);
7✔
118
    try {
7✔
119
      const { data, error } = await retrievePVs({
7✔
120
        variables: {
7✔
121
          modelName: datacommon.name,
7✔
122
          modelVersion: versionData?.model,
7✔
123
          propertyNames: allProperties,
9✔
124
        },
9✔
125
      });
9✔
126

127
      if (error || !data?.retrievePVsByPropertyName?.length) {
9✔
128
        throw new Error(error?.message || "No permissible values returned by the API");
2✔
129
      }
2✔
130

131
      populatePermissibleValues(dictionary, allProperties, data.retrievePVsByPropertyName);
5✔
132
    } catch (error) {
9✔
133
      Logger.error("populateStore: Received an error while retrieving permissible values", error);
2✔
134
      populatePermissibleValues(dictionary, allProperties, []);
2✔
135
    }
2✔
136

137
    store.dispatch({ type: "RECEIVE_VERSION_INFO", data: versionData });
7✔
138

139
    store.dispatch({
7✔
140
      type: "REACT_FLOW_GRAPH_DICTIONARY",
7✔
141
      dictionary,
7✔
142
      pdfDownloadConfig: {
7✔
143
        iconSrc: logo,
7✔
144
        ...dmnConfig.pdfConfig,
7✔
145
      },
7✔
146
      graphViewConfig,
7✔
147
    });
7✔
148

149
    store.dispatch({
7✔
150
      type: "RECEIVE_DICTIONARY",
7✔
151
      payload: {
7✔
152
        data: dictionary,
7✔
153
        facetfilterConfig: {
7✔
154
          ...baseConfiguration,
7✔
155
          facetSearchData: dmnConfig.facetFilterSearchData,
7✔
156
          facetSectionVariables: dmnConfig.facetFilterSectionVariables,
7✔
157
          baseFilters: buildBaseFilterContainers(dmnConfig),
7✔
158
          filterSections: dmnConfig.facetFilterSearchData.map((s) => s?.datafield),
7✔
159
          filterOptions: buildFilterOptionsList(dmnConfig),
7✔
160
        },
7✔
161
        pageConfig: {
7✔
162
          title: dmnConfig.pageTitle,
7✔
163
          iconSrc: assets.navigator_icon,
7✔
164
        },
7✔
165
        readMeConfig: {
7✔
166
          readMeUrl: assets.readme,
7✔
167
          readMeTitle: dmnConfig?.readMeTitle || defaultReadMeTitle,
9✔
168
          allowDownload: false,
9✔
169
        },
9✔
170
        pdfDownloadConfig: dmnConfig.pdfConfig,
9✔
171
        loadingExampleConfig: {
9✔
172
          type: "static",
9✔
173
          url: assets.loading_file,
9✔
174
        },
9✔
175
      },
9✔
176
    });
9✔
177

178
    if (changelogMD) {
9✔
179
      store.dispatch({
3✔
180
        type: "RECEIVE_CHANGELOG_INFO",
3✔
181
        data: {
3✔
182
          changelogMD,
3✔
183
          changelogTabName: "Version History",
3✔
184
        },
3✔
185
      });
3✔
186
    }
3✔
187

188
    if (datacommon?.assets?.["model-navigator-config"]?.iconMap) {
9!
189
      store.dispatch({
×
190
        type: "RECEIVE_ICON_MAP",
×
191
        data: datacommon?.assets?.["model-navigator-config"]?.iconMap,
×
192
      });
×
193
    }
✔
194

195
    // MVP-2 M2 NOTE: This resets the search history to prevent the data models
196
    // from overlapping on searches. A future improvement would be to isolate
197
    // the localStorage history key to the data model based on a config option.
198
    store.dispatch({ type: "SEARCH_CLEAR_HISTORY" });
7✔
199

200
    setStatus("success");
7✔
201
  };
9✔
202

203
  return [{ status, store }, populateStore];
39✔
204
};
39✔
205

206
export default useBuildReduxStore;
1✔
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