@gen3/core 0.10.79 → 0.10.81

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.
Files changed (87) hide show
  1. package/dist/cjs/index.js +681 -444
  2. package/dist/cjs/index.js.map +1 -1
  3. package/dist/dts/constants.d.ts.map +1 -1
  4. package/dist/dts/dataAccess.d.ts.map +1 -1
  5. package/dist/dts/features/cohort/cohortSlice.d.ts.map +1 -1
  6. package/dist/dts/features/cohort/filterCombineModeSlice.d.ts +12 -0
  7. package/dist/dts/features/cohort/filterCombineModeSlice.d.ts.map +1 -0
  8. package/dist/dts/features/cohort/filterExpandSlice.d.ts +15 -0
  9. package/dist/dts/features/cohort/filterExpandSlice.d.ts.map +1 -0
  10. package/dist/dts/features/cohort/index.d.ts +6 -2
  11. package/dist/dts/features/cohort/index.d.ts.map +1 -1
  12. package/dist/dts/features/cohort/reducers.d.ts +20 -0
  13. package/dist/dts/features/cohort/reducers.d.ts.map +1 -0
  14. package/dist/dts/features/cohort/sharedFiltersSlice.d.ts +17 -0
  15. package/dist/dts/features/cohort/sharedFiltersSlice.d.ts.map +1 -0
  16. package/dist/dts/features/cohort/types.d.ts +1 -0
  17. package/dist/dts/features/cohort/types.d.ts.map +1 -1
  18. package/dist/dts/features/dataLibrary/dataLibraryIndexDB.d.ts.map +1 -1
  19. package/dist/dts/features/dataLibrary/dataLibrarySelectionSlice.d.ts.map +1 -1
  20. package/dist/dts/features/dataLibrary/types.d.ts.map +1 -1
  21. package/dist/dts/features/dataLibrary/useDataLibrary.d.ts.map +1 -1
  22. package/dist/dts/features/dataLibrary/utils.d.ts.map +1 -1
  23. package/dist/dts/features/drsResolver/drsHostnameSlice.d.ts.map +1 -1
  24. package/dist/dts/features/drsResolver/resolvers/cachedDRSResolver.d.ts.map +1 -1
  25. package/dist/dts/features/drsResolver/resolvers/dataGUIDSDotOrg.d.ts.map +1 -1
  26. package/dist/dts/features/drsResolver/utils.d.ts.map +1 -1
  27. package/dist/dts/features/fence/credentialsApi.d.ts.map +1 -1
  28. package/dist/dts/features/fence/fenceApi.d.ts +270 -1
  29. package/dist/dts/features/fence/fenceApi.d.ts.map +1 -1
  30. package/dist/dts/features/fence/index.d.ts +2 -2
  31. package/dist/dts/features/fence/index.d.ts.map +1 -1
  32. package/dist/dts/features/fence/utils.d.ts +1 -0
  33. package/dist/dts/features/fence/utils.d.ts.map +1 -1
  34. package/dist/dts/features/filters/filters.d.ts +2 -0
  35. package/dist/dts/features/filters/filters.d.ts.map +1 -1
  36. package/dist/dts/features/filters/index.d.ts +2 -2
  37. package/dist/dts/features/filters/index.d.ts.map +1 -1
  38. package/dist/dts/features/filters/types.d.ts +4 -0
  39. package/dist/dts/features/filters/types.d.ts.map +1 -1
  40. package/dist/dts/features/filters/utils.d.ts.map +1 -1
  41. package/dist/dts/features/gen3/index.d.ts.map +1 -1
  42. package/dist/dts/features/gen3Apps/Gen3App.d.ts.map +1 -1
  43. package/dist/dts/features/gen3Apps/Gen3AppRTKQ.d.ts.map +1 -1
  44. package/dist/dts/features/gen3Apps/gen3AppRegistry.d.ts.map +1 -1
  45. package/dist/dts/features/gen3Apps/gen3AppsSlice.d.ts.map +1 -1
  46. package/dist/dts/features/guppy/guppySlice.d.ts +373 -0
  47. package/dist/dts/features/guppy/guppySlice.d.ts.map +1 -1
  48. package/dist/dts/features/guppy/index.d.ts +2 -2
  49. package/dist/dts/features/guppy/index.d.ts.map +1 -1
  50. package/dist/dts/features/guppy/tests/grouping.unit.test.d.ts +2 -0
  51. package/dist/dts/features/guppy/tests/grouping.unit.test.d.ts.map +1 -0
  52. package/dist/dts/features/guppy/types.d.ts +6 -0
  53. package/dist/dts/features/guppy/types.d.ts.map +1 -1
  54. package/dist/dts/features/guppy/utils.d.ts +2 -1
  55. package/dist/dts/features/guppy/utils.d.ts.map +1 -1
  56. package/dist/dts/features/modals/modalsSlice.d.ts.map +1 -1
  57. package/dist/dts/features/submission/authMappingUtils.d.ts.map +1 -1
  58. package/dist/dts/features/user/hooks.d.ts +10 -14
  59. package/dist/dts/features/user/hooks.d.ts.map +1 -1
  60. package/dist/dts/features/user/userSlice.d.ts.map +1 -1
  61. package/dist/dts/features/user/userSliceRTK.d.ts +30 -3
  62. package/dist/dts/features/user/userSliceRTK.d.ts.map +1 -1
  63. package/dist/dts/features/user/utils.d.ts.map +1 -1
  64. package/dist/dts/features/workspace/utils.d.ts.map +1 -1
  65. package/dist/dts/features/workspace/workspaceSlice.d.ts.map +1 -1
  66. package/dist/dts/hooks.d.ts +20 -2
  67. package/dist/dts/hooks.d.ts.map +1 -1
  68. package/dist/dts/reducers.d.ts +29 -2
  69. package/dist/dts/reducers.d.ts.map +1 -1
  70. package/dist/dts/store.d.ts +40 -4
  71. package/dist/dts/store.d.ts.map +1 -1
  72. package/dist/dts/types/index.d.ts.map +1 -1
  73. package/dist/dts/utils/extractvalues.d.ts.map +1 -1
  74. package/dist/dts/utils/fetch.d.ts +21 -2
  75. package/dist/dts/utils/fetch.d.ts.map +1 -1
  76. package/dist/dts/utils/index.d.ts +2 -2
  77. package/dist/dts/utils/index.d.ts.map +1 -1
  78. package/dist/dts/utils/time.d.ts.map +1 -1
  79. package/dist/dts/utils/ts-utils.d.ts.map +1 -1
  80. package/dist/dts/utils/url.d.ts.map +1 -1
  81. package/dist/esm/index.js +664 -444
  82. package/dist/esm/index.js.map +1 -1
  83. package/dist/index.d.ts +5200 -4656
  84. package/package.json +2 -3
  85. package/LICENSE +0 -201
  86. package/dist/dts/features/cohort/cohortBuilderConfigSlice.d.ts +0 -1
  87. package/dist/dts/features/cohort/cohortBuilderConfigSlice.d.ts.map +0 -1
package/dist/cjs/index.js CHANGED
@@ -46,7 +46,7 @@ const GEN3_DOMAIN = process.env.NEXT_PUBLIC_GEN3_DOMAIN || '';
46
46
  */ const GEN3_GUPPY_API = process.env.NEXT_PUBLIC_GEN3_GUPPY_API || `${GEN3_API}/guppy`;
47
47
  const GEN3_MDS_API = process.env.NEXT_PUBLIC_GEN3_MDS_API || `${GEN3_API}/mds`;
48
48
  const GEN3_DOWNLOADS_ENDPOINT = process.env.NEXT_PUBLIC_GEN3_DOWNLOADS_ENDPOINT || 'downloads';
49
- const GEN3_FENCE_API = process.env.NEXT_PUBLIC_GEN3_FENCE_API || GEN3_API;
49
+ const GEN3_FENCE_API = process.env.NEXT_PUBLIC_GEN3_FENCE_API || `${GEN3_API}/user`;
50
50
  const GEN3_AI_SEARCH_API = process.env.NEXT_PUBLIC_GEN3_AI_SEARCH_API || `${GEN3_API}/ai-search`;
51
51
  const GEN3_AUTHZ_API = process.env.NEXT_PUBLIC_GEN3_AUTHZ_API || `${GEN3_API}/authz`;
52
52
  const GEN3_REDIRECT_URL = process.env.NEXT_PUBLIC_GEN3_REDIRECT_URL || GEN3_API;
@@ -67,6 +67,13 @@ const FILE_DELIMITERS = {
67
67
  csv: ','
68
68
  };
69
69
 
