@gen3/core 0.11.32 → 0.11.34
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/dist/cjs/index.js +887 -672
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/server.js +45 -0
- package/dist/cjs/server.js.map +1 -0
- package/dist/dts/constants.d.ts +1 -0
- package/dist/dts/constants.d.ts.map +1 -1
- package/dist/dts/features/cart/cartSelectors.d.ts +129 -0
- package/dist/dts/features/cart/cartSelectors.d.ts.map +1 -0
- package/dist/dts/features/cart/cartSlice.d.ts +24 -0
- package/dist/dts/features/cart/cartSlice.d.ts.map +1 -0
- package/dist/dts/features/cart/index.d.ts +5 -0
- package/dist/dts/features/cart/index.d.ts.map +1 -0
- package/dist/dts/features/cart/test/cartSelector.unit.test.d.ts +2 -0
- package/dist/dts/features/cart/test/cartSelector.unit.test.d.ts.map +1 -0
- package/dist/dts/features/cohort/cohortManagerSelector.d.ts +4 -0
- package/dist/dts/features/cohort/cohortManagerSelector.d.ts.map +1 -1
- package/dist/dts/features/cohort/cohortManagerSlice.d.ts +1 -0
- package/dist/dts/features/cohort/cohortManagerSlice.d.ts.map +1 -1
- package/dist/dts/features/cohort/utils.d.ts +13 -0
- package/dist/dts/features/cohort/utils.d.ts.map +1 -1
- package/dist/dts/features/filters/filters.d.ts +14 -0
- package/dist/dts/features/filters/filters.d.ts.map +1 -1
- package/dist/dts/features/filters/types.d.ts +7 -0
- package/dist/dts/features/filters/types.d.ts.map +1 -1
- package/dist/dts/features/guppy/guppyApi.d.ts.map +1 -1
- package/dist/dts/features/guppy/guppySlice.d.ts +0 -4
- package/dist/dts/features/guppy/guppySlice.d.ts.map +1 -1
- package/dist/dts/features/guppy/index.d.ts +6 -0
- package/dist/dts/features/guppy/index.d.ts.map +1 -1
- package/dist/dts/features/guppy/queryGenerators.d.ts +6 -0
- package/dist/dts/features/guppy/queryGenerators.d.ts.map +1 -0
- package/dist/dts/features/guppy/tests/queryGenerators.unit.test.d.ts +2 -0
- package/dist/dts/features/guppy/tests/queryGenerators.unit.test.d.ts.map +1 -0
- package/dist/dts/features/guppy/utils.d.ts +1 -1
- package/dist/dts/features/guppy/utils.d.ts.map +1 -1
- package/dist/dts/features/user/userSliceRTK.d.ts +3 -0
- package/dist/dts/features/user/userSliceRTK.d.ts.map +1 -1
- package/dist/dts/hooks.d.ts +2 -0
- package/dist/dts/hooks.d.ts.map +1 -1
- package/dist/dts/index.d.ts +3 -2
- package/dist/dts/index.d.ts.map +1 -1
- package/dist/dts/reducers.d.ts +2 -0
- package/dist/dts/reducers.d.ts.map +1 -1
- package/dist/dts/server.d.ts +4 -0
- package/dist/dts/server.d.ts.map +1 -0
- package/dist/dts/store.d.ts +4 -0
- package/dist/dts/store.d.ts.map +1 -1
- package/dist/dts/utils/conversions.d.ts +7 -0
- package/dist/dts/utils/conversions.d.ts.map +1 -1
- package/dist/dts/utils/extractvalues.d.ts +1 -0
- package/dist/dts/utils/extractvalues.d.ts.map +1 -1
- package/dist/dts/utils/index.d.ts +3 -2
- package/dist/dts/utils/index.d.ts.map +1 -1
- package/dist/esm/index.js +868 -673
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/server.js +29 -0
- package/dist/esm/server.js.map +1 -0
- package/dist/index.d.ts +420 -199
- package/dist/server.d.ts +31 -0
- package/package.json +7 -2
package/dist/esm/index.js
CHANGED
|
@@ -5,18 +5,18 @@ import { QueryStatus, setupListeners } from '@reduxjs/toolkit/query';
|
|
|
5
5
|
import { useSelector, useDispatch, Provider, createSelectorHook, createDispatchHook, createStoreHook } from 'react-redux';
|
|
6
6
|
import * as React from 'react';
|
|
7
7
|
import React__default, { useEffect, useState, useRef, useCallback } from 'react';
|
|
8
|
+
import { GraphQLError, parse } from 'graphql';
|
|
9
|
+
import { JSONPath } from 'jsonpath-plus';
|
|
10
|
+
import { isEqual } from 'lodash';
|
|
8
11
|
import { customAlphabet } from 'nanoid';
|
|
9
12
|
import useSWR from 'swr';
|
|
10
|
-
import { isEqual } from 'lodash';
|
|
11
13
|
import { flatten } from 'flat';
|
|
12
14
|
import Papa from 'papaparse';
|
|
13
|
-
import { JSONPath } from 'jsonpath-plus';
|
|
14
15
|
import { persistReducer, FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER, persistStore } from 'redux-persist';
|
|
15
16
|
import createWebStorage from 'redux-persist/lib/storage/createWebStorage';
|
|
16
17
|
import { PersistGate } from 'redux-persist/integration/react';
|
|
17
18
|
import { openDB } from 'idb';
|
|
18
19
|
import { useDeepCompareMemo } from 'use-deep-compare';
|
|
19
|
-
import { parse } from 'graphql';
|
|
20
20
|
import { v5 } from 'uuid';
|
|
21
21
|
import { CookiesProvider } from 'react-cookie';
|
|
22
22
|
import Queue from 'queue';
|
|
@@ -52,6 +52,7 @@ const FILE_DELIMITERS = {
|
|
|
52
52
|
tsv: '\t',
|
|
53
53
|
csv: ','
|
|
54
54
|
};
|
|
55
|
+
const CART_LIMIT = 10000;
|
|
55
56
|
|
|
56
57
|
const isFetchError = (obj)=>{
|
|
57
58
|
if (typeof obj !== 'object' || obj === null) {
|
|
@@ -406,7 +407,7 @@ const useCoreDispatch = useDispatch.withTypes();
|
|
|
406
407
|
});
|
|
407
408
|
const isAuthenticated = (loginStatus)=>loginStatus === 'authenticated';
|
|
408
409
|
const isPending = (loginStatus)=>loginStatus === 'pending';
|
|
409
|
-
const initialState$
|
|
410
|
+
const initialState$9 = {
|
|
410
411
|
status: 'uninitialized',
|
|
411
412
|
loginStatus: 'unauthenticated',
|
|
412
413
|
error: undefined
|
|
@@ -417,9 +418,9 @@ const initialState$8 = {
|
|
|
417
418
|
* @returns: status messages wrapped around fetchUserState response dict
|
|
418
419
|
*/ const slice$4 = createSlice({
|
|
419
420
|
name: 'fence/user',
|
|
420
|
-
initialState: initialState$
|
|
421
|
+
initialState: initialState$9,
|
|
421
422
|
reducers: {
|
|
422
|
-
resetUserState: ()=>initialState$
|
|
423
|
+
resetUserState: ()=>initialState$9
|
|
423
424
|
},
|
|
424
425
|
extraReducers: (builder)=>{
|
|
425
426
|
builder.addCase(fetchUserState.fulfilled, (_, action)=>{
|
|
@@ -561,11 +562,11 @@ const { useGetExternalLoginsQuery, useLazyGetExternalLoginsQuery, useLazyIsExter
|
|
|
561
562
|
}
|
|
562
563
|
};
|
|
563
564
|
|
|
564
|
-
const initialState$
|
|
565
|
+
const initialState$8 = {};
|
|
565
566
|
// TODO: document what this does
|
|
566
567
|
const slice$3 = createSlice({
|
|
567
568
|
name: 'drsResolver',
|
|
568
|
-
initialState: initialState$
|
|
569
|
+
initialState: initialState$8,
|
|
569
570
|
reducers: {
|
|
570
571
|
setDRSHostnames: (_state, action)=>{
|
|
571
572
|
return action.payload;
|
|
@@ -587,12 +588,12 @@ const lookupGen3App = (id)=>{
|
|
|
587
588
|
else return null;
|
|
588
589
|
};
|
|
589
590
|
|
|
590
|
-
const initialState$
|
|
591
|
+
const initialState$7 = {
|
|
591
592
|
gen3Apps: {}
|
|
592
593
|
};
|
|
593
594
|
const slice$2 = createSlice({
|
|
594
595
|
name: 'gen3Apps',
|
|
595
|
-
initialState: initialState$
|
|
596
|
+
initialState: initialState$7,
|
|
596
597
|
reducers: {
|
|
597
598
|
addGen3AppMetadata: (state, action)=>{
|
|
598
599
|
const { name, requiredEntityTypes } = action.payload;
|
|
@@ -623,13 +624,13 @@ const selectGen3AppByName = (appName)=>lookupGen3App(appName); // TODO: memoize
|
|
|
623
624
|
Modals["GeneralErrorModal"] = "GeneralErrorModal";
|
|
624
625
|
return Modals;
|
|
625
626
|
}({});
|
|
626
|
-
const initialState$
|
|
627
|
+
const initialState$6 = {
|
|
627
628
|
currentModal: null
|
|
628
629
|
};
|
|
629
630
|
//Creates a modal slice for tracking showModal and hideModal state.
|
|
630
631
|
const slice$1 = createSlice({
|
|
631
632
|
name: 'modals',
|
|
632
|
-
initialState: initialState$
|
|
633
|
+
initialState: initialState$6,
|
|
633
634
|
reducers: {
|
|
634
635
|
showModal: (state, action)=>{
|
|
635
636
|
state.currentModal = action.payload.modal;
|
|
@@ -702,7 +703,7 @@ const getTimestamp = ()=>{
|
|
|
702
703
|
};
|
|
703
704
|
|
|
704
705
|
const NO_WORKSPACE_ID = 'none';
|
|
705
|
-
const initialState$
|
|
706
|
+
const initialState$5 = {
|
|
706
707
|
id: NO_WORKSPACE_ID,
|
|
707
708
|
status: WorkspaceStatus.NotFound,
|
|
708
709
|
requestedStatus: RequestedWorkspaceStatus.Unset,
|
|
@@ -710,7 +711,7 @@ const initialState$4 = {
|
|
|
710
711
|
};
|
|
711
712
|
const slice = createSlice({
|
|
712
713
|
name: 'ActiveWorkspace',
|
|
713
|
-
initialState: initialState$
|
|
714
|
+
initialState: initialState$5,
|
|
714
715
|
reducers: {
|
|
715
716
|
setActiveWorkspaceId: (state, action)=>{
|
|
716
717
|
state = {
|
|
@@ -752,6 +753,25 @@ const selectActiveWorkspaceStatus = (state)=>state.activeWorkspace.status;
|
|
|
752
753
|
const selectRequestedWorkspaceStatus = (state)=>state.activeWorkspace.requestedStatus;
|
|
753
754
|
const selectRequestedWorkspaceStatusTimestamp = (state)=>state.activeWorkspace.requestedStatusTimestamp;
|
|
754
755
|
|
|
756
|
+
const cartAdapter = createEntityAdapter({
|
|
757
|
+
selectId: (item)=>item.id
|
|
758
|
+
});
|
|
759
|
+
const initialState$4 = cartAdapter.getInitialState({});
|
|
760
|
+
const cartSlice = createSlice({
|
|
761
|
+
name: 'cart',
|
|
762
|
+
initialState: initialState$4,
|
|
763
|
+
reducers: {
|
|
764
|
+
addItemsToCart: cartAdapter.addMany,
|
|
765
|
+
removeItemsFromCart: cartAdapter.removeMany
|
|
766
|
+
}
|
|
767
|
+
});
|
|
768
|
+
const cartReducer = cartSlice.reducer;
|
|
769
|
+
const { addItemsToCart, removeItemsFromCart } = cartSlice.actions;
|
|
770
|
+
|
|
771
|
+
const { selectById: selectCartItem, selectIds: selectCartItems, selectAll: selectCart, selectTotal: selectCartCount } = cartAdapter.getSelectors((state)=>state.cart);
|
|
772
|
+
|
|
773
|
+
const cartReducerPath = 'cart';
|
|
774
|
+
|
|
755
775
|
/**
|
|
756
776
|
* Creates a base class core API for guppy API calls.
|
|
757
777
|
* @returns: guppy core API with guppyAPIFetch base query
|
|
@@ -786,6 +806,15 @@ const selectRequestedWorkspaceStatusTimestamp = (state)=>state.activeWorkspace.r
|
|
|
786
806
|
data: await response.json()
|
|
787
807
|
};
|
|
788
808
|
} catch (e) {
|
|
809
|
+
if (e instanceof GraphQLError) {
|
|
810
|
+
return {
|
|
811
|
+
error: {
|
|
812
|
+
message: e.message,
|
|
813
|
+
locations: e.locations,
|
|
814
|
+
path: e.path
|
|
815
|
+
}
|
|
816
|
+
};
|
|
817
|
+
}
|
|
789
818
|
if (e instanceof Error) return {
|
|
790
819
|
error: e.message
|
|
791
820
|
};
|
|
@@ -800,578 +829,176 @@ const guppyAPISliceMiddleware = guppyApi.middleware;
|
|
|
800
829
|
const guppyApiSliceReducerPath = guppyApi.reducerPath;
|
|
801
830
|
const guppyApiReducer = guppyApi.reducer;
|
|
802
831
|
|
|
803
|
-
const
|
|
804
|
-
|
|
805
|
-
hour12: false
|
|
806
|
-
}).replace(',', '')}`;
|
|
807
|
-
const isNameUnique = (entities, name, excludeId)=>{
|
|
808
|
-
const trimmedName = name.trim();
|
|
809
|
-
if (!trimmedName) return false;
|
|
810
|
-
return !entities.some((cohort)=>cohort && cohort.id !== excludeId && cohort.name.trim().toLowerCase() === trimmedName.toLowerCase());
|
|
832
|
+
const isOperationWithField = (operation)=>{
|
|
833
|
+
return operation?.field !== undefined;
|
|
811
834
|
};
|
|
812
|
-
const
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
return
|
|
835
|
+
const isOperatorWithFieldAndArrayOfOperands = (operation)=>{
|
|
836
|
+
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
|
|
837
|
+
) {
|
|
838
|
+
const { operator } = operation.operator;
|
|
839
|
+
return operator === 'in' || operator === 'exclude' || operator === 'excludeifany';
|
|
840
|
+
}
|
|
841
|
+
return false;
|
|
842
|
+
};
|
|
843
|
+
const extractFilterValue = (op)=>{
|
|
844
|
+
const valueExtractorHandler = new ValueExtractorHandler();
|
|
845
|
+
return handleOperation(valueExtractorHandler, op);
|
|
846
|
+
};
|
|
847
|
+
const extractEnumFilterValue = (op)=>{
|
|
848
|
+
const enumValueExtractorHandler = new EnumValueExtractorHandler();
|
|
849
|
+
const results = handleOperation(enumValueExtractorHandler, op);
|
|
850
|
+
return results ?? [];
|
|
851
|
+
};
|
|
852
|
+
const assertNever = (x)=>{
|
|
853
|
+
throw Error(`Exhaustive comparison did not handle: ${x}`);
|
|
854
|
+
};
|
|
855
|
+
const handleOperation = (handler, op)=>{
|
|
856
|
+
switch(op.operator){
|
|
857
|
+
case '=':
|
|
858
|
+
return handler.handleEquals(op);
|
|
859
|
+
case '!=':
|
|
860
|
+
return handler.handleNotEquals(op);
|
|
861
|
+
case '<':
|
|
862
|
+
return handler.handleLessThan(op);
|
|
863
|
+
case '<=':
|
|
864
|
+
return handler.handleLessThanOrEquals(op);
|
|
865
|
+
case '>':
|
|
866
|
+
return handler.handleGreaterThan(op);
|
|
867
|
+
case '>=':
|
|
868
|
+
return handler.handleGreaterThanOrEquals(op);
|
|
869
|
+
case 'and':
|
|
870
|
+
return handler.handleIntersection(op);
|
|
871
|
+
case 'or':
|
|
872
|
+
return handler.handleUnion(op);
|
|
873
|
+
case 'nested':
|
|
874
|
+
return handler.handleNestedFilter(op);
|
|
875
|
+
case 'in':
|
|
876
|
+
case 'includes':
|
|
877
|
+
return handler.handleIncludes(op);
|
|
878
|
+
case 'excludeifany':
|
|
879
|
+
return handler.handleExcludeIfAny(op);
|
|
880
|
+
case 'excludes':
|
|
881
|
+
return handler.handleExcludes(op);
|
|
882
|
+
case 'exists':
|
|
883
|
+
return handler.handleExists(op);
|
|
884
|
+
case 'missing':
|
|
885
|
+
return handler.handleMissing(op);
|
|
886
|
+
default:
|
|
887
|
+
return assertNever(op);
|
|
817
888
|
}
|
|
818
|
-
// Find a unique name by appending numbers
|
|
819
|
-
let counter = 1;
|
|
820
|
-
let uniqueName;
|
|
821
|
-
do {
|
|
822
|
-
uniqueName = `${trimmedBaseName} (${counter})`;
|
|
823
|
-
counter++;
|
|
824
|
-
}while (!isNameUnique(entities, uniqueName))
|
|
825
|
-
return uniqueName;
|
|
826
889
|
};
|
|
827
|
-
|
|
828
890
|
/**
|
|
829
|
-
*
|
|
830
|
-
*
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
return
|
|
838
|
-
name: newName,
|
|
839
|
-
id: newId,
|
|
840
|
-
filters: filters ?? {},
|
|
841
|
-
modified: false,
|
|
842
|
-
saved: false,
|
|
843
|
-
createdDatetime: ts,
|
|
844
|
-
modifiedDatetime: ts,
|
|
845
|
-
counts: {}
|
|
846
|
-
};
|
|
891
|
+
* Return true if a FilterSet's root value is an empty object
|
|
892
|
+
* @param fs - FilterSet to test
|
|
893
|
+
*/ const isFilterEmpty = (fs)=>isEqual({}, fs);
|
|
894
|
+
/**
|
|
895
|
+
* Type guard to check if an object is a GQLIntersection
|
|
896
|
+
* @param value - The value to check
|
|
897
|
+
* @returns True if the value is a GQLIntersection
|
|
898
|
+
*/ const isGQLIntersection = (value)=>{
|
|
899
|
+
return typeof value === 'object' && value !== null && 'and' in value && Array.isArray(value.and);
|
|
847
900
|
};
|
|
848
|
-
const nanoid = customAlphabet('1234567890abcdef', 16);
|
|
849
|
-
const createCohortId = ()=>nanoid();
|
|
850
|
-
const cohortsAdapter = createEntityAdapter({
|
|
851
|
-
sortComparer: (a, b)=>{
|
|
852
|
-
if (a.modifiedDatetime <= b.modifiedDatetime) return 1;
|
|
853
|
-
else return -1;
|
|
854
|
-
},
|
|
855
|
-
selectId: (cohort)=>cohort.id
|
|
856
|
-
});
|
|
857
|
-
// Create an initial unsaved cohort
|
|
858
|
-
const initialCohort = newCohort({
|
|
859
|
-
customName: DEFAULT_COHORT_NAME
|
|
860
|
-
});
|
|
861
|
-
const emptyInitialState = cohortsAdapter.getInitialState({
|
|
862
|
-
currentCohortId: initialCohort.id,
|
|
863
|
-
message: undefined
|
|
864
|
-
});
|
|
865
|
-
// Set the initial cohort in the adapter state
|
|
866
|
-
const initialState$3 = cohortsAdapter.setOne(emptyInitialState, initialCohort);
|
|
867
|
-
const getCurrentCohortId = (state)=>state.currentCohortId;
|
|
868
901
|
/**
|
|
869
|
-
*
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
902
|
+
* Type guard to check if an object is a GQLIntersection
|
|
903
|
+
* @param value - The value to check
|
|
904
|
+
* @returns True if the value is a GQLIntersection
|
|
905
|
+
*/ const isGQLUnion = (value)=>{
|
|
906
|
+
return typeof value === 'object' && value !== null && 'or' in value && Array.isArray(value.or);
|
|
907
|
+
};
|
|
908
|
+
class ToGqlHandler {
|
|
909
|
+
constructor(){
|
|
910
|
+
this.handleEquals = (op)=>({
|
|
911
|
+
'=': {
|
|
912
|
+
[op.field]: op.operand
|
|
913
|
+
}
|
|
880
914
|
});
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
updateCohortName: (state, action)=>{
|
|
885
|
-
const { id, name } = action.payload;
|
|
886
|
-
cohortsAdapter.updateOne(state, {
|
|
887
|
-
id: id,
|
|
888
|
-
changes: {
|
|
889
|
-
name: name,
|
|
890
|
-
modified: true,
|
|
891
|
-
modifiedDatetime: new Date().toISOString()
|
|
915
|
+
this.handleNotEquals = (op)=>({
|
|
916
|
+
'!=': {
|
|
917
|
+
[op.field]: op.operand
|
|
892
918
|
}
|
|
893
919
|
});
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
const removedCohortName = state.entities[cohortId].name;
|
|
898
|
-
const totalCohorts = Object.keys(state.entities).length;
|
|
899
|
-
if (totalCohorts <= 1) {
|
|
900
|
-
cohortsAdapter.removeAll(state);
|
|
901
|
-
const defaultCohort = newCohort({
|
|
902
|
-
filters: {},
|
|
903
|
-
customName: DEFAULT_COHORT_NAME
|
|
904
|
-
});
|
|
905
|
-
cohortsAdapter.addOne(state, defaultCohort);
|
|
906
|
-
state.currentCohortId = defaultCohort.id;
|
|
907
|
-
if (action?.payload.shouldShowMessage) {
|
|
908
|
-
state.message = [
|
|
909
|
-
`deleteCohort|${removedCohortName}|${state.currentCohortId}`
|
|
910
|
-
];
|
|
920
|
+
this.handleLessThan = (op)=>({
|
|
921
|
+
'<': {
|
|
922
|
+
[op.field]: op.operand
|
|
911
923
|
}
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
if (state.currentCohortId === cohortId) {
|
|
917
|
-
const remainingIds = Object.keys(state.entities);
|
|
918
|
-
state.currentCohortId = remainingIds[0];
|
|
919
|
-
}
|
|
920
|
-
if (action?.payload.shouldShowMessage) {
|
|
921
|
-
state.message = [
|
|
922
|
-
`deleteCohort|${removedCohortName}|${state.currentCohortId}`
|
|
923
|
-
];
|
|
924
|
-
}
|
|
925
|
-
},
|
|
926
|
-
// adds a filter to the cohort filter set at the given index
|
|
927
|
-
updateCohortFilter: (state, action)=>{
|
|
928
|
-
const { index, field, filter } = action.payload;
|
|
929
|
-
const currentCohortId = getCurrentCohortId(state);
|
|
930
|
-
if (!state.entities[currentCohortId]) {
|
|
931
|
-
return;
|
|
932
|
-
}
|
|
933
|
-
cohortsAdapter.updateOne(state, {
|
|
934
|
-
id: currentCohortId,
|
|
935
|
-
changes: {
|
|
936
|
-
filters: {
|
|
937
|
-
...state.entities[currentCohortId].filters,
|
|
938
|
-
[index]: {
|
|
939
|
-
mode: state.entities[currentCohortId]?.filters[index]?.mode ?? 'and',
|
|
940
|
-
root: {
|
|
941
|
-
...state.entities[currentCohortId]?.filters[index]?.root ?? {},
|
|
942
|
-
[field]: filter
|
|
943
|
-
}
|
|
944
|
-
}
|
|
945
|
-
},
|
|
946
|
-
modified: true,
|
|
947
|
-
modifiedDatetime: new Date().toISOString()
|
|
924
|
+
});
|
|
925
|
+
this.handleLessThanOrEquals = (op)=>({
|
|
926
|
+
'<=': {
|
|
927
|
+
[op.field]: op.operand
|
|
948
928
|
}
|
|
949
929
|
});
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
const currentCohortId = getCurrentCohortId(state);
|
|
954
|
-
if (!state.entities[currentCohortId]) {
|
|
955
|
-
console.error(`no cohort with id=${currentCohortId} defined`);
|
|
956
|
-
return;
|
|
957
|
-
}
|
|
958
|
-
cohortsAdapter.updateOne(state, {
|
|
959
|
-
id: currentCohortId,
|
|
960
|
-
changes: {
|
|
961
|
-
filters: {
|
|
962
|
-
...state.entities[currentCohortId].filters,
|
|
963
|
-
[index]: filters
|
|
964
|
-
},
|
|
965
|
-
modified: true,
|
|
966
|
-
modifiedDatetime: new Date().toISOString()
|
|
930
|
+
this.handleGreaterThan = (op)=>({
|
|
931
|
+
'>': {
|
|
932
|
+
[op.field]: op.operand
|
|
967
933
|
}
|
|
968
934
|
});
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
if (!state.entities[currentCohortId]) {
|
|
973
|
-
console.error(`no cohort with id=${currentCohortId} defined`);
|
|
974
|
-
return;
|
|
975
|
-
}
|
|
976
|
-
cohortsAdapter.updateOne(state, {
|
|
977
|
-
id: currentCohortId,
|
|
978
|
-
changes: {
|
|
979
|
-
filters: action.payload.filters,
|
|
980
|
-
modified: true,
|
|
981
|
-
modifiedDatetime: new Date().toISOString()
|
|
935
|
+
this.handleGreaterThanOrEquals = (op)=>({
|
|
936
|
+
'>=': {
|
|
937
|
+
[op.field]: op.operand
|
|
982
938
|
}
|
|
983
939
|
});
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
const { index, field } = action.payload;
|
|
988
|
-
const currentCohortId = getCurrentCohortId(state);
|
|
989
|
-
if (!state.entities[currentCohortId]) {
|
|
990
|
-
console.error(`no cohort with id=${currentCohortId} defined`);
|
|
991
|
-
return;
|
|
992
|
-
}
|
|
993
|
-
const filters = state.entities[currentCohortId]?.filters[index]?.root;
|
|
994
|
-
if (!filters) {
|
|
995
|
-
return;
|
|
996
|
-
}
|
|
997
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
998
|
-
const { [field]: _a, ...updated } = filters;
|
|
999
|
-
cohortsAdapter.updateOne(state, {
|
|
1000
|
-
id: currentCohortId,
|
|
1001
|
-
changes: {
|
|
1002
|
-
filters: {
|
|
1003
|
-
...state.entities[currentCohortId]?.filters,
|
|
1004
|
-
[index]: {
|
|
1005
|
-
mode: state.entities[currentCohortId].filters[index].mode,
|
|
1006
|
-
root: updated
|
|
1007
|
-
}
|
|
1008
|
-
},
|
|
1009
|
-
modified: true,
|
|
1010
|
-
modifiedDatetime: new Date().toISOString()
|
|
940
|
+
this.handleIncludes = (op)=>({
|
|
941
|
+
in: {
|
|
942
|
+
[op.field]: op.operands
|
|
1011
943
|
}
|
|
1012
944
|
});
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
const currentCohort = state.entities[currentCohortId];
|
|
1017
|
-
const newName = generateUniqueName(Object.values(state.entities), currentCohort.name);
|
|
1018
|
-
const duplicatedCohort = newCohort({
|
|
1019
|
-
filters: {
|
|
1020
|
-
...currentCohort.filters
|
|
1021
|
-
},
|
|
1022
|
-
customName: newName
|
|
1023
|
-
});
|
|
1024
|
-
cohortsAdapter.addOne(state, {
|
|
1025
|
-
...duplicatedCohort,
|
|
1026
|
-
counts: {
|
|
1027
|
-
...currentCohort.counts
|
|
945
|
+
this.handleExcludes = (op)=>({
|
|
946
|
+
exclude: {
|
|
947
|
+
[op.field]: op.operands
|
|
1028
948
|
}
|
|
1029
949
|
});
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
clearCohortFilters: (state, action)=>{
|
|
1034
|
-
const { index } = action.payload;
|
|
1035
|
-
const currentCohortId = getCurrentCohortId(state);
|
|
1036
|
-
if (!state.entities[currentCohortId]) {
|
|
1037
|
-
console.error(`no cohort with id=${currentCohortId} defined`);
|
|
1038
|
-
return;
|
|
1039
|
-
}
|
|
1040
|
-
const filters = state.entities[currentCohortId]?.filters[index]?.root;
|
|
1041
|
-
if (!filters) {
|
|
1042
|
-
return;
|
|
1043
|
-
}
|
|
1044
|
-
cohortsAdapter.updateOne(state, {
|
|
1045
|
-
id: currentCohortId,
|
|
1046
|
-
changes: {
|
|
1047
|
-
filters: {
|
|
1048
|
-
...state.entities[currentCohortId]?.filters,
|
|
1049
|
-
[index]: {
|
|
1050
|
-
mode: 'and',
|
|
1051
|
-
root: {}
|
|
1052
|
-
}
|
|
1053
|
-
},
|
|
1054
|
-
modified: true,
|
|
1055
|
-
modifiedDatetime: new Date().toISOString()
|
|
950
|
+
this.handleExcludeIfAny = (op)=>({
|
|
951
|
+
excludeifany: {
|
|
952
|
+
[op.field]: op.operands
|
|
1056
953
|
}
|
|
1057
954
|
});
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
const currentCohortId = getCurrentCohortId(state);
|
|
1061
|
-
const currentCohort = state.entities[currentCohortId];
|
|
1062
|
-
cohortsAdapter.updateOne(state, {
|
|
1063
|
-
id: currentCohortId,
|
|
1064
|
-
changes: {
|
|
1065
|
-
counts: {
|
|
1066
|
-
...currentCohort.counts,
|
|
1067
|
-
...action.payload
|
|
1068
|
-
}
|
|
1069
|
-
}
|
|
955
|
+
this.handleIntersection = (op)=>({
|
|
956
|
+
and: op.operands.map((x)=>convertFilterToGqlFilter(x))
|
|
1070
957
|
});
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
changes: {
|
|
1078
|
-
counts: {
|
|
1079
|
-
...cohort.counts,
|
|
1080
|
-
...{
|
|
1081
|
-
[index]: counts
|
|
1082
|
-
}
|
|
1083
|
-
}
|
|
958
|
+
this.handleUnion = (op)=>({
|
|
959
|
+
or: op.operands.map((x)=>convertFilterToGqlFilter(x))
|
|
960
|
+
});
|
|
961
|
+
this.handleMissing = (op)=>({
|
|
962
|
+
is: {
|
|
963
|
+
[op.field]: 'MISSING'
|
|
1084
964
|
}
|
|
1085
965
|
});
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
},
|
|
1090
|
-
/** @hidden */ setCohortList: (state, action)=>{
|
|
1091
|
-
if (!action.payload) {
|
|
1092
|
-
cohortsAdapter.removeMany(state, state.ids);
|
|
1093
|
-
} else {
|
|
1094
|
-
cohortsAdapter.upsertMany(state, [
|
|
1095
|
-
...action.payload
|
|
1096
|
-
]);
|
|
1097
|
-
}
|
|
1098
|
-
}
|
|
1099
|
-
}
|
|
1100
|
-
});
|
|
1101
|
-
/**
|
|
1102
|
-
* Returns the selectors for the cohorts EntityAdapter
|
|
1103
|
-
* @param state - the CoreState
|
|
1104
|
-
*
|
|
1105
|
-
* @hidden
|
|
1106
|
-
*/ const cohortSelectors = cohortsAdapter.getSelectors((state)=>state.cohorts.cohortManager);
|
|
1107
|
-
// Filter actions: addFilter, removeFilter, updateFilter
|
|
1108
|
-
const { createNewCohort, updateCohortFilter, setCohortFilter, setCohortIndexFilters, duplicateCohort, removeCohortFilter, clearCohortFilters, removeCohort, setCurrentCohortId, updateCohortName, updateCohortCounts, updateCohortIndexCountById, setCohortList } = cohortManagerSlice.actions;
|
|
1109
|
-
const cohortReducer = cohortManagerSlice.reducer;
|
|
1110
|
-
|
|
1111
|
-
const initialState$2 = {};
|
|
1112
|
-
const expandSlice$1 = createSlice({
|
|
1113
|
-
name: 'CohortBuilder/filterExpand',
|
|
1114
|
-
initialState: initialState$2,
|
|
1115
|
-
reducers: {
|
|
1116
|
-
toggleCohortBuilderCategoryFilter: (state, action)=>{
|
|
1117
|
-
return {
|
|
1118
|
-
...state,
|
|
1119
|
-
[action.payload.index]: {
|
|
1120
|
-
...state[action.payload.index],
|
|
1121
|
-
[action.payload.field]: action.payload.expanded
|
|
966
|
+
this.handleExists = (op)=>({
|
|
967
|
+
not: {
|
|
968
|
+
[op.field]: op?.operand ?? null
|
|
1122
969
|
}
|
|
1123
|
-
};
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
return {
|
|
1127
|
-
...state,
|
|
1128
|
-
[action.payload.index]: Object.keys(state[action.payload.index]).reduce((acc, k)=>{
|
|
1129
|
-
acc[k] = action.payload.expand;
|
|
1130
|
-
return acc;
|
|
1131
|
-
}, {})
|
|
1132
|
-
};
|
|
1133
|
-
}
|
|
1134
|
-
}
|
|
1135
|
-
});
|
|
1136
|
-
const cohortBuilderFiltersExpandedReducer = expandSlice$1.reducer;
|
|
1137
|
-
const { toggleCohortBuilderCategoryFilter, toggleCohortBuilderAllFilters } = expandSlice$1.actions;
|
|
1138
|
-
const selectCohortFilterExpanded = (state, index, field)=>state.cohorts.filtersExpanded?.[index]?.[field];
|
|
1139
|
-
const selectAllCohortFiltersCollapsed = (state, index)=>index in state.cohorts.filtersExpanded ? Object.values(state.cohorts.filtersExpanded?.[index]).every((e)=>!e) : false;
|
|
1140
|
-
|
|
1141
|
-
const initialState$1 = {};
|
|
1142
|
-
const expandSlice = createSlice({
|
|
1143
|
-
name: 'CohortBuilder/filterCombineMode',
|
|
1144
|
-
initialState: initialState$1,
|
|
1145
|
-
reducers: {
|
|
1146
|
-
setCohortFilterCombineMode: (state, action)=>{
|
|
970
|
+
});
|
|
971
|
+
this.handleNestedFilter = (op)=>{
|
|
972
|
+
const child = convertFilterToGqlFilter(op.operand);
|
|
1147
973
|
return {
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
...
|
|
1151
|
-
[action.payload.field]: action.payload.mode
|
|
974
|
+
nested: {
|
|
975
|
+
path: op.path,
|
|
976
|
+
...child
|
|
1152
977
|
}
|
|
1153
978
|
};
|
|
1154
|
-
}
|
|
979
|
+
};
|
|
1155
980
|
}
|
|
1156
|
-
}
|
|
1157
|
-
const
|
|
1158
|
-
const
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
const initialState = {
|
|
1162
|
-
shouldShareFilters: false,
|
|
1163
|
-
sharedFiltersMap: {}
|
|
981
|
+
}
|
|
982
|
+
const convertFilterToGqlFilter = (filter)=>{
|
|
983
|
+
const handler = new ToGqlHandler();
|
|
984
|
+
return handleOperation(handler, filter);
|
|
1164
985
|
};
|
|
1165
|
-
const
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
const
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
field
|
|
1182
|
-
];
|
|
1183
|
-
const { setShouldShareFilters, setSharedFilters } = cohortSharedFiltersSlice.actions;
|
|
1184
|
-
const cohortSharedFiltersReducer = cohortSharedFiltersSlice.reducer;
|
|
1185
|
-
|
|
1186
|
-
const cohortReducers = combineReducers({
|
|
1187
|
-
filtersExpanded: cohortBuilderFiltersExpandedReducer,
|
|
1188
|
-
filtersCombineMode: cohortBuilderFiltersCombineModeReducer,
|
|
1189
|
-
sharedFilters: cohortSharedFiltersReducer,
|
|
1190
|
-
cohortManager: cohortReducer
|
|
1191
|
-
});
|
|
1192
|
-
|
|
1193
|
-
const rootReducer = combineReducers({
|
|
1194
|
-
gen3Services: gen3ServicesReducer,
|
|
1195
|
-
user: userReducer,
|
|
1196
|
-
gen3Apps: gen3AppReducer,
|
|
1197
|
-
drsHostnames: drsHostnamesReducer,
|
|
1198
|
-
modals: modalReducer,
|
|
1199
|
-
cohorts: cohortReducers,
|
|
1200
|
-
activeWorkspace: activeWorkspaceReducer,
|
|
1201
|
-
[guppyApiSliceReducerPath]: guppyApiReducer,
|
|
1202
|
-
[userAuthApiReducerPath]: userAuthApiReducer
|
|
1203
|
-
});
|
|
1204
|
-
|
|
1205
|
-
const isOperationWithField = (operation)=>{
|
|
1206
|
-
return operation?.field !== undefined;
|
|
1207
|
-
};
|
|
1208
|
-
const isOperatorWithFieldAndArrayOfOperands = (operation)=>{
|
|
1209
|
-
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
|
|
1210
|
-
) {
|
|
1211
|
-
const { operator } = operation.operator;
|
|
1212
|
-
return operator === 'in' || operator === 'exclude' || operator === 'excludeifany';
|
|
1213
|
-
}
|
|
1214
|
-
return false;
|
|
1215
|
-
};
|
|
1216
|
-
const extractFilterValue = (op)=>{
|
|
1217
|
-
const valueExtractorHandler = new ValueExtractorHandler();
|
|
1218
|
-
return handleOperation(valueExtractorHandler, op);
|
|
1219
|
-
};
|
|
1220
|
-
const extractEnumFilterValue = (op)=>{
|
|
1221
|
-
const enumValueExtractorHandler = new EnumValueExtractorHandler();
|
|
1222
|
-
const results = handleOperation(enumValueExtractorHandler, op);
|
|
1223
|
-
return results ?? [];
|
|
1224
|
-
};
|
|
1225
|
-
const assertNever = (x)=>{
|
|
1226
|
-
throw Error(`Exhaustive comparison did not handle: ${x}`);
|
|
1227
|
-
};
|
|
1228
|
-
const handleOperation = (handler, op)=>{
|
|
1229
|
-
switch(op.operator){
|
|
1230
|
-
case '=':
|
|
1231
|
-
return handler.handleEquals(op);
|
|
1232
|
-
case '!=':
|
|
1233
|
-
return handler.handleNotEquals(op);
|
|
1234
|
-
case '<':
|
|
1235
|
-
return handler.handleLessThan(op);
|
|
1236
|
-
case '<=':
|
|
1237
|
-
return handler.handleLessThanOrEquals(op);
|
|
1238
|
-
case '>':
|
|
1239
|
-
return handler.handleGreaterThan(op);
|
|
1240
|
-
case '>=':
|
|
1241
|
-
return handler.handleGreaterThanOrEquals(op);
|
|
1242
|
-
case 'and':
|
|
1243
|
-
return handler.handleIntersection(op);
|
|
1244
|
-
case 'or':
|
|
1245
|
-
return handler.handleUnion(op);
|
|
1246
|
-
case 'nested':
|
|
1247
|
-
return handler.handleNestedFilter(op);
|
|
1248
|
-
case 'in':
|
|
1249
|
-
case 'includes':
|
|
1250
|
-
return handler.handleIncludes(op);
|
|
1251
|
-
case 'excludeifany':
|
|
1252
|
-
return handler.handleExcludeIfAny(op);
|
|
1253
|
-
case 'excludes':
|
|
1254
|
-
return handler.handleExcludes(op);
|
|
1255
|
-
case 'exists':
|
|
1256
|
-
return handler.handleExists(op);
|
|
1257
|
-
case 'missing':
|
|
1258
|
-
return handler.handleMissing(op);
|
|
1259
|
-
default:
|
|
1260
|
-
return assertNever(op);
|
|
1261
|
-
}
|
|
1262
|
-
};
|
|
1263
|
-
/**
|
|
1264
|
-
* Return true if a FilterSet's root value is an empty object
|
|
1265
|
-
* @param fs - FilterSet to test
|
|
1266
|
-
*/ const isFilterEmpty = (fs)=>isEqual({}, fs);
|
|
1267
|
-
/**
|
|
1268
|
-
* Type guard to check if an object is a GQLIntersection
|
|
1269
|
-
* @param value - The value to check
|
|
1270
|
-
* @returns True if the value is a GQLIntersection
|
|
1271
|
-
*/ const isGQLIntersection = (value)=>{
|
|
1272
|
-
return typeof value === 'object' && value !== null && 'and' in value && Array.isArray(value.and);
|
|
1273
|
-
};
|
|
1274
|
-
/**
|
|
1275
|
-
* Type guard to check if an object is a GQLIntersection
|
|
1276
|
-
* @param value - The value to check
|
|
1277
|
-
* @returns True if the value is a GQLIntersection
|
|
1278
|
-
*/ const isGQLUnion = (value)=>{
|
|
1279
|
-
return typeof value === 'object' && value !== null && 'or' in value && Array.isArray(value.or);
|
|
1280
|
-
};
|
|
1281
|
-
class ToGqlHandler {
|
|
1282
|
-
constructor(){
|
|
1283
|
-
this.handleEquals = (op)=>({
|
|
1284
|
-
'=': {
|
|
1285
|
-
[op.field]: op.operand
|
|
1286
|
-
}
|
|
1287
|
-
});
|
|
1288
|
-
this.handleNotEquals = (op)=>({
|
|
1289
|
-
'!=': {
|
|
1290
|
-
[op.field]: op.operand
|
|
1291
|
-
}
|
|
1292
|
-
});
|
|
1293
|
-
this.handleLessThan = (op)=>({
|
|
1294
|
-
'<': {
|
|
1295
|
-
[op.field]: op.operand
|
|
1296
|
-
}
|
|
1297
|
-
});
|
|
1298
|
-
this.handleLessThanOrEquals = (op)=>({
|
|
1299
|
-
'<=': {
|
|
1300
|
-
[op.field]: op.operand
|
|
1301
|
-
}
|
|
1302
|
-
});
|
|
1303
|
-
this.handleGreaterThan = (op)=>({
|
|
1304
|
-
'>': {
|
|
1305
|
-
[op.field]: op.operand
|
|
1306
|
-
}
|
|
1307
|
-
});
|
|
1308
|
-
this.handleGreaterThanOrEquals = (op)=>({
|
|
1309
|
-
'>=': {
|
|
1310
|
-
[op.field]: op.operand
|
|
1311
|
-
}
|
|
1312
|
-
});
|
|
1313
|
-
this.handleIncludes = (op)=>({
|
|
1314
|
-
in: {
|
|
1315
|
-
[op.field]: op.operands
|
|
1316
|
-
}
|
|
1317
|
-
});
|
|
1318
|
-
this.handleExcludes = (op)=>({
|
|
1319
|
-
exclude: {
|
|
1320
|
-
[op.field]: op.operands
|
|
1321
|
-
}
|
|
1322
|
-
});
|
|
1323
|
-
this.handleExcludeIfAny = (op)=>({
|
|
1324
|
-
excludeifany: {
|
|
1325
|
-
[op.field]: op.operands
|
|
1326
|
-
}
|
|
1327
|
-
});
|
|
1328
|
-
this.handleIntersection = (op)=>({
|
|
1329
|
-
and: op.operands.map((x)=>convertFilterToGqlFilter(x))
|
|
1330
|
-
});
|
|
1331
|
-
this.handleUnion = (op)=>({
|
|
1332
|
-
or: op.operands.map((x)=>convertFilterToGqlFilter(x))
|
|
1333
|
-
});
|
|
1334
|
-
this.handleMissing = (op)=>({
|
|
1335
|
-
is: {
|
|
1336
|
-
[op.field]: 'MISSING'
|
|
1337
|
-
}
|
|
1338
|
-
});
|
|
1339
|
-
this.handleExists = (op)=>({
|
|
1340
|
-
not: {
|
|
1341
|
-
[op.field]: op?.operand ?? null
|
|
1342
|
-
}
|
|
1343
|
-
});
|
|
1344
|
-
this.handleNestedFilter = (op)=>{
|
|
1345
|
-
const child = convertFilterToGqlFilter(op.operand);
|
|
1346
|
-
return {
|
|
1347
|
-
nested: {
|
|
1348
|
-
path: op.path,
|
|
1349
|
-
...child
|
|
1350
|
-
}
|
|
1351
|
-
};
|
|
1352
|
-
};
|
|
1353
|
-
}
|
|
1354
|
-
}
|
|
1355
|
-
const convertFilterToGqlFilter = (filter)=>{
|
|
1356
|
-
const handler = new ToGqlHandler();
|
|
1357
|
-
return handleOperation(handler, filter);
|
|
1358
|
-
};
|
|
1359
|
-
const convertFilterSetToGqlFilter = (fs, toplevelOp = 'and')=>{
|
|
1360
|
-
const fsKeys = Object.keys(fs.root);
|
|
1361
|
-
// if no keys return undefined
|
|
1362
|
-
if (fsKeys.length === 0) return {
|
|
1363
|
-
and: []
|
|
1364
|
-
};
|
|
1365
|
-
return toplevelOp === 'and' ? {
|
|
1366
|
-
and: fsKeys.map((key)=>convertFilterToGqlFilter(fs.root[key]))
|
|
1367
|
-
} : {
|
|
1368
|
-
or: fsKeys.map((key)=>convertFilterToGqlFilter(fs.root[key]))
|
|
1369
|
-
};
|
|
1370
|
-
};
|
|
1371
|
-
const handleGqlOperation = (handler, op)=>{
|
|
1372
|
-
const operationKeys = Object.keys(op);
|
|
1373
|
-
if (operationKeys.includes('=')) {
|
|
1374
|
-
return handler.handleEquals(op);
|
|
986
|
+
const convertFilterSetToGqlFilter = (fs, toplevelOp = 'and')=>{
|
|
987
|
+
const fsKeys = Object.keys(fs.root);
|
|
988
|
+
// if no keys return undefined
|
|
989
|
+
if (fsKeys.length === 0) return {
|
|
990
|
+
and: []
|
|
991
|
+
};
|
|
992
|
+
return toplevelOp === 'and' ? {
|
|
993
|
+
and: fsKeys.map((key)=>convertFilterToGqlFilter(fs.root[key]))
|
|
994
|
+
} : {
|
|
995
|
+
or: fsKeys.map((key)=>convertFilterToGqlFilter(fs.root[key]))
|
|
996
|
+
};
|
|
997
|
+
};
|
|
998
|
+
const handleGqlOperation = (handler, op)=>{
|
|
999
|
+
const operationKeys = Object.keys(op);
|
|
1000
|
+
if (operationKeys.includes('=')) {
|
|
1001
|
+
return handler.handleEquals(op);
|
|
1375
1002
|
}
|
|
1376
1003
|
if (operationKeys.includes('!=')) {
|
|
1377
1004
|
return handler.handleNotEquals(op);
|
|
@@ -1595,6 +1222,36 @@ const filterSetToOperation = (fs)=>{
|
|
|
1595
1222
|
}
|
|
1596
1223
|
return undefined;
|
|
1597
1224
|
};
|
|
1225
|
+
/**
|
|
1226
|
+
* Constructs a nested operation object based on the provided field and leaf operand.
|
|
1227
|
+
* If the field does not contain a dot '.', it either assigns the field to the leaf operand (if applicable)
|
|
1228
|
+
* or returns the leaf operand as is. When the field contains dots, it splits the field into parts,
|
|
1229
|
+
* creates a "nested" operation for the root field, and recursively constructs the nested structure
|
|
1230
|
+
* for the remaining portion of the field.
|
|
1231
|
+
*
|
|
1232
|
+
* @param {string} field - The hierarchical field path, with segments separated by dots (e.g., "root.child").
|
|
1233
|
+
* @param {Operation} leafOperand - The operation to be nested within the specified path.
|
|
1234
|
+
* @param parentPath - The parent path of the current field. Guppy nested filters require a parent path.
|
|
1235
|
+
* @param depth
|
|
1236
|
+
* @returns {Operation} A nested operation object that represents the structured path and operand.
|
|
1237
|
+
*/ const buildNestedGQLFilter = (field, leafOperand, parentPath = undefined)=>{
|
|
1238
|
+
if (!field.includes('.')) {
|
|
1239
|
+
return leafOperand;
|
|
1240
|
+
}
|
|
1241
|
+
const splitFieldArray = field.split('.');
|
|
1242
|
+
const nextField = splitFieldArray.shift();
|
|
1243
|
+
if (!nextField) {
|
|
1244
|
+
console.warn('Invalid field path:', field);
|
|
1245
|
+
return leafOperand;
|
|
1246
|
+
}
|
|
1247
|
+
const currentPath = parentPath ? `${parentPath}.${nextField}` : nextField;
|
|
1248
|
+
return {
|
|
1249
|
+
nested: {
|
|
1250
|
+
path: currentPath,
|
|
1251
|
+
...buildNestedGQLFilter(splitFieldArray.join('.'), leafOperand, currentPath)
|
|
1252
|
+
}
|
|
1253
|
+
};
|
|
1254
|
+
};
|
|
1598
1255
|
|
|
1599
1256
|
const isFilterSet = (input)=>{
|
|
1600
1257
|
if (typeof input !== 'object' || input === null) {
|
|
@@ -1618,9 +1275,17 @@ const isUnion = (value)=>{
|
|
|
1618
1275
|
const isIntersection = (value)=>{
|
|
1619
1276
|
return typeof value === 'object' && value !== null && value.operator === 'and' && Array.isArray(value.operands);
|
|
1620
1277
|
};
|
|
1278
|
+
/**
|
|
1279
|
+
* Type guard for Union or Intersection
|
|
1280
|
+
* @param o - operator to check
|
|
1281
|
+
* @category Filters
|
|
1282
|
+
*/ const isIntersectionOrUnion = (o)=>o.operator === 'and' || o.operator === 'or';
|
|
1621
1283
|
const isOperandsType = (operation)=>{
|
|
1622
1284
|
return operation?.operands !== undefined;
|
|
1623
1285
|
};
|
|
1286
|
+
const isNestedFilter = (operation)=>{
|
|
1287
|
+
return operation.operator === 'nested';
|
|
1288
|
+
};
|
|
1624
1289
|
const isIndexedFilterSetEmpty = (filters)=>Object.values(filters).every((filterSet)=>Object.keys(filterSet).length === 0);
|
|
1625
1290
|
const EmptyFilterSet = {
|
|
1626
1291
|
mode: 'and',
|
|
@@ -1649,7 +1314,7 @@ const COMMON_PREPOSITIONS = [
|
|
|
1649
1314
|
'up',
|
|
1650
1315
|
'yet'
|
|
1651
1316
|
];
|
|
1652
|
-
const capitalize = (s)=>s.length > 0 ? s[0].toUpperCase() + s.slice(1) : '';
|
|
1317
|
+
const capitalize$1 = (s)=>s.length > 0 ? s[0].toUpperCase() + s.slice(1) : '';
|
|
1653
1318
|
const trimFirstFieldNameToTitle = (fieldName, trim = false)=>{
|
|
1654
1319
|
if (trim) {
|
|
1655
1320
|
const source = fieldName.slice(fieldName.indexOf('.') + 1);
|
|
@@ -1667,28 +1332,459 @@ const trimFirstFieldNameToTitle = (fieldName, trim = false)=>{
|
|
|
1667
1332
|
if (fieldName in FieldNameOverrides) {
|
|
1668
1333
|
return FieldNameOverrides[fieldName];
|
|
1669
1334
|
}
|
|
1670
|
-
if (fieldName === undefined) return 'No Title';
|
|
1671
|
-
return fieldName.split('.').slice(-sections).map((s)=>s.split('_')).flat().map((word)=>COMMON_PREPOSITIONS.includes(word) ? word : capitalize(word)).join(' ');
|
|
1672
|
-
};
|
|
1673
|
-
/**
|
|
1674
|
-
* Extracts the index name from the field name
|
|
1675
|
-
* @param fieldName
|
|
1676
|
-
*/ const extractIndexFromFullFieldName = (fieldName)=>fieldName.split('.')[0];
|
|
1677
|
-
/**
|
|
1678
|
-
* prepend the index name to the field name
|
|
1679
|
-
*/ const prependIndexToFieldName = (fieldName, index)=>`${index}.${fieldName}`;
|
|
1680
|
-
/**
|
|
1681
|
-
* extract the field name from the index.field name
|
|
1682
|
-
*/ const extractFieldNameFromFullFieldName = (fieldName)=>fieldName.split('.').slice(1).join('.');
|
|
1683
|
-
/**
|
|
1684
|
-
* extract the field name and the index from the index.field name returning as a tuple
|
|
1685
|
-
*/ const extractIndexAndFieldNameFromFullFieldName = (fieldName)=>{
|
|
1686
|
-
const [index, ...rest] = fieldName.split('.');
|
|
1687
|
-
return [
|
|
1688
|
-
index,
|
|
1689
|
-
rest.join('.')
|
|
1335
|
+
if (fieldName === undefined) return 'No Title';
|
|
1336
|
+
return fieldName.split('.').slice(-sections).map((s)=>s.split('_')).flat().map((word)=>COMMON_PREPOSITIONS.includes(word) ? word : capitalize$1(word)).join(' ');
|
|
1337
|
+
};
|
|
1338
|
+
/**
|
|
1339
|
+
* Extracts the index name from the field name
|
|
1340
|
+
* @param fieldName
|
|
1341
|
+
*/ const extractIndexFromFullFieldName = (fieldName)=>fieldName.split('.')[0];
|
|
1342
|
+
/**
|
|
1343
|
+
* prepend the index name to the field name
|
|
1344
|
+
*/ const prependIndexToFieldName = (fieldName, index)=>`${index}.${fieldName}`;
|
|
1345
|
+
/**
|
|
1346
|
+
* extract the field name from the index.field name
|
|
1347
|
+
*/ const extractFieldNameFromFullFieldName = (fieldName)=>fieldName.split('.').slice(1).join('.');
|
|
1348
|
+
/**
|
|
1349
|
+
* extract the field name and the index from the index.field name returning as a tuple
|
|
1350
|
+
*/ const extractIndexAndFieldNameFromFullFieldName = (fieldName)=>{
|
|
1351
|
+
const [index, ...rest] = fieldName.split('.');
|
|
1352
|
+
return [
|
|
1353
|
+
index,
|
|
1354
|
+
rest.join('.')
|
|
1355
|
+
];
|
|
1356
|
+
};
|
|
1357
|
+
|
|
1358
|
+
const defaultCohortNameGenerator = ()=>`Custom cohort ${new Date().toLocaleString('en-CA', {
|
|
1359
|
+
timeZone: 'America/Chicago',
|
|
1360
|
+
hour12: false
|
|
1361
|
+
}).replace(',', '')}`;
|
|
1362
|
+
const isNameUnique = (entities, name, excludeId)=>{
|
|
1363
|
+
const trimmedName = name.trim();
|
|
1364
|
+
if (!trimmedName) return false;
|
|
1365
|
+
return !entities.some((cohort)=>cohort && cohort.id !== excludeId && cohort.name.trim().toLowerCase() === trimmedName.toLowerCase());
|
|
1366
|
+
};
|
|
1367
|
+
const generateUniqueName = (entities, baseName)=>{
|
|
1368
|
+
const trimmedBaseName = baseName.trim();
|
|
1369
|
+
// If base name is unique, use it
|
|
1370
|
+
if (isNameUnique(entities, trimmedBaseName)) {
|
|
1371
|
+
return trimmedBaseName;
|
|
1372
|
+
}
|
|
1373
|
+
// Find a unique name by appending numbers
|
|
1374
|
+
let counter = 1;
|
|
1375
|
+
let uniqueName;
|
|
1376
|
+
do {
|
|
1377
|
+
uniqueName = `${trimmedBaseName} (${counter})`;
|
|
1378
|
+
counter++;
|
|
1379
|
+
}while (!isNameUnique(entities, uniqueName))
|
|
1380
|
+
return uniqueName;
|
|
1381
|
+
};
|
|
1382
|
+
/**
|
|
1383
|
+
* This function takes a FilterSet object and a prefix string as input.
|
|
1384
|
+
* It filters the root property of the FilterSet object and returns a
|
|
1385
|
+
* new FilterSet object that only contains filters with field names
|
|
1386
|
+
* that start with the specified prefix.
|
|
1387
|
+
*
|
|
1388
|
+
* @param fs - The FilterSet object to filter
|
|
1389
|
+
* @param prefix - The prefix to filter by
|
|
1390
|
+
* @returns - A new FilterSet object that only contains filters with field names that start with the specified prefix
|
|
1391
|
+
* @category Filters
|
|
1392
|
+
*/ const extractFiltersWithPrefixFromFilterSet = (fs, prefix)=>{
|
|
1393
|
+
if (fs === undefined || fs.root === undefined) {
|
|
1394
|
+
return {
|
|
1395
|
+
mode: 'and',
|
|
1396
|
+
root: {}
|
|
1397
|
+
};
|
|
1398
|
+
}
|
|
1399
|
+
return Object.values(fs.root).reduce((acc, filter)=>{
|
|
1400
|
+
if (isIntersectionOrUnion(filter) || isNestedFilter(filter)) return acc;
|
|
1401
|
+
if (filter.field.startsWith(prefix)) {
|
|
1402
|
+
acc.root[filter.field] = filter;
|
|
1403
|
+
}
|
|
1404
|
+
return acc;
|
|
1405
|
+
}, {
|
|
1406
|
+
mode: 'and',
|
|
1407
|
+
root: {}
|
|
1408
|
+
});
|
|
1409
|
+
};
|
|
1410
|
+
|
|
1411
|
+
/**
|
|
1412
|
+
* Cohorts in Gen3 are defined as a set of filters for each index in the data.
|
|
1413
|
+
* This means one cohort id defined for all "tabs" in CohortBuilder (explorer)
|
|
1414
|
+
* Switching a cohort id means all the cohorts for the index are changed.
|
|
1415
|
+
*/ const DEFAULT_COHORT_NAME = 'Cohort';
|
|
1416
|
+
const newCohort = ({ filters = {}, customName })=>{
|
|
1417
|
+
const ts = new Date().toISOString();
|
|
1418
|
+
const newName = customName ?? defaultCohortNameGenerator();
|
|
1419
|
+
const newId = createCohortId();
|
|
1420
|
+
return {
|
|
1421
|
+
name: newName,
|
|
1422
|
+
id: newId,
|
|
1423
|
+
filters: filters ?? {},
|
|
1424
|
+
modified: false,
|
|
1425
|
+
saved: false,
|
|
1426
|
+
createdDatetime: ts,
|
|
1427
|
+
modifiedDatetime: ts,
|
|
1428
|
+
counts: {}
|
|
1429
|
+
};
|
|
1430
|
+
};
|
|
1431
|
+
const nanoid = customAlphabet('1234567890abcdef', 16);
|
|
1432
|
+
const createCohortId = ()=>nanoid();
|
|
1433
|
+
const cohortsAdapter = createEntityAdapter({
|
|
1434
|
+
sortComparer: (a, b)=>{
|
|
1435
|
+
if (a.modifiedDatetime <= b.modifiedDatetime) return 1;
|
|
1436
|
+
else return -1;
|
|
1437
|
+
},
|
|
1438
|
+
selectId: (cohort)=>cohort.id
|
|
1439
|
+
});
|
|
1440
|
+
// Create an initial unsaved cohort
|
|
1441
|
+
const initialCohort = newCohort({
|
|
1442
|
+
customName: DEFAULT_COHORT_NAME
|
|
1443
|
+
});
|
|
1444
|
+
const emptyInitialState = cohortsAdapter.getInitialState({
|
|
1445
|
+
currentCohortId: initialCohort.id,
|
|
1446
|
+
message: undefined
|
|
1447
|
+
});
|
|
1448
|
+
// Set the initial cohort in the adapter state
|
|
1449
|
+
const initialState$3 = cohortsAdapter.setOne(emptyInitialState, initialCohort);
|
|
1450
|
+
const getCurrentCohortId = (state)=>state.currentCohortId;
|
|
1451
|
+
/**
|
|
1452
|
+
* Redux slice for cohort filters
|
|
1453
|
+
*/ const cohortManagerSlice = createSlice({
|
|
1454
|
+
name: 'cohort',
|
|
1455
|
+
initialState: initialState$3,
|
|
1456
|
+
reducers: {
|
|
1457
|
+
createNewCohort: (state, action)=>{
|
|
1458
|
+
const baseName = action.payload.name || `Cohort`;
|
|
1459
|
+
const uniqueName = generateUniqueName(Object.values(state.entities), baseName);
|
|
1460
|
+
const cohort = newCohort({
|
|
1461
|
+
filters: action.payload.filters,
|
|
1462
|
+
customName: uniqueName
|
|
1463
|
+
});
|
|
1464
|
+
cohortsAdapter.addOne(state, cohort);
|
|
1465
|
+
state.currentCohortId = cohort.id;
|
|
1466
|
+
},
|
|
1467
|
+
updateCohortName: (state, action)=>{
|
|
1468
|
+
const { id, name } = action.payload;
|
|
1469
|
+
cohortsAdapter.updateOne(state, {
|
|
1470
|
+
id: id,
|
|
1471
|
+
changes: {
|
|
1472
|
+
name: name,
|
|
1473
|
+
modified: true,
|
|
1474
|
+
modifiedDatetime: new Date().toISOString()
|
|
1475
|
+
}
|
|
1476
|
+
});
|
|
1477
|
+
},
|
|
1478
|
+
removeCohort: (state, action)=>{
|
|
1479
|
+
const { id: cohortId } = action.payload;
|
|
1480
|
+
const removedCohortName = state.entities[cohortId].name;
|
|
1481
|
+
const totalCohorts = Object.keys(state.entities).length;
|
|
1482
|
+
if (totalCohorts <= 1) {
|
|
1483
|
+
cohortsAdapter.removeAll(state);
|
|
1484
|
+
const defaultCohort = newCohort({
|
|
1485
|
+
filters: {},
|
|
1486
|
+
customName: DEFAULT_COHORT_NAME
|
|
1487
|
+
});
|
|
1488
|
+
cohortsAdapter.addOne(state, defaultCohort);
|
|
1489
|
+
state.currentCohortId = defaultCohort.id;
|
|
1490
|
+
if (action?.payload.shouldShowMessage) {
|
|
1491
|
+
state.message = [
|
|
1492
|
+
`deleteCohort|${removedCohortName}|${state.currentCohortId}`
|
|
1493
|
+
];
|
|
1494
|
+
}
|
|
1495
|
+
return;
|
|
1496
|
+
}
|
|
1497
|
+
cohortsAdapter.removeOne(state, cohortId);
|
|
1498
|
+
// deleted the current cohort so set to the most recent cohort
|
|
1499
|
+
if (state.currentCohortId === cohortId) {
|
|
1500
|
+
const remainingIds = Object.keys(state.entities);
|
|
1501
|
+
state.currentCohortId = remainingIds[0];
|
|
1502
|
+
}
|
|
1503
|
+
if (action?.payload.shouldShowMessage) {
|
|
1504
|
+
state.message = [
|
|
1505
|
+
`deleteCohort|${removedCohortName}|${state.currentCohortId}`
|
|
1506
|
+
];
|
|
1507
|
+
}
|
|
1508
|
+
},
|
|
1509
|
+
// adds a filter to the cohort filter set at the given index
|
|
1510
|
+
updateCohortFilter: (state, action)=>{
|
|
1511
|
+
const { index, field, filter } = action.payload;
|
|
1512
|
+
const currentCohortId = getCurrentCohortId(state);
|
|
1513
|
+
if (!state.entities[currentCohortId]) {
|
|
1514
|
+
return;
|
|
1515
|
+
}
|
|
1516
|
+
cohortsAdapter.updateOne(state, {
|
|
1517
|
+
id: currentCohortId,
|
|
1518
|
+
changes: {
|
|
1519
|
+
filters: {
|
|
1520
|
+
...state.entities[currentCohortId].filters,
|
|
1521
|
+
[index]: {
|
|
1522
|
+
mode: state.entities[currentCohortId]?.filters[index]?.mode ?? 'and',
|
|
1523
|
+
root: {
|
|
1524
|
+
...state.entities[currentCohortId]?.filters[index]?.root ?? {},
|
|
1525
|
+
[field]: filter
|
|
1526
|
+
}
|
|
1527
|
+
}
|
|
1528
|
+
},
|
|
1529
|
+
modified: true,
|
|
1530
|
+
modifiedDatetime: new Date().toISOString()
|
|
1531
|
+
}
|
|
1532
|
+
});
|
|
1533
|
+
},
|
|
1534
|
+
setCohortFilter: (state, action)=>{
|
|
1535
|
+
const { index, filters } = action.payload;
|
|
1536
|
+
const currentCohortId = getCurrentCohortId(state);
|
|
1537
|
+
if (!state.entities[currentCohortId]) {
|
|
1538
|
+
console.error(`no cohort with id=${currentCohortId} defined`);
|
|
1539
|
+
return;
|
|
1540
|
+
}
|
|
1541
|
+
cohortsAdapter.updateOne(state, {
|
|
1542
|
+
id: currentCohortId,
|
|
1543
|
+
changes: {
|
|
1544
|
+
filters: {
|
|
1545
|
+
...state.entities[currentCohortId].filters,
|
|
1546
|
+
[index]: filters
|
|
1547
|
+
},
|
|
1548
|
+
modified: true,
|
|
1549
|
+
modifiedDatetime: new Date().toISOString()
|
|
1550
|
+
}
|
|
1551
|
+
});
|
|
1552
|
+
},
|
|
1553
|
+
setCohortIndexFilters: (state, action)=>{
|
|
1554
|
+
const currentCohortId = getCurrentCohortId(state);
|
|
1555
|
+
if (!state.entities[currentCohortId]) {
|
|
1556
|
+
console.error(`no cohort with id=${currentCohortId} defined`);
|
|
1557
|
+
return;
|
|
1558
|
+
}
|
|
1559
|
+
cohortsAdapter.updateOne(state, {
|
|
1560
|
+
id: currentCohortId,
|
|
1561
|
+
changes: {
|
|
1562
|
+
filters: action.payload.filters,
|
|
1563
|
+
modified: true,
|
|
1564
|
+
modifiedDatetime: new Date().toISOString()
|
|
1565
|
+
}
|
|
1566
|
+
});
|
|
1567
|
+
},
|
|
1568
|
+
// removes a filter to the cohort filter set at the given index
|
|
1569
|
+
removeCohortFilter: (state, action)=>{
|
|
1570
|
+
const { index, field } = action.payload;
|
|
1571
|
+
const currentCohortId = getCurrentCohortId(state);
|
|
1572
|
+
if (!state.entities[currentCohortId]) {
|
|
1573
|
+
console.error(`no cohort with id=${currentCohortId} defined`);
|
|
1574
|
+
return;
|
|
1575
|
+
}
|
|
1576
|
+
const filters = state.entities[currentCohortId]?.filters[index]?.root;
|
|
1577
|
+
if (!filters) {
|
|
1578
|
+
return;
|
|
1579
|
+
}
|
|
1580
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1581
|
+
const { [field]: _a, ...updated } = filters;
|
|
1582
|
+
cohortsAdapter.updateOne(state, {
|
|
1583
|
+
id: currentCohortId,
|
|
1584
|
+
changes: {
|
|
1585
|
+
filters: {
|
|
1586
|
+
...state.entities[currentCohortId]?.filters,
|
|
1587
|
+
[index]: {
|
|
1588
|
+
mode: state.entities[currentCohortId].filters[index].mode,
|
|
1589
|
+
root: updated
|
|
1590
|
+
}
|
|
1591
|
+
},
|
|
1592
|
+
modified: true,
|
|
1593
|
+
modifiedDatetime: new Date().toISOString()
|
|
1594
|
+
}
|
|
1595
|
+
});
|
|
1596
|
+
},
|
|
1597
|
+
duplicateCohort: (state)=>{
|
|
1598
|
+
const currentCohortId = getCurrentCohortId(state);
|
|
1599
|
+
const currentCohort = state.entities[currentCohortId];
|
|
1600
|
+
const newName = generateUniqueName(Object.values(state.entities), currentCohort.name);
|
|
1601
|
+
const duplicatedCohort = newCohort({
|
|
1602
|
+
filters: {
|
|
1603
|
+
...currentCohort.filters
|
|
1604
|
+
},
|
|
1605
|
+
customName: newName
|
|
1606
|
+
});
|
|
1607
|
+
cohortsAdapter.addOne(state, {
|
|
1608
|
+
...duplicatedCohort,
|
|
1609
|
+
counts: {
|
|
1610
|
+
...currentCohort.counts
|
|
1611
|
+
}
|
|
1612
|
+
});
|
|
1613
|
+
state.currentCohortId = duplicatedCohort.id;
|
|
1614
|
+
},
|
|
1615
|
+
// removes all filters from the cohort filter set at the given index
|
|
1616
|
+
clearCohortFilters: (state, action)=>{
|
|
1617
|
+
const { index } = action.payload;
|
|
1618
|
+
const currentCohortId = getCurrentCohortId(state);
|
|
1619
|
+
if (!state.entities[currentCohortId]) {
|
|
1620
|
+
console.error(`no cohort with id=${currentCohortId} defined`);
|
|
1621
|
+
return;
|
|
1622
|
+
}
|
|
1623
|
+
const filters = state.entities[currentCohortId]?.filters[index]?.root;
|
|
1624
|
+
if (!filters) {
|
|
1625
|
+
return;
|
|
1626
|
+
}
|
|
1627
|
+
cohortsAdapter.updateOne(state, {
|
|
1628
|
+
id: currentCohortId,
|
|
1629
|
+
changes: {
|
|
1630
|
+
filters: {
|
|
1631
|
+
...state.entities[currentCohortId]?.filters,
|
|
1632
|
+
[index]: {
|
|
1633
|
+
mode: 'and',
|
|
1634
|
+
root: {}
|
|
1635
|
+
}
|
|
1636
|
+
},
|
|
1637
|
+
modified: true,
|
|
1638
|
+
modifiedDatetime: new Date().toISOString()
|
|
1639
|
+
}
|
|
1640
|
+
});
|
|
1641
|
+
},
|
|
1642
|
+
updateCohortCounts: (state, action)=>{
|
|
1643
|
+
const currentCohortId = getCurrentCohortId(state);
|
|
1644
|
+
const currentCohort = state.entities[currentCohortId];
|
|
1645
|
+
cohortsAdapter.updateOne(state, {
|
|
1646
|
+
id: currentCohortId,
|
|
1647
|
+
changes: {
|
|
1648
|
+
counts: {
|
|
1649
|
+
...currentCohort.counts,
|
|
1650
|
+
...action.payload
|
|
1651
|
+
}
|
|
1652
|
+
}
|
|
1653
|
+
});
|
|
1654
|
+
},
|
|
1655
|
+
updateCohortIndexCountById: (state, action)=>{
|
|
1656
|
+
const { index, cohortId, counts } = action.payload;
|
|
1657
|
+
const cohort = state.entities[cohortId];
|
|
1658
|
+
cohortsAdapter.updateOne(state, {
|
|
1659
|
+
id: cohortId,
|
|
1660
|
+
changes: {
|
|
1661
|
+
counts: {
|
|
1662
|
+
...cohort.counts,
|
|
1663
|
+
...{
|
|
1664
|
+
[index]: counts
|
|
1665
|
+
}
|
|
1666
|
+
}
|
|
1667
|
+
}
|
|
1668
|
+
});
|
|
1669
|
+
},
|
|
1670
|
+
setCurrentCohortId: (state, action)=>{
|
|
1671
|
+
state.currentCohortId = action.payload;
|
|
1672
|
+
},
|
|
1673
|
+
/** @hidden */ setCohortList: (state, action)=>{
|
|
1674
|
+
if (!action.payload) {
|
|
1675
|
+
cohortsAdapter.removeMany(state, state.ids);
|
|
1676
|
+
} else {
|
|
1677
|
+
cohortsAdapter.upsertMany(state, [
|
|
1678
|
+
...action.payload
|
|
1679
|
+
]);
|
|
1680
|
+
}
|
|
1681
|
+
}
|
|
1682
|
+
}
|
|
1683
|
+
});
|
|
1684
|
+
/**
|
|
1685
|
+
* Returns the selectors for the cohorts EntityAdapter
|
|
1686
|
+
* @param state - the CoreState
|
|
1687
|
+
*
|
|
1688
|
+
* @hidden
|
|
1689
|
+
*/ const cohortSelectors = cohortsAdapter.getSelectors((state)=>state.cohorts.cohortManager);
|
|
1690
|
+
// Filter actions: addFilter, removeFilter, updateFilter
|
|
1691
|
+
const { createNewCohort, updateCohortFilter, setCohortFilter, setCohortIndexFilters, duplicateCohort, removeCohortFilter, clearCohortFilters, removeCohort, setCurrentCohortId, updateCohortName, updateCohortCounts, updateCohortIndexCountById, setCohortList } = cohortManagerSlice.actions;
|
|
1692
|
+
const cohortReducer = cohortManagerSlice.reducer;
|
|
1693
|
+
|
|
1694
|
+
const initialState$2 = {};
|
|
1695
|
+
const expandSlice$1 = createSlice({
|
|
1696
|
+
name: 'CohortBuilder/filterExpand',
|
|
1697
|
+
initialState: initialState$2,
|
|
1698
|
+
reducers: {
|
|
1699
|
+
toggleCohortBuilderCategoryFilter: (state, action)=>{
|
|
1700
|
+
return {
|
|
1701
|
+
...state,
|
|
1702
|
+
[action.payload.index]: {
|
|
1703
|
+
...state[action.payload.index],
|
|
1704
|
+
[action.payload.field]: action.payload.expanded
|
|
1705
|
+
}
|
|
1706
|
+
};
|
|
1707
|
+
},
|
|
1708
|
+
toggleCohortBuilderAllFilters: (state, action)=>{
|
|
1709
|
+
return {
|
|
1710
|
+
...state,
|
|
1711
|
+
[action.payload.index]: Object.keys(state[action.payload.index]).reduce((acc, k)=>{
|
|
1712
|
+
acc[k] = action.payload.expand;
|
|
1713
|
+
return acc;
|
|
1714
|
+
}, {})
|
|
1715
|
+
};
|
|
1716
|
+
}
|
|
1717
|
+
}
|
|
1718
|
+
});
|
|
1719
|
+
const cohortBuilderFiltersExpandedReducer = expandSlice$1.reducer;
|
|
1720
|
+
const { toggleCohortBuilderCategoryFilter, toggleCohortBuilderAllFilters } = expandSlice$1.actions;
|
|
1721
|
+
const selectCohortFilterExpanded = (state, index, field)=>state.cohorts.filtersExpanded?.[index]?.[field];
|
|
1722
|
+
const selectAllCohortFiltersCollapsed = (state, index)=>index in state.cohorts.filtersExpanded ? Object.values(state.cohorts.filtersExpanded?.[index]).every((e)=>!e) : false;
|
|
1723
|
+
|
|
1724
|
+
const initialState$1 = {};
|
|
1725
|
+
const expandSlice = createSlice({
|
|
1726
|
+
name: 'CohortBuilder/filterCombineMode',
|
|
1727
|
+
initialState: initialState$1,
|
|
1728
|
+
reducers: {
|
|
1729
|
+
setCohortFilterCombineMode: (state, action)=>{
|
|
1730
|
+
return {
|
|
1731
|
+
...state,
|
|
1732
|
+
[action.payload.index]: {
|
|
1733
|
+
...state[action.payload.index],
|
|
1734
|
+
[action.payload.field]: action.payload.mode
|
|
1735
|
+
}
|
|
1736
|
+
};
|
|
1737
|
+
}
|
|
1738
|
+
}
|
|
1739
|
+
});
|
|
1740
|
+
const cohortBuilderFiltersCombineModeReducer = expandSlice.reducer;
|
|
1741
|
+
const { setCohortFilterCombineMode } = expandSlice.actions;
|
|
1742
|
+
const selectCohortFilterCombineMode = (state, index, field)=>state.cohorts.filtersCombineMode?.[index]?.[field] ?? 'or';
|
|
1743
|
+
|
|
1744
|
+
const initialState = {
|
|
1745
|
+
shouldShareFilters: false,
|
|
1746
|
+
sharedFiltersMap: {}
|
|
1747
|
+
};
|
|
1748
|
+
const cohortSharedFiltersSlice = createSlice({
|
|
1749
|
+
name: 'cohortSharedFilters',
|
|
1750
|
+
initialState: initialState,
|
|
1751
|
+
reducers: {
|
|
1752
|
+
setShouldShareFilters: (state, action)=>{
|
|
1753
|
+
state.shouldShareFilters = action.payload;
|
|
1754
|
+
return state;
|
|
1755
|
+
},
|
|
1756
|
+
setSharedFilters: (state, action)=>{
|
|
1757
|
+
state.sharedFiltersMap = action.payload;
|
|
1758
|
+
}
|
|
1759
|
+
}
|
|
1760
|
+
});
|
|
1761
|
+
const selectShouldShareFilters = (state)=>state.cohorts.sharedFilters.shouldShareFilters;
|
|
1762
|
+
const selectSharedFilters = (state)=>state.cohorts.sharedFilters.sharedFiltersMap;
|
|
1763
|
+
const selectSharedFiltersForFields = (state, field)=>state.cohorts.sharedFilters.sharedFiltersMap?.[field] ?? [
|
|
1764
|
+
field
|
|
1690
1765
|
];
|
|
1691
|
-
};
|
|
1766
|
+
const { setShouldShareFilters, setSharedFilters } = cohortSharedFiltersSlice.actions;
|
|
1767
|
+
const cohortSharedFiltersReducer = cohortSharedFiltersSlice.reducer;
|
|
1768
|
+
|
|
1769
|
+
const cohortReducers = combineReducers({
|
|
1770
|
+
filtersExpanded: cohortBuilderFiltersExpandedReducer,
|
|
1771
|
+
filtersCombineMode: cohortBuilderFiltersCombineModeReducer,
|
|
1772
|
+
sharedFilters: cohortSharedFiltersReducer,
|
|
1773
|
+
cohortManager: cohortReducer
|
|
1774
|
+
});
|
|
1775
|
+
|
|
1776
|
+
const rootReducer = combineReducers({
|
|
1777
|
+
gen3Services: gen3ServicesReducer,
|
|
1778
|
+
user: userReducer,
|
|
1779
|
+
gen3Apps: gen3AppReducer,
|
|
1780
|
+
drsHostnames: drsHostnamesReducer,
|
|
1781
|
+
modals: modalReducer,
|
|
1782
|
+
cohorts: cohortReducers,
|
|
1783
|
+
activeWorkspace: activeWorkspaceReducer,
|
|
1784
|
+
[guppyApiSliceReducerPath]: guppyApiReducer,
|
|
1785
|
+
[userAuthApiReducerPath]: userAuthApiReducer,
|
|
1786
|
+
[cartReducerPath]: cartReducer
|
|
1787
|
+
});
|
|
1692
1788
|
|
|
1693
1789
|
/**
|
|
1694
1790
|
* Flattens a deep nested JSON object skipping
|
|
@@ -1850,14 +1946,22 @@ function isHttpStatusError(error) {
|
|
|
1850
1946
|
* @param {string} csrfToken - The CSRF token to include in the request headers.
|
|
1851
1947
|
* @returns {FetchConfig} - The prepared fetch configuration object.
|
|
1852
1948
|
*/ const prepareFetchConfig = (parameters, csrfToken)=>{
|
|
1949
|
+
const headers = new Headers({
|
|
1950
|
+
Accept: 'application/json',
|
|
1951
|
+
'Content-Type': 'application/json',
|
|
1952
|
+
...csrfToken !== undefined && {
|
|
1953
|
+
'X-CSRF-Token': csrfToken
|
|
1954
|
+
}
|
|
1955
|
+
});
|
|
1956
|
+
if (process.env.NODE_ENV === 'development') {
|
|
1957
|
+
// NOTE: This cookie can only be accessed from the client side
|
|
1958
|
+
// in development mode. Otherwise, the cookie is set as httpOnly
|
|
1959
|
+
const accessToken = getCookie('credentials_token');
|
|
1960
|
+
if (accessToken) headers.set('Authorization', `Bearer ${accessToken}`);
|
|
1961
|
+
}
|
|
1853
1962
|
return {
|
|
1854
1963
|
method: 'POST',
|
|
1855
|
-
headers:
|
|
1856
|
-
'Content-Type': 'application/json',
|
|
1857
|
-
...csrfToken !== undefined && {
|
|
1858
|
-
'X-CSRF-Token': csrfToken
|
|
1859
|
-
}
|
|
1860
|
-
},
|
|
1964
|
+
headers: headers,
|
|
1861
1965
|
body: JSON.stringify({
|
|
1862
1966
|
type: parameters.type,
|
|
1863
1967
|
filter: convertFilterSetToGqlFilter(parameters.filter),
|
|
@@ -2042,6 +2146,88 @@ const groupSharedFields = (data)=>{
|
|
|
2042
2146
|
return data;
|
|
2043
2147
|
};
|
|
2044
2148
|
|
|
2149
|
+
const customQueryStrForField = (field, query, depth = 0)=>{
|
|
2150
|
+
const indent = ' '.repeat(depth);
|
|
2151
|
+
const splittedFieldArray = field.split('.');
|
|
2152
|
+
const splittedField = splittedFieldArray.shift();
|
|
2153
|
+
if (splittedFieldArray.length === 0) {
|
|
2154
|
+
return `${indent}${splittedField} ${query}`;
|
|
2155
|
+
}
|
|
2156
|
+
return `${indent}${splittedField} {
|
|
2157
|
+
${customQueryStrForField(splittedFieldArray.join('.'), query, depth + 1)}
|
|
2158
|
+
${indent}}`;
|
|
2159
|
+
};
|
|
2160
|
+
// TODO: refactor the function below using customQueryStrForEachField and a wrapper function that passes the query
|
|
2161
|
+
const histogramQueryStrForEachField = (field)=>{
|
|
2162
|
+
const splittedFieldArray = field.split('.');
|
|
2163
|
+
const splittedField = splittedFieldArray.shift();
|
|
2164
|
+
if (splittedFieldArray.length === 0) {
|
|
2165
|
+
return `
|
|
2166
|
+
${splittedField} {
|
|
2167
|
+
histogram {
|
|
2168
|
+
key
|
|
2169
|
+
count
|
|
2170
|
+
}
|
|
2171
|
+
}`;
|
|
2172
|
+
}
|
|
2173
|
+
return `
|
|
2174
|
+
${splittedField} {
|
|
2175
|
+
${histogramQueryStrForEachField(splittedFieldArray.join('.'))}
|
|
2176
|
+
}`;
|
|
2177
|
+
};
|
|
2178
|
+
const statsQueryStrForEachField = (field)=>{
|
|
2179
|
+
const splittedFieldArray = field.split('.');
|
|
2180
|
+
const splittedField = splittedFieldArray.shift();
|
|
2181
|
+
if (splittedFieldArray.length === 0) {
|
|
2182
|
+
return `
|
|
2183
|
+
${splittedField} {
|
|
2184
|
+
histogram {
|
|
2185
|
+
count
|
|
2186
|
+
min
|
|
2187
|
+
max
|
|
2188
|
+
avg
|
|
2189
|
+
sum
|
|
2190
|
+
}
|
|
2191
|
+
}`;
|
|
2192
|
+
}
|
|
2193
|
+
return `
|
|
2194
|
+
${splittedField} {
|
|
2195
|
+
${statsQueryStrForEachField(splittedFieldArray.join('.'))}
|
|
2196
|
+
}`;
|
|
2197
|
+
};
|
|
2198
|
+
const nestedHistogramQueryStrForEachField = (mainField, numericAggAsText)=>`
|
|
2199
|
+
${mainField} {
|
|
2200
|
+
${numericAggAsText ? 'asTextHistogram' : 'histogram'} {
|
|
2201
|
+
key
|
|
2202
|
+
count
|
|
2203
|
+
missingFields {
|
|
2204
|
+
field
|
|
2205
|
+
count
|
|
2206
|
+
}
|
|
2207
|
+
termsFields {
|
|
2208
|
+
field
|
|
2209
|
+
count
|
|
2210
|
+
terms {
|
|
2211
|
+
key
|
|
2212
|
+
count
|
|
2213
|
+
}
|
|
2214
|
+
}
|
|
2215
|
+
}
|
|
2216
|
+
}`;
|
|
2217
|
+
const rawDataQueryStrForEachField = (field)=>{
|
|
2218
|
+
const splitFieldArray = field.split('.');
|
|
2219
|
+
const splitField = splitFieldArray.shift();
|
|
2220
|
+
if (splitFieldArray.length === 0) {
|
|
2221
|
+
return `
|
|
2222
|
+
${splitField}
|
|
2223
|
+
`;
|
|
2224
|
+
}
|
|
2225
|
+
return `
|
|
2226
|
+
${splitField} {
|
|
2227
|
+
${rawDataQueryStrForEachField(splitFieldArray.join('.'))}
|
|
2228
|
+
}`;
|
|
2229
|
+
};
|
|
2230
|
+
|
|
2045
2231
|
const statusEndpoint = '/_status';
|
|
2046
2232
|
const fetchJson = async (url)=>{
|
|
2047
2233
|
const res = await fetch(url, {
|
|
@@ -2322,75 +2508,6 @@ const explorerTags = guppyApi.enhanceEndpoints({
|
|
|
2322
2508
|
})
|
|
2323
2509
|
})
|
|
2324
2510
|
});
|
|
2325
|
-
const histogramQueryStrForEachField = (field)=>{
|
|
2326
|
-
const splittedFieldArray = field.split('.');
|
|
2327
|
-
const splittedField = splittedFieldArray.shift();
|
|
2328
|
-
if (splittedFieldArray.length === 0) {
|
|
2329
|
-
return `
|
|
2330
|
-
${splittedField} {
|
|
2331
|
-
histogram {
|
|
2332
|
-
key
|
|
2333
|
-
count
|
|
2334
|
-
}
|
|
2335
|
-
}`;
|
|
2336
|
-
}
|
|
2337
|
-
return `
|
|
2338
|
-
${splittedField} {
|
|
2339
|
-
${histogramQueryStrForEachField(splittedFieldArray.join('.'))}
|
|
2340
|
-
}`;
|
|
2341
|
-
};
|
|
2342
|
-
const statsQueryStrForEachField = (field)=>{
|
|
2343
|
-
const splittedFieldArray = field.split('.');
|
|
2344
|
-
const splittedField = splittedFieldArray.shift();
|
|
2345
|
-
if (splittedFieldArray.length === 0) {
|
|
2346
|
-
return `
|
|
2347
|
-
${splittedField} {
|
|
2348
|
-
histogram {
|
|
2349
|
-
count
|
|
2350
|
-
min
|
|
2351
|
-
max
|
|
2352
|
-
avg
|
|
2353
|
-
sum
|
|
2354
|
-
}
|
|
2355
|
-
}`;
|
|
2356
|
-
}
|
|
2357
|
-
return `
|
|
2358
|
-
${splittedField} {
|
|
2359
|
-
${statsQueryStrForEachField(splittedFieldArray.join('.'))}
|
|
2360
|
-
}`;
|
|
2361
|
-
};
|
|
2362
|
-
const nestedHistogramQueryStrForEachField = (mainField, numericAggAsText)=>`
|
|
2363
|
-
${mainField} {
|
|
2364
|
-
${numericAggAsText ? 'asTextHistogram' : 'histogram'} {
|
|
2365
|
-
key
|
|
2366
|
-
count
|
|
2367
|
-
missingFields {
|
|
2368
|
-
field
|
|
2369
|
-
count
|
|
2370
|
-
}
|
|
2371
|
-
termsFields {
|
|
2372
|
-
field
|
|
2373
|
-
count
|
|
2374
|
-
terms {
|
|
2375
|
-
key
|
|
2376
|
-
count
|
|
2377
|
-
}
|
|
2378
|
-
}
|
|
2379
|
-
}
|
|
2380
|
-
}`;
|
|
2381
|
-
const rawDataQueryStrForEachField = (field)=>{
|
|
2382
|
-
const splitFieldArray = field.split('.');
|
|
2383
|
-
const splitField = splitFieldArray.shift();
|
|
2384
|
-
if (splitFieldArray.length === 0) {
|
|
2385
|
-
return `
|
|
2386
|
-
${splitField}
|
|
2387
|
-
`;
|
|
2388
|
-
}
|
|
2389
|
-
return `
|
|
2390
|
-
${splitField} {
|
|
2391
|
-
${rawDataQueryStrForEachField(splitFieldArray.join('.'))}
|
|
2392
|
-
}`;
|
|
2393
|
-
};
|
|
2394
2511
|
const useGetArrayTypes = ()=>{
|
|
2395
2512
|
{
|
|
2396
2513
|
const { data, error } = useGetStatus();
|
|
@@ -2494,7 +2611,8 @@ const persistConfig = {
|
|
|
2494
2611
|
storage,
|
|
2495
2612
|
whitelist: [
|
|
2496
2613
|
'cohorts',
|
|
2497
|
-
'activeWorkspace'
|
|
2614
|
+
'activeWorkspace',
|
|
2615
|
+
'cart'
|
|
2498
2616
|
]
|
|
2499
2617
|
};
|
|
2500
2618
|
const persistedReducer = persistReducer(persistConfig, rootReducer);
|
|
@@ -2742,6 +2860,28 @@ const fetchFencePresignedURL = async ({ guid, method = 'GET', onAbort = ()=>null
|
|
|
2742
2860
|
return await response.json();
|
|
2743
2861
|
};
|
|
2744
2862
|
|
|
2863
|
+
const extractValuesFromObject = (jsonPathMappings, obj)=>{
|
|
2864
|
+
const result = {};
|
|
2865
|
+
const extractObjectValue = (jsonPath, obj)=>{
|
|
2866
|
+
const extractedValues = JSONPath({
|
|
2867
|
+
path: jsonPath,
|
|
2868
|
+
json: obj
|
|
2869
|
+
});
|
|
2870
|
+
return extractedValues.length > 0 ? extractedValues[0] : undefined;
|
|
2871
|
+
};
|
|
2872
|
+
for(const key in jsonPathMappings){
|
|
2873
|
+
if (key in Object.keys(jsonPathMappings)) {
|
|
2874
|
+
// Extract value from an object and store it in the result.
|
|
2875
|
+
result[key] = extractObjectValue(jsonPathMappings[key], obj);
|
|
2876
|
+
}
|
|
2877
|
+
}
|
|
2878
|
+
return result;
|
|
2879
|
+
};
|
|
2880
|
+
const ExtractValueFromObject = (obj, key, valueIfNotFound)=>{
|
|
2881
|
+
return obj?.[key] ?? valueIfNotFound;
|
|
2882
|
+
};
|
|
2883
|
+
|
|
2884
|
+
const DAYS_IN_YEAR = 365.25;
|
|
2745
2885
|
/**
|
|
2746
2886
|
* Converts HistogramData to HistogramDataAsStringKey by ensuring the key is a string.
|
|
2747
2887
|
* If the key is already a string, it's used as is.
|
|
@@ -2757,6 +2897,79 @@ const fetchFencePresignedURL = async ({ guid, method = 'GET', onAbort = ()=>null
|
|
|
2757
2897
|
};
|
|
2758
2898
|
const calculatePercentageAsNumber = (count, total)=>count ? count / total * 100 : 0;
|
|
2759
2899
|
const calculatePercentageAsString = (count, total)=>`${(count / total * 100).toFixed(2)}%`;
|
|
2900
|
+
const capitalize = (original)=>{
|
|
2901
|
+
const customCapitalizations = {
|
|
2902
|
+
id: 'ID',
|
|
2903
|
+
uuid: 'UUID',
|
|
2904
|
+
dna: 'DNA',
|
|
2905
|
+
dbsnp: 'dbSNP',
|
|
2906
|
+
cosmic: 'COSMIC',
|
|
2907
|
+
civic: 'CIViC',
|
|
2908
|
+
dbgap: 'dbGaP',
|
|
2909
|
+
ecog: 'ECOG',
|
|
2910
|
+
bmi: 'BMI',
|
|
2911
|
+
gdc: 'GDC',
|
|
2912
|
+
cnv: 'CNV',
|
|
2913
|
+
ssm: 'SSM',
|
|
2914
|
+
aa: 'AA'
|
|
2915
|
+
};
|
|
2916
|
+
return original.split(' ').map((word)=>customCapitalizations[word.toLowerCase()] || `${word.charAt(0).toUpperCase()}${word.slice(1)}`).join(' ');
|
|
2917
|
+
};
|
|
2918
|
+
const humanify = ({ term = '', capitalize: cap = true, facetTerm = false })=>{
|
|
2919
|
+
let original;
|
|
2920
|
+
let humanified;
|
|
2921
|
+
if (facetTerm) {
|
|
2922
|
+
// Splits on capital letters followed by lowercase letters to find
|
|
2923
|
+
// words squished together in a string.
|
|
2924
|
+
original = term?.split(/(?=[A-Z][a-z])/).join(' ');
|
|
2925
|
+
humanified = term?.replace(/\./g, ' ').replace(/_/g, ' ').trim();
|
|
2926
|
+
} else {
|
|
2927
|
+
const split = (original || term)?.split('.');
|
|
2928
|
+
humanified = split[split.length - 1]?.replace(/_/g, ' ').trim();
|
|
2929
|
+
// Special case 'name' to include any parent nested for sake of
|
|
2930
|
+
// specificity in the UI
|
|
2931
|
+
if (humanified === 'name' && split?.length > 1) {
|
|
2932
|
+
humanified = `${split[split?.length - 2]} ${humanified}`;
|
|
2933
|
+
}
|
|
2934
|
+
}
|
|
2935
|
+
return cap ? capitalize(humanified) : humanified;
|
|
2936
|
+
};
|
|
2937
|
+
/*https://github.com/NCI-GDC/portal-ui/blob/develop/src/packages/%40ncigdc/utils/ageDisplay.js*/ /**
|
|
2938
|
+
* Converts age in days into a human-readable format.
|
|
2939
|
+
*
|
|
2940
|
+
* @param ageInDays - The age in days.
|
|
2941
|
+
* @param yearsOnly - If true, only display years.
|
|
2942
|
+
* @defaultValue false
|
|
2943
|
+
* @param defaultValue - The default value to return if ageInDays is falsy.
|
|
2944
|
+
* @defaultValue "--"
|
|
2945
|
+
* @returns The formatted age string.
|
|
2946
|
+
*/ const ageDisplay = (ageInDays, yearsOnly = false, defaultValue = '--')=>{
|
|
2947
|
+
if (ageInDays !== 0 && !ageInDays) {
|
|
2948
|
+
return defaultValue;
|
|
2949
|
+
}
|
|
2950
|
+
const calculateYearsAndDays = (years, days)=>days === 365 ? [
|
|
2951
|
+
years + 1,
|
|
2952
|
+
0
|
|
2953
|
+
] : [
|
|
2954
|
+
years,
|
|
2955
|
+
days
|
|
2956
|
+
];
|
|
2957
|
+
const ABS_AGE_DAYS = Math.abs(ageInDays);
|
|
2958
|
+
const [years, remainingDays] = calculateYearsAndDays(Math.floor(ABS_AGE_DAYS / DAYS_IN_YEAR), Math.ceil(ABS_AGE_DAYS % DAYS_IN_YEAR));
|
|
2959
|
+
const formattedYears = years === 0 ? '' : `${years} ${years === 1 ? 'year' : 'years'}`;
|
|
2960
|
+
const formattedDays = !yearsOnly && remainingDays > 0 ? `${remainingDays} ${remainingDays === 1 ? 'day' : 'days'}` : years === 0 && remainingDays === 0 ? '0 days' : '';
|
|
2961
|
+
const ageString = [
|
|
2962
|
+
formattedYears,
|
|
2963
|
+
formattedDays
|
|
2964
|
+
].filter(Boolean).join(' ');
|
|
2965
|
+
return ageInDays >= 0 ? ageString : `-${ageString}`;
|
|
2966
|
+
};
|
|
2967
|
+
/**
|
|
2968
|
+
* Given an object of JSON, stringify it into a string.
|
|
2969
|
+
* @param obj - the object to stringify
|
|
2970
|
+
* @param defaults - the default value to return if the object is undefined
|
|
2971
|
+
* @category Utility
|
|
2972
|
+
*/ const stringifyJSONParam = (obj, defaults = '{}')=>obj ? JSON.stringify(obj) : defaults;
|
|
2760
2973
|
|
|
2761
2974
|
const queryWTSFederatedLoginStatus = async (signal)=>{
|
|
2762
2975
|
try {
|
|
@@ -4748,7 +4961,7 @@ const { useGraphQLQuery } = graphQLAPI;
|
|
|
4748
4961
|
return {
|
|
4749
4962
|
url: `${GEN3_GUPPY_API}/download`,
|
|
4750
4963
|
method: 'POST',
|
|
4751
|
-
body:
|
|
4964
|
+
body: queryBody,
|
|
4752
4965
|
cache: 'no-cache'
|
|
4753
4966
|
};
|
|
4754
4967
|
},
|
|
@@ -5301,24 +5514,6 @@ const userHasMethodOnAnyProject = (method, userAuthMapping = {})=>{
|
|
|
5301
5514
|
};
|
|
5302
5515
|
const userHasCreateOrUpdateOnAnyProject = (userAuthMapping = {})=>userHasMethodOnAnyProject('create', userAuthMapping) || userHasMethodOnAnyProject('update', userAuthMapping);
|
|
5303
5516
|
|
|
5304
|
-
const extractValuesFromObject = (jsonPathMappings, obj)=>{
|
|
5305
|
-
const result = {};
|
|
5306
|
-
const extractObjectValue = (jsonPath, obj)=>{
|
|
5307
|
-
const extractedValues = JSONPath({
|
|
5308
|
-
path: jsonPath,
|
|
5309
|
-
json: obj
|
|
5310
|
-
});
|
|
5311
|
-
return extractedValues.length > 0 ? extractedValues[0] : undefined;
|
|
5312
|
-
};
|
|
5313
|
-
for(const key in jsonPathMappings){
|
|
5314
|
-
if (key in Object.keys(jsonPathMappings)) {
|
|
5315
|
-
// Extract value from an object and store it in the result.
|
|
5316
|
-
result[key] = extractObjectValue(jsonPathMappings[key], obj);
|
|
5317
|
-
}
|
|
5318
|
-
}
|
|
5319
|
-
return result;
|
|
5320
|
-
};
|
|
5321
|
-
|
|
5322
5517
|
const SubmissionGraphqlQuery = `query transactionList {
|
|
5323
5518
|
transactionList: transaction_log(last: 20) {
|
|
5324
5519
|
id
|
|
@@ -5601,5 +5796,5 @@ const selectPaymodelStatus = createSelector(paymodelStatusSelector, (status)=>st
|
|
|
5601
5796
|
const isWorkspaceActive = (status)=>status === WorkspaceStatus.Running || status === WorkspaceStatus.Launching || status === WorkspaceStatus.Terminating;
|
|
5602
5797
|
const isWorkspaceRunningOrStopping = (status)=>status === WorkspaceStatus.Running || status === WorkspaceStatus.Terminating;
|
|
5603
5798
|
|
|
5604
|
-
export { Accessibility, CohortStorage, CoreProvider, DataLibraryStoreMode, EmptyFilterSet, EmptyWorkspaceStatusResponse, EnumValueExtractorHandler, GEN3_API, GEN3_AUTHZ_API, GEN3_COMMONS_NAME, GEN3_CROSSWALK_API, GEN3_DOMAIN, GEN3_DOWNLOADS_ENDPOINT, GEN3_FENCE_API, GEN3_GUPPY_API, GEN3_MANIFEST_API, GEN3_MDS_API, GEN3_REDIRECT_URL, GEN3_SOWER_API, GEN3_SUBMISSION_API, GEN3_WORKSPACE_API, HTTPError, HTTPErrorMessages, HttpMethod, MissingServiceConfigurationError, Modals, PodConditionType, PodStatus, RequestedWorkspaceStatus, ToGqlHandler, ValueExtractorHandler, WorkspaceStatus, appendFilterToOperation, buildGetAggregationQuery, buildGetStatsAggregationQuery, buildListItemsGroupedByDataset, calculatePercentageAsNumber, calculatePercentageAsString, clearActiveWorkspaceId, clearCohortFilters, cohortReducer, convertFilterSetToGqlFilter, convertFilterToGqlFilter, convertGqlFilterToFilter, convertToHistogramDataAsStringKey, convertToQueryString, coreStore, createAppApiForRTKQ, createAppStore, createGen3App, createGen3AppWithOwnStore, createNewCohort, createUseCoreDataHook, defaultCohortNameGenerator, downloadFromGuppyToBlob, downloadJSONDataFromGuppy, drsHostnamesReducer, duplicateCohort, explorerApi, explorerTags, extractEnumFilterValue, extractFieldNameFromFullFieldName, extractFileDatasetsInRecords, extractFilterValue, extractIndexAndFieldNameFromFullFieldName, extractIndexFromDataLibraryCohort, extractIndexFromFullFieldName, fetchFence, fetchFencePresignedURL, fetchJSONDataFromURL, fetchJson, fetchUserState, fieldNameToTitle, filterSetToOperation, gen3Api, generateUniqueName, getCurrentTimestamp, getFederatedLoginStatus, getGen3AppId, getNumberOfItemsInDatalist, getRemoteSupportServiceRegistry, getTimestamp, graphQLAPI, graphQLWithTags, groupSharedFields, guppyAPISliceMiddleware, guppyApi, guppyApiReducer, guppyApiSliceReducerPath, handleGqlOperation, handleOperation, hideModal, histogramQueryStrForEachField, isAdditionalDataItem, isArray, isAuthenticated, isCohortItem, isDataLibraryAPIResponse, isDatalistAPI, isErrorWithMessage, isFetchBaseQueryError, isFetchError, isFetchParseError, isFileItem, isFilterEmpty, isFilterSet, isGQLIntersection, isGQLUnion, isGuppyAggregationData, isHistogramData, isHistogramDataAArray, isHistogramDataAnEnum, isHistogramDataArray, isHistogramDataArrayARange, isHistogramDataArrayAnEnum, isHistogramDataCollection, isHistogramRangeData, isHttpStatusError, isIndexedFilterSetEmpty, isIntersection, isJSONObject, isJSONValue, isJSONValueArray, isNameUnique, isNotDefined, isObject, isOperandsType, isOperationWithField, isOperatorWithFieldAndArrayOfOperands, isPending, isProgramUrl, isRootUrl, isStatsValue, isStatsValuesArray, isString, isTimeGreaterThan, isUnion, isWorkspaceActive, isWorkspaceRunningOrStopping, listifyMethodsFromMapping, logoutFence, manifestApi, manifestTags, nestedHistogramQueryStrForEachField, prepareUrl, prependIndexToFieldName, processHistogramResponse, projectCodeFromResourcePath, queryMultipleMDSRecords, rawDataQueryStrForEachField, registerDefaultRemoteSupport, removeCohort, removeCohortFilter, requestorApi, resetUserState, resourcePathFromProjectID, roundHistogramResponse, selectActiveWorkspaceId, selectActiveWorkspaceStatus, selectAllCohortFiltersCollapsed, selectAllCohorts, selectAuthzMappingData, selectAvailableCohortByName, selectAvailableCohorts, selectCSRFToken, selectCSRFTokenData, selectCohortById, selectCohortFilterCombineMode, selectCohortFilterExpanded, selectCohortFilters, selectCohortIds, selectCurrentCohort, selectCurrentCohortFilters, selectCurrentCohortId, selectCurrentCohortModified, selectCurrentCohortName, selectCurrentCohortSaved, selectCurrentMessage, selectCurrentModal, selectGen3AppByName, selectGen3AppMetadataByName, selectHeadersWithCSRFToken, selectIndexFilters, selectIndexedFilterByName, selectPaymodelStatus, selectRequestedWorkspaceStatus, selectRequestedWorkspaceStatusTimestamp, selectSharedFilters, selectSharedFiltersForFields, selectShouldShareFilters, selectTotalCohorts, selectUser, selectUserAuthStatus, selectUserData, selectUserDetails, selectUserLoginStatus, selectWorkspaceStatus, selectWorkspaceStatusFromService, setActiveWorkspace, setActiveWorkspaceId, setActiveWorkspaceStatus, setCohortFilter, setCohortFilterCombineMode, setCohortIndexFilters, setCohortList, setCurrentCohortId, setDRSHostnames, setRequestedWorkspaceStatus, setSharedFilters, setShouldShareFilters, setupCoreStore, showModal, statsQueryStrForEachField, submissionApi, toggleCohortBuilderAllFilters, toggleCohortBuilderCategoryFilter, trimFirstFieldNameToTitle, updateCohortFilter, updateCohortName, useAddCohortManifestMutation, useAddFileManifestMutation, useAddMetadataManifestMutation, useAddNewCredentialMutation, useAskQuestionMutation, useAuthorizeFromCredentialsMutation, useCoreDispatch, useCoreSelector, useCreateAuthzResourceMutation, useCreateRequestMutation, useDataLibrary, useDownloadFromGuppyMutation, useFetchUserDetailsQuery, useGeneralGQLQuery, useGetAISearchStatusQuery, useGetAISearchVersionQuery, useGetAccessibleDataQuery, useGetActivePayModelQuery, useGetAggMDSQuery, useGetAggsQuery, useGetAllFieldsForTypeQuery, useGetArrayTypes, useGetAuthzMappingsQuery, useGetAuthzResourcesQuery, useGetCSRFQuery, useGetCohortManifestQuery, useGetCountsQuery, useGetCredentialsQuery, useGetCrosswalkDataQuery, useGetDataQuery, useGetDictionaryQuery, useGetDownloadQuery, useGetExternalLoginsQuery, useGetFederatedLoginStatus, useGetFieldCountSummaryQuery, useGetFieldsForIndexQuery, useGetFileFromManifestQuery, useGetFileManifestQuery, useGetIndexAggMDSQuery, useGetIndexFields, useGetJWKKeysQuery, useGetLoginProvidersQuery, useGetMDSQuery, useGetManifestServiceStatusQuery, useGetMetadataByIdQuery, useGetMetadataFromManifestQuery, useGetMetadataManifestQuery, useGetProjectsDetailsQuery, useGetProjectsQuery, useGetRawDataAndTotalCountsQuery, useGetSharedFieldsForIndexQuery, useGetSowerJobListQuery, useGetSowerJobStatusQuery, useGetSowerOutputQuery, useGetSowerServiceStatusQuery, useGetStatsAggregationsQuery, useGetStatus, useGetSubAggsQuery, useGetSubmissionGraphQLQuery, useGetSubmissionsQuery, useGetTagsQuery, useGetWorkspaceOptionsQuery, useGetWorkspacePayModelsQuery, useGetWorkspaceStatusQuery, useGraphQLQuery, useIsExternalConnectedQuery, useIsUserLoggedIn, useLaunchWorkspaceMutation, useLazyFetchUserDetailsQuery, useLazyGeneralGQLQuery, useLazyGetAggsQuery, useLazyGetAuthzMappingsQuery, useLazyGetAuthzResourcesQuery, useLazyGetCSRFQuery, useLazyGetCountsQuery, useLazyGetCrosswalkDataQuery, useLazyGetDownloadQuery, useLazyGetExternalLoginsQuery, useLazyGetManifestServiceStatusQuery, useLazyGetProjectsQuery, useLazyGetSowerJobListQuery, useLazyGetStatsAggregationsQuery, useLazyGetSubmissionGraphQLQuery, useLazyIsExternalConnectedQuery, useLazyRequestQuery, usePrevious, useRemoveCredentialMutation, useRequestByIdQuery, useRequestQuery, useRequestorStatusQuery, useSetCurrentPayModelMutation, useSubmitSowerJobMutation, useTerminateWorkspaceMutation, useUserAuth, useUserRequestQuery, userHasCreateOrUpdateOnAnyProject, userHasDataUpload, userHasMethodForServiceOnProject, userHasMethodForServiceOnResource, userHasMethodOnAnyProject, userHasSheepdogProgramAdmin, userHasSheepdogProjectAdmin };
|
|
5799
|
+
export { Accessibility, CART_LIMIT, CohortStorage, CoreProvider, DAYS_IN_YEAR, DataLibraryStoreMode, EmptyFilterSet, EmptyWorkspaceStatusResponse, EnumValueExtractorHandler, ExtractValueFromObject, GEN3_API, GEN3_AUTHZ_API, GEN3_COMMONS_NAME, GEN3_CROSSWALK_API, GEN3_DOMAIN, GEN3_DOWNLOADS_ENDPOINT, GEN3_FENCE_API, GEN3_GUPPY_API, GEN3_MANIFEST_API, GEN3_MDS_API, GEN3_REDIRECT_URL, GEN3_SOWER_API, GEN3_SUBMISSION_API, GEN3_WORKSPACE_API, HTTPError, HTTPErrorMessages, HttpMethod, MissingServiceConfigurationError, Modals, PodConditionType, PodStatus, RequestedWorkspaceStatus, ToGqlHandler, ValueExtractorHandler, WorkspaceStatus, addItemsToCart, ageDisplay, appendFilterToOperation, buildGetAggregationQuery, buildGetStatsAggregationQuery, buildListItemsGroupedByDataset, buildNestedGQLFilter, calculatePercentageAsNumber, calculatePercentageAsString, capitalize, cartReducer, cartReducerPath, clearActiveWorkspaceId, clearCohortFilters, cohortReducer, convertFilterSetToGqlFilter, convertFilterToGqlFilter, convertGqlFilterToFilter, convertToHistogramDataAsStringKey, convertToQueryString, coreStore, createAppApiForRTKQ, createAppStore, createGen3App, createGen3AppWithOwnStore, createNewCohort, createUseCoreDataHook, customQueryStrForField, defaultCohortNameGenerator, downloadFromGuppyToBlob, downloadJSONDataFromGuppy, drsHostnamesReducer, duplicateCohort, explorerApi, explorerTags, extractEnumFilterValue, extractFieldNameFromFullFieldName, extractFileDatasetsInRecords, extractFilterValue, extractFiltersWithPrefixFromFilterSet, extractIndexAndFieldNameFromFullFieldName, extractIndexFromDataLibraryCohort, extractIndexFromFullFieldName, fetchFence, fetchFencePresignedURL, fetchJSONDataFromURL, fetchJson, fetchUserState, fieldNameToTitle, filterSetToOperation, gen3Api, generateUniqueName, getCurrentTimestamp, getFederatedLoginStatus, getGen3AppId, getNumberOfItemsInDatalist, getRemoteSupportServiceRegistry, getTimestamp, graphQLAPI, graphQLWithTags, groupSharedFields, guppyAPISliceMiddleware, guppyApi, guppyApiReducer, guppyApiSliceReducerPath, handleGqlOperation, handleOperation, hideModal, histogramQueryStrForEachField, humanify, isAdditionalDataItem, isArray, isAuthenticated, isCohortItem, isDataLibraryAPIResponse, isDatalistAPI, isErrorWithMessage, isFetchBaseQueryError, isFetchError, isFetchParseError, isFileItem, isFilterEmpty, isFilterSet, isGQLIntersection, isGQLUnion, isGuppyAggregationData, isHistogramData, isHistogramDataAArray, isHistogramDataAnEnum, isHistogramDataArray, isHistogramDataArrayARange, isHistogramDataArrayAnEnum, isHistogramDataCollection, isHistogramRangeData, isHttpStatusError, isIndexedFilterSetEmpty, isIntersection, isIntersectionOrUnion, isJSONObject, isJSONValue, isJSONValueArray, isNameUnique, isNestedFilter, isNotDefined, isObject, isOperandsType, isOperationWithField, isOperatorWithFieldAndArrayOfOperands, isPending, isProgramUrl, isRootUrl, isStatsValue, isStatsValuesArray, isString, isTimeGreaterThan, isUnion, isWorkspaceActive, isWorkspaceRunningOrStopping, listifyMethodsFromMapping, logoutFence, manifestApi, manifestTags, nestedHistogramQueryStrForEachField, prepareUrl, prependIndexToFieldName, processHistogramResponse, projectCodeFromResourcePath, queryMultipleMDSRecords, rawDataQueryStrForEachField, registerDefaultRemoteSupport, removeCohort, removeCohortFilter, removeItemsFromCart, requestorApi, resetUserState, resourcePathFromProjectID, roundHistogramResponse, selectActiveWorkspaceId, selectActiveWorkspaceStatus, selectAllCohortFiltersCollapsed, selectAllCohorts, selectAuthzMappingData, selectAvailableCohortByName, selectAvailableCohorts, selectCSRFToken, selectCSRFTokenData, selectCart, selectCartCount, selectCartItem, selectCartItems, selectCohortById, selectCohortFilterCombineMode, selectCohortFilterExpanded, selectCohortFilters, selectCohortIds, selectCurrentCohort, selectCurrentCohortFilters, selectCurrentCohortId, selectCurrentCohortModified, selectCurrentCohortName, selectCurrentCohortSaved, selectCurrentMessage, selectCurrentModal, selectGen3AppByName, selectGen3AppMetadataByName, selectHeadersWithCSRFToken, selectIndexFilters, selectIndexedFilterByName, selectPaymodelStatus, selectRequestedWorkspaceStatus, selectRequestedWorkspaceStatusTimestamp, selectSharedFilters, selectSharedFiltersForFields, selectShouldShareFilters, selectTotalCohorts, selectUser, selectUserAuthStatus, selectUserData, selectUserDetails, selectUserLoginStatus, selectWorkspaceStatus, selectWorkspaceStatusFromService, setActiveWorkspace, setActiveWorkspaceId, setActiveWorkspaceStatus, setCohortFilter, setCohortFilterCombineMode, setCohortIndexFilters, setCohortList, setCurrentCohortId, setDRSHostnames, setRequestedWorkspaceStatus, setSharedFilters, setShouldShareFilters, setupCoreStore, showModal, statsQueryStrForEachField, stringifyJSONParam, submissionApi, toggleCohortBuilderAllFilters, toggleCohortBuilderCategoryFilter, trimFirstFieldNameToTitle, updateCohortFilter, updateCohortName, useAddCohortManifestMutation, useAddFileManifestMutation, useAddMetadataManifestMutation, useAddNewCredentialMutation, useAskQuestionMutation, useAuthorizeFromCredentialsMutation, useCoreDispatch, useCoreSelector, useCreateAuthzResourceMutation, useCreateRequestMutation, useDataLibrary, useDownloadFromGuppyMutation, useFetchUserDetailsQuery, useGeneralGQLQuery, useGetAISearchStatusQuery, useGetAISearchVersionQuery, useGetAccessibleDataQuery, useGetActivePayModelQuery, useGetAggMDSQuery, useGetAggsQuery, useGetAllFieldsForTypeQuery, useGetArrayTypes, useGetAuthzMappingsQuery, useGetAuthzResourcesQuery, useGetCSRFQuery, useGetCohortManifestQuery, useGetCountsQuery, useGetCredentialsQuery, useGetCrosswalkDataQuery, useGetDataQuery, useGetDictionaryQuery, useGetDownloadQuery, useGetExternalLoginsQuery, useGetFederatedLoginStatus, useGetFieldCountSummaryQuery, useGetFieldsForIndexQuery, useGetFileFromManifestQuery, useGetFileManifestQuery, useGetIndexAggMDSQuery, useGetIndexFields, useGetJWKKeysQuery, useGetLoginProvidersQuery, useGetMDSQuery, useGetManifestServiceStatusQuery, useGetMetadataByIdQuery, useGetMetadataFromManifestQuery, useGetMetadataManifestQuery, useGetProjectsDetailsQuery, useGetProjectsQuery, useGetRawDataAndTotalCountsQuery, useGetSharedFieldsForIndexQuery, useGetSowerJobListQuery, useGetSowerJobStatusQuery, useGetSowerOutputQuery, useGetSowerServiceStatusQuery, useGetStatsAggregationsQuery, useGetStatus, useGetSubAggsQuery, useGetSubmissionGraphQLQuery, useGetSubmissionsQuery, useGetTagsQuery, useGetWorkspaceOptionsQuery, useGetWorkspacePayModelsQuery, useGetWorkspaceStatusQuery, useGraphQLQuery, useIsExternalConnectedQuery, useIsUserLoggedIn, useLaunchWorkspaceMutation, useLazyFetchUserDetailsQuery, useLazyGeneralGQLQuery, useLazyGetAggsQuery, useLazyGetAuthzMappingsQuery, useLazyGetAuthzResourcesQuery, useLazyGetCSRFQuery, useLazyGetCountsQuery, useLazyGetCrosswalkDataQuery, useLazyGetDownloadQuery, useLazyGetExternalLoginsQuery, useLazyGetManifestServiceStatusQuery, useLazyGetProjectsQuery, useLazyGetSowerJobListQuery, useLazyGetStatsAggregationsQuery, useLazyGetSubmissionGraphQLQuery, useLazyIsExternalConnectedQuery, useLazyRequestQuery, usePrevious, useRemoveCredentialMutation, useRequestByIdQuery, useRequestQuery, useRequestorStatusQuery, useSetCurrentPayModelMutation, useSubmitSowerJobMutation, useTerminateWorkspaceMutation, useUserAuth, useUserRequestQuery, userHasCreateOrUpdateOnAnyProject, userHasDataUpload, userHasMethodForServiceOnProject, userHasMethodForServiceOnResource, userHasMethodOnAnyProject, userHasSheepdogProgramAdmin, userHasSheepdogProjectAdmin };
|
|
5605
5800
|
//# sourceMappingURL=index.js.map
|