@bento-core/query-bar 1.0.1-ccdiintegrated.1 → 1.0.1-ccdiintegrated.3

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/README.md CHANGED
@@ -84,12 +84,19 @@ const CONFIG = {
84
84
  clearAutocomplete: () => {},
85
85
 
86
86
  /**
87
- * Delete a specific Local Find searchbox filter (case)
87
+ * Delete a specific Local Find searchbox filter item. The full
88
+ * autocomplete item object is passed (not just the title) so consumers
89
+ * can disambiguate between participant IDs and synonym/associated IDs
90
+ * that may share the same title.
88
91
  *
89
- * @param {string} title
92
+ * @param {object} item the full autocomplete item to remove
93
+ * @param {string} item.title the participant identifier
94
+ * @param {string} [item.type] 'associatedIds' for synonym entries, any
95
+ * other value for participant IDs
96
+ * @param {string} [item.synonym] synonym value (associated-IDs only)
90
97
  * @returns {void}
91
98
  */
92
- deleteAutocompleteItem: (title) => {},
99
+ deleteAutocompleteItem: (item) => {},
93
100
 
94
101
  /**
95
102
  * Reset a specific facet section (e.g. Program)
@@ -17,18 +17,49 @@ var _default = _ref => {
17
17
  } = _ref;
18
18
  const {
19
19
  items,
20
- section
20
+ section,
21
+ unknownAges
21
22
  } = data;
23
+
24
+ // Determine the display logic based on unknownAges selection
25
+ const getDisplayContent = () => {
26
+ const baseLabel = data.label;
27
+ if (unknownAges === 'only') {
28
+ // Only: Show base label with unknown ages only, no range
29
+ return {
30
+ label: "".concat(baseLabel, " (Unknown Ages Only)"),
31
+ showRange: false,
32
+ rangeText: ''
33
+ };
34
+ }
35
+ if (unknownAges === 'exclude') {
36
+ // Exclude: Show base label with unknown ages excluded, with range only if items exist
37
+ const hasRange = items && items.length >= 2;
38
+ return {
39
+ label: "".concat(baseLabel, " (Unknown Ages Excluded)"),
40
+ showRange: hasRange,
41
+ rangeText: hasRange ? "".concat(items[0], " \u2013 ").concat(items[1]) : ''
42
+ };
43
+ }
44
+
45
+ // Include: Normal display (base label with range)
46
+ return {
47
+ label: baseLabel,
48
+ showRange: true,
49
+ rangeText: items && items.length >= 2 ? "".concat(items[0], " \u2013 ").concat(items[1]) : ''
50
+ };
51
+ };
52
+ const displayContent = getDisplayContent();
22
53
  return /*#__PURE__*/_react.default.createElement("span", null, /*#__PURE__*/_react.default.createElement("span", null, ' ', index !== 0 ? /*#__PURE__*/_react.default.createElement("span", {
23
54
  className: classes.operators
24
55
  }, " AND ") : '', /*#__PURE__*/_react.default.createElement("span", {
25
56
  className: (0, _clsx.default)(classes.filterName, classes["facetSection".concat(section, "Background")]),
26
57
  onClick: () => onSectionClick(data)
27
- }, data.label), ' '), /*#__PURE__*/_react.default.createElement("span", null, ' ', /*#__PURE__*/_react.default.createElement("span", {
58
+ }, displayContent.label), ' '), displayContent.showRange && /*#__PURE__*/_react.default.createElement("span", null, ' ', /*#__PURE__*/_react.default.createElement("span", {
28
59
  className: classes.operators
29
60
  }, "IS BETWEEN", ' '), /*#__PURE__*/_react.default.createElement("span", {
30
61
  className: (0, _clsx.default)(classes.filterCheckboxes, classes["facetSection".concat(section)]),
31
62
  onClick: () => onItemClick(data, items[0])
32
- }, "".concat(items[0], " \u2013 ").concat(items[1]))));
63
+ }, displayContent.rangeText)));
33
64
  };
34
65
  exports.default = _default;
@@ -81,7 +81,7 @@ const QueryBarGenerator = function QueryBarGenerator() {
81
81
  return _objectSpread(_objectSpread({}, facet), {}, {
82
82
  items: itemKeys
83
83
  });
84
- }).filter(facet => facet.items.length > 0);
84
+ }).filter(facet => facet.items.length > 0 || facet.unknownAges && facet.unknownAges !== 'include');
85
85
  if (!hasImportFrom && (mappedInputs.length || autocomplete.length || upload.length) <= 0) {
86
86
  return null;
87
87
  }