70
+ const isFetchError = (obj)=>{
71
+ if (typeof obj !== 'object' || obj === null) {
72
+ return false;
73
+ }
74
+ const { url, status, statusText, text } = obj;
75
+ return typeof url === 'string' && typeof status === 'number' && typeof statusText === 'string' && typeof text === 'string';
76
+ };
70
77
  /**
71
78
  * Template for fence error response dict
72
79
  * @returns: An error dict response from a RESTFUL API request
@@ -127,7 +134,8 @@ const userAuthApi = react.createApi({
127
134
  endpoint,
128
135
  headers
129
136
  });
130
- } catch (e) {
137
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
138
+ } catch (_e) {
131
139
  /*
132
140
  Because an "error" response is valid for the auth requests we don't want to
133
141
  put the request in an error state, or it will attempt the request over and over again
@@ -142,7 +150,7 @@ const userAuthApi = react.createApi({
142
150
  endpoints: (builder)=>({
143
151
  fetchUserDetails: builder.query({
144
152
  query: ()=>({
145
- endpoint: '/user/user'
153
+ endpoint: '/user'
146
154
  }),
147
155
  transformResponse (response) {
148
156
  return {
@@ -153,12 +161,33 @@ const userAuthApi = react.createApi({
153
161
  }
154
162
  }),
155
163
  getCSRF: builder.query({
156
- query: ()=>({
157
- endpoint: '/_status'
158
- }),
159
- transformResponse: (response)=>{
164
+ queryFn: async ()=>{
165
+ const headers = {
166
+ Accept: 'application/json',
167
+ 'Content-Type': 'application/json'
168
+ };
169
+ try {
170
+ const res = await fetch(`${GEN3_API}/_status`, {
171
+ headers: headers
172
+ });
173
+ if (res.ok) {
174
+ const jsonData = await res.json();
175
+ const token = jsonData?.data?.csrf ?? '';
176
+ return {
177
+ data: {
178
+ csrfToken: token
179
+ }
180
+ };
181
+ }
182
+ } catch (error) {
183
+ if (error instanceof Error) {
184
+ return {
185
+ error: error
186
+ };
187
+ }
188
+ }
160
189
  return {
161
- csrfToken: response?.data?.csrf ?? ''
190
+ error: 'Unknown Error'
162
191
  };
163
192
  }
164
193
  })
@@ -220,24 +249,27 @@ const gen3ServicesReducer = gen3Api.reducer;
220
249
  const gen3ServicesReducerMiddleware = gen3Api.middleware;
221
250
 
222
251
  /**
223
- * Creates a fence API endpoint for handling login processes
252
+ * Creates a fence API endpoint for handling login/data processes
224
253
  * @param endpoints - defined endpoint query for logging in
225
254
  * @returns: The generated fence login API slice
226
255
  */ const loginProvidersApi = gen3Api.injectEndpoints({
227
256
  endpoints: (builder)=>({
228
257
  getLoginProviders: builder.query({
229
- query: ()=>`${GEN3_FENCE_API}/user/login`
258
+ query: ()=>`${GEN3_FENCE_API}/login`
230
259
  }),
231
260
  getDownload: builder.query({
232
- query: (guid)=>`${GEN3_FENCE_API}/user/data/download/${guid}`
261
+ query: (guid)=>`${GEN3_FENCE_API}/data/download/${guid}`
262
+ }),
263
+ getPresignedUrl: builder.query({
264
+ query: ({ guid, what })=>`${GEN3_FENCE_API}/data/${what}/${guid}`
233
265
  })
234
266
  })
235
267
  });
236
- const { useGetLoginProvidersQuery, useGetDownloadQuery, useLazyGetDownloadQuery } = loginProvidersApi;
268
+ const { useGetLoginProvidersQuery, useGetDownloadQuery, useLazyGetDownloadQuery, useGetPresignedUrlQuery, useLazyGetPresignedUrlQuery } = loginProvidersApi;
237
269
  /**
238
270
  * Logout from fence
239
271
  */ const logoutFence = async (redirect = '/')=>await fetchFence({
240
- endpoint: `${GEN3_FENCE_API}/user/logout?next=${GEN3_REDIRECT_URL}${redirect}`,
272
+ endpoint: `${GEN3_FENCE_API}/logout?next=${GEN3_REDIRECT_URL}${redirect}`,
241
273
  method: 'GET'
242
274
  });
243
275
 
@@ -258,7 +290,7 @@ const credentialsWithTags$1 = gen3Api.enhanceEndpoints({
258
290
  */ const credentialsApi = credentialsWithTags$1.injectEndpoints({
259
291
  endpoints: (builder)=>({
260
292
  getCredentials: builder.query({
261
- query: ()=>`${GEN3_FENCE_API}/user/credentials/api`,
293
+ query: ()=>`${GEN3_FENCE_API}/credentials/api`,
262
294
  transformResponse: (response)=>response['jtis'],
263
295
  // "jtis", which is an array of API keys
264
296
  // no need to transform the response, since the API returns the correct format
@@ -268,7 +300,7 @@ const credentialsWithTags$1 = gen3Api.enhanceEndpoints({
268
300
  }),
269
301
  addNewCredential: builder.mutation({
270
302
  query: (csrfToken)=>({
271
- url: `${GEN3_FENCE_API}/user/credentials/api`,
303
+ url: `${GEN3_FENCE_API}/credentials/api`,
272
304
  method: 'POST',
273
305
  headers: {
274
306
  'Content-Type': 'application/json',
@@ -287,7 +319,7 @@ const credentialsWithTags$1 = gen3Api.enhanceEndpoints({
287
319
  }),
288
320
  removeCredential: builder.mutation({
289
321
  query: ({ csrfToken, id })=>({
290
- url: `${GEN3_FENCE_API}/user/credentials/api/${id}`,
322
+ url: `${GEN3_FENCE_API}/credentials/api/${id}`,
291
323
  method: 'DELETE',
292
324
  headers: {
293
325
  'Content-Type': 'application/json',
@@ -302,7 +334,7 @@ const credentialsWithTags$1 = gen3Api.enhanceEndpoints({
302
334
  }),
303
335
  authorizeFromCredentials: builder.mutation({
304
336
  query: (params)=>({
305
- url: `${GEN3_FENCE_API}/user/credentials/api/access_token`,
337
+ url: `${GEN3_FENCE_API}/credentials/api/access_token`,
306
338
  method: 'POST',
307
339
  headers: {
308
340
  'Content-Type': 'application/json'
@@ -400,7 +432,7 @@ const createUseCoreDataHook = (fetchDataActionCreator, dataSelector)=>{
400
432
  accessToken = cookiesNext.getCookie('credentials_token');
401
433
  }
402
434
  return await fetchFence({
403
- endpoint: '/user/user',
435
+ endpoint: '/user',
404
436
  method: 'GET',
405
437
  headers: {
406
438
  Accept: 'application/json',
@@ -417,7 +449,7 @@ const createUseCoreDataHook = (fetchDataActionCreator, dataSelector)=>{
417
449
  });
418
450
  const isAuthenticated = (loginStatus)=>loginStatus === 'authenticated';
419
451
  const isPending = (loginStatus)=>loginStatus === 'pending';
420
- const initialState$5 = {
452
+ const initialState$8 = {
421
453
  status: 'uninitialized',
422
454
  loginStatus: 'unauthenticated',
423
455
  error: undefined
@@ -428,9 +460,9 @@ const initialState$5 = {
428
460
  * @returns: status messages wrapped around fetchUserState response dict
429
461
  */ const slice$4 = toolkit.createSlice({
430
462
  name: 'fence/user',
431
- initialState: initialState$5,
463
+ initialState: initialState$8,
432
464
  reducers: {
433
- resetUserState: ()=>initialState$5
465
+ resetUserState: ()=>initialState$8
434
466
  },
435
467
  extraReducers: (builder)=>{
436
468
  builder.addCase(fetchUserState.fulfilled, (_, action)=>{
@@ -600,12 +632,12 @@ const lookupGen3App = (id)=>{
600
632
  return REGISTRY[id];
601
633
  };
602
634
 
603
- const initialState$4 = {
635
+ const initialState$7 = {
604
636
  gen3Apps: {}
605
637
  };
606
638
  const slice$3 = toolkit.createSlice({
607
639
  name: 'gen3Apps',
608
- initialState: initialState$4,
640
+ initialState: initialState$7,
609
641
  reducers: {
610
642
  addGen3AppMetadata: (state, action)=>{
611
643
  const { name, requiredEntityTypes } = action.payload;
@@ -624,11 +656,11 @@ const { addGen3AppMetadata } = slice$3.actions;
624
656
  const selectGen3AppMetadataByName = (state, appName)=>state.gen3Apps.gen3Apps[appName];
625
657
  const selectGen3AppByName = (appName)=>lookupGen3App(appName); // TODO: memoize this selector
626
658
 
627
- const initialState$3 = {};
659
+ const initialState$6 = {};
628
660
  // TODO: document what this does
629
661
  const slice$2 = toolkit.createSlice({
630
662
  name: 'drsResolver',
631
- initialState: initialState$3,
663
+ initialState: initialState$6,
632
664
  reducers: {
633
665
  setDRSHostnames: (_state, action)=>{
634
666
  return action.payload;
@@ -650,13 +682,13 @@ const { setDRSHostnames } = slice$2.actions;
650
682
  Modals["GeneralErrorModal"] = "GeneralErrorModal";
651
683
  return Modals;
652
684
  }({});
653
- const initialState$2 = {
685
+ const initialState$5 = {
654
686
  currentModal: null
655
687
  };
656
688
  //Creates a modal slice for tracking showModal and hideModal state.
657
689
  const slice$1 = toolkit.createSlice({
658
690
  name: 'modals',
659
- initialState: initialState$2,
691
+ initialState: initialState$5,
660
692
  reducers: {
661
693
  showModal: (state, action)=>{
662
694
  state.currentModal = action.payload.modal;
@@ -674,141 +706,6 @@ const { showModal, hideModal } = slice$1.actions;
674
706
  const selectCurrentModal = (state)=>state.modals.currentModal;
675
707
  const selectCurrentMessage = (state)=>state.modals.message;
676
708
 
677
- const EmptyCohort = {
678
- id: 'default',
679
- name: 'Filters',
680
- filters: {},
681
- modified_datetime: new Date().toISOString()
682
- };
683
- const initialCohortState = {
684
- cohort: {
685
- ...EmptyCohort
686
- }
687
- };
688
- // TODO: start using this adapter
689
- /*
690
- const cohortsAdapter = createEntityAdapter<Cohort>({
691
- sortComparer: (a, b) => {
692
- if (a.modified_datetime <= b.modified_datetime) return 1;
693
- else return -1;
694
- },
695
- });
696
- */ /**
697
- * Redux slice for cohort filters
698
- */ const cohortSlice = toolkit.createSlice({
699
- name: 'cohort',
700
- initialState: initialCohortState,
701
- reducers: {
702
- // adds a filter to the cohort filter set at the given index
703
- updateCohortFilter: (state, action)=>{
704
- const { index, field, filter } = action.payload;
705
- return {
706
- cohort: {
707
- ...state.cohort,
708
- filters: {
709
- ...state.cohort.filters,
710
- [index]: {
711
- mode: state.cohort.filters?.[index]?.mode ?? 'and',
712
- root: {
713
- ...state.cohort.filters?.[index]?.root ?? {},
714
- [field]: filter
715
- }
716
- }
717
- }
718
- }
719
- };
720
- },
721
- setCohortFilter: (state, action)=>{
722
- const { index, filters } = action.payload;
723
- return {
724
- cohort: {
725
- ...state.cohort,
726
- filters: {
727
- ...state.cohort.filters,
728
- [index]: filters
729
- }
730
- }
731
- };
732
- },
733
- setCohortIndexFilters: (state, action)=>{
734
- return {
735
- cohort: {
736
- ...state.cohort,
737
- filters: {
738
- ...action.payload.filters
739
- }
740
- }
741
- };
742
- },
743
- // removes a filter to the cohort filter set at the given index
744
- removeCohortFilter: (state, action)=>{
745
- const { index, field } = action.payload;
746
- const filters = state.cohort?.filters?.[index]?.root;
747
- if (!filters) {
748
- return;
749
- }
750
- const { [field]: _a, ...updated } = filters;
751
- return {
752
- cohort: {
753
- ...state.cohort,
754
- filters: {
755
- ...state.cohort.filters,
756
- [index]: {
757
- mode: state.cohort.filters[index].mode,
758
- root: updated
759
- }
760
- }
761
- }
762
- };
763
- },
764
- // removes all filters from the cohort filter set at the given index
765
- clearCohortFilters: (state, action)=>{
766
- const { index } = action.payload;
767
- return {
768
- cohort: {
769
- ...state.cohort,
770
- filters: {
771
- ...state.cohort.filters,
772
- [index]: {
773
- // empty filter set
774
- mode: 'and',
775
- root: {}
776
- }
777
- }
778
- }
779
- };
780
- }
781
- }
782
- });
783
- // Filter actions: addFilter, removeFilter, updateFilter
784
- const { updateCohortFilter, setCohortFilter, setCohortIndexFilters, removeCohortFilter, clearCohortFilters } = cohortSlice.actions;
785
- const selectCohortFilters = (state)=>state.cohorts.cohort.filters;
786
- const selectCurrentCohortId = (state)=>state.cohorts.cohort.id;
787
- const selectCurrentCohort = (state)=>state.cohorts.cohort;
788
- const selectCurrentCohortName = (state)=>state.cohorts.cohort.name;
789
- /**
790
- * Select a filter by its name from the current cohort. If the filter is not found
791
- * returns undefined.
792
- * @param state - Core
793
- * @param index which cohort index to select from
794
- * @param name name of the filter to select
795
- */ const selectIndexedFilterByName = (state, index, name)=>{
796
- return state.cohorts.cohort.filters[index]?.root[name];
797
- };
798
- const EmptyFilterSet = {
799
- mode: 'and',
800
- root: {}
801
- };
802
- /**
803
- * Select a filter from the index.
804
- * returns undefined.
805
- * @param state - Core
806
- * @param index which cohort index to select from
807
- */ const selectIndexFilters = (state, index)=>{
808
- return state.cohorts.cohort.filters?.[index] ?? EmptyFilterSet; // TODO: check if this is undefined
809
- };
810
- const cohortReducer = cohortSlice.reducer;
811
-
812
709
  const isFileItem = (item)=>{
813
710
  return item && 'guid' in item;
814
711
  };
@@ -1366,17 +1263,17 @@ const useDataLibrary = (useApi)=>{
1366
1263
  };
1367
1264
  };
1368
1265
 
1369
- const initialState$1 = {};
1266
+ const initialState$4 = {};
1370
1267
  const dataLibrarySlice = toolkit.createSlice({
1371
1268
  name: 'dataLibrary',
1372
- initialState: initialState$1,
1269
+ initialState: initialState$4,
1373
1270
  reducers: {
1374
1271
  setDataLibraryListSelection: (state, action)=>{
1375
1272
  const { listId, itemIds } = action.payload;
1376
1273
  state[listId] = itemIds;
1377
1274
  },
1378
1275
  clearDataLibrarySelection: ()=>{
1379
- return initialState$1;
1276
+ return initialState$4;
1380
1277
  }
1381
1278
  }
1382
1279
  });
@@ -1442,7 +1339,7 @@ const isTimeGreaterThan = (startTime, minutes)=>{
1442
1339
  };
1443
1340
 
1444
1341
  const NO_WORKSPACE_ID = 'none';
1445
- const initialState = {
1342
+ const initialState$3 = {
1446
1343
  id: NO_WORKSPACE_ID,
1447
1344
  status: WorkspaceStatus.NotFound,
1448
1345
  requestedStatus: RequestedWorkspaceStatus.Unset,
@@ -1450,7 +1347,7 @@ const initialState = {
1450
1347
  };
1451
1348
  const slice = toolkit.createSlice({
1452
1349
  name: 'ActiveWorkspace',
1453
- initialState,
1350
+ initialState: initialState$3,
1454
1351
  reducers: {
1455
1352
  setActiveWorkspaceId: (state, action)=>{
1456
1353
  state = {
@@ -1544,6 +1441,14 @@ const guppyApiReducer = guppyApi.reducer;
1544
1441
  const isOperationWithField = (operation)=>{
1545
1442
  return operation?.field !== undefined;
1546
1443
  };
1444
+ const isOperatorWithFieldAndArrayOfOperands = (operation)=>{
1445
+ if (typeof operation === 'object' && operation !== null && 'operands' in operation && Array.isArray(operation.operands) && 'field' in operation && typeof operation.field === 'string' // Assuming `field` should be a string
1446
+ ) {
1447
+ const { operator } = operation.operator;
1448
+ return operator === 'in' || operator === 'exclude' || operator === 'excludeifany';
1449
+ }
1450
+ return false;
1451
+ };
1547
1452
  const extractFilterValue = (op)=>{
1548
1453
  const valueExtractorHandler = new ValueExtractorHandler();
1549
1454
  return handleOperation(valueExtractorHandler, op);
@@ -1725,6 +1630,12 @@ const isFilterSet = (input)=>{
1725
1630
  }
1726
1631
  return true;
1727
1632
  };
1633
+ function isUnion(value) {
1634
+ return typeof value === 'object' && value !== null && value.operator === 'or' && Array.isArray(value.operands);
1635
+ }
1636
+ function isIntersection(value) {
1637
+ return typeof value === 'object' && value !== null && value.operator === 'and' && Array.isArray(value.operands);
1638
+ }
1728
1639
 
1729
1640
  const FieldNameOverrides = {};
1730
1641
  const COMMON_PREPOSITIONS = [
@@ -1789,65 +1700,248 @@ const trimFirstFieldNameToTitle = (fieldName, trim = false)=>{
1789
1700
  ];
1790
1701
  };
1791
1702
 
1792
- const statusEndpoint = '/_status';
1793
- const processHistogramResponse = (data)=>{
1794
- const valueData = jsonpathPlus.JSONPath({
1795
- json: data,
1796
- path: '$..histogram',
1797
- resultType: 'value'
1798
- });
1799
- const pointerData = jsonpathPlus.JSONPath({
1800
- json: data,
1801
- path: '$..histogram',
1802
- resultType: 'pointer'
1803
- });
1804
- const results = pointerData.reduce((acc, element, idx)=>{
1805
- const key = element.slice(1).replace(/\/histogram/g, '').replace(/\//g, '.');
1806
- return {
1807
- ...acc,
1808
- [key]: valueData[idx]
1809
- };
1810
- }, {});
1811
- return results;
1812
- };
1813
- const fetchJson = async (url)=>{
1814
- const res = await fetch(url, {
1815
- method: 'GET',
1816
- headers: {
1817
- 'Content-type': 'application/json'
1818
- }
1703
+ /**
1704
+ * Flattens a deep nested JSON object skipping
1705
+ * the first level to avoid potentially flattening
1706
+ * non-nested data.
1707
+ * @param {JSON} json
1708
+ */ function flattenJson(json) {
1709
+ const flattenedJson = [];
1710
+ Object.keys(json).forEach((key)=>{
1711
+ flattenedJson.push(flat.flatten(json[key], {
1712
+ delimiter: '_'
1713
+ }));
1819
1714
  });
1820
- if (!res.ok) throw new Error('An error occurred while fetching the data.');
1821
- return await res.json();
1822
- };
1823
- const useGetStatus = ()=>{
1824
- const fetcher = ()=>fetchJson(`${GEN3_GUPPY_API}${statusEndpoint}`);
1825
- return useSWR('explorerStatus', fetcher);
1826
- };
1715
+ return flattenedJson;
1716
+ }
1827
1717
  /**
1828
- * The main endpoint used in templating Exploration page queries.
1829
- * Includes table, filter and aggregation query types and leverages guppyApi defined in ./gupplApi.ts
1830
- * Query templates support filters where applicable
1718
+ * Converts JSON based on a config.
1719
+ * @param {JSON} json
1720
+ * @param {Object} config
1721
+ */ async function conversion(json, config) {
1722
+ return Papa.unparse(json, config);
1723
+ }
1724
+ /**
1725
+ * Converts JSON to a specified file format.
1726
+ * Defaults to JSON if file format is not supported.
1727
+ * @param {JSON} json
1728
+ * @param {string} format
1729
+ */ async function jsonToFormat(json, format) {
1730
+ if (Object.keys(FILE_DELIMITERS).includes(format)) {
1731
+ const flatJson = await flattenJson(json);
1732
+ const data = await conversion(flatJson, {
1733
+ delimiter: FILE_DELIMITERS[format]
1734
+ });
1735
+ return data;
1736
+ }
1737
+ return json;
1738
+ }
1739
+
1740
+ /**
1741
+ * Prepares a URL for downloading by appending '/download' to the provided apiUrl.
1831
1742
  *
1832
- * @param endpoints - Defines endpoints used in Exploration page:
1833
- * @param getAllFieldsForType - A mapping query that returns all property key names vertex types specified.
1834
- * @see https://github.com/uc-cdis/guppy/blob/master/doc/queries.md#mapping-query
1835
- * @param getAccessibleData - An aggregation histogram counts query that filters based on access type
1836
- * @see https://github.com/uc-cdis/guppy/blob/master/doc/queries.md#accessibility-argument-for-regular-tier-access-level
1837
- * @param getRawDataAndTotalCounts - Queries both _totalCount for selected vertex types and
1838
- * tabular results containing the raw data in the rows of selected vertex types
1839
- * @see https://github.com/uc-cdis/guppy/blob/master/doc/queries.md#1-total-count-aggregation
1840
- * @param getAggs - An aggregated histogram counts query which outputs vertex property frequencies
1841
- * @param getSubAggs - TODO: not sure what this one does. Looks like nested aggregation
1842
- * @param getCounts - Returns total counts of a vertex type
1843
- * @returns: A guppy API endpoint for templating queriable data displayed on the exploration page
1844
- */ const explorerApi = guppyApi.injectEndpoints({
1845
- endpoints: (builder)=>({
1846
- getAllFieldsForType: builder.query({
1847
- query: (type)=>({
1848
- query: `{ _mapping ${type} } }`
1849
- }),
1850
- transformResponse: (response, _meta, params)=>{
1743
+ * @param {string} apiUrl - The base URL to be used for preparing the download URL.
1744
+ * @returns {URL} - The prepared download URL as a URL object.
1745
+ */ const prepareUrl$1 = (apiUrl)=>`${apiUrl}/download`;
1746
+ /**
1747
+ * Prepares a fetch configuration object for downloading files from Guppy.
1748
+ *
1749
+ * @param {GuppyFileDownloadRequestParams} parameters - The parameters to include in the request body.
1750
+ * @param {string} csrfToken - The CSRF token to include in the request headers.
1751
+ * @returns {FetchConfig} - The prepared fetch configuration object.
1752
+ */ const prepareFetchConfig = (parameters, csrfToken)=>{
1753
+ return {
1754
+ method: 'POST',
1755
+ headers: {
1756
+ 'Content-Type': 'application/json',
1757
+ ...csrfToken !== undefined && {
1758
+ 'X-CSRF-Token': csrfToken
1759
+ }
1760
+ },
1761
+ body: JSON.stringify({
1762
+ type: parameters.type,
1763
+ filter: convertFilterSetToGqlFilter(parameters.filter),
1764
+ accessibility: parameters.accessibility,
1765
+ fields: parameters?.fields,
1766
+ sort: parameters?.sort
1767
+ })
1768
+ };
1769
+ };
1770
+ /**
1771
+ * Downloads a file from Guppy using the provided parameters.
1772
+ * It will optionally convert the data to the specified format.
1773
+ *
1774
+ * @param {DownloadFromGuppyParams} parameters - The parameters to use for the download request.
1775
+ * @param onStart - The function to call when the download starts.
1776
+ * @param onDone - The function to call when the download is done.
1777
+ * @param onError - The function to call when the download fails.
1778
+ * @param onAbort - The function to call when the download is aborted.
1779
+ * @param signal - AbortSignal to use for the request.
1780
+ */ const downloadFromGuppyToBlob = async ({ parameters, onStart = ()=>null, onDone = (_)=>null, onError = (_)=>null, onAbort = ()=>null, signal = undefined })=>{
1781
+ const csrfToken = selectCSRFToken(coreStore.getState());
1782
+ onStart?.();
1783
+ const url = prepareUrl$1(GEN3_GUPPY_API);
1784
+ const fetchConfig = prepareFetchConfig(parameters, csrfToken);
1785
+ fetch(url.toString(), {
1786
+ ...fetchConfig,
1787
+ ...signal ? {
1788
+ signal: signal
1789
+ } : {}
1790
+ }).then(async (response)=>{
1791
+ if (!response.ok) {
1792
+ throw new Error(response.statusText);
1793
+ }
1794
+ let jsonData = await response.json();
1795
+ if (parameters?.rootPath && parameters.rootPath) {
1796
+ // if rootPath is provided, extract the data from the rootPath
1797
+ jsonData = jsonpathPlus.JSONPath({
1798
+ json: jsonData,
1799
+ path: `$.[${parameters.rootPath}]`,
1800
+ resultType: 'value'
1801
+ });
1802
+ }
1803
+ // convert the data to the specified format and return a Blob
1804
+ let str = '';
1805
+ if (parameters.format === 'json') {
1806
+ str = JSON.stringify(jsonData);
1807
+ } else {
1808
+ const convertedData = await jsonToFormat(jsonData, parameters.format);
1809
+ if (isJSONObject(convertedData)) {
1810
+ str = JSON.stringify(convertedData, null, 2);
1811
+ } else {
1812
+ str = convertedData;
1813
+ }
1814
+ }
1815
+ return new Blob([
1816
+ str
1817
+ ], {
1818
+ type: 'application/json'
1819
+ });
1820
+ }).then((blob)=>onDone?.(blob)).catch((error)=>{
1821
+ // Abort is handle as an exception
1822
+ if (error.name == 'AbortError') {
1823
+ // handle abort()
1824
+ onAbort?.();
1825
+ }
1826
+ onError?.(error);
1827
+ });
1828
+ };
1829
+ const downloadJSONDataFromGuppy = async ({ parameters, onAbort = ()=>null, signal = undefined })=>{
1830
+ const csrfToken = selectCSRFToken(coreStore.getState());
1831
+ const url = prepareUrl$1(GEN3_GUPPY_API);
1832
+ const fetchConfig = prepareFetchConfig(parameters, csrfToken);
1833
+ try {
1834
+ const response = await fetch(url.toString(), {
1835
+ ...fetchConfig,
1836
+ ...signal ? {
1837
+ signal: signal
1838
+ } : {}
1839
+ });
1840
+ let jsonData = await response.json();
1841
+ if (parameters?.rootPath && parameters.rootPath) {
1842
+ // if rootPath is provided, extract the data from the rootPath
1843
+ jsonData = jsonpathPlus.JSONPath({
1844
+ json: jsonData,
1845
+ path: `$.[${parameters.rootPath}]`,
1846
+ resultType: 'value'
1847
+ });
1848
+ }
1849
+ // convert the data to the specified format and return a Blob
1850
+ return jsonData;
1851
+ } catch (error) {
1852
+ // Abort is handle as an exception
1853
+ if (error.name == 'AbortError') {
1854
+ // handle abort()
1855
+ onAbort?.();
1856
+ }
1857
+ throw new Error(error);
1858
+ }
1859
+ };
1860
+ const useGetIndexFields = (index)=>{
1861
+ const { data } = useGetFieldsForIndexQuery(index);
1862
+ return data ?? [];
1863
+ };
1864
+ const groupSharedFields = (data)=>{
1865
+ const reverseIndex = {};
1866
+ // Build reverse index: track which root keys contain each element
1867
+ for(const rootKey in data){
1868
+ data[rootKey].forEach((value)=>{
1869
+ if (!reverseIndex[value]) {
1870
+ reverseIndex[value] = new Set();
1871
+ }
1872
+ reverseIndex[value].add(rootKey);
1873
+ });
1874
+ }
1875
+ return Object.entries(reverseIndex).reduce((acc, [field, indexSet])=>{
1876
+ if (indexSet.size > 1) {
1877
+ acc[field] = Array.from(indexSet).map((x)=>({
1878
+ index: x,
1879
+ field: field
1880
+ }));
1881
+ }
1882
+ return acc;
1883
+ }, {});
1884
+ };
1885
+
1886
+ const statusEndpoint = '/_status';
1887
+ const processHistogramResponse = (data)=>{
1888
+ const valueData = jsonpathPlus.JSONPath({
1889
+ json: data,
1890
+ path: '$..histogram',
1891
+ resultType: 'value'
1892
+ });
1893
+ const pointerData = jsonpathPlus.JSONPath({
1894
+ json: data,
1895
+ path: '$..histogram',
1896
+ resultType: 'pointer'
1897
+ });
1898
+ const results = pointerData.reduce((acc, element, idx)=>{
1899
+ const key = element.slice(1).replace(/\/histogram/g, '').replace(/\//g, '.');
1900
+ return {
1901
+ ...acc,
1902
+ [key]: valueData[idx]
1903
+ };
1904
+ }, {});
1905
+ return results;
1906
+ };
1907
+ const fetchJson = async (url)=>{
1908
+ const res = await fetch(url, {
1909
+ method: 'GET',
1910
+ headers: {
1911
+ 'Content-type': 'application/json'
1912
+ }
1913
+ });
1914
+ if (!res.ok) throw new Error('An error occurred while fetching the data.');
1915
+ return await res.json();
1916
+ };
1917
+ const useGetStatus = ()=>{
1918
+ const fetcher = ()=>fetchJson(`${GEN3_GUPPY_API}${statusEndpoint}`);
1919
+ return useSWR('explorerStatus', fetcher);
1920
+ };
1921
+ /**
1922
+ * The main endpoint used in templating Exploration page queries.
1923
+ * Includes table, filter and aggregation query types and leverages guppyApi defined in ./gupplApi.ts
1924
+ * Query templates support filters where applicable
1925
+ *
1926
+ * @param endpoints - Defines endpoints used in Exploration page:
1927
+ * @param getAllFieldsForType - A mapping query that returns all property key names vertex types specified.
1928
+ * @see https://github.com/uc-cdis/guppy/blob/master/doc/queries.md#mapping-query
1929
+ * @param getAccessibleData - An aggregation histogram counts query that filters based on access type
1930
+ * @see https://github.com/uc-cdis/guppy/blob/master/doc/queries.md#accessibility-argument-for-regular-tier-access-level
1931
+ * @param getRawDataAndTotalCounts - Queries both _totalCount for selected vertex types and
1932
+ * tabular results containing the raw data in the rows of selected vertex types
1933
+ * @see https://github.com/uc-cdis/guppy/blob/master/doc/queries.md#1-total-count-aggregation
1934
+ * @param getAggs - An aggregated histogram counts query which outputs vertex property frequencies
1935
+ * @param getSubAggs - TODO: not sure what this one does. Looks like nested aggregation
1936
+ * @param getCounts - Returns total counts of a vertex type
1937
+ * @returns: A guppy API endpoint for templating queryable data displayed on the exploration page
1938
+ */ const explorerApi = guppyApi.injectEndpoints({
1939
+ endpoints: (builder)=>({
1940
+ getAllFieldsForType: builder.query({
1941
+ query: (type)=>({
1942
+ query: `{ _mapping ${type} } }`
1943
+ }),
1944
+ transformResponse: (response, _meta, params)=>{
1851
1945
  return response[params.type];
1852
1946
  }
1853
1947
  }),
@@ -1942,7 +2036,32 @@ const useGetStatus = ()=>{
1942
2036
  return queryBody;
1943
2037
  },
1944
2038
  transformResponse: (response, _meta, args)=>{
1945
- return processHistogramResponse(response.data._aggregation[args.type]);
2039
+ return processHistogramResponse(response?.data?._aggregation[args.type] ?? {});
2040
+ }
2041
+ }),
2042
+ getAggsNoFilterSelf: builder.query({
2043
+ query: ({ type, fields, filters, accessibility = Accessibility.ALL })=>{
2044
+ const queryStart = isFilterEmpty(filters) ? `
2045
+ query getAggs {
2046
+ _aggregation {
2047
+ ${type} (accessibility: ${accessibility}) {` : `query getAggs ($filter: JSON) {
2048
+ _aggregation {
2049
+ ${type} (filter: $filter, filterSelf: true, accessibility: ${accessibility}) {`;
2050
+ const query = `${queryStart}
2051
+ ${fields.map((field)=>histogramQueryStrForEachField(field))}
2052
+ }
2053
+ }
2054
+ }`;
2055
+ const queryBody = {
2056
+ query: query,
2057
+ variables: {
2058
+ filter: convertFilterSetToGqlFilter(filters)
2059
+ }
2060
+ };
2061
+ return queryBody;
2062
+ },
2063
+ transformResponse: (response, _meta, args)=>{
2064
+ return processHistogramResponse(response?.data?._aggregation[args.type] ?? {});
1946
2065
  }
1947
2066
  }),
1948
2067
  getSubAggs: builder.query({
@@ -1967,7 +2086,7 @@ const useGetStatus = ()=>{
1967
2086
  };
1968
2087
  },
1969
2088
  transformResponse: (response, _meta, args)=>{
1970
- return processHistogramResponse(response.data._aggregation[args.type]);
2089
+ return processHistogramResponse(response?.data?._aggregation[args.type] ?? {});
1971
2090
  }
1972
2091
  }),
1973
2092
  getCounts: builder.query({
@@ -1991,7 +2110,13 @@ const useGetStatus = ()=>{
1991
2110
  };
1992
2111
  },
1993
2112
  transformResponse: (response, _meta, args)=>{
1994
- return response.data._aggregation[args.type]._totalCount;
2113
+ if (!response.data || !response.data._aggregation) {
2114
+ throw new Error('Invalid response: Missing data or _aggregation field');
2115
+ }
2116
+ if (!(args.type in response.data._aggregation)) {
2117
+ throw new Error(`Invalid response: Missing expected key '${args.type}' in _aggregation`);
2118
+ }
2119
+ return response.data._aggregation[args.type]._totalCount ?? 0;
1995
2120
  }
1996
2121
  }),
1997
2122
  getFieldCountSummary: builder.query({
@@ -2022,7 +2147,7 @@ const useGetStatus = ()=>{
2022
2147
  query: (index)=>{
2023
2148
  return {
2024
2149
  query: `{
2025
- _mapping ${index}
2150
+ _mapping { ${index} }
2026
2151
  }`
2027
2152
  };
2028
2153
  },
@@ -2030,6 +2155,21 @@ const useGetStatus = ()=>{
2030
2155
  return response['_mapping'];
2031
2156
  }
2032
2157
  }),
2158
+ getSharedFieldsForIndex: builder.query({
2159
+ query: (indices)=>{
2160
+ return {
2161
+ query: `{
2162
+ _mapping { ${indices.join(' ')} }
2163
+ }`
2164
+ };
2165
+ },
2166
+ transformResponse: (response)=>{
2167
+ if ('_mapping' in response.data) {
2168
+ return groupSharedFields(response.data['_mapping']);
2169
+ }
2170
+ return {};
2171
+ }
2172
+ }),
2033
2173
  generalGQL: builder.query({
2034
2174
  query: ({ query, variables })=>{
2035
2175
  return {
@@ -2100,169 +2240,7 @@ const useGetArrayTypes = ()=>{
2100
2240
  return data ? data['indices'] : {};
2101
2241
  }
2102
2242
  };
2103
- const { useGetRawDataAndTotalCountsQuery, useGetAccessibleDataQuery, useGetAllFieldsForTypeQuery, useGetAggsQuery, useLazyGetAggsQuery, useGetSubAggsQuery, useGetCountsQuery, useGetFieldCountSummaryQuery, useGetFieldsForIndexQuery, useGeneralGQLQuery, useLazyGeneralGQLQuery } = explorerApi;
2104
-
2105
- /**
2106
- * Flattens a deep nested JSON object skipping
2107
- * the first level to avoid potentially flattening
2108
- * non-nested data.
2109
- * @param {JSON} json
2110
- */ function flattenJson(json) {
2111
- const flattenedJson = [];
2112
- Object.keys(json).forEach((key)=>{
2113
- flattenedJson.push(flat.flatten(json[key], {
2114
- delimiter: '_'
2115
- }));
2116
- });
2117
- return flattenedJson;
2118
- }
2119
- /**
2120
- * Converts JSON based on a config.
2121
- * @param {JSON} json
2122
- * @param {Object} config
2123
- */ async function conversion(json, config) {
2124
- return Papa.unparse(json, config);
2125
- }
2126
- /**
2127
- * Converts JSON to a specified file format.
2128
- * Defaults to JSON if file format is not supported.
2129
- * @param {JSON} json
2130
- * @param {string} format
2131
- */ async function jsonToFormat(json, format) {
2132
- if (Object.keys(FILE_DELIMITERS).includes(format)) {
2133
- const flatJson = await flattenJson(json);
2134
- const data = await conversion(flatJson, {
2135
- delimiter: FILE_DELIMITERS[format]
2136
- });
2137
- return data;
2138
- }
2139
- return json;
2140
- }
2141
-
2142
- /**
2143
- * Prepares a URL for downloading by appending '/download' to the provided apiUrl.
2144
- *
2145
- * @param {string} apiUrl - The base URL to be used for preparing the download URL.
2146
- * @returns {URL} - The prepared download URL as a URL object.
2147
- */ const prepareUrl$1 = (apiUrl)=>`${apiUrl}/download`;
2148
- /**
2149
- * Prepares a fetch configuration object for downloading files from Guppy.
2150
- *
2151
- * @param {GuppyFileDownloadRequestParams} parameters - The parameters to include in the request body.
2152
- * @param {string} csrfToken - The CSRF token to include in the request headers.
2153
- * @returns {FetchConfig} - The prepared fetch configuration object.
2154
- */ const prepareFetchConfig = (parameters, csrfToken)=>{
2155
- return {
2156
- method: 'POST',
2157
- headers: {
2158
- 'Content-Type': 'application/json',
2159
- ...csrfToken !== undefined && {
2160
- 'X-CSRF-Token': csrfToken
2161
- }
2162
- },
2163
- body: JSON.stringify({
2164
- type: parameters.type,
2165
- filter: convertFilterSetToGqlFilter(parameters.filter),
2166
- accessibility: parameters.accessibility,
2167
- fields: parameters?.fields,
2168
- sort: parameters?.sort
2169
- })
2170
- };
2171
- };
2172
- /**
2173
- * Downloads a file from Guppy using the provided parameters.
2174
- * It will optionally convert the data to the specified format.
2175
- *
2176
- * @param {DownloadFromGuppyParams} parameters - The parameters to use for the download request.
2177
- * @param onStart - The function to call when the download starts.
2178
- * @param onDone - The function to call when the download is done.
2179
- * @param onError - The function to call when the download fails.
2180
- * @param onAbort - The function to call when the download is aborted.
2181
- * @param signal - AbortSignal to use for the request.
2182
- */ const downloadFromGuppyToBlob = async ({ parameters, onStart = ()=>null, onDone = (_)=>null, onError = (_)=>null, onAbort = ()=>null, signal = undefined })=>{
2183
- const csrfToken = selectCSRFToken(coreStore.getState());
2184
- onStart?.();
2185
- const url = prepareUrl$1(GEN3_GUPPY_API);
2186
- const fetchConfig = prepareFetchConfig(parameters, csrfToken);
2187
- fetch(url.toString(), {
2188
- ...fetchConfig,
2189
- ...signal ? {
2190
- signal: signal
2191
- } : {}
2192
- }).then(async (response)=>{
2193
- if (!response.ok) {
2194
- throw new Error(response.statusText);
2195
- }
2196
- let jsonData = await response.json();
2197
- if (parameters?.rootPath && parameters.rootPath) {
2198
- // if rootPath is provided, extract the data from the rootPath
2199
- jsonData = jsonpathPlus.JSONPath({
2200
- json: jsonData,
2201
- path: `$.[${parameters.rootPath}]`,
2202
- resultType: 'value'
2203
- });
2204
- }
2205
- // convert the data to the specified format and return a Blob
2206
- let str = '';
2207
- if (parameters.format === 'json') {
2208
- str = JSON.stringify(jsonData);
2209
- } else {
2210
- const convertedData = await jsonToFormat(jsonData, parameters.format);
2211
- if (isJSONObject(convertedData)) {
2212
- str = JSON.stringify(convertedData, null, 2);
2213
- } else {
2214
- str = convertedData;
2215
- }
2216
- }
2217
- return new Blob([
2218
- str
2219
- ], {
2220
- type: 'application/json'
2221
- });
2222
- }).then((blob)=>onDone?.(blob)).catch((error)=>{
2223
- // Abort is handle as an exception
2224
- if (error.name == 'AbortError') {
2225
- // handle abort()
2226
- onAbort?.();
2227
- }
2228
- onError?.(error);
2229
- });
2230
- };
2231
- const downloadJSONDataFromGuppy = async ({ parameters, onAbort = ()=>null, signal = undefined })=>{
2232
- const csrfToken = selectCSRFToken(coreStore.getState());
2233
- const url = prepareUrl$1(GEN3_GUPPY_API);
2234
- const fetchConfig = prepareFetchConfig(parameters, csrfToken);
2235
- try {
2236
- const response = await fetch(url.toString(), {
2237
- ...fetchConfig,
2238
- ...signal ? {
2239
- signal: signal
2240
- } : {}
2241
- });
2242
- let jsonData = await response.json();
2243
- if (parameters?.rootPath && parameters.rootPath) {
2244
- // if rootPath is provided, extract the data from the rootPath
2245
- jsonData = jsonpathPlus.JSONPath({
2246
- json: jsonData,
2247
- path: `$.[${parameters.rootPath}]`,
2248
- resultType: 'value'
2249
- });
2250
- }
2251
- // convert the data to the specified format and return a Blob
2252
- return jsonData;
2253
- } catch (error) {
2254
- // Abort is handle as an exception
2255
- if (error.name == 'AbortError') {
2256
- // handle abort()
2257
- onAbort?.();
2258
- }
2259
- throw new Error(error);
2260
- }
2261
- };
2262
- const useGetIndexFields = (index)=>{
2263
- const { data } = useGetFieldsForIndexQuery(index);
2264
- return data ?? [];
2265
- };
2243
+ const { useGetRawDataAndTotalCountsQuery, useGetAccessibleDataQuery, useGetAllFieldsForTypeQuery, useGetAggsQuery, useGetAggsNoFilterSelfQuery, useLazyGetAggsQuery, useGetSubAggsQuery, useGetCountsQuery, useGetFieldCountSummaryQuery, useGetFieldsForIndexQuery, useGetSharedFieldsForIndexQuery, useGeneralGQLQuery, useLazyGeneralGQLQuery } = explorerApi;
2266
2244
 
2267
2245
  /**
2268
2246
  * Creates a Guppy API for fetching bulk (> 10K rows) elasticsearch data
@@ -2298,13 +2276,230 @@ const useGetIndexFields = (index)=>{
2298
2276
  });
2299
2277
  const { useDownloadFromGuppyMutation } = downloadRequestApi;
2300
2278
 
2279
+ const EmptyCohort = {
2280
+ id: 'default',
2281
+ name: 'Filters',
2282
+ filters: {},
2283
+ modified_datetime: new Date().toISOString()
2284
+ };
2285
+ const initialCohortState = {
2286
+ cohort: {
2287
+ ...EmptyCohort
2288
+ }
2289
+ };
2290
+ // TODO: start using this adapter
2291
+ /*
2292
+ const cohortsAdapter = createEntityAdapter<Cohort>({
2293
+ sortComparer: (a, b) => {
2294
+ if (a.modified_datetime <= b.modified_datetime) return 1;
2295
+ else return -1;
2296
+ },
2297
+ });
2298
+ */ /**
2299
+ * Redux slice for cohort filters
2300
+ */ const cohortSlice = toolkit.createSlice({
2301
+ name: 'cohort',
2302
+ initialState: initialCohortState,
2303
+ reducers: {
2304
+ // adds a filter to the cohort filter set at the given index
2305
+ updateCohortFilter: (state, action)=>{
2306
+ const { index, field, filter } = action.payload;
2307
+ return {
2308
+ cohort: {
2309
+ ...state.cohort,
2310
+ filters: {
2311
+ ...state.cohort.filters,
2312
+ [index]: {
2313
+ mode: state.cohort.filters?.[index]?.mode ?? 'and',
2314
+ root: {
2315
+ ...state.cohort.filters?.[index]?.root ?? {},
2316
+ [field]: filter
2317
+ }
2318
+ }
2319
+ }
2320
+ }
2321
+ };
2322
+ },
2323
+ setCohortFilter: (state, action)=>{
2324
+ const { index, filters } = action.payload;
2325
+ return {
2326
+ cohort: {
2327
+ ...state.cohort,
2328
+ filters: {
2329
+ ...state.cohort.filters,
2330
+ [index]: filters
2331
+ }
2332
+ }
2333
+ };
2334
+ },
2335
+ setCohortIndexFilters: (state, action)=>{
2336
+ return {
2337
+ cohort: {
2338
+ ...state.cohort,
2339
+ filters: {
2340
+ ...action.payload.filters
2341
+ }
2342
+ }
2343
+ };
2344
+ },
2345
+ // removes a filter to the cohort filter set at the given index
2346
+ removeCohortFilter: (state, action)=>{
2347
+ const { index, field } = action.payload;
2348
+ const filters = state.cohort?.filters?.[index]?.root;
2349
+ if (!filters) {
2350
+ return;
2351
+ }
2352
+ const { [field]: _a, ...updated } = filters;
2353
+ return {
2354
+ cohort: {
2355
+ ...state.cohort,
2356
+ filters: {
2357
+ ...state.cohort.filters,
2358
+ [index]: {
2359
+ mode: state.cohort.filters[index].mode,
2360
+ root: updated
2361
+ }
2362
+ }
2363
+ }
2364
+ };
2365
+ },
2366
+ // removes all filters from the cohort filter set at the given index
2367
+ clearCohortFilters: (state, action)=>{
2368
+ const { index } = action.payload;
2369
+ return {
2370
+ cohort: {
2371
+ ...state.cohort,
2372
+ filters: {
2373
+ ...state.cohort.filters,
2374
+ [index]: {
2375
+ // empty filter set
2376
+ mode: 'and',
2377
+ root: {}
2378
+ }
2379
+ }
2380
+ }
2381
+ };
2382
+ }
2383
+ }
2384
+ });
2385
+ // Filter actions: addFilter, removeFilter, updateFilter
2386
+ const { updateCohortFilter, setCohortFilter, setCohortIndexFilters, removeCohortFilter, clearCohortFilters } = cohortSlice.actions;
2387
+ const selectCohortFilters = (state)=>state.cohorts.cohort.cohort.filters;
2388
+ const selectCurrentCohortId = (state)=>state.cohorts.cohort.cohort.id;
2389
+ const selectCurrentCohort = (state)=>state.cohorts.cohort.cohort;
2390
+ const selectCurrentCohortName = (state)=>state.cohorts.cohort.cohort.name;
2391
+ /**
2392
+ * Select a filter by its name from the current cohort. If the filter is not found
2393
+ * returns undefined.
2394
+ * @param state - Core
2395
+ * @param index which cohort index to select from
2396
+ * @param name name of the filter to select
2397
+ */ const selectIndexedFilterByName = (state, index, name)=>{
2398
+ return state.cohorts.cohort.cohort.filters[index]?.root[name];
2399
+ };
2400
+ const EmptyFilterSet = {
2401
+ mode: 'and',
2402
+ root: {}
2403
+ };
2404
+ /**
2405
+ * Select a filter from the index.
2406
+ * returns undefined.
2407
+ * @param state - Core
2408
+ * @param index which cohort index to select from
2409
+ */ const selectIndexFilters = (state, index)=>{
2410
+ return state.cohorts.cohort.cohort.filters?.[index] ?? EmptyFilterSet; // TODO: check if this is undefined
2411
+ };
2412
+ const cohortReducer = cohortSlice.reducer;
2413
+
2414
+ const initialState$2 = {};
2415
+ const expandSlice$1 = toolkit.createSlice({
2416
+ name: 'CohortBuilder/filterExpand',
2417
+ initialState: initialState$2,
2418
+ reducers: {
2419
+ toggleCohortBuilderCategoryFilter: (state, action)=>{
2420
+ return {
2421
+ ...state,
2422
+ [action.payload.index]: {
2423
+ ...state[action.payload.index],
2424
+ [action.payload.field]: action.payload.expanded
2425
+ }
2426
+ };
2427
+ },
2428
+ toggleCohortBuilderAllFilters: (state, action)=>{
2429
+ return {
2430
+ ...state,
2431
+ [action.payload.index]: Object.keys(state[action.payload.index]).reduce((acc, k)=>{
2432
+ acc[k] = action.payload.expand;
2433
+ return acc;
2434
+ }, {})
2435
+ };
2436
+ }
2437
+ }
2438
+ });
2439
+ const cohortBuilderFiltersExpandedReducer = expandSlice$1.reducer;
2440
+ const { toggleCohortBuilderCategoryFilter, toggleCohortBuilderAllFilters } = expandSlice$1.actions;
2441
+ const selectCohortFilterExpanded = (state, index, field)=>state.cohorts.filtersExpanded?.[index]?.[field];
2442
+ const selectAllCohortFiltersCollapsed = (state, index)=>index in state.cohorts.filtersExpanded ? Object.values(state.cohorts.filtersExpanded?.[index]).every((e)=>!e) : false;
2443
+
2444
+ const initialState$1 = {};
2445
+ const expandSlice = toolkit.createSlice({
2446
+ name: 'CohortBuilder/filterCombineMode',
2447
+ initialState: initialState$1,
2448
+ reducers: {
2449
+ setCohortFilterCombineMode: (state, action)=>{
2450
+ return {
2451
+ ...state,
2452
+ [action.payload.index]: {
2453
+ ...state[action.payload.index],
2454
+ [action.payload.field]: action.payload.mode
2455
+ }
2456
+ };
2457
+ }
2458
+ }
2459
+ });
2460
+ const cohortBuilderFiltersCombineModeReducer = expandSlice.reducer;
2461
+ const { setCohortFilterCombineMode } = expandSlice.actions;
2462
+ const selectCohortFilterCombineMode = (state, index, field)=>state.cohorts.filtersCombineMode?.[index]?.[field] ?? 'or';
2463
+
2464
+ const initialState = {
2465
+ shouldShareFilters: false,
2466
+ sharedFiltersMap: {}
2467
+ };
2468
+ const cohortSharedFiltersSlice = toolkit.createSlice({
2469
+ name: 'cohortSharedFilters',
2470
+ initialState: initialState,
2471
+ reducers: {
2472
+ setShouldShareFilters: (state, action)=>{
2473
+ state.shouldShareFilters = action.payload;
2474
+ return state;
2475
+ },
2476
+ setSharedFilters: (state, action)=>{
2477
+ state.sharedFiltersMap = action.payload;
2478
+ }
2479
+ }
2480
+ });
2481
+ const selectShouldShareFilters = (state)=>state.cohorts.sharedFilters.shouldShareFilters;
2482
+ const selectSharedFilters = (state)=>state.cohorts.sharedFilters.sharedFiltersMap;
2483
+ const selectSharedFiltersForFields = (state, field)=>state.cohorts.sharedFilters.sharedFiltersMap?.[field] ?? [
2484
+ field
2485
+ ];
2486
+ const { setShouldShareFilters, setSharedFilters } = cohortSharedFiltersSlice.actions;
2487
+ const cohortSharedFiltersReducer = cohortSharedFiltersSlice.reducer;
2488
+
2489
+ const cohortReducers = toolkit.combineReducers({
2490
+ filtersExpanded: cohortBuilderFiltersExpandedReducer,
2491
+ filtersCombineMode: cohortBuilderFiltersCombineModeReducer,
2492
+ sharedFilters: cohortSharedFiltersReducer,
2493
+ cohort: cohortReducer
2494
+ });
2495
+
2301
2496
  const rootReducer = toolkit.combineReducers({
2302
2497
  gen3Services: gen3ServicesReducer,
2303
2498
  user: userReducer,
2304
2499
  gen3Apps: gen3AppReducer,
2305
2500
  drsHostnames: drsHostnamesReducer,
2306
2501
  modals: modalReducer,
2307
- cohorts: cohortReducer,
2502
+ cohorts: cohortReducers,
2308
2503
  activeWorkspace: activeWorkspaceReducer,
2309
2504
  dataLibrarySelection: dataLibrarySelectionReducer,
2310
2505
  [guppyApiSliceReducerPath]: guppyApiReducer,
@@ -2333,7 +2528,7 @@ const persistConfig = {
2333
2528
  version: 1,
2334
2529
  storage,
2335
2530
  whitelist: [
2336
- 'cohorts',
2531
+ 'cohort',
2337
2532
  'activeWorkspace'
2338
2533
  ]
2339
2534
  };
@@ -2358,7 +2553,7 @@ const coreStore = setupCoreStore();
2358
2553
  query.setupListeners(coreStore.dispatch);
2359
2554
 
2360
2555
  const isNotDefined = (x)=>{
2361
- return x === undefined || x === null || x === undefined;
2556
+ return x === undefined || x === null || x === void 0;
2362
2557
  };
2363
2558
  const isObject = (x)=>{
2364
2559
  return typeof x === 'object';
@@ -2377,51 +2572,14 @@ const isString = (x)=>{
2377
2572
  * @returns {URL} - The prepared download URL as a URL object.
2378
2573
  */ const prepareUrl = (apiUrl)=>new URL(apiUrl + '/download');
2379
2574
 
2380
- const HTTPErrorMessages = {
2381
- // 4xx Client Errors
2382
- 400: 'Bad Request',
2383
- 401: 'Unauthorized',
2384
- 402: 'Payment Required',
2385
- 403: 'Forbidden',
2386
- 404: 'Not Found',
2387
- 405: 'Method Not Allowed',
2388
- 406: 'Not Acceptable',
2389
- 407: 'Proxy Authentication Required',
2390
- 408: 'Request Timeout',
2391
- 409: 'Conflict',
2392
- 410: 'Gone',
2393
- 411: 'Length Required',
2394
- 412: 'Precondition Failed',
2395
- 413: 'Payload Too Large',
2396
- 414: 'URI Too Long',
2397
- 415: 'Unsupported Media Type',
2398
- 416: 'Range Not Satisfiable',
2399
- 417: 'Expectation Failed',
2400
- 418: "I'm a teapot",
2401
- 421: 'Misdirected Request',
2402
- 422: 'Unprocessable Entity',
2403
- 423: 'Locked',
2404
- 424: 'Failed Dependency',
2405
- 425: 'Too Early',
2406
- 426: 'Upgrade Required',
2407
- 428: 'Precondition Required',
2408
- 429: 'Too Many Requests',
2409
- 431: 'Request Header Fields Too Large',
2410
- 451: 'Unavailable For Legal Reasons',
2411
- // 5xx Server Errors
2412
- 500: 'Internal Server Error',
2413
- 501: 'Not Implemented',
2414
- 502: 'Bad Gateway',
2415
- 503: 'Service Unavailable',
2416
- 504: 'Gateway Timeout',
2417
- 505: 'HTTP Version Not Supported',
2418
- 506: 'Variant Also Negotiates',
2419
- 507: 'Insufficient Storage',
2420
- 508: 'Loop Detected',
2421
- 510: 'Not Extended',
2422
- 511: 'Network Authentication Required'
2423
- };
2424
- class HTTPError extends Error {
2575
+ const DEFAULT_METHOD = 'GET';
2576
+ const CONTENT_TYPE_HEADER = 'Content-Type';
2577
+ const CONTENT_TYPE_JSON = 'application/json';
2578
+ /**
2579
+ * Represents an error that occurs during an HTTP request.
2580
+ * Extends the built-in `Error` class to provide additional information
2581
+ * about the HTTP status code and optional response data.
2582
+ */ class HTTPError extends Error {
2425
2583
  constructor(status, message, responseData){
2426
2584
  super(message), this.status = status, this.responseData = responseData;
2427
2585
  this.name = 'HTTPError';
@@ -2431,15 +2589,16 @@ const fetchFencePresignedURL = async ({ guid, method = 'GET', onAbort = ()=>null
2431
2589
  const csrfToken = selectCSRFToken(coreStore.getState());
2432
2590
  const headers = new Headers();
2433
2591
  headers.set('Content-Type', 'application/json');
2434
- let accessToken = undefined;
2435
2592
  if (process.env.NODE_ENV === 'development') {
2436
2593
  // NOTE: This cookie can only be accessed from the client side
2437
2594
  // in development mode. Otherwise, the cookie is set as httpOnly
2438
- accessToken = cookiesNext.getCookie('credentials_token');
2595
+ const accessToken = cookiesNext.getCookie('credentials_token');
2596
+ if (accessToken) {
2597
+ headers.set('Authorization', `Bearer ${accessToken}`);
2598
+ }
2439
2599
  }
2440
2600
  if (csrfToken) headers.set('X-CSRF-Token', csrfToken);
2441
- if (accessToken) headers.set('Authorization', `Bearer ${accessToken}`);
2442
- const url = `${GEN3_FENCE_API}/user/data/download/${guid}`;
2601
+ const url = `${GEN3_FENCE_API}/data/download/${guid}`;
2443
2602
  try {
2444
2603
  const response = await fetch(url, {
2445
2604
  method: method,
@@ -2472,6 +2631,67 @@ const fetchFencePresignedURL = async ({ guid, method = 'GET', onAbort = ()=>null
2472
2631
  throw error;
2473
2632
  }
2474
2633
  };
2634
+ /**
2635
+ * Retrieves a CSRF token from the server.
2636
+ *
2637
+ * This asynchronous function sends a GET request to the server's status endpoint
2638
+ * to fetch the CSRF token in the response. The token is expected to be included
2639
+ * in the JSON response under the `csrf_token` field.
2640
+ *
2641
+ * @returns {Promise<string | null>} A promise that resolves to the CSRF token as a string if successfully retrieved,
2642
+ * or null if the token is not present in the response.
2643
+ * @throws {HTTPError} Throws an HTTPError if the server response is not successful.
2644
+ */ const getCSRFToken = async ()=>{
2645
+ const requestHeaders = new Headers({
2646
+ [CONTENT_TYPE_HEADER]: CONTENT_TYPE_JSON
2647
+ });
2648
+ const response = await fetch(`${GEN3_API}/_status`, {
2649
+ headers: requestHeaders
2650
+ });
2651
+ if (!response.ok) {
2652
+ throw new HTTPError(response.status, response.statusText);
2653
+ }
2654
+ const { csrf_token: csrfToken } = await response.json();
2655
+ return csrfToken || null;
2656
+ };
2657
+ /**
2658
+ * Fetches JSON data from a specified URL using the Fetch API.
2659
+ *
2660
+ * @param {string} url - The URL to fetch the JSON data from.
2661
+ * @param {boolean} [requiresCSRF=false] - Indicates whether a CSRF token is required for the request.
2662
+ * If true, the CSRF token will be added to the request headers.
2663
+ * @param {string} [method=DEFAULT_METHOD] - The HTTP method to use for the request (e.g., 'GET', 'POST').
2664
+ * @param {unknown} [body=undefined] - The request body to send, applicable when using methods like 'POST'.
2665
+ *
2666
+ * @returns {Promise<any>} A promise that resolves to the parsed JSON data from the response.
2667
+ *
2668
+ * @throws {HTTPError} Throws an error if the HTTP response status indicates a failure.
2669
+ */ const fetchJSONDataFromURL = async (url, requiresCSRF = false, method = DEFAULT_METHOD, body = undefined)=>{
2670
+ const requestHeaders = new Headers({
2671
+ [CONTENT_TYPE_HEADER]: CONTENT_TYPE_JSON
2672
+ });
2673
+ if (requiresCSRF) {
2674
+ const csrfToken = await getCSRFToken();
2675
+ if (csrfToken) {
2676
+ requestHeaders.set('X-CSRF-Token', csrfToken);
2677
+ }
2678
+ }
2679
+ if (process.env.NODE_ENV === 'development') {
2680
+ const accessToken = cookiesNext.getCookie('credentials_token');
2681
+ if (accessToken) {
2682
+ requestHeaders.set('Authorization', `Bearer ${accessToken}`);
2683
+ }
2684
+ }
2685
+ const response = await fetch(url, {
2686
+ method,
2687
+ headers: requestHeaders,
2688
+ body: method === 'POST' ? JSON.stringify(body) : null
2689
+ });
2690
+ if (!response.ok) {
2691
+ throw new HTTPError(response.status, response.statusText);
2692
+ }
2693
+ return response.json();
2694
+ };
2475
2695
 
2476
2696
  const persistor = reduxPersist.persistStore(coreStore);
2477
2697
  const CoreProvider = ({ children })=>{
@@ -3298,7 +3518,6 @@ exports.GEN3_SOWER_API = GEN3_SOWER_API;
3298
3518
  exports.GEN3_SUBMISSION_API = GEN3_SUBMISSION_API;
3299
3519
  exports.GEN3_WORKSPACE_API = GEN3_WORKSPACE_API;
3300
3520
  exports.HTTPError = HTTPError;
3301
- exports.HTTPErrorMessages = HTTPErrorMessages;
3302
3521
  exports.Modals = Modals;
3303
3522
  exports.PodConditionType = PodConditionType;
3304
3523
  exports.PodStatus = PodStatus;
@@ -3307,7 +3526,6 @@ exports.WorkspaceStatus = WorkspaceStatus;
3307
3526
  exports.clearActiveWorkspaceId = clearActiveWorkspaceId;
3308
3527
  exports.clearCohortFilters = clearCohortFilters;
3309
3528
  exports.clearDataLibrarySelection = clearDataLibrarySelection;
3310
- exports.cohortReducer = cohortReducer;
3311
3529
  exports.convertFilterSetToGqlFilter = convertFilterSetToGqlFilter;
3312
3530
  exports.coreStore = coreStore;
3313
3531
  exports.createAppApiForRTKQ = createAppApiForRTKQ;
@@ -3326,6 +3544,7 @@ exports.extractIndexAndFieldNameFromFullFieldName = extractIndexAndFieldNameFrom
3326
3544
  exports.extractIndexFromFullFieldName = extractIndexFromFullFieldName;
3327
3545
  exports.fetchFence = fetchFence;
3328
3546
  exports.fetchFencePresignedURL = fetchFencePresignedURL;
3547
+ exports.fetchJSONDataFromURL = fetchJSONDataFromURL;
3329
3548
  exports.fetchJson = fetchJson;
3330
3549
  exports.fetchUserState = fetchUserState;
3331
3550
  exports.fieldNameToTitle = fieldNameToTitle;
@@ -3336,6 +3555,7 @@ exports.getNumberOfItemsInDatalist = getNumberOfItemsInDatalist;
3336
3555
  exports.getTimestamp = getTimestamp;
3337
3556
  exports.graphQLAPI = graphQLAPI;
3338
3557
  exports.graphQLWithTags = graphQLWithTags;
3558
+ exports.groupSharedFields = groupSharedFields;
3339
3559
  exports.guppyAPISliceMiddleware = guppyAPISliceMiddleware;
3340
3560
  exports.guppyApi = guppyApi;
3341
3561
  exports.guppyApiReducer = guppyApiReducer;
@@ -3348,6 +3568,7 @@ exports.isAuthenticated = isAuthenticated;
3348
3568
  exports.isCohortItem = isCohortItem;
3349
3569
  exports.isErrorWithMessage = isErrorWithMessage;
3350
3570
  exports.isFetchBaseQueryError = isFetchBaseQueryError;
3571
+ exports.isFetchError = isFetchError;
3351
3572
  exports.isFetchParseError = isFetchParseError;
3352
3573
  exports.isFileItem = isFileItem;
3353
3574
  exports.isFilterEmpty = isFilterEmpty;
@@ -3362,17 +3583,20 @@ exports.isHistogramDataArrayAnEnum = isHistogramDataArrayAnEnum;
3362
3583
  exports.isHistogramDataCollection = isHistogramDataCollection;
3363
3584
  exports.isHistogramRangeData = isHistogramRangeData;
3364
3585
  exports.isHttpStatusError = isHttpStatusError;
3586
+ exports.isIntersection = isIntersection;
3365
3587
  exports.isJSONObject = isJSONObject;
3366
3588
  exports.isJSONValue = isJSONValue;
3367
3589
  exports.isJSONValueArray = isJSONValueArray;
3368
3590
  exports.isNotDefined = isNotDefined;
3369
3591
  exports.isObject = isObject;
3370
3592
  exports.isOperationWithField = isOperationWithField;
3593
+ exports.isOperatorWithFieldAndArrayOfOperands = isOperatorWithFieldAndArrayOfOperands;
3371
3594
  exports.isPending = isPending;
3372
3595
  exports.isProgramUrl = isProgramUrl;
3373
3596
  exports.isRootUrl = isRootUrl;
3374
3597
  exports.isString = isString;
3375
3598
  exports.isTimeGreaterThan = isTimeGreaterThan;
3599
+ exports.isUnion = isUnion;
3376
3600
  exports.isWorkspaceActive = isWorkspaceActive;
3377
3601
  exports.isWorkspaceRunningOrStopping = isWorkspaceRunningOrStopping;
3378
3602
  exports.listifyMethodsFromMapping = listifyMethodsFromMapping;
@@ -3387,9 +3611,12 @@ exports.resetUserState = resetUserState;
3387
3611
  exports.resourcePathFromProjectID = resourcePathFromProjectID;
3388
3612
  exports.selectActiveWorkspaceId = selectActiveWorkspaceId;
3389
3613
  exports.selectActiveWorkspaceStatus = selectActiveWorkspaceStatus;
3614
+ exports.selectAllCohortFiltersCollapsed = selectAllCohortFiltersCollapsed;
3390
3615
  exports.selectAuthzMappingData = selectAuthzMappingData;
3391
3616
  exports.selectCSRFToken = selectCSRFToken;
3392
3617
  exports.selectCSRFTokenData = selectCSRFTokenData;
3618
+ exports.selectCohortFilterCombineMode = selectCohortFilterCombineMode;
3619
+ exports.selectCohortFilterExpanded = selectCohortFilterExpanded;
3393
3620
  exports.selectCohortFilters = selectCohortFilters;
3394
3621
  exports.selectCurrentCohort = selectCurrentCohort;
3395
3622
  exports.selectCurrentCohortId = selectCurrentCohortId;
@@ -3404,6 +3631,9 @@ exports.selectIndexedFilterByName = selectIndexedFilterByName;
3404
3631
  exports.selectPaymodelStatus = selectPaymodelStatus;
3405
3632
  exports.selectRequestedWorkspaceStatus = selectRequestedWorkspaceStatus;
3406
3633
  exports.selectRequestedWorkspaceStatusTimestamp = selectRequestedWorkspaceStatusTimestamp;
3634
+ exports.selectSharedFilters = selectSharedFilters;
3635
+ exports.selectSharedFiltersForFields = selectSharedFiltersForFields;
3636
+ exports.selectShouldShareFilters = selectShouldShareFilters;
3407
3637
  exports.selectUser = selectUser;
3408
3638
  exports.selectUserAuthStatus = selectUserAuthStatus;
3409
3639
  exports.selectUserData = selectUserData;
@@ -3415,13 +3645,18 @@ exports.setActiveWorkspace = setActiveWorkspace;
3415
3645
  exports.setActiveWorkspaceId = setActiveWorkspaceId;
3416
3646
  exports.setActiveWorkspaceStatus = setActiveWorkspaceStatus;
3417
3647
  exports.setCohortFilter = setCohortFilter;
3648
+ exports.setCohortFilterCombineMode = setCohortFilterCombineMode;
3418
3649
  exports.setCohortIndexFilters = setCohortIndexFilters;
3419
3650
  exports.setDRSHostnames = setDRSHostnames;
3420
3651
  exports.setDataLibraryListSelection = setDataLibraryListSelection;
3421
3652
  exports.setRequestedWorkspaceStatus = setRequestedWorkspaceStatus;
3653
+ exports.setSharedFilters = setSharedFilters;
3654
+ exports.setShouldShareFilters = setShouldShareFilters;
3422
3655
  exports.setupCoreStore = setupCoreStore;
3423
3656
  exports.showModal = showModal;
3424
3657
  exports.submissionApi = submissionApi;
3658
+ exports.toggleCohortBuilderAllFilters = toggleCohortBuilderAllFilters;
3659
+ exports.toggleCohortBuilderCategoryFilter = toggleCohortBuilderCategoryFilter;
3425
3660
  exports.trimFirstFieldNameToTitle = trimFirstFieldNameToTitle;
3426
3661
  exports.updateCohortFilter = updateCohortFilter;
3427
3662
  exports.useAddDataLibraryListMutation = useAddDataLibraryListMutation;
@@ -3440,6 +3675,7 @@ exports.useGetAISearchVersionQuery = useGetAISearchVersionQuery;
3440
3675
  exports.useGetAccessibleDataQuery = useGetAccessibleDataQuery;
3441
3676
  exports.useGetActivePayModelQuery = useGetActivePayModelQuery;
3442
3677
  exports.useGetAggMDSQuery = useGetAggMDSQuery;
3678
+ exports.useGetAggsNoFilterSelfQuery = useGetAggsNoFilterSelfQuery;
3443
3679
  exports.useGetAggsQuery = useGetAggsQuery;
3444
3680
  exports.useGetAllFieldsForTypeQuery = useGetAllFieldsForTypeQuery;
3445
3681
  exports.useGetArrayTypes = useGetArrayTypes;
@@ -3465,6 +3701,7 @@ exports.useGetMetadataByIdQuery = useGetMetadataByIdQuery;
3465
3701
  exports.useGetProjectsDetailsQuery = useGetProjectsDetailsQuery;
3466
3702
  exports.useGetProjectsQuery = useGetProjectsQuery;
3467
3703
  exports.useGetRawDataAndTotalCountsQuery = useGetRawDataAndTotalCountsQuery;
3704
+ exports.useGetSharedFieldsForIndexQuery = useGetSharedFieldsForIndexQuery;
3468
3705
  exports.useGetSowerJobListQuery = useGetSowerJobListQuery;
3469
3706
  exports.useGetSowerJobStatusQuery = useGetSowerJobStatusQuery;
3470
3707
  exports.useGetSowerOutputQuery = useGetSowerOutputQuery;