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

CBIIT / bento-c3dc-frontend / 21596379376

02 Feb 2026 03:33PM UTC coverage: 0.154% (-0.01%) from 0.167%
21596379376

push

github

web-flow
Merge pull request #478 from CBIIT/C3DC-1935

C3DC-1912 & C3DC-1935, Restricted Constructed URL + Interop URL feature

6 of 4070 branches covered (0.15%)

Branch coverage included in aggregate %.

0 of 489 new or added lines in 14 files covered. (0.0%)

24 existing lines in 6 files now uncovered.

10 of 6301 relevant lines covered (0.16%)

0.08 hits per line

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

0.0
/src/utils/urlManager.js
NEW
1
import { generateQueryStr } from '@bento-core/util';
×
NEW
2
import { queryParams, URL_CHARACTER_LIMIT, whitelistedUrlParams } from '../bento/dashTemplate';
×
NEW
3
import { generateUrl } from '../pages/inventory/filterQueryBar/QueryBarUtils';
×
4

5
/**
6
 * Builds the complete filter state object from Redux state
7
 *
8
 * @param {object} activeFilters - Redux state from statusReducer.filterState
9
 * @param {object} localFind - Redux state from localFind
10
 * @param {object} unknownAgesState - Redux state from statusReducer.unknownAgesState
11
 * @param {array} whitelist - Optional list of datafields to include (if null, includes all)
12
 * @returns {object} Complete filter state object
13
 */
NEW
14
export const buildFilterStateObject = (activeFilters, localFind, unknownAgesState, whitelist = null) => {
×
NEW
15
  const filterObject = {};
×
16

17
  // Add facet filters
NEW
18
  if (activeFilters) {
×
NEW
19
    Object.keys(activeFilters).forEach((key) => {
×
20
      // Skip if whitelist provided and key not in whitelist
NEW
21
      if (whitelist && !whitelist.includes(key)) {
×
NEW
22
        return;
×
23
      }
NEW
24
      const filterValue = activeFilters[key];
×
NEW
25
      if (filterValue && typeof filterValue === 'object') {
×
26
        // Convert object of {value: true} to array of values
NEW
27
        const values = Object.keys(filterValue).filter((v) => filterValue[v] === true);
×
NEW
28
        if (values.length > 0) {
×
NEW
29
          filterObject[key] = values;
×
30
        }
NEW
31
      } else if (Array.isArray(filterValue) && filterValue.length > 0) {
×
32
        // Already an array (e.g., slider values)
NEW
33
        filterObject[key] = filterValue;
×
34
      }
35
    });
36
  }
37

38
  // Add autocomplete participant IDs
NEW
39
  if (localFind && localFind.autocomplete && localFind.autocomplete.length > 0) {
×
NEW
40
    filterObject.autocomplete = localFind.autocomplete;
×
41
  }
42

43
  // Add uploaded participant data
NEW
44
  if (localFind && localFind.upload && localFind.upload.length > 0) {
×
NEW
45
    filterObject.upload = localFind.upload;
×
46
  }
47

48
  // Add upload metadata
NEW
49
  if (localFind && localFind.uploadMetadata) {
×
NEW
50
    filterObject.uploadMetadata = localFind.uploadMetadata;
×
51
  }
52

53
  // Add unknownAges state
NEW
54
  if (unknownAgesState && Object.keys(unknownAgesState).length > 0) {
×
NEW
55
    filterObject.unknownAgesState = unknownAgesState;
×
56
  }
57

NEW
58
  return filterObject;
×
59
};
60

NEW
61
/**
×
62
 * Updates the browser URL, using filterQuery approach if URL would exceed character limit
63
 *
64
 * @param {object} paramValue - URL parameters to set
65
 * @param {object} options - Configuration options
66
 * @param {object} options.activeFilters - Redux state from statusReducer.filterState
67
 * @param {object} options.localFind - Redux state from localFind
68
 * @param {object} options.unknownAgesState - Redux state from statusReducer.unknownAgesState
69
 * @param {string} options.basePath - Base path (default: '/explore')
70
 * @returns {Promise<void>}
71
 */