@@ -99,28 +99,61 @@ const QueryBarGenerator = function QueryBarGenerator() {
99
99
  }, hasImportFrom && /*#__PURE__*/_react.default.createElement("span", {
100
100
  className: (0, _clsx.default)(classes.filterCheckboxes, classes.localFindBackground),
101
101
  onClick: clearImportFrom
102
- }, "IMPORTED PARTICIPANT SET"), (autocomplete.length || upload.length) && mappedInputs.length ? /*#__PURE__*/_react.default.createElement("span", {
102
+ }, "IMPORTED PARTICIPANT SET"), hasImportFrom && (mappedInputs.length || autocomplete.length || upload.length) ? /*#__PURE__*/_react.default.createElement("span", {
103
103
  className: classes.operators
104
- }, " AND ") : null, autocomplete.length || upload.length ? /*#__PURE__*/_react.default.createElement("span", null, upload.length && !autocomplete.length ? /*#__PURE__*/_react.default.createElement("span", {
105
- className: (0, _clsx.default)(classes.filterCheckboxes, classes.localFindBackground),
106
- onClick: clearUpload
107
- }, "INPUT PARTICIPANT SET") : null, autocomplete.length ? /*#__PURE__*/_react.default.createElement("span", null, ' ', /*#__PURE__*/_react.default.createElement("span", {
108
- className: (0, _clsx.default)(classes.filterName, classes.localFindBackground),
109
- onClick: clearAutocomplete
110
- }, "Participant ID"), ' ', ' ', /*#__PURE__*/_react.default.createElement("span", {
104
+ }, " AND ") : null, (autocomplete.length || upload.length) > 0 && /*#__PURE__*/_react.default.createElement("span", null, (() => {
105
+ const participantItems = autocomplete.filter(i => i.type !== 'associatedIds');
106
+ const participantCount = upload.length + participantItems.length;
107
+ if (upload.length > 0 && participantItems.length === 0) {
108
+ return /*#__PURE__*/_react.default.createElement("span", {
109
+ className: (0, _clsx.default)(classes.filterCheckboxes, classes.localFindBackground),
110
+ onClick: clearUpload
111
+ }, "INPUT PARTICIPANT SET");
112
+ }
113
+ if (participantCount > 0) {
114
+ const operator = participantCount === 1 ? 'IS' : 'IN';
115
+ return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement("span", {
116
+ className: (0, _clsx.default)(classes.filterName, classes.localFindBackground),
117
+ onClick: clearAutocomplete
118
+ }, "Participant ID"), /*#__PURE__*/_react.default.createElement("span", {
119
+ className: classes.operators
120
+ }, operator), operator === 'IN' && /*#__PURE__*/_react.default.createElement("span", {
121
+ className: classes.bracketsOpen
122
+ }, "("), upload.length > 0 && /*#__PURE__*/_react.default.createElement("span", {
123
+ className: (0, _clsx.default)(classes.filterCheckboxes, classes.localFind),
124
+ onClick: clearUpload
125
+ }, "INPUT PARTICIPANT SET"), participantItems.slice(0, maxItems).map((d, idx, arr) => /*#__PURE__*/_react.default.createElement(_react.default.Fragment, {
126
+ key: "pid-".concat(idx)
127
+ }, /*#__PURE__*/_react.default.createElement("span", {
128
+ className: (0, _clsx.default)(classes.filterCheckboxes, classes.facetSectionCases),
129
+ onClick: () => deleteAutocompleteItem(d)
130
+ }, d.title), idx < arr.length - 1 && ' ')), participantItems.length > maxItems && '...', operator === 'IN' && /*#__PURE__*/_react.default.createElement("span", {
131
+ className: classes.bracketsClose
132
+ }, ")"));
133
+ }
134
+ return null;
135
+ })(), (upload.length > 0 || autocomplete.some(i => i.type !== 'associatedIds')) && autocomplete.some(i => i.type === 'associatedIds') && /*#__PURE__*/_react.default.createElement("span", {
111
136
  className: classes.operators
112
- }, autocomplete.length === 1 && !upload.length ? 'IS ' : 'IN ')) : null, /*#__PURE__*/_react.default.createElement("span", null, (upload.length > 0 ? 1 : 0) + autocomplete.length > 1 ? /*#__PURE__*/_react.default.createElement("span", {
113
- className: classes.bracketsOpen
114
- }, "(") : null, upload.length && autocomplete.length ? /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, ' ', /*#__PURE__*/_react.default.createElement("span", {
115
- className: (0, _clsx.default)(classes.filterCheckboxes, classes.localFind),
116
- onClick: clearUpload
117
- }, "INPUT PARTICIPANT SET"), ' ') : null, autocomplete.slice(0, maxItems).map((d, idx) => /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement("span", {
118
- className: (0, _clsx.default)(classes.filterCheckboxes, classes.facetSectionCases),
119
- key: idx,
120
- onClick: () => deleteAutocompleteItem(d.title)
121
- }, d.title), idx === maxItems - 1 ? null : ' ')), autocomplete.length > maxItems && '...', (upload.length > 0 ? 1 : 0) + autocomplete.length > 1 ? /*#__PURE__*/_react.default.createElement("span", {
122
- className: classes.bracketsClose
123
- }, ")") : null)) : null, (autocomplete.length || upload.length) && mappedInputs.length ? /*#__PURE__*/_react.default.createElement("span", {
137
+ }, "OR"), (() => {
138
+ const associatedItems = autocomplete.filter(i => i.type === 'associatedIds');
139
+ if (associatedItems.length === 0) return null;
140
+ const operator = associatedItems.length === 1 ? 'IS' : 'IN';
141
+ return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement("span", {
142
+ className: (0, _clsx.default)(classes.filterName, classes.localFindAssociatedIdsBackground),
143
+ onClick: clearAutocomplete
144
+ }, "Synonym"), /*#__PURE__*/_react.default.createElement("span", {
145
+ className: classes.operators
146
+ }, operator), operator === 'IN' && /*#__PURE__*/_react.default.createElement("span", {
147
+ className: classes.bracketsOpen
148
+ }, "("), associatedItems.slice(0, maxItems).map((d, idx, arr) => /*#__PURE__*/_react.default.createElement(_react.default.Fragment, {
149
+ key: "aid-".concat(idx)
150
+ }, /*#__PURE__*/_react.default.createElement("span", {
151
+ className: (0, _clsx.default)(classes.filterCheckboxes, classes.localFindAssociatedIdsText),
152
+ onClick: () => deleteAutocompleteItem(d)
153
+ }, d.synonym), idx < arr.length - 1 && ' ')), associatedItems.length > maxItems && '...', operator === 'IN' && /*#__PURE__*/_react.default.createElement("span", {
154
+ className: classes.bracketsClose
155
+ }, ")"));
156
+ })()), (autocomplete.length || upload.length) && mappedInputs.length ? /*#__PURE__*/_react.default.createElement("span", {
124
157
  className: classes.operators
125
158
  }, " AND ") : null, mappedInputs.map((filter, index) => /*#__PURE__*/_react.default.createElement(_FilterMap.Filter, {
126
159
  index: index,
@@ -51,12 +51,20 @@ var _default = {
51
51
  */
52
52
  clearAutocomplete: () => {},
53
53
  /**
54
- * Delete a specific Local Find searchbox filter (case)
54
+ * Delete a specific Local Find searchbox filter item.
55
+ * The full autocomplete item is passed (not just the title) so consumers
56
+ * can disambiguate between participant IDs and synonym/associated IDs that
57
+ * may share the same title.
55
58
  *
56
- * @param {string} title
59
+ * @param {object} item the autocomplete item to remove
60
+ * @param {string} item.title the participant identifier
61
+ * @param {string} [item.type] either 'associatedIds' for synonym entries
62
+ * or any other value (e.g. 'subjectIds', 'participantIds') for
63
+ * participant IDs
64
+ * @param {string} [item.synonym] the synonym value (associated-IDs only)
57
65
  * @returns {void}
58
66
  */
59
- deleteAutocompleteItem: title => {},
67
+ deleteAutocompleteItem: item => {},
60
68
  /**
61
69
  * Reset a specific facet section (e.g. Program)
62
70
  *
@@ -9,9 +9,8 @@ exports.default = void 0;
9
9
  */
10
10
  var _default = () => ({
11
11
  queryWrapper: {
12
- height: '120px',
13
12
  backgroundColor: '#f1f1f1',
14
- padding: '14px 14px 0px 35px',
13
+ padding: '5px 15px 15px 15px',
15
14
  overflowY: 'auto'
16
15
  },
17
16
  queryContainer: {
@@ -173,6 +172,12 @@ var _default = () => ({
173
172
  facetSectionSequencinglibraryBackground: {
174
173
  backgroundColor: '#E1C9E140',
175
174
  border: '1px solid #646464'
175
+ },
176
+ localFindAssociatedIdsBackground: {
177
+ backgroundColor: '#F6A700'
178
+ },
179
+ localFindAssociatedIdsText: {
180
+ color: '#B36B00'
176
181
  }
177
182
  });
178
183
  exports.default = _default;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bento-core/query-bar",
3
- "version": "1.0.1-ccdiintegrated.1",
3
+ "version": "1.0.1-ccdiintegrated.3",
4
4
  "description": "This package provides the Query Bar component that displays the current Facet Search and Local Find filters on the Dashboard/Explore page. It also provides the direct ability to reset all or some of the filters with the click of a button. It is designed to be implemented directly with the:",
5
5
  "homepage": "https://github.com/CBIIT/bento-frontend#readme",
6
6
  "bugs": {
@@ -121,70 +121,120 @@ export const QueryBarGenerator = (uiConfig = DEFAULT_CONFIG) => {
121
121
  {hasImportFrom && (mappedInputs.length || autocomplete.length || upload.length)
122
122
  ? <span className={classes.operators}> AND </span>
123
123
  : null}
124
- {(autocomplete.length || upload.length) ? (
124
+ {/* Section: Localfind Results */}
125
+ {(autocomplete.length || upload.length) > 0 && (
125
126
  <span>
126
- {/* Standalone case set button */}
127
- {(upload.length && !autocomplete.length)
128
- ? (
129
- <span
130
- className={clsx(classes.filterCheckboxes, classes.localFindBackground)}
131
- onClick={clearUpload}
132
- >
133
- INPUT PARTICIPANT SET
134
- </span>
135
- ) : null}
136
- {autocomplete.length
137
- ? (
138
- <span>
139
- {' '}
140
- <span
141
- className={clsx(classes.filterName, classes.localFindBackground)}
142
- onClick={clearAutocomplete}
143
- >
144
- Participant ID
145
- </span>
146
- {' '}
147
- {' '}
148
- <span className={classes.operators}>
149
- {(autocomplete.length === 1 && !upload.length) ? 'IS ' : 'IN '}
150
- </span>
151
- </span>
152
- ) : null}
153
- <span>
154
- {(((upload.length > 0 ? 1 : 0) + autocomplete.length) > 1)
155
- ? <span className={classes.bracketsOpen}>(</span>
156
- : null}
157
- {upload.length && autocomplete.length ? (
158
- <>
159
- {' '}
127
+ {/* Participant ID Section
128
+ * Treats any autocomplete item that is not explicitly an
129
+ * associated/synonym ID as a participant ID, so legacy items
130
+ * (e.g. type === 'subjectIds') keep working alongside the new
131
+ * synonym section. */}
132
+ {(() => {
133
+ const participantItems = autocomplete.filter((i) => i.type !== 'associatedIds');
134
+ const participantCount = upload.length + participantItems.length;
135
+
136
+ if (upload.length > 0 && participantItems.length === 0) {
137
+ return (
160
138
  <span
161
- className={clsx(classes.filterCheckboxes, classes.localFind)}
139
+ className={clsx(classes.filterCheckboxes, classes.localFindBackground)}
162
140
  onClick={clearUpload}
163
141
  >
164
142
  INPUT PARTICIPANT SET
165
143
  </span>
166
- {' '}
167
- </>
168
- ) : null}
169
- {autocomplete.slice(0, maxItems).map((d, idx) => (
144
+ );
145
+ }
146
+
147
+ if (participantCount > 0) {
148
+ const operator = participantCount === 1 ? 'IS' : 'IN';
149
+
150
+ return (
151
+ <>
152
+ <span
153
+ className={clsx(classes.filterName, classes.localFindBackground)}
154
+ onClick={clearAutocomplete}
155
+ >
156
+ Participant ID
157
+ </span>
158
+ <span className={classes.operators}>{operator}</span>
159
+
160
+ {operator === 'IN' && <span className={classes.bracketsOpen}>(</span>}
161
+
162
+ {upload.length > 0 && (
163
+ <span
164
+ className={clsx(classes.filterCheckboxes, classes.localFind)}
165
+ onClick={clearUpload}
166
+ >
167
+ INPUT PARTICIPANT SET
168
+ </span>
169
+ )}
170
+
171
+ {participantItems.slice(0, maxItems).map((d, idx, arr) => (
172
+ <React.Fragment key={`pid-${idx}`}>
173
+ <span
174
+ className={clsx(classes.filterCheckboxes, classes.facetSectionCases)}
175
+ onClick={() => deleteAutocompleteItem(d)}
176
+ >
177
+ {d.title}
178
+ </span>
179
+ {idx < arr.length - 1 && ' '}
180
+ </React.Fragment>
181
+ ))}
182
+ {participantItems.length > maxItems && '...'}
183
+ {operator === 'IN' && <span className={classes.bracketsClose}>)</span>}
184
+ </>
185
+ );
186
+ }
187
+
188
+ return null;
189
+ })()}
190
+
191
+ {/* OR connector between Participant IDs (or upload) and Synonyms */}
192
+ {(upload.length > 0 || autocomplete.some((i) => i.type !== 'associatedIds'))
193
+ && autocomplete.some((i) => i.type === 'associatedIds')
194
+ && (<span className={classes.operators}>OR</span>)}
195
+
196
+ {/* Associated ID (Synonym) Section */}
197
+ {(() => {
198
+ const associatedItems = autocomplete.filter((i) => i.type === 'associatedIds');
199
+ if (associatedItems.length === 0) return null;
200
+
201
+ const operator = associatedItems.length === 1 ? 'IS' : 'IN';
202
+
203
+ return (
170
204
  <>
171
205
  <span
172
- className={clsx(classes.filterCheckboxes, classes.facetSectionCases)}
173
- key={idx}
174
- onClick={() => deleteAutocompleteItem(d.title)}
206
+ className={clsx(
207
+ classes.filterName,
208
+ classes.localFindAssociatedIdsBackground,
209
+ )}
210
+ onClick={clearAutocomplete}
175
211
  >
176
- {d.title}
212
+ Synonym
177
213
  </span>
178
- {idx === (maxItems - 1) ? null : ' '}
214
+ <span className={classes.operators}>{operator}</span>
215
+ {operator === 'IN' && <span className={classes.bracketsOpen}>(</span>}
216
+
217
+ {associatedItems.slice(0, maxItems).map((d, idx, arr) => (
218
+ <React.Fragment key={`aid-${idx}`}>
219
+ <span
220
+ className={clsx(
221
+ classes.filterCheckboxes,
222
+ classes.localFindAssociatedIdsText,
223
+ )}
224
+ onClick={() => deleteAutocompleteItem(d)}
225
+ >
226
+ {d.synonym}
227
+ </span>
228
+ {idx < arr.length - 1 && ' '}
229
+ </React.Fragment>
230
+ ))}
231
+ {associatedItems.length > maxItems && '...'}
232
+ {operator === 'IN' && <span className={classes.bracketsClose}>)</span>}
179
233
  </>
180
- ))}
181
- {autocomplete.length > maxItems && '...'}
182
- {(((upload.length > 0 ? 1 : 0) + autocomplete.length) > 1)
183
- ? <span className={classes.bracketsClose}>)</span>
184
- : null}
185
- </span>
234
+ );
235
+ })()}
186
236
  </span>
187
- ) : null}
237
+ )}
188
238
 
189
239
  {/* Facet Sidebar Selections */}
190
240
  {((autocomplete.length || upload.length) && mappedInputs.length)
@@ -50,12 +50,20 @@ export default {
50
50
  clearAutocomplete: () => { },
51
51
 
52
52
  /**
53
- * Delete a specific Local Find searchbox filter (case)
53
+ * Delete a specific Local Find searchbox filter item.
54
+ * The full autocomplete item is passed (not just the title) so consumers
55
+ * can disambiguate between participant IDs and synonym/associated IDs that
56
+ * may share the same title.
54
57
  *
55
- * @param {string} title
58
+ * @param {object} item the autocomplete item to remove
59
+ * @param {string} item.title the participant identifier
60
+ * @param {string} [item.type] either 'associatedIds' for synonym entries
61
+ * or any other value (e.g. 'subjectIds', 'participantIds') for
62
+ * participant IDs
63
+ * @param {string} [item.synonym] the synonym value (associated-IDs only)
56
64
  * @returns {void}
57
65
  */
58
- deleteAutocompleteItem: (title) => { },
66
+ deleteAutocompleteItem: (item) => { },
59
67
 
60
68
  /**
61
69
  * Reset a specific facet section (e.g. Program)
@@ -167,4 +167,10 @@ export default () => ({
167
167
  backgroundColor: '#E1C9E140',
168
168
  border: '1px solid #646464',
169
169
  },
170
+ localFindAssociatedIdsBackground: {
171
+ backgroundColor: '#F6A700',
172
+ },
173
+ localFindAssociatedIdsText: {
174
+ color: '#B36B00',
175
+ },
170
176
  });