NEW
72
export const updateBrowserUrlWithLimit = async (paramValue, options = {}) => {
×
73
  const {
NEW
74
    activeFilters = {},
×
NEW
75
    localFind = {},
×
NEW
76
    unknownAgesState = {},
×
NEW
77
    basePath = '/explore',
×
NEW
78
  } = options;
×
79

80
  // Check if we're currently using a filterQuery URL
NEW
81
  const currentQuery = new URLSearchParams(window.location.search);
×
NEW
82
  const hasFilterQuery = currentQuery.has('filterQuery');
×
83

84
  // If we're using filterQuery, we need to rebuild from Redux state, not from URL
85
  // Remove filterQuery from current query to avoid mixing approaches
NEW
86
  if (hasFilterQuery) {
×
NEW
87
    currentQuery.delete('filterQuery');
×
88
  }
89

90
  // IMPORTANT: Always sync from Redux state to ensure data is preserved in URL
NEW
91
  const completeParamValue = { ...paramValue };
×
92

93
  // Sync whitelisted facet filters from Redux state
NEW
94
  if (activeFilters && whitelistedUrlParams) {
×
NEW
95
    whitelistedUrlParams.forEach((datafield) => {
×
NEW
96
      const filterValue = activeFilters[datafield];
×
NEW
97
      if (filterValue && typeof filterValue === 'object' && !Array.isArray(filterValue)) {
×
98
        // Convert object of {value: true} to pipe-separated string
NEW
99
        const values = Object.keys(filterValue).filter((v) => filterValue[v] === true);
×
NEW
100
        if (values.length > 0) {
×
NEW
101
          completeParamValue[datafield] = values.join('|');
×
NEW
102
        } else if (!paramValue[datafield]) {
×
NEW
103
          completeParamValue[datafield] = '';
×
104
        }
NEW
105
      } else if (Array.isArray(filterValue) && filterValue.length > 0) {
×
106
        // Slider values - join with comma
NEW
107
        completeParamValue[datafield] = filterValue.join(',');
×
NEW
108
      } else if (!paramValue[datafield]) {
×
NEW
109
        completeParamValue[datafield] = '';
×
110
      }
111
    });
112
  }
113

114
  // Sync autocomplete participant IDs from Redux state
NEW
115
  if (localFind.autocomplete && localFind.autocomplete.length > 0) {
×
NEW
116
    completeParamValue.p_id = localFind.autocomplete.map((data) => data.title).join('|');
×
NEW
117
  } else if (!paramValue.p_id) {
×
118
    // Only clear if not explicitly set in paramValue
NEW
119
    completeParamValue.p_id = '';
×
120
  }
121

122
  // Sync uploaded participant IDs from Redux state
NEW
123
  if (localFind.upload && localFind.upload.length > 0) {
×
NEW
124
    completeParamValue.u = localFind.upload.map((data) => data.participant_id).join('|');
×
125

126
    // Sync upload metadata (file content and unmatched IDs)
NEW
127
    if (localFind.uploadMetadata && localFind.uploadMetadata.fileContent) {
×
NEW
128
      const fc = localFind.uploadMetadata.fileContent
×
129
        .split(/[,\n]/g)
NEW
130
        .map((e) => e.trim().replace(/\r/g, '').toUpperCase())
×
NEW
131
        .filter((e) => e && e.length > 1);
×
NEW
132
      completeParamValue.u_fc = fc.join('|');
×
133
    }
134

NEW
135
    if (localFind.uploadMetadata
×
136
      && localFind.uploadMetadata.unmatched
137
      && localFind.uploadMetadata.unmatched.length > 0) {
NEW
138
      completeParamValue.u_um = localFind.uploadMetadata.unmatched.join('|');
×
139
    }
NEW
140
  } else if (!paramValue.u) {
×
141
    // Only clear if not explicitly set in paramValue
NEW
142
    completeParamValue.u = '';
×
NEW
143
    completeParamValue.u_fc = '';
×
NEW
144
    completeParamValue.u_um = '';
×
145
  }
146

147
  // Generate the query string with current parameters (excluding old filterQuery)
NEW
148
  const queryStr = generateQueryStr(currentQuery, queryParams, completeParamValue);
×
NEW
149
  const fullUrl = `${basePath}${queryStr}`;
×
150

151
  // Check if URL exceeds character limit
NEW
152
  if (fullUrl.length > URL_CHARACTER_LIMIT) {
×
153
    // Build filter state with ONLY whitelisted facets for browser URL
154
    // This ensures browser URL only contains updateURL: true facets + participant IDs
NEW
155
    const filterObject = buildFilterStateObject(activeFilters, localFind, unknownAgesState, whitelistedUrlParams);
×
NEW
156
    const filterQueryStr = JSON.stringify(filterObject);
×
157

158
    // Generate filterQuery URL using interop service
NEW
159
    await generateUrl(filterQueryStr, basePath, (filterQueryUrl) => {
×
160
      // The generateUrl callback receives the full URL with filterQuery parameter
NEW
161
      window.history.replaceState(null, '', filterQueryUrl);
×
162
    });
NEW
163
  } else if (hasFilterQuery) {
×
164
    // We were using filterQuery but the deconstructed URL is now under the limit
165
    // We can switch back to normal URL to make it more readable
NEW
166
    window.history.replaceState(null, '', fullUrl);
×
167
  } else {
168
    // URL is under limit, use normal approach
NEW
169
    window.history.replaceState(null, '', fullUrl);
×
170
  }
NEW
171
};
×
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