@gen3/core 0.11.33 → 0.11.35
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 +782 -710
- 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/types.d.ts +7 -0
- package/dist/dts/features/filters/types.d.ts.map +1 -1
- package/dist/dts/features/guppy/guppySlice.d.ts +61 -14
- package/dist/dts/features/guppy/guppySlice.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/esm/index.js +771 -711
- 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 +433 -209
- package/dist/server.d.ts +31 -0
- package/package.json +7 -2
package/dist/cjs/index.js
CHANGED
|
@@ -8,9 +8,9 @@ var reactRedux = require('react-redux');
|
|
|
8
8
|
var React = require('react');
|
|
9
9
|
var graphql = require('graphql');
|
|
10
10
|
var jsonpathPlus = require('jsonpath-plus');
|
|
11
|
+
var lodash = require('lodash');
|
|
11
12
|
var nanoid$1 = require('nanoid');
|
|
12
13
|
var useSWR = require('swr');
|
|
13
|
-
var lodash = require('lodash');
|
|
14
14
|
var flat = require('flat');
|
|
15
15
|
var Papa = require('papaparse');
|
|
16
16
|
var reduxPersist = require('redux-persist');
|
|
@@ -72,6 +72,7 @@ const FILE_DELIMITERS = {
|
|
|
72
72
|
tsv: '\t',
|
|
73
73
|
csv: ','
|
|
74
74
|
};
|
|
75
|
+
const CART_LIMIT = 10000;
|
|
75
76
|
|
|
76
77
|
const isFetchError = (obj)=>{
|
|
77
78
|
if (typeof obj !== 'object' || obj === null) {
|
|
@@ -426,7 +427,7 @@ const useCoreDispatch = reactRedux.useDispatch.withTypes();
|
|
|
426
427
|
});
|
|
427
428
|
const isAuthenticated = (loginStatus)=>loginStatus === 'authenticated';
|
|
428
429
|
const isPending = (loginStatus)=>loginStatus === 'pending';
|
|
429
|
-
const initialState$
|
|
430
|
+
const initialState$9 = {
|
|
430
431
|
status: 'uninitialized',
|
|
431
432
|
loginStatus: 'unauthenticated',
|
|
432
433
|
error: undefined
|
|
@@ -437,9 +438,9 @@ const initialState$8 = {
|
|
|
437
438
|
* @returns: status messages wrapped around fetchUserState response dict
|
|
438
439
|
*/ const slice$4 = toolkit.createSlice({
|
|
439
440
|
name: 'fence/user',
|
|
440
|
-
initialState: initialState$
|
|
441
|
+
initialState: initialState$9,
|
|
441
442
|
reducers: {
|
|
442
|
-
resetUserState: ()=>initialState$
|
|
443
|
+
resetUserState: ()=>initialState$9
|
|
443
444
|
},
|
|
444
445
|
extraReducers: (builder)=>{
|
|
445
446
|
builder.addCase(fetchUserState.fulfilled, (_, action)=>{
|
|
@@ -581,11 +582,11 @@ const { useGetExternalLoginsQuery, useLazyGetExternalLoginsQuery, useLazyIsExter
|
|
|
581
582
|
}
|
|
582
583
|
};
|
|
583
584
|
|
|
584
|
-
const initialState$
|
|
585
|
+
const initialState$8 = {};
|
|
585
586
|
// TODO: document what this does
|
|
586
587
|
const slice$3 = toolkit.createSlice({
|
|
587
588
|
name: 'drsResolver',
|
|
588
|
-
initialState: initialState$
|
|
589
|
+
initialState: initialState$8,
|
|
589
590
|
reducers: {
|
|
590
591
|
setDRSHostnames: (_state, action)=>{
|
|
591
592
|
return action.payload;
|
|
@@ -607,12 +608,12 @@ const lookupGen3App = (id)=>{
|
|
|
607
608
|
else return null;
|
|
608
609
|
};
|
|
609
610
|
|
|
610
|
-
const initialState$
|
|
611
|
+
const initialState$7 = {
|
|
611
612
|
gen3Apps: {}
|
|
612
613
|
};
|
|
613
614
|
const slice$2 = toolkit.createSlice({
|
|
614
615
|
name: 'gen3Apps',
|
|
615
|
-
initialState: initialState$
|
|
616
|
+
initialState: initialState$7,
|
|
616
617
|
reducers: {
|
|
617
618
|
addGen3AppMetadata: (state, action)=>{
|
|
618
619
|
const { name, requiredEntityTypes } = action.payload;
|
|
@@ -643,13 +644,13 @@ const selectGen3AppByName = (appName)=>lookupGen3App(appName); // TODO: memoize
|
|
|
643
644
|
Modals["GeneralErrorModal"] = "GeneralErrorModal";
|
|
644
645
|
return Modals;
|
|
645
646
|
}({});
|
|
646
|
-
const initialState$
|
|
647
|
+
const initialState$6 = {
|
|
647
648
|
currentModal: null
|
|
648
649
|
};
|
|
649
650
|
//Creates a modal slice for tracking showModal and hideModal state.
|
|
650
651
|
const slice$1 = toolkit.createSlice({
|
|
651
652
|
name: 'modals',
|
|
652
|
-
initialState: initialState$
|
|
653
|
+
initialState: initialState$6,
|
|
653
654
|
reducers: {
|
|
654
655
|
showModal: (state, action)=>{
|
|
655
656
|
state.currentModal = action.payload.modal;
|
|
@@ -722,7 +723,7 @@ const getTimestamp = ()=>{
|
|
|
722
723
|
};
|
|
723
724
|
|
|
724
725
|
const NO_WORKSPACE_ID = 'none';
|
|
725
|
-
const initialState$
|
|
726
|
+
const initialState$5 = {
|
|
726
727
|
id: NO_WORKSPACE_ID,
|
|
727
728
|
status: WorkspaceStatus.NotFound,
|
|
728
729
|
requestedStatus: RequestedWorkspaceStatus.Unset,
|
|
@@ -730,7 +731,7 @@ const initialState$4 = {
|
|
|
730
731
|
};
|
|
731
732
|
const slice = toolkit.createSlice({
|
|
732
733
|
name: 'ActiveWorkspace',
|
|
733
|
-
initialState: initialState$
|
|
734
|
+
initialState: initialState$5,
|
|
734
735
|
reducers: {
|
|
735
736
|
setActiveWorkspaceId: (state, action)=>{
|
|
736
737
|
state = {
|
|
@@ -772,6 +773,25 @@ const selectActiveWorkspaceStatus = (state)=>state.activeWorkspace.status;
|
|
|
772
773
|
const selectRequestedWorkspaceStatus = (state)=>state.activeWorkspace.requestedStatus;
|
|
773
774
|
const selectRequestedWorkspaceStatusTimestamp = (state)=>state.activeWorkspace.requestedStatusTimestamp;
|
|
774
775
|
|
|
776
|
+
const cartAdapter = toolkit.createEntityAdapter({
|
|
777
|
+
selectId: (item)=>item.id
|
|
778
|
+
});
|
|
779
|
+
const initialState$4 = cartAdapter.getInitialState({});
|
|
780
|
+
const cartSlice = toolkit.createSlice({
|
|
781
|
+
name: 'cart',
|
|
782
|
+
initialState: initialState$4,
|
|
783
|
+
reducers: {
|
|
784
|
+
addItemsToCart: cartAdapter.addMany,
|
|
785
|
+
removeItemsFromCart: cartAdapter.removeMany
|
|
786
|
+
}
|
|
787
|
+
});
|
|
788
|
+
const cartReducer = cartSlice.reducer;
|
|
789
|
+
const { addItemsToCart, removeItemsFromCart } = cartSlice.actions;
|
|
790
|
+
|
|
791
|
+
const { selectById: selectCartItem, selectIds: selectCartItems, selectAll: selectCart, selectTotal: selectCartCount } = cartAdapter.getSelectors((state)=>state.cart);
|
|
792
|
+
|
|
793
|
+
const cartReducerPath = 'cart';
|
|
794
|
+
|
|
775
795
|
/**
|
|
776
796
|
* Creates a base class core API for guppy API calls.
|
|
777
797
|
* @returns: guppy core API with guppyAPIFetch base query
|
|
@@ -829,578 +849,176 @@ const guppyAPISliceMiddleware = guppyApi.middleware;
|
|
|
829
849
|
const guppyApiSliceReducerPath = guppyApi.reducerPath;
|
|
830
850
|
const guppyApiReducer = guppyApi.reducer;
|
|
831
851
|
|
|
832
|
-
const
|
|
833
|
-
|
|
834
|
-
hour12: false
|
|
835
|
-
}).replace(',', '')}`;
|
|
836
|
-
const isNameUnique = (entities, name, excludeId)=>{
|
|
837
|
-
const trimmedName = name.trim();
|
|
838
|
-
if (!trimmedName) return false;
|
|
839
|
-
return !entities.some((cohort)=>cohort && cohort.id !== excludeId && cohort.name.trim().toLowerCase() === trimmedName.toLowerCase());
|
|
852
|
+
const isOperationWithField = (operation)=>{
|
|
853
|
+
return operation?.field !== undefined;
|
|
840
854
|
};
|
|
841
|
-
const
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
return
|
|
855
|
+
const isOperatorWithFieldAndArrayOfOperands = (operation)=>{
|
|
856
|
+
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
|
|
857
|
+
) {
|
|
858
|
+
const { operator } = operation.operator;
|
|
859
|
+
return operator === 'in' || operator === 'exclude' || operator === 'excludeifany';
|
|
860
|
+
}
|
|
861
|
+
return false;
|
|
862
|
+
};
|
|
863
|
+
const extractFilterValue = (op)=>{
|
|
864
|
+
const valueExtractorHandler = new ValueExtractorHandler();
|
|
865
|
+
return handleOperation(valueExtractorHandler, op);
|
|
866
|
+
};
|
|
867
|
+
const extractEnumFilterValue = (op)=>{
|
|
868
|
+
const enumValueExtractorHandler = new EnumValueExtractorHandler();
|
|
869
|
+
const results = handleOperation(enumValueExtractorHandler, op);
|
|
870
|
+
return results ?? [];
|
|
871
|
+
};
|
|
872
|
+
const assertNever = (x)=>{
|
|
873
|
+
throw Error(`Exhaustive comparison did not handle: ${x}`);
|
|
874
|
+
};
|
|
875
|
+
const handleOperation = (handler, op)=>{
|
|
876
|
+
switch(op.operator){
|
|
877
|
+
case '=':
|
|
878
|
+
return handler.handleEquals(op);
|
|
879
|
+
case '!=':
|
|
880
|
+
return handler.handleNotEquals(op);
|
|
881
|
+
case '<':
|
|
882
|
+
return handler.handleLessThan(op);
|
|
883
|
+
case '<=':
|
|
884
|
+
return handler.handleLessThanOrEquals(op);
|
|
885
|
+
case '>':
|
|
886
|
+
return handler.handleGreaterThan(op);
|
|
887
|
+
case '>=':
|
|
888
|
+
return handler.handleGreaterThanOrEquals(op);
|
|
889
|
+
case 'and':
|
|
890
|
+
return handler.handleIntersection(op);
|
|
891
|
+
case 'or':
|
|
892
|
+
return handler.handleUnion(op);
|
|
893
|
+
case 'nested':
|
|
894
|
+
return handler.handleNestedFilter(op);
|
|
895
|
+
case 'in':
|
|
896
|
+
case 'includes':
|
|
897
|
+
return handler.handleIncludes(op);
|
|
898
|
+
case 'excludeifany':
|
|
899
|
+
return handler.handleExcludeIfAny(op);
|
|
900
|
+
case 'excludes':
|
|
901
|
+
return handler.handleExcludes(op);
|
|
902
|
+
case 'exists':
|
|
903
|
+
return handler.handleExists(op);
|
|
904
|
+
case 'missing':
|
|
905
|
+
return handler.handleMissing(op);
|
|
906
|
+
default:
|
|
907
|
+
return assertNever(op);
|
|
846
908
|
}
|
|
847
|
-
// Find a unique name by appending numbers
|
|
848
|
-
let counter = 1;
|
|
849
|
-
let uniqueName;
|
|
850
|
-
do {
|
|
851
|
-
uniqueName = `${trimmedBaseName} (${counter})`;
|
|
852
|
-
counter++;
|
|
853
|
-
}while (!isNameUnique(entities, uniqueName))
|
|
854
|
-
return uniqueName;
|
|
855
909
|
};
|
|
856
|
-
|
|
857
910
|
/**
|
|
858
|
-
*
|
|
859
|
-
*
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
return
|
|
867
|
-
name: newName,
|
|
868
|
-
id: newId,
|
|
869
|
-
filters: filters ?? {},
|
|
870
|
-
modified: false,
|
|
871
|
-
saved: false,
|
|
872
|
-
createdDatetime: ts,
|
|
873
|
-
modifiedDatetime: ts,
|
|
874
|
-
counts: {}
|
|
875
|
-
};
|
|
911
|
+
* Return true if a FilterSet's root value is an empty object
|
|
912
|
+
* @param fs - FilterSet to test
|
|
913
|
+
*/ const isFilterEmpty = (fs)=>lodash.isEqual({}, fs);
|
|
914
|
+
/**
|
|
915
|
+
* Type guard to check if an object is a GQLIntersection
|
|
916
|
+
* @param value - The value to check
|
|
917
|
+
* @returns True if the value is a GQLIntersection
|
|
918
|
+
*/ const isGQLIntersection = (value)=>{
|
|
919
|
+
return typeof value === 'object' && value !== null && 'and' in value && Array.isArray(value.and);
|
|
876
920
|
};
|
|
877
|
-
const nanoid = nanoid$1.customAlphabet('1234567890abcdef', 16);
|
|
878
|
-
const createCohortId = ()=>nanoid();
|
|
879
|
-
const cohortsAdapter = toolkit.createEntityAdapter({
|
|
880
|
-
sortComparer: (a, b)=>{
|
|
881
|
-
if (a.modifiedDatetime <= b.modifiedDatetime) return 1;
|
|
882
|
-
else return -1;
|
|
883
|
-
},
|
|
884
|
-
selectId: (cohort)=>cohort.id
|
|
885
|
-
});
|
|
886
|
-
// Create an initial unsaved cohort
|
|
887
|
-
const initialCohort = newCohort({
|
|
888
|
-
customName: DEFAULT_COHORT_NAME
|
|
889
|
-
});
|
|
890
|
-
const emptyInitialState = cohortsAdapter.getInitialState({
|
|
891
|
-
currentCohortId: initialCohort.id,
|
|
892
|
-
message: undefined
|
|
893
|
-
});
|
|
894
|
-
// Set the initial cohort in the adapter state
|
|
895
|
-
const initialState$3 = cohortsAdapter.setOne(emptyInitialState, initialCohort);
|
|
896
|
-
const getCurrentCohortId = (state)=>state.currentCohortId;
|
|
897
921
|
/**
|
|
898
|
-
*
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
922
|
+
* Type guard to check if an object is a GQLIntersection
|
|
923
|
+
* @param value - The value to check
|
|
924
|
+
* @returns True if the value is a GQLIntersection
|
|
925
|
+
*/ const isGQLUnion = (value)=>{
|
|
926
|
+
return typeof value === 'object' && value !== null && 'or' in value && Array.isArray(value.or);
|
|
927
|
+
};
|
|
928
|
+
class ToGqlHandler {
|
|
929
|
+
constructor(){
|
|
930
|
+
this.handleEquals = (op)=>({
|
|
931
|
+
'=': {
|
|
932
|
+
[op.field]: op.operand
|
|
933
|
+
}
|
|
909
934
|
});
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
updateCohortName: (state, action)=>{
|
|
914
|
-
const { id, name } = action.payload;
|
|
915
|
-
cohortsAdapter.updateOne(state, {
|
|
916
|
-
id: id,
|
|
917
|
-
changes: {
|
|
918
|
-
name: name,
|
|
919
|
-
modified: true,
|
|
920
|
-
modifiedDatetime: new Date().toISOString()
|
|
935
|
+
this.handleNotEquals = (op)=>({
|
|
936
|
+
'!=': {
|
|
937
|
+
[op.field]: op.operand
|
|
921
938
|
}
|
|
922
939
|
});
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
const removedCohortName = state.entities[cohortId].name;
|
|
927
|
-
const totalCohorts = Object.keys(state.entities).length;
|
|
928
|
-
if (totalCohorts <= 1) {
|
|
929
|
-
cohortsAdapter.removeAll(state);
|
|
930
|
-
const defaultCohort = newCohort({
|
|
931
|
-
filters: {},
|
|
932
|
-
customName: DEFAULT_COHORT_NAME
|
|
933
|
-
});
|
|
934
|
-
cohortsAdapter.addOne(state, defaultCohort);
|
|
935
|
-
state.currentCohortId = defaultCohort.id;
|
|
936
|
-
if (action?.payload.shouldShowMessage) {
|
|
937
|
-
state.message = [
|
|
938
|
-
`deleteCohort|${removedCohortName}|${state.currentCohortId}`
|
|
939
|
-
];
|
|
940
|
+
this.handleLessThan = (op)=>({
|
|
941
|
+
'<': {
|
|
942
|
+
[op.field]: op.operand
|
|
940
943
|
}
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
if (state.currentCohortId === cohortId) {
|
|
946
|
-
const remainingIds = Object.keys(state.entities);
|
|
947
|
-
state.currentCohortId = remainingIds[0];
|
|
948
|
-
}
|
|
949
|
-
if (action?.payload.shouldShowMessage) {
|
|
950
|
-
state.message = [
|
|
951
|
-
`deleteCohort|${removedCohortName}|${state.currentCohortId}`
|
|
952
|
-
];
|
|
953
|
-
}
|
|
954
|
-
},
|
|
955
|
-
// adds a filter to the cohort filter set at the given index
|
|
956
|
-
updateCohortFilter: (state, action)=>{
|
|
957
|
-
const { index, field, filter } = action.payload;
|
|
958
|
-
const currentCohortId = getCurrentCohortId(state);
|
|
959
|
-
if (!state.entities[currentCohortId]) {
|
|
960
|
-
return;
|
|
961
|
-
}
|
|
962
|
-
cohortsAdapter.updateOne(state, {
|
|
963
|
-
id: currentCohortId,
|
|
964
|
-
changes: {
|
|
965
|
-
filters: {
|
|
966
|
-
...state.entities[currentCohortId].filters,
|
|
967
|
-
[index]: {
|
|
968
|
-
mode: state.entities[currentCohortId]?.filters[index]?.mode ?? 'and',
|
|
969
|
-
root: {
|
|
970
|
-
...state.entities[currentCohortId]?.filters[index]?.root ?? {},
|
|
971
|
-
[field]: filter
|
|
972
|
-
}
|
|
973
|
-
}
|
|
974
|
-
},
|
|
975
|
-
modified: true,
|
|
976
|
-
modifiedDatetime: new Date().toISOString()
|
|
944
|
+
});
|
|
945
|
+
this.handleLessThanOrEquals = (op)=>({
|
|
946
|
+
'<=': {
|
|
947
|
+
[op.field]: op.operand
|
|
977
948
|
}
|
|
978
949
|
});
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
const currentCohortId = getCurrentCohortId(state);
|
|
983
|
-
if (!state.entities[currentCohortId]) {
|
|
984
|
-
console.error(`no cohort with id=${currentCohortId} defined`);
|
|
985
|
-
return;
|
|
986
|
-
}
|
|
987
|
-
cohortsAdapter.updateOne(state, {
|
|
988
|
-
id: currentCohortId,
|
|
989
|
-
changes: {
|
|
990
|
-
filters: {
|
|
991
|
-
...state.entities[currentCohortId].filters,
|
|
992
|
-
[index]: filters
|
|
993
|
-
},
|
|
994
|
-
modified: true,
|
|
995
|
-
modifiedDatetime: new Date().toISOString()
|
|
950
|
+
this.handleGreaterThan = (op)=>({
|
|
951
|
+
'>': {
|
|
952
|
+
[op.field]: op.operand
|
|
996
953
|
}
|
|
997
954
|
});
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
if (!state.entities[currentCohortId]) {
|
|
1002
|
-
console.error(`no cohort with id=${currentCohortId} defined`);
|
|
1003
|
-
return;
|
|
1004
|
-
}
|
|
1005
|
-
cohortsAdapter.updateOne(state, {
|
|
1006
|
-
id: currentCohortId,
|
|
1007
|
-
changes: {
|
|
1008
|
-
filters: action.payload.filters,
|
|
1009
|
-
modified: true,
|
|
1010
|
-
modifiedDatetime: new Date().toISOString()
|
|
955
|
+
this.handleGreaterThanOrEquals = (op)=>({
|
|
956
|
+
'>=': {
|
|
957
|
+
[op.field]: op.operand
|
|
1011
958
|
}
|
|
1012
959
|
});
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
const { index, field } = action.payload;
|
|
1017
|
-
const currentCohortId = getCurrentCohortId(state);
|
|
1018
|
-
if (!state.entities[currentCohortId]) {
|
|
1019
|
-
console.error(`no cohort with id=${currentCohortId} defined`);
|
|
1020
|
-
return;
|
|
1021
|
-
}
|
|
1022
|
-
const filters = state.entities[currentCohortId]?.filters[index]?.root;
|
|
1023
|
-
if (!filters) {
|
|
1024
|
-
return;
|
|
1025
|
-
}
|
|
1026
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1027
|
-
const { [field]: _a, ...updated } = filters;
|
|
1028
|
-
cohortsAdapter.updateOne(state, {
|
|
1029
|
-
id: currentCohortId,
|
|
1030
|
-
changes: {
|
|
1031
|
-
filters: {
|
|
1032
|
-
...state.entities[currentCohortId]?.filters,
|
|
1033
|
-
[index]: {
|
|
1034
|
-
mode: state.entities[currentCohortId].filters[index].mode,
|
|
1035
|
-
root: updated
|
|
1036
|
-
}
|
|
1037
|
-
},
|
|
1038
|
-
modified: true,
|
|
1039
|
-
modifiedDatetime: new Date().toISOString()
|
|
960
|
+
this.handleIncludes = (op)=>({
|
|
961
|
+
in: {
|
|
962
|
+
[op.field]: op.operands
|
|
1040
963
|
}
|
|
1041
964
|
});
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
const currentCohort = state.entities[currentCohortId];
|
|
1046
|
-
const newName = generateUniqueName(Object.values(state.entities), currentCohort.name);
|
|
1047
|
-
const duplicatedCohort = newCohort({
|
|
1048
|
-
filters: {
|
|
1049
|
-
...currentCohort.filters
|
|
1050
|
-
},
|
|
1051
|
-
customName: newName
|
|
1052
|
-
});
|
|
1053
|
-
cohortsAdapter.addOne(state, {
|
|
1054
|
-
...duplicatedCohort,
|
|
1055
|
-
counts: {
|
|
1056
|
-
...currentCohort.counts
|
|
965
|
+
this.handleExcludes = (op)=>({
|
|
966
|
+
exclude: {
|
|
967
|
+
[op.field]: op.operands
|
|
1057
968
|
}
|
|
1058
969
|
});
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
clearCohortFilters: (state, action)=>{
|
|
1063
|
-
const { index } = action.payload;
|
|
1064
|
-
const currentCohortId = getCurrentCohortId(state);
|
|
1065
|
-
if (!state.entities[currentCohortId]) {
|
|
1066
|
-
console.error(`no cohort with id=${currentCohortId} defined`);
|
|
1067
|
-
return;
|
|
1068
|
-
}
|
|
1069
|
-
const filters = state.entities[currentCohortId]?.filters[index]?.root;
|
|
1070
|
-
if (!filters) {
|
|
1071
|
-
return;
|
|
1072
|
-
}
|
|
1073
|
-
cohortsAdapter.updateOne(state, {
|
|
1074
|
-
id: currentCohortId,
|
|
1075
|
-
changes: {
|
|
1076
|
-
filters: {
|
|
1077
|
-
...state.entities[currentCohortId]?.filters,
|
|
1078
|
-
[index]: {
|
|
1079
|
-
mode: 'and',
|
|
1080
|
-
root: {}
|
|
1081
|
-
}
|
|
1082
|
-
},
|
|
1083
|
-
modified: true,
|
|
1084
|
-
modifiedDatetime: new Date().toISOString()
|
|
970
|
+
this.handleExcludeIfAny = (op)=>({
|
|
971
|
+
excludeifany: {
|
|
972
|
+
[op.field]: op.operands
|
|
1085
973
|
}
|
|
1086
974
|
});
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
const currentCohortId = getCurrentCohortId(state);
|
|
1090
|
-
const currentCohort = state.entities[currentCohortId];
|
|
1091
|
-
cohortsAdapter.updateOne(state, {
|
|
1092
|
-
id: currentCohortId,
|
|
1093
|
-
changes: {
|
|
1094
|
-
counts: {
|
|
1095
|
-
...currentCohort.counts,
|
|
1096
|
-
...action.payload
|
|
1097
|
-
}
|
|
1098
|
-
}
|
|
975
|
+
this.handleIntersection = (op)=>({
|
|
976
|
+
and: op.operands.map((x)=>convertFilterToGqlFilter(x))
|
|
1099
977
|
});
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
changes: {
|
|
1107
|
-
counts: {
|
|
1108
|
-
...cohort.counts,
|
|
1109
|
-
...{
|
|
1110
|
-
[index]: counts
|
|
1111
|
-
}
|
|
1112
|
-
}
|
|
978
|
+
this.handleUnion = (op)=>({
|
|
979
|
+
or: op.operands.map((x)=>convertFilterToGqlFilter(x))
|
|
980
|
+
});
|
|
981
|
+
this.handleMissing = (op)=>({
|
|
982
|
+
is: {
|
|
983
|
+
[op.field]: 'MISSING'
|
|
1113
984
|
}
|
|
1114
985
|
});
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
},
|
|
1119
|
-
/** @hidden */ setCohortList: (state, action)=>{
|
|
1120
|
-
if (!action.payload) {
|
|
1121
|
-
cohortsAdapter.removeMany(state, state.ids);
|
|
1122
|
-
} else {
|
|
1123
|
-
cohortsAdapter.upsertMany(state, [
|
|
1124
|
-
...action.payload
|
|
1125
|
-
]);
|
|
1126
|
-
}
|
|
1127
|
-
}
|
|
1128
|
-
}
|
|
1129
|
-
});
|
|
1130
|
-
/**
|
|
1131
|
-
* Returns the selectors for the cohorts EntityAdapter
|
|
1132
|
-
* @param state - the CoreState
|
|
1133
|
-
*
|
|
1134
|
-
* @hidden
|
|
1135
|
-
*/ const cohortSelectors = cohortsAdapter.getSelectors((state)=>state.cohorts.cohortManager);
|
|
1136
|
-
// Filter actions: addFilter, removeFilter, updateFilter
|
|
1137
|
-
const { createNewCohort, updateCohortFilter, setCohortFilter, setCohortIndexFilters, duplicateCohort, removeCohortFilter, clearCohortFilters, removeCohort, setCurrentCohortId, updateCohortName, updateCohortCounts, updateCohortIndexCountById, setCohortList } = cohortManagerSlice.actions;
|
|
1138
|
-
const cohortReducer = cohortManagerSlice.reducer;
|
|
1139
|
-
|
|
1140
|
-
const initialState$2 = {};
|
|
1141
|
-
const expandSlice$1 = toolkit.createSlice({
|
|
1142
|
-
name: 'CohortBuilder/filterExpand',
|
|
1143
|
-
initialState: initialState$2,
|
|
1144
|
-
reducers: {
|
|
1145
|
-
toggleCohortBuilderCategoryFilter: (state, action)=>{
|
|
1146
|
-
return {
|
|
1147
|
-
...state,
|
|
1148
|
-
[action.payload.index]: {
|
|
1149
|
-
...state[action.payload.index],
|
|
1150
|
-
[action.payload.field]: action.payload.expanded
|
|
986
|
+
this.handleExists = (op)=>({
|
|
987
|
+
not: {
|
|
988
|
+
[op.field]: op?.operand ?? null
|
|
1151
989
|
}
|
|
1152
|
-
};
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
return {
|
|
1156
|
-
...state,
|
|
1157
|
-
[action.payload.index]: Object.keys(state[action.payload.index]).reduce((acc, k)=>{
|
|
1158
|
-
acc[k] = action.payload.expand;
|
|
1159
|
-
return acc;
|
|
1160
|
-
}, {})
|
|
1161
|
-
};
|
|
1162
|
-
}
|
|
1163
|
-
}
|
|
1164
|
-
});
|
|
1165
|
-
const cohortBuilderFiltersExpandedReducer = expandSlice$1.reducer;
|
|
1166
|
-
const { toggleCohortBuilderCategoryFilter, toggleCohortBuilderAllFilters } = expandSlice$1.actions;
|
|
1167
|
-
const selectCohortFilterExpanded = (state, index, field)=>state.cohorts.filtersExpanded?.[index]?.[field];
|
|
1168
|
-
const selectAllCohortFiltersCollapsed = (state, index)=>index in state.cohorts.filtersExpanded ? Object.values(state.cohorts.filtersExpanded?.[index]).every((e)=>!e) : false;
|
|
1169
|
-
|
|
1170
|
-
const initialState$1 = {};
|
|
1171
|
-
const expandSlice = toolkit.createSlice({
|
|
1172
|
-
name: 'CohortBuilder/filterCombineMode',
|
|
1173
|
-
initialState: initialState$1,
|
|
1174
|
-
reducers: {
|
|
1175
|
-
setCohortFilterCombineMode: (state, action)=>{
|
|
990
|
+
});
|
|
991
|
+
this.handleNestedFilter = (op)=>{
|
|
992
|
+
const child = convertFilterToGqlFilter(op.operand);
|
|
1176
993
|
return {
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
...
|
|
1180
|
-
[action.payload.field]: action.payload.mode
|
|
994
|
+
nested: {
|
|
995
|
+
path: op.path,
|
|
996
|
+
...child
|
|
1181
997
|
}
|
|
1182
998
|
};
|
|
1183
|
-
}
|
|
999
|
+
};
|
|
1184
1000
|
}
|
|
1185
|
-
}
|
|
1186
|
-
const
|
|
1187
|
-
const
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
const initialState = {
|
|
1191
|
-
shouldShareFilters: false,
|
|
1192
|
-
sharedFiltersMap: {}
|
|
1001
|
+
}
|
|
1002
|
+
const convertFilterToGqlFilter = (filter)=>{
|
|
1003
|
+
const handler = new ToGqlHandler();
|
|
1004
|
+
return handleOperation(handler, filter);
|
|
1193
1005
|
};
|
|
1194
|
-
const
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
const
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
field
|
|
1211
|
-
];
|
|
1212
|
-
const { setShouldShareFilters, setSharedFilters } = cohortSharedFiltersSlice.actions;
|
|
1213
|
-
const cohortSharedFiltersReducer = cohortSharedFiltersSlice.reducer;
|
|
1214
|
-
|
|
1215
|
-
const cohortReducers = toolkit.combineReducers({
|
|
1216
|
-
filtersExpanded: cohortBuilderFiltersExpandedReducer,
|
|
1217
|
-
filtersCombineMode: cohortBuilderFiltersCombineModeReducer,
|
|
1218
|
-
sharedFilters: cohortSharedFiltersReducer,
|
|
1219
|
-
cohortManager: cohortReducer
|
|
1220
|
-
});
|
|
1221
|
-
|
|
1222
|
-
const rootReducer = toolkit.combineReducers({
|
|
1223
|
-
gen3Services: gen3ServicesReducer,
|
|
1224
|
-
user: userReducer,
|
|
1225
|
-
gen3Apps: gen3AppReducer,
|
|
1226
|
-
drsHostnames: drsHostnamesReducer,
|
|
1227
|
-
modals: modalReducer,
|
|
1228
|
-
cohorts: cohortReducers,
|
|
1229
|
-
activeWorkspace: activeWorkspaceReducer,
|
|
1230
|
-
[guppyApiSliceReducerPath]: guppyApiReducer,
|
|
1231
|
-
[userAuthApiReducerPath]: userAuthApiReducer
|
|
1232
|
-
});
|
|
1233
|
-
|
|
1234
|
-
const isOperationWithField = (operation)=>{
|
|
1235
|
-
return operation?.field !== undefined;
|
|
1236
|
-
};
|
|
1237
|
-
const isOperatorWithFieldAndArrayOfOperands = (operation)=>{
|
|
1238
|
-
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
|
|
1239
|
-
) {
|
|
1240
|
-
const { operator } = operation.operator;
|
|
1241
|
-
return operator === 'in' || operator === 'exclude' || operator === 'excludeifany';
|
|
1242
|
-
}
|
|
1243
|
-
return false;
|
|
1244
|
-
};
|
|
1245
|
-
const extractFilterValue = (op)=>{
|
|
1246
|
-
const valueExtractorHandler = new ValueExtractorHandler();
|
|
1247
|
-
return handleOperation(valueExtractorHandler, op);
|
|
1248
|
-
};
|
|
1249
|
-
const extractEnumFilterValue = (op)=>{
|
|
1250
|
-
const enumValueExtractorHandler = new EnumValueExtractorHandler();
|
|
1251
|
-
const results = handleOperation(enumValueExtractorHandler, op);
|
|
1252
|
-
return results ?? [];
|
|
1253
|
-
};
|
|
1254
|
-
const assertNever = (x)=>{
|
|
1255
|
-
throw Error(`Exhaustive comparison did not handle: ${x}`);
|
|
1256
|
-
};
|
|
1257
|
-
const handleOperation = (handler, op)=>{
|
|
1258
|
-
switch(op.operator){
|
|
1259
|
-
case '=':
|
|
1260
|
-
return handler.handleEquals(op);
|
|
1261
|
-
case '!=':
|
|
1262
|
-
return handler.handleNotEquals(op);
|
|
1263
|
-
case '<':
|
|
1264
|
-
return handler.handleLessThan(op);
|
|
1265
|
-
case '<=':
|
|
1266
|
-
return handler.handleLessThanOrEquals(op);
|
|
1267
|
-
case '>':
|
|
1268
|
-
return handler.handleGreaterThan(op);
|
|
1269
|
-
case '>=':
|
|
1270
|
-
return handler.handleGreaterThanOrEquals(op);
|
|
1271
|
-
case 'and':
|
|
1272
|
-
return handler.handleIntersection(op);
|
|
1273
|
-
case 'or':
|
|
1274
|
-
return handler.handleUnion(op);
|
|
1275
|
-
case 'nested':
|
|
1276
|
-
return handler.handleNestedFilter(op);
|
|
1277
|
-
case 'in':
|
|
1278
|
-
case 'includes':
|
|
1279
|
-
return handler.handleIncludes(op);
|
|
1280
|
-
case 'excludeifany':
|
|
1281
|
-
return handler.handleExcludeIfAny(op);
|
|
1282
|
-
case 'excludes':
|
|
1283
|
-
return handler.handleExcludes(op);
|
|
1284
|
-
case 'exists':
|
|
1285
|
-
return handler.handleExists(op);
|
|
1286
|
-
case 'missing':
|
|
1287
|
-
return handler.handleMissing(op);
|
|
1288
|
-
default:
|
|
1289
|
-
return assertNever(op);
|
|
1290
|
-
}
|
|
1291
|
-
};
|
|
1292
|
-
/**
|
|
1293
|
-
* Return true if a FilterSet's root value is an empty object
|
|
1294
|
-
* @param fs - FilterSet to test
|
|
1295
|
-
*/ const isFilterEmpty = (fs)=>lodash.isEqual({}, fs);
|
|
1296
|
-
/**
|
|
1297
|
-
* Type guard to check if an object is a GQLIntersection
|
|
1298
|
-
* @param value - The value to check
|
|
1299
|
-
* @returns True if the value is a GQLIntersection
|
|
1300
|
-
*/ const isGQLIntersection = (value)=>{
|
|
1301
|
-
return typeof value === 'object' && value !== null && 'and' in value && Array.isArray(value.and);
|
|
1302
|
-
};
|
|
1303
|
-
/**
|
|
1304
|
-
* Type guard to check if an object is a GQLIntersection
|
|
1305
|
-
* @param value - The value to check
|
|
1306
|
-
* @returns True if the value is a GQLIntersection
|
|
1307
|
-
*/ const isGQLUnion = (value)=>{
|
|
1308
|
-
return typeof value === 'object' && value !== null && 'or' in value && Array.isArray(value.or);
|
|
1309
|
-
};
|
|
1310
|
-
class ToGqlHandler {
|
|
1311
|
-
constructor(){
|
|
1312
|
-
this.handleEquals = (op)=>({
|
|
1313
|
-
'=': {
|
|
1314
|
-
[op.field]: op.operand
|
|
1315
|
-
}
|
|
1316
|
-
});
|
|
1317
|
-
this.handleNotEquals = (op)=>({
|
|
1318
|
-
'!=': {
|
|
1319
|
-
[op.field]: op.operand
|
|
1320
|
-
}
|
|
1321
|
-
});
|
|
1322
|
-
this.handleLessThan = (op)=>({
|
|
1323
|
-
'<': {
|
|
1324
|
-
[op.field]: op.operand
|
|
1325
|
-
}
|
|
1326
|
-
});
|
|
1327
|
-
this.handleLessThanOrEquals = (op)=>({
|
|
1328
|
-
'<=': {
|
|
1329
|
-
[op.field]: op.operand
|
|
1330
|
-
}
|
|
1331
|
-
});
|
|
1332
|
-
this.handleGreaterThan = (op)=>({
|
|
1333
|
-
'>': {
|
|
1334
|
-
[op.field]: op.operand
|
|
1335
|
-
}
|
|
1336
|
-
});
|
|
1337
|
-
this.handleGreaterThanOrEquals = (op)=>({
|
|
1338
|
-
'>=': {
|
|
1339
|
-
[op.field]: op.operand
|
|
1340
|
-
}
|
|
1341
|
-
});
|
|
1342
|
-
this.handleIncludes = (op)=>({
|
|
1343
|
-
in: {
|
|
1344
|
-
[op.field]: op.operands
|
|
1345
|
-
}
|
|
1346
|
-
});
|
|
1347
|
-
this.handleExcludes = (op)=>({
|
|
1348
|
-
exclude: {
|
|
1349
|
-
[op.field]: op.operands
|
|
1350
|
-
}
|
|
1351
|
-
});
|
|
1352
|
-
this.handleExcludeIfAny = (op)=>({
|
|
1353
|
-
excludeifany: {
|
|
1354
|
-
[op.field]: op.operands
|
|
1355
|
-
}
|
|
1356
|
-
});
|
|
1357
|
-
this.handleIntersection = (op)=>({
|
|
1358
|
-
and: op.operands.map((x)=>convertFilterToGqlFilter(x))
|
|
1359
|
-
});
|
|
1360
|
-
this.handleUnion = (op)=>({
|
|
1361
|
-
or: op.operands.map((x)=>convertFilterToGqlFilter(x))
|
|
1362
|
-
});
|
|
1363
|
-
this.handleMissing = (op)=>({
|
|
1364
|
-
is: {
|
|
1365
|
-
[op.field]: 'MISSING'
|
|
1366
|
-
}
|
|
1367
|
-
});
|
|
1368
|
-
this.handleExists = (op)=>({
|
|
1369
|
-
not: {
|
|
1370
|
-
[op.field]: op?.operand ?? null
|
|
1371
|
-
}
|
|
1372
|
-
});
|
|
1373
|
-
this.handleNestedFilter = (op)=>{
|
|
1374
|
-
const child = convertFilterToGqlFilter(op.operand);
|
|
1375
|
-
return {
|
|
1376
|
-
nested: {
|
|
1377
|
-
path: op.path,
|
|
1378
|
-
...child
|
|
1379
|
-
}
|
|
1380
|
-
};
|
|
1381
|
-
};
|
|
1382
|
-
}
|
|
1383
|
-
}
|
|
1384
|
-
const convertFilterToGqlFilter = (filter)=>{
|
|
1385
|
-
const handler = new ToGqlHandler();
|
|
1386
|
-
return handleOperation(handler, filter);
|
|
1387
|
-
};
|
|
1388
|
-
const convertFilterSetToGqlFilter = (fs, toplevelOp = 'and')=>{
|
|
1389
|
-
const fsKeys = Object.keys(fs.root);
|
|
1390
|
-
// if no keys return undefined
|
|
1391
|
-
if (fsKeys.length === 0) return {
|
|
1392
|
-
and: []
|
|
1393
|
-
};
|
|
1394
|
-
return toplevelOp === 'and' ? {
|
|
1395
|
-
and: fsKeys.map((key)=>convertFilterToGqlFilter(fs.root[key]))
|
|
1396
|
-
} : {
|
|
1397
|
-
or: fsKeys.map((key)=>convertFilterToGqlFilter(fs.root[key]))
|
|
1398
|
-
};
|
|
1399
|
-
};
|
|
1400
|
-
const handleGqlOperation = (handler, op)=>{
|
|
1401
|
-
const operationKeys = Object.keys(op);
|
|
1402
|
-
if (operationKeys.includes('=')) {
|
|
1403
|
-
return handler.handleEquals(op);
|
|
1006
|
+
const convertFilterSetToGqlFilter = (fs, toplevelOp = 'and')=>{
|
|
1007
|
+
const fsKeys = Object.keys(fs.root);
|
|
1008
|
+
// if no keys return undefined
|
|
1009
|
+
if (fsKeys.length === 0) return {
|
|
1010
|
+
and: []
|
|
1011
|
+
};
|
|
1012
|
+
return toplevelOp === 'and' ? {
|
|
1013
|
+
and: fsKeys.map((key)=>convertFilterToGqlFilter(fs.root[key]))
|
|
1014
|
+
} : {
|
|
1015
|
+
or: fsKeys.map((key)=>convertFilterToGqlFilter(fs.root[key]))
|
|
1016
|
+
};
|
|
1017
|
+
};
|
|
1018
|
+
const handleGqlOperation = (handler, op)=>{
|
|
1019
|
+
const operationKeys = Object.keys(op);
|
|
1020
|
+
if (operationKeys.includes('=')) {
|
|
1021
|
+
return handler.handleEquals(op);
|
|
1404
1022
|
}
|
|
1405
1023
|
if (operationKeys.includes('!=')) {
|
|
1406
1024
|
return handler.handleNotEquals(op);
|
|
@@ -1622,132 +1240,571 @@ const filterSetToOperation = (fs)=>{
|
|
|
1622
1240
|
})
|
|
1623
1241
|
};
|
|
1624
1242
|
}
|
|
1625
|
-
return undefined;
|
|
1626
|
-
};
|
|
1243
|
+
return undefined;
|
|
1244
|
+
};
|
|
1245
|
+
/**
|
|
1246
|
+
* Constructs a nested operation object based on the provided field and leaf operand.
|
|
1247
|
+
* If the field does not contain a dot '.', it either assigns the field to the leaf operand (if applicable)
|
|
1248
|
+
* or returns the leaf operand as is. When the field contains dots, it splits the field into parts,
|
|
1249
|
+
* creates a "nested" operation for the root field, and recursively constructs the nested structure
|
|
1250
|
+
* for the remaining portion of the field.
|
|
1251
|
+
*
|
|
1252
|
+
* @param {string} field - The hierarchical field path, with segments separated by dots (e.g., "root.child").
|
|
1253
|
+
* @param {Operation} leafOperand - The operation to be nested within the specified path.
|
|
1254
|
+
* @param parentPath - The parent path of the current field. Guppy nested filters require a parent path.
|
|
1255
|
+
* @param depth
|
|
1256
|
+
* @returns {Operation} A nested operation object that represents the structured path and operand.
|
|
1257
|
+
*/ const buildNestedGQLFilter = (field, leafOperand, parentPath = undefined)=>{
|
|
1258
|
+
if (!field.includes('.')) {
|
|
1259
|
+
return leafOperand;
|
|
1260
|
+
}
|
|
1261
|
+
const splitFieldArray = field.split('.');
|
|
1262
|
+
const nextField = splitFieldArray.shift();
|
|
1263
|
+
if (!nextField) {
|
|
1264
|
+
console.warn('Invalid field path:', field);
|
|
1265
|
+
return leafOperand;
|
|
1266
|
+
}
|
|
1267
|
+
const currentPath = parentPath ? `${parentPath}.${nextField}` : nextField;
|
|
1268
|
+
return {
|
|
1269
|
+
nested: {
|
|
1270
|
+
path: currentPath,
|
|
1271
|
+
...buildNestedGQLFilter(splitFieldArray.join('.'), leafOperand, currentPath)
|
|
1272
|
+
}
|
|
1273
|
+
};
|
|
1274
|
+
};
|
|
1275
|
+
|
|
1276
|
+
const isFilterSet = (input)=>{
|
|
1277
|
+
if (typeof input !== 'object' || input === null) {
|
|
1278
|
+
return false;
|
|
1279
|
+
}
|
|
1280
|
+
const { root, mode } = input;
|
|
1281
|
+
if (typeof root !== 'object' || root === null) {
|
|
1282
|
+
return false;
|
|
1283
|
+
}
|
|
1284
|
+
if (![
|
|
1285
|
+
'and',
|
|
1286
|
+
'or'
|
|
1287
|
+
].includes(mode)) {
|
|
1288
|
+
return false;
|
|
1289
|
+
}
|
|
1290
|
+
return true;
|
|
1291
|
+
};
|
|
1292
|
+
const isUnion = (value)=>{
|
|
1293
|
+
return typeof value === 'object' && value !== null && value.operator === 'or' && Array.isArray(value.operands);
|
|
1294
|
+
};
|
|
1295
|
+
const isIntersection = (value)=>{
|
|
1296
|
+
return typeof value === 'object' && value !== null && value.operator === 'and' && Array.isArray(value.operands);
|
|
1297
|
+
};
|
|
1298
|
+
/**
|
|
1299
|
+
* Type guard for Union or Intersection
|
|
1300
|
+
* @param o - operator to check
|
|
1301
|
+
* @category Filters
|
|
1302
|
+
*/ const isIntersectionOrUnion = (o)=>o.operator === 'and' || o.operator === 'or';
|
|
1303
|
+
const isOperandsType = (operation)=>{
|
|
1304
|
+
return operation?.operands !== undefined;
|
|
1305
|
+
};
|
|
1306
|
+
const isNestedFilter = (operation)=>{
|
|
1307
|
+
return operation.operator === 'nested';
|
|
1308
|
+
};
|
|
1309
|
+
const isIndexedFilterSetEmpty = (filters)=>Object.values(filters).every((filterSet)=>Object.keys(filterSet).length === 0);
|
|
1310
|
+
const EmptyFilterSet = {
|
|
1311
|
+
mode: 'and',
|
|
1312
|
+
root: {}
|
|
1313
|
+
};
|
|
1314
|
+
|
|
1315
|
+
const FieldNameOverrides = {};
|
|
1316
|
+
const COMMON_PREPOSITIONS = [
|
|
1317
|
+
'a',
|
|
1318
|
+
'an',
|
|
1319
|
+
'and',
|
|
1320
|
+
'at',
|
|
1321
|
+
'but',
|
|
1322
|
+
'by',
|
|
1323
|
+
'for',
|
|
1324
|
+
'in',
|
|
1325
|
+
'is',
|
|
1326
|
+
'nor',
|
|
1327
|
+
'of',
|
|
1328
|
+
'on',
|
|
1329
|
+
'or',
|
|
1330
|
+
'out',
|
|
1331
|
+
'so',
|
|
1332
|
+
'the',
|
|
1333
|
+
'to',
|
|
1334
|
+
'up',
|
|
1335
|
+
'yet'
|
|
1336
|
+
];
|
|
1337
|
+
const capitalize$1 = (s)=>s.length > 0 ? s[0].toUpperCase() + s.slice(1) : '';
|
|
1338
|
+
const trimFirstFieldNameToTitle = (fieldName, trim = false)=>{
|
|
1339
|
+
if (trim) {
|
|
1340
|
+
const source = fieldName.slice(fieldName.indexOf('.') + 1);
|
|
1341
|
+
return fieldNameToTitle(source ? source : fieldName, 0);
|
|
1342
|
+
}
|
|
1343
|
+
return fieldNameToTitle(fieldName);
|
|
1344
|
+
};
|
|
1345
|
+
/**
|
|
1346
|
+
* Converts a filter name to a title,
|
|
1347
|
+
* For example files.input.experimental_strategy will get converted to Experimental Strategy
|
|
1348
|
+
* if sections == 2 then the output would be Input Experimental Strategy
|
|
1349
|
+
* @param fieldName input filter expected to be: string.firstpart_secondpart
|
|
1350
|
+
* @param sections number of "sections" string.string.string to got back from the end of the field
|
|
1351
|
+
*/ const fieldNameToTitle = (fieldName, sections = 1)=>{
|
|
1352
|
+
if (fieldName in FieldNameOverrides) {
|
|
1353
|
+
return FieldNameOverrides[fieldName];
|
|
1354
|
+
}
|
|
1355
|
+
if (fieldName === undefined) return 'No Title';
|
|
1356
|
+
return fieldName.split('.').slice(-sections).map((s)=>s.split('_')).flat().map((word)=>COMMON_PREPOSITIONS.includes(word) ? word : capitalize$1(word)).join(' ');
|
|
1357
|
+
};
|
|
1358
|
+
/**
|
|
1359
|
+
* Extracts the index name from the field name
|
|
1360
|
+
* @param fieldName
|
|
1361
|
+
*/ const extractIndexFromFullFieldName = (fieldName)=>fieldName.split('.')[0];
|
|
1362
|
+
/**
|
|
1363
|
+
* prepend the index name to the field name
|
|
1364
|
+
*/ const prependIndexToFieldName = (fieldName, index)=>`${index}.${fieldName}`;
|
|
1365
|
+
/**
|
|
1366
|
+
* extract the field name from the index.field name
|
|
1367
|
+
*/ const extractFieldNameFromFullFieldName = (fieldName)=>fieldName.split('.').slice(1).join('.');
|
|
1368
|
+
/**
|
|
1369
|
+
* extract the field name and the index from the index.field name returning as a tuple
|
|
1370
|
+
*/ const extractIndexAndFieldNameFromFullFieldName = (fieldName)=>{
|
|
1371
|
+
const [index, ...rest] = fieldName.split('.');
|
|
1372
|
+
return [
|
|
1373
|
+
index,
|
|
1374
|
+
rest.join('.')
|
|
1375
|
+
];
|
|
1376
|
+
};
|
|
1377
|
+
|
|
1378
|
+
const defaultCohortNameGenerator = ()=>`Custom cohort ${new Date().toLocaleString('en-CA', {
|
|
1379
|
+
timeZone: 'America/Chicago',
|
|
1380
|
+
hour12: false
|
|
1381
|
+
}).replace(',', '')}`;
|
|
1382
|
+
const isNameUnique = (entities, name, excludeId)=>{
|
|
1383
|
+
const trimmedName = name.trim();
|
|
1384
|
+
if (!trimmedName) return false;
|
|
1385
|
+
return !entities.some((cohort)=>cohort && cohort.id !== excludeId && cohort.name.trim().toLowerCase() === trimmedName.toLowerCase());
|
|
1386
|
+
};
|
|
1387
|
+
const generateUniqueName = (entities, baseName)=>{
|
|
1388
|
+
const trimmedBaseName = baseName.trim();
|
|
1389
|
+
// If base name is unique, use it
|
|
1390
|
+
if (isNameUnique(entities, trimmedBaseName)) {
|
|
1391
|
+
return trimmedBaseName;
|
|
1392
|
+
}
|
|
1393
|
+
// Find a unique name by appending numbers
|
|
1394
|
+
let counter = 1;
|
|
1395
|
+
let uniqueName;
|
|
1396
|
+
do {
|
|
1397
|
+
uniqueName = `${trimmedBaseName} (${counter})`;
|
|
1398
|
+
counter++;
|
|
1399
|
+
}while (!isNameUnique(entities, uniqueName))
|
|
1400
|
+
return uniqueName;
|
|
1401
|
+
};
|
|
1402
|
+
/**
|
|
1403
|
+
* This function takes a FilterSet object and a prefix string as input.
|
|
1404
|
+
* It filters the root property of the FilterSet object and returns a
|
|
1405
|
+
* new FilterSet object that only contains filters with field names
|
|
1406
|
+
* that start with the specified prefix.
|
|
1407
|
+
*
|
|
1408
|
+
* @param fs - The FilterSet object to filter
|
|
1409
|
+
* @param prefix - The prefix to filter by
|
|
1410
|
+
* @returns - A new FilterSet object that only contains filters with field names that start with the specified prefix
|
|
1411
|
+
* @category Filters
|
|
1412
|
+
*/ const extractFiltersWithPrefixFromFilterSet = (fs, prefix)=>{
|
|
1413
|
+
if (fs === undefined || fs.root === undefined) {
|
|
1414
|
+
return {
|
|
1415
|
+
mode: 'and',
|
|
1416
|
+
root: {}
|
|
1417
|
+
};
|
|
1418
|
+
}
|
|
1419
|
+
return Object.values(fs.root).reduce((acc, filter)=>{
|
|
1420
|
+
if (isIntersectionOrUnion(filter) || isNestedFilter(filter)) return acc;
|
|
1421
|
+
if (filter.field.startsWith(prefix)) {
|
|
1422
|
+
acc.root[filter.field] = filter;
|
|
1423
|
+
}
|
|
1424
|
+
return acc;
|
|
1425
|
+
}, {
|
|
1426
|
+
mode: 'and',
|
|
1427
|
+
root: {}
|
|
1428
|
+
});
|
|
1429
|
+
};
|
|
1430
|
+
|
|
1431
|
+
/**
|
|
1432
|
+
* Cohorts in Gen3 are defined as a set of filters for each index in the data.
|
|
1433
|
+
* This means one cohort id defined for all "tabs" in CohortBuilder (explorer)
|
|
1434
|
+
* Switching a cohort id means all the cohorts for the index are changed.
|
|
1435
|
+
*/ const DEFAULT_COHORT_NAME = 'Cohort';
|
|
1436
|
+
const newCohort = ({ filters = {}, customName })=>{
|
|
1437
|
+
const ts = new Date().toISOString();
|
|
1438
|
+
const newName = customName ?? defaultCohortNameGenerator();
|
|
1439
|
+
const newId = createCohortId();
|
|
1440
|
+
return {
|
|
1441
|
+
name: newName,
|
|
1442
|
+
id: newId,
|
|
1443
|
+
filters: filters ?? {},
|
|
1444
|
+
modified: false,
|
|
1445
|
+
saved: false,
|
|
1446
|
+
createdDatetime: ts,
|
|
1447
|
+
modifiedDatetime: ts,
|
|
1448
|
+
counts: {}
|
|
1449
|
+
};
|
|
1450
|
+
};
|
|
1451
|
+
const nanoid = nanoid$1.customAlphabet('1234567890abcdef', 16);
|
|
1452
|
+
const createCohortId = ()=>nanoid();
|
|
1453
|
+
const cohortsAdapter = toolkit.createEntityAdapter({
|
|
1454
|
+
sortComparer: (a, b)=>{
|
|
1455
|
+
if (a.modifiedDatetime <= b.modifiedDatetime) return 1;
|
|
1456
|
+
else return -1;
|
|
1457
|
+
},
|
|
1458
|
+
selectId: (cohort)=>cohort.id
|
|
1459
|
+
});
|
|
1460
|
+
// Create an initial unsaved cohort
|
|
1461
|
+
const initialCohort = newCohort({
|
|
1462
|
+
customName: DEFAULT_COHORT_NAME
|
|
1463
|
+
});
|
|
1464
|
+
const emptyInitialState = cohortsAdapter.getInitialState({
|
|
1465
|
+
currentCohortId: initialCohort.id,
|
|
1466
|
+
message: undefined
|
|
1467
|
+
});
|
|
1468
|
+
// Set the initial cohort in the adapter state
|
|
1469
|
+
const initialState$3 = cohortsAdapter.setOne(emptyInitialState, initialCohort);
|
|
1470
|
+
const getCurrentCohortId = (state)=>state.currentCohortId;
|
|
1471
|
+
/**
|
|
1472
|
+
* Redux slice for cohort filters
|
|
1473
|
+
*/ const cohortManagerSlice = toolkit.createSlice({
|
|
1474
|
+
name: 'cohort',
|
|
1475
|
+
initialState: initialState$3,
|
|
1476
|
+
reducers: {
|
|
1477
|
+
createNewCohort: (state, action)=>{
|
|
1478
|
+
const baseName = action.payload.name || `Cohort`;
|
|
1479
|
+
const uniqueName = generateUniqueName(Object.values(state.entities), baseName);
|
|
1480
|
+
const cohort = newCohort({
|
|
1481
|
+
filters: action.payload.filters,
|
|
1482
|
+
customName: uniqueName
|
|
1483
|
+
});
|
|
1484
|
+
cohortsAdapter.addOne(state, cohort);
|
|
1485
|
+
state.currentCohortId = cohort.id;
|
|
1486
|
+
},
|
|
1487
|
+
updateCohortName: (state, action)=>{
|
|
1488
|
+
const { id, name } = action.payload;
|
|
1489
|
+
cohortsAdapter.updateOne(state, {
|
|
1490
|
+
id: id,
|
|
1491
|
+
changes: {
|
|
1492
|
+
name: name,
|
|
1493
|
+
modified: true,
|
|
1494
|
+
modifiedDatetime: new Date().toISOString()
|
|
1495
|
+
}
|
|
1496
|
+
});
|
|
1497
|
+
},
|
|
1498
|
+
removeCohort: (state, action)=>{
|
|
1499
|
+
const { id: cohortId } = action.payload;
|
|
1500
|
+
const removedCohortName = state.entities[cohortId].name;
|
|
1501
|
+
const totalCohorts = Object.keys(state.entities).length;
|
|
1502
|
+
if (totalCohorts <= 1) {
|
|
1503
|
+
cohortsAdapter.removeAll(state);
|
|
1504
|
+
const defaultCohort = newCohort({
|
|
1505
|
+
filters: {},
|
|
1506
|
+
customName: DEFAULT_COHORT_NAME
|
|
1507
|
+
});
|
|
1508
|
+
cohortsAdapter.addOne(state, defaultCohort);
|
|
1509
|
+
state.currentCohortId = defaultCohort.id;
|
|
1510
|
+
if (action?.payload.shouldShowMessage) {
|
|
1511
|
+
state.message = [
|
|
1512
|
+
`deleteCohort|${removedCohortName}|${state.currentCohortId}`
|
|
1513
|
+
];
|
|
1514
|
+
}
|
|
1515
|
+
return;
|
|
1516
|
+
}
|
|
1517
|
+
cohortsAdapter.removeOne(state, cohortId);
|
|
1518
|
+
// deleted the current cohort so set to the most recent cohort
|
|
1519
|
+
if (state.currentCohortId === cohortId) {
|
|
1520
|
+
const remainingIds = Object.keys(state.entities);
|
|
1521
|
+
state.currentCohortId = remainingIds[0];
|
|
1522
|
+
}
|
|
1523
|
+
if (action?.payload.shouldShowMessage) {
|
|
1524
|
+
state.message = [
|
|
1525
|
+
`deleteCohort|${removedCohortName}|${state.currentCohortId}`
|
|
1526
|
+
];
|
|
1527
|
+
}
|
|
1528
|
+
},
|
|
1529
|
+
// adds a filter to the cohort filter set at the given index
|
|
1530
|
+
updateCohortFilter: (state, action)=>{
|
|
1531
|
+
const { index, field, filter } = action.payload;
|
|
1532
|
+
const currentCohortId = getCurrentCohortId(state);
|
|
1533
|
+
if (!state.entities[currentCohortId]) {
|
|
1534
|
+
return;
|
|
1535
|
+
}
|
|
1536
|
+
cohortsAdapter.updateOne(state, {
|
|
1537
|
+
id: currentCohortId,
|
|
1538
|
+
changes: {
|
|
1539
|
+
filters: {
|
|
1540
|
+
...state.entities[currentCohortId].filters,
|
|
1541
|
+
[index]: {
|
|
1542
|
+
mode: state.entities[currentCohortId]?.filters[index]?.mode ?? 'and',
|
|
1543
|
+
root: {
|
|
1544
|
+
...state.entities[currentCohortId]?.filters[index]?.root ?? {},
|
|
1545
|
+
[field]: filter
|
|
1546
|
+
}
|
|
1547
|
+
}
|
|
1548
|
+
},
|
|
1549
|
+
modified: true,
|
|
1550
|
+
modifiedDatetime: new Date().toISOString()
|
|
1551
|
+
}
|
|
1552
|
+
});
|
|
1553
|
+
},
|
|
1554
|
+
setCohortFilter: (state, action)=>{
|
|
1555
|
+
const { index, filters } = action.payload;
|
|
1556
|
+
const currentCohortId = getCurrentCohortId(state);
|
|
1557
|
+
if (!state.entities[currentCohortId]) {
|
|
1558
|
+
console.error(`no cohort with id=${currentCohortId} defined`);
|
|
1559
|
+
return;
|
|
1560
|
+
}
|
|
1561
|
+
cohortsAdapter.updateOne(state, {
|
|
1562
|
+
id: currentCohortId,
|
|
1563
|
+
changes: {
|
|
1564
|
+
filters: {
|
|
1565
|
+
...state.entities[currentCohortId].filters,
|
|
1566
|
+
[index]: filters
|
|
1567
|
+
},
|
|
1568
|
+
modified: true,
|
|
1569
|
+
modifiedDatetime: new Date().toISOString()
|
|
1570
|
+
}
|
|
1571
|
+
});
|
|
1572
|
+
},
|
|
1573
|
+
setCohortIndexFilters: (state, action)=>{
|
|
1574
|
+
const currentCohortId = getCurrentCohortId(state);
|
|
1575
|
+
if (!state.entities[currentCohortId]) {
|
|
1576
|
+
console.error(`no cohort with id=${currentCohortId} defined`);
|
|
1577
|
+
return;
|
|
1578
|
+
}
|
|
1579
|
+
cohortsAdapter.updateOne(state, {
|
|
1580
|
+
id: currentCohortId,
|
|
1581
|
+
changes: {
|
|
1582
|
+
filters: action.payload.filters,
|
|
1583
|
+
modified: true,
|
|
1584
|
+
modifiedDatetime: new Date().toISOString()
|
|
1585
|
+
}
|
|
1586
|
+
});
|
|
1587
|
+
},
|
|
1588
|
+
// removes a filter to the cohort filter set at the given index
|
|
1589
|
+
removeCohortFilter: (state, action)=>{
|
|
1590
|
+
const { index, field } = action.payload;
|
|
1591
|
+
const currentCohortId = getCurrentCohortId(state);
|
|
1592
|
+
if (!state.entities[currentCohortId]) {
|
|
1593
|
+
console.error(`no cohort with id=${currentCohortId} defined`);
|
|
1594
|
+
return;
|
|
1595
|
+
}
|
|
1596
|
+
const filters = state.entities[currentCohortId]?.filters[index]?.root;
|
|
1597
|
+
if (!filters) {
|
|
1598
|
+
return;
|
|
1599
|
+
}
|
|
1600
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1601
|
+
const { [field]: _a, ...updated } = filters;
|
|
1602
|
+
cohortsAdapter.updateOne(state, {
|
|
1603
|
+
id: currentCohortId,
|
|
1604
|
+
changes: {
|
|
1605
|
+
filters: {
|
|
1606
|
+
...state.entities[currentCohortId]?.filters,
|
|
1607
|
+
[index]: {
|
|
1608
|
+
mode: state.entities[currentCohortId].filters[index].mode,
|
|
1609
|
+
root: updated
|
|
1610
|
+
}
|
|
1611
|
+
},
|
|
1612
|
+
modified: true,
|
|
1613
|
+
modifiedDatetime: new Date().toISOString()
|
|
1614
|
+
}
|
|
1615
|
+
});
|
|
1616
|
+
},
|
|
1617
|
+
duplicateCohort: (state)=>{
|
|
1618
|
+
const currentCohortId = getCurrentCohortId(state);
|
|
1619
|
+
const currentCohort = state.entities[currentCohortId];
|
|
1620
|
+
const newName = generateUniqueName(Object.values(state.entities), currentCohort.name);
|
|
1621
|
+
const duplicatedCohort = newCohort({
|
|
1622
|
+
filters: {
|
|
1623
|
+
...currentCohort.filters
|
|
1624
|
+
},
|
|
1625
|
+
customName: newName
|
|
1626
|
+
});
|
|
1627
|
+
cohortsAdapter.addOne(state, {
|
|
1628
|
+
...duplicatedCohort,
|
|
1629
|
+
counts: {
|
|
1630
|
+
...currentCohort.counts
|
|
1631
|
+
}
|
|
1632
|
+
});
|
|
1633
|
+
state.currentCohortId = duplicatedCohort.id;
|
|
1634
|
+
},
|
|
1635
|
+
// removes all filters from the cohort filter set at the given index
|
|
1636
|
+
clearCohortFilters: (state, action)=>{
|
|
1637
|
+
const { index } = action.payload;
|
|
1638
|
+
const currentCohortId = getCurrentCohortId(state);
|
|
1639
|
+
if (!state.entities[currentCohortId]) {
|
|
1640
|
+
console.error(`no cohort with id=${currentCohortId} defined`);
|
|
1641
|
+
return;
|
|
1642
|
+
}
|
|
1643
|
+
const filters = state.entities[currentCohortId]?.filters[index]?.root;
|
|
1644
|
+
if (!filters) {
|
|
1645
|
+
return;
|
|
1646
|
+
}
|
|
1647
|
+
cohortsAdapter.updateOne(state, {
|
|
1648
|
+
id: currentCohortId,
|
|
1649
|
+
changes: {
|
|
1650
|
+
filters: {
|
|
1651
|
+
...state.entities[currentCohortId]?.filters,
|
|
1652
|
+
[index]: {
|
|
1653
|
+
mode: 'and',
|
|
1654
|
+
root: {}
|
|
1655
|
+
}
|
|
1656
|
+
},
|
|
1657
|
+
modified: true,
|
|
1658
|
+
modifiedDatetime: new Date().toISOString()
|
|
1659
|
+
}
|
|
1660
|
+
});
|
|
1661
|
+
},
|
|
1662
|
+
updateCohortCounts: (state, action)=>{
|
|
1663
|
+
const currentCohortId = getCurrentCohortId(state);
|
|
1664
|
+
const currentCohort = state.entities[currentCohortId];
|
|
1665
|
+
cohortsAdapter.updateOne(state, {
|
|
1666
|
+
id: currentCohortId,
|
|
1667
|
+
changes: {
|
|
1668
|
+
counts: {
|
|
1669
|
+
...currentCohort.counts,
|
|
1670
|
+
...action.payload
|
|
1671
|
+
}
|
|
1672
|
+
}
|
|
1673
|
+
});
|
|
1674
|
+
},
|
|
1675
|
+
updateCohortIndexCountById: (state, action)=>{
|
|
1676
|
+
const { index, cohortId, counts } = action.payload;
|
|
1677
|
+
const cohort = state.entities[cohortId];
|
|
1678
|
+
cohortsAdapter.updateOne(state, {
|
|
1679
|
+
id: cohortId,
|
|
1680
|
+
changes: {
|
|
1681
|
+
counts: {
|
|
1682
|
+
...cohort.counts,
|
|
1683
|
+
...{
|
|
1684
|
+
[index]: counts
|
|
1685
|
+
}
|
|
1686
|
+
}
|
|
1687
|
+
}
|
|
1688
|
+
});
|
|
1689
|
+
},
|
|
1690
|
+
setCurrentCohortId: (state, action)=>{
|
|
1691
|
+
state.currentCohortId = action.payload;
|
|
1692
|
+
},
|
|
1693
|
+
/** @hidden */ setCohortList: (state, action)=>{
|
|
1694
|
+
if (!action.payload) {
|
|
1695
|
+
cohortsAdapter.removeMany(state, state.ids);
|
|
1696
|
+
} else {
|
|
1697
|
+
cohortsAdapter.upsertMany(state, [
|
|
1698
|
+
...action.payload
|
|
1699
|
+
]);
|
|
1700
|
+
}
|
|
1701
|
+
}
|
|
1702
|
+
}
|
|
1703
|
+
});
|
|
1627
1704
|
/**
|
|
1628
|
-
*
|
|
1629
|
-
*
|
|
1630
|
-
* or returns the leaf operand as is. When the field contains dots, it splits the field into parts,
|
|
1631
|
-
* creates a "nested" operation for the root field, and recursively constructs the nested structure
|
|
1632
|
-
* for the remaining portion of the field.
|
|
1705
|
+
* Returns the selectors for the cohorts EntityAdapter
|
|
1706
|
+
* @param state - the CoreState
|
|
1633
1707
|
*
|
|
1634
|
-
* @
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
*/ const buildNestedGQLFilter = (field, leafOperand, parentPath = undefined)=>{
|
|
1640
|
-
if (!field.includes('.')) {
|
|
1641
|
-
return leafOperand;
|
|
1642
|
-
}
|
|
1643
|
-
const splitFieldArray = field.split('.');
|
|
1644
|
-
const nextField = splitFieldArray.shift();
|
|
1645
|
-
if (!nextField) {
|
|
1646
|
-
console.warn('Invalid field path:', field);
|
|
1647
|
-
return leafOperand;
|
|
1648
|
-
}
|
|
1649
|
-
const currentPath = parentPath ? `${parentPath}.${nextField}` : nextField;
|
|
1650
|
-
return {
|
|
1651
|
-
nested: {
|
|
1652
|
-
path: currentPath,
|
|
1653
|
-
...buildNestedGQLFilter(splitFieldArray.join('.'), leafOperand, currentPath)
|
|
1654
|
-
}
|
|
1655
|
-
};
|
|
1656
|
-
};
|
|
1708
|
+
* @hidden
|
|
1709
|
+
*/ const cohortSelectors = cohortsAdapter.getSelectors((state)=>state.cohorts.cohortManager);
|
|
1710
|
+
// Filter actions: addFilter, removeFilter, updateFilter
|
|
1711
|
+
const { createNewCohort, updateCohortFilter, setCohortFilter, setCohortIndexFilters, duplicateCohort, removeCohortFilter, clearCohortFilters, removeCohort, setCurrentCohortId, updateCohortName, updateCohortCounts, updateCohortIndexCountById, setCohortList } = cohortManagerSlice.actions;
|
|
1712
|
+
const cohortReducer = cohortManagerSlice.reducer;
|
|
1657
1713
|
|
|
1658
|
-
const
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1714
|
+
const initialState$2 = {};
|
|
1715
|
+
const expandSlice$1 = toolkit.createSlice({
|
|
1716
|
+
name: 'CohortBuilder/filterExpand',
|
|
1717
|
+
initialState: initialState$2,
|
|
1718
|
+
reducers: {
|
|
1719
|
+
toggleCohortBuilderCategoryFilter: (state, action)=>{
|
|
1720
|
+
return {
|
|
1721
|
+
...state,
|
|
1722
|
+
[action.payload.index]: {
|
|
1723
|
+
...state[action.payload.index],
|
|
1724
|
+
[action.payload.field]: action.payload.expanded
|
|
1725
|
+
}
|
|
1726
|
+
};
|
|
1727
|
+
},
|
|
1728
|
+
toggleCohortBuilderAllFilters: (state, action)=>{
|
|
1729
|
+
return {
|
|
1730
|
+
...state,
|
|
1731
|
+
[action.payload.index]: Object.keys(state[action.payload.index]).reduce((acc, k)=>{
|
|
1732
|
+
acc[k] = action.payload.expand;
|
|
1733
|
+
return acc;
|
|
1734
|
+
}, {})
|
|
1735
|
+
};
|
|
1736
|
+
}
|
|
1671
1737
|
}
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
const
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
const isIntersection = (value)=>{
|
|
1678
|
-
return typeof value === 'object' && value !== null && value.operator === 'and' && Array.isArray(value.operands);
|
|
1679
|
-
};
|
|
1680
|
-
const isOperandsType = (operation)=>{
|
|
1681
|
-
return operation?.operands !== undefined;
|
|
1682
|
-
};
|
|
1683
|
-
const isIndexedFilterSetEmpty = (filters)=>Object.values(filters).every((filterSet)=>Object.keys(filterSet).length === 0);
|
|
1684
|
-
const EmptyFilterSet = {
|
|
1685
|
-
mode: 'and',
|
|
1686
|
-
root: {}
|
|
1687
|
-
};
|
|
1738
|
+
});
|
|
1739
|
+
const cohortBuilderFiltersExpandedReducer = expandSlice$1.reducer;
|
|
1740
|
+
const { toggleCohortBuilderCategoryFilter, toggleCohortBuilderAllFilters } = expandSlice$1.actions;
|
|
1741
|
+
const selectCohortFilterExpanded = (state, index, field)=>state.cohorts.filtersExpanded?.[index]?.[field];
|
|
1742
|
+
const selectAllCohortFiltersCollapsed = (state, index)=>index in state.cohorts.filtersExpanded ? Object.values(state.cohorts.filtersExpanded?.[index]).every((e)=>!e) : false;
|
|
1688
1743
|
|
|
1689
|
-
const
|
|
1690
|
-
const
|
|
1691
|
-
'
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
'or',
|
|
1704
|
-
'out',
|
|
1705
|
-
'so',
|
|
1706
|
-
'the',
|
|
1707
|
-
'to',
|
|
1708
|
-
'up',
|
|
1709
|
-
'yet'
|
|
1710
|
-
];
|
|
1711
|
-
const capitalize$1 = (s)=>s.length > 0 ? s[0].toUpperCase() + s.slice(1) : '';
|
|
1712
|
-
const trimFirstFieldNameToTitle = (fieldName, trim = false)=>{
|
|
1713
|
-
if (trim) {
|
|
1714
|
-
const source = fieldName.slice(fieldName.indexOf('.') + 1);
|
|
1715
|
-
return fieldNameToTitle(source ? source : fieldName, 0);
|
|
1744
|
+
const initialState$1 = {};
|
|
1745
|
+
const expandSlice = toolkit.createSlice({
|
|
1746
|
+
name: 'CohortBuilder/filterCombineMode',
|
|
1747
|
+
initialState: initialState$1,
|
|
1748
|
+
reducers: {
|
|
1749
|
+
setCohortFilterCombineMode: (state, action)=>{
|
|
1750
|
+
return {
|
|
1751
|
+
...state,
|
|
1752
|
+
[action.payload.index]: {
|
|
1753
|
+
...state[action.payload.index],
|
|
1754
|
+
[action.payload.field]: action.payload.mode
|
|
1755
|
+
}
|
|
1756
|
+
};
|
|
1757
|
+
}
|
|
1716
1758
|
}
|
|
1717
|
-
|
|
1759
|
+
});
|
|
1760
|
+
const cohortBuilderFiltersCombineModeReducer = expandSlice.reducer;
|
|
1761
|
+
const { setCohortFilterCombineMode } = expandSlice.actions;
|
|
1762
|
+
const selectCohortFilterCombineMode = (state, index, field)=>state.cohorts.filtersCombineMode?.[index]?.[field] ?? 'or';
|
|
1763
|
+
|
|
1764
|
+
const initialState = {
|
|
1765
|
+
shouldShareFilters: false,
|
|
1766
|
+
sharedFiltersMap: {}
|
|
1718
1767
|
};
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1768
|
+
const cohortSharedFiltersSlice = toolkit.createSlice({
|
|
1769
|
+
name: 'cohortSharedFilters',
|
|
1770
|
+
initialState: initialState,
|
|
1771
|
+
reducers: {
|
|
1772
|
+
setShouldShareFilters: (state, action)=>{
|
|
1773
|
+
state.shouldShareFilters = action.payload;
|
|
1774
|
+
return state;
|
|
1775
|
+
},
|
|
1776
|
+
setSharedFilters: (state, action)=>{
|
|
1777
|
+
state.sharedFiltersMap = action.payload;
|
|
1778
|
+
}
|
|
1728
1779
|
}
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
* @param fieldName
|
|
1735
|
-
*/ const extractIndexFromFullFieldName = (fieldName)=>fieldName.split('.')[0];
|
|
1736
|
-
/**
|
|
1737
|
-
* prepend the index name to the field name
|
|
1738
|
-
*/ const prependIndexToFieldName = (fieldName, index)=>`${index}.${fieldName}`;
|
|
1739
|
-
/**
|
|
1740
|
-
* extract the field name from the index.field name
|
|
1741
|
-
*/ const extractFieldNameFromFullFieldName = (fieldName)=>fieldName.split('.').slice(1).join('.');
|
|
1742
|
-
/**
|
|
1743
|
-
* extract the field name and the index from the index.field name returning as a tuple
|
|
1744
|
-
*/ const extractIndexAndFieldNameFromFullFieldName = (fieldName)=>{
|
|
1745
|
-
const [index, ...rest] = fieldName.split('.');
|
|
1746
|
-
return [
|
|
1747
|
-
index,
|
|
1748
|
-
rest.join('.')
|
|
1780
|
+
});
|
|
1781
|
+
const selectShouldShareFilters = (state)=>state.cohorts.sharedFilters.shouldShareFilters;
|
|
1782
|
+
const selectSharedFilters = (state)=>state.cohorts.sharedFilters.sharedFiltersMap;
|
|
1783
|
+
const selectSharedFiltersForFields = (state, field)=>state.cohorts.sharedFilters.sharedFiltersMap?.[field] ?? [
|
|
1784
|
+
field
|
|
1749
1785
|
];
|
|
1750
|
-
};
|
|
1786
|
+
const { setShouldShareFilters, setSharedFilters } = cohortSharedFiltersSlice.actions;
|
|
1787
|
+
const cohortSharedFiltersReducer = cohortSharedFiltersSlice.reducer;
|
|
1788
|
+
|
|
1789
|
+
const cohortReducers = toolkit.combineReducers({
|
|
1790
|
+
filtersExpanded: cohortBuilderFiltersExpandedReducer,
|
|
1791
|
+
filtersCombineMode: cohortBuilderFiltersCombineModeReducer,
|
|
1792
|
+
sharedFilters: cohortSharedFiltersReducer,
|
|
1793
|
+
cohortManager: cohortReducer
|
|
1794
|
+
});
|
|
1795
|
+
|
|
1796
|
+
const rootReducer = toolkit.combineReducers({
|
|
1797
|
+
gen3Services: gen3ServicesReducer,
|
|
1798
|
+
user: userReducer,
|
|
1799
|
+
gen3Apps: gen3AppReducer,
|
|
1800
|
+
drsHostnames: drsHostnamesReducer,
|
|
1801
|
+
modals: modalReducer,
|
|
1802
|
+
cohorts: cohortReducers,
|
|
1803
|
+
activeWorkspace: activeWorkspaceReducer,
|
|
1804
|
+
[guppyApiSliceReducerPath]: guppyApiReducer,
|
|
1805
|
+
[userAuthApiReducerPath]: userAuthApiReducer,
|
|
1806
|
+
[cartReducerPath]: cartReducer
|
|
1807
|
+
});
|
|
1751
1808
|
|
|
1752
1809
|
/**
|
|
1753
1810
|
* Flattens a deep nested JSON object skipping
|
|
@@ -2235,18 +2292,18 @@ const explorerTags = guppyApi.enhanceEndpoints({
|
|
|
2235
2292
|
*/ const explorerApi = explorerTags.injectEndpoints({
|
|
2236
2293
|
endpoints: (builder)=>({
|
|
2237
2294
|
getAllFieldsForType: builder.query({
|
|
2238
|
-
query: (type)=>({
|
|
2239
|
-
query: `{ _mapping ${type} } }`
|
|
2295
|
+
query: ({ type, indexPrefix = '' })=>({
|
|
2296
|
+
query: `{ ${indexPrefix}_mapping ${type} } }`
|
|
2240
2297
|
}),
|
|
2241
2298
|
transformResponse: (response, _meta, params)=>{
|
|
2242
2299
|
return response[params.type];
|
|
2243
2300
|
}
|
|
2244
2301
|
}),
|
|
2245
2302
|
getAccessibleData: builder.query({
|
|
2246
|
-
query: ({ type, fields, accessibility })=>{
|
|
2303
|
+
query: ({ type, fields, accessibility, indexPrefix = '' })=>{
|
|
2247
2304
|
const fieldParts = fields.map((field)=>`${field} { histogram { key count } }`);
|
|
2248
2305
|
return {
|
|
2249
|
-
query:
|
|
2306
|
+
query: `${indexPrefix}_aggregation {
|
|
2250
2307
|
${type} (accessibility: ${accessibility}) {
|
|
2251
2308
|
${fieldParts.join(',')}
|
|
2252
2309
|
}
|
|
@@ -2255,7 +2312,7 @@ const explorerTags = guppyApi.enhanceEndpoints({
|
|
|
2255
2312
|
}
|
|
2256
2313
|
}),
|
|
2257
2314
|
getRawDataAndTotalCounts: builder.query({
|
|
2258
|
-
query: ({ type, fields, filters, sort, offset = 0, size = 20, accessibility = Accessibility.ALL, format = undefined })=>{
|
|
2315
|
+
query: ({ type, fields, filters, sort, offset = 0, size = 20, accessibility = Accessibility.ALL, format = undefined, indexPrefix = '' })=>{
|
|
2259
2316
|
const gqlFilter = convertFilterSetToGqlFilter(filters);
|
|
2260
2317
|
const params = [
|
|
2261
2318
|
...sort ? [
|
|
@@ -2280,7 +2337,7 @@ const explorerTags = guppyApi.enhanceEndpoints({
|
|
|
2280
2337
|
'filter: $filter'
|
|
2281
2338
|
] : []
|
|
2282
2339
|
].join(',');
|
|
2283
|
-
const dataTypeLine = `${type} (accessibility: ${accessibility}, offset: ${offset}, first: ${size},
|
|
2340
|
+
const dataTypeLine = `${indexPrefix}${type} (accessibility: ${accessibility}, offset: ${offset}, first: ${size},
|
|
2284
2341
|
${dataParams}) {`;
|
|
2285
2342
|
const typeAggsLine = `${type} (${gqlFilter && 'filter: $filter,'} accessibility: ${accessibility}) {`;
|
|
2286
2343
|
const processedFields = fields.map((field)=>rawDataQueryStrForEachField(field));
|
|
@@ -2288,7 +2345,7 @@ const explorerTags = guppyApi.enhanceEndpoints({
|
|
|
2288
2345
|
${dataTypeLine}
|
|
2289
2346
|
${processedFields.join(' ')}
|
|
2290
2347
|
}
|
|
2291
|
-
_aggregation {
|
|
2348
|
+
${indexPrefix}_aggregation {
|
|
2292
2349
|
${typeAggsLine}
|
|
2293
2350
|
_totalCount
|
|
2294
2351
|
}
|
|
@@ -2316,13 +2373,13 @@ const explorerTags = guppyApi.enhanceEndpoints({
|
|
|
2316
2373
|
]
|
|
2317
2374
|
}),
|
|
2318
2375
|
getAggs: builder.query({
|
|
2319
|
-
query: ({ type, fields, filters, accessibility = Accessibility.ALL, filterSelf = false })=>{
|
|
2320
|
-
return buildGetAggregationQuery(type, fields, filters, accessibility, filterSelf);
|
|
2376
|
+
query: ({ type, fields, filters, accessibility = Accessibility.ALL, filterSelf = false, indexPrefix = '' })=>{
|
|
2377
|
+
return buildGetAggregationQuery(type, fields, filters, accessibility, filterSelf, undefined, indexPrefix);
|
|
2321
2378
|
},
|
|
2322
2379
|
transformResponse: (response, _meta, args)=>{
|
|
2323
|
-
const buckets = processHistogramResponse(response?.data?._aggregation[args.type] ?? {});
|
|
2380
|
+
const buckets = processHistogramResponse(response?.data?.[`${args?.indexPrefix ?? ''}_aggregation`][args.type] ?? {});
|
|
2324
2381
|
// check for totals
|
|
2325
|
-
const count = response?.data?._aggregation[args.type]?._totalCount ?? null;
|
|
2382
|
+
const count = response?.data?.[`${args?.indexPrefix ?? ''}_aggregation`][args.type]?._totalCount ?? null;
|
|
2326
2383
|
return {
|
|
2327
2384
|
_totalCount: [
|
|
2328
2385
|
{
|
|
@@ -2338,24 +2395,24 @@ const explorerTags = guppyApi.enhanceEndpoints({
|
|
|
2338
2395
|
]
|
|
2339
2396
|
}),
|
|
2340
2397
|
getStatsAggregations: builder.query({
|
|
2341
|
-
query: ({ type, fields, filters, accessibility = Accessibility.ALL, filterSelf = false, queryId = undefined })=>{
|
|
2342
|
-
return buildGetStatsAggregationQuery(type, fields, filters, accessibility, filterSelf, queryId);
|
|
2398
|
+
query: ({ type, fields, filters, accessibility = Accessibility.ALL, filterSelf = false, queryId = undefined, indexPrefix = '' })=>{
|
|
2399
|
+
return buildGetStatsAggregationQuery(type, fields, filters, accessibility, filterSelf, queryId, indexPrefix);
|
|
2343
2400
|
},
|
|
2344
2401
|
transformResponse: (response, _meta, args)=>{
|
|
2345
|
-
return processHistogramResponse(response?.data?._aggregation[args.type] ?? {});
|
|
2402
|
+
return processHistogramResponse(response?.data?.[`${args?.indexPrefix ?? ''}_aggregation`][args.type] ?? {});
|
|
2346
2403
|
},
|
|
2347
2404
|
providesTags: [
|
|
2348
2405
|
'STATS'
|
|
2349
2406
|
]
|
|
2350
2407
|
}),
|
|
2351
2408
|
getSubAggs: builder.query({
|
|
2352
|
-
query: ({ type, mainField, termsFields = undefined, missingFields = undefined, numericAggAsText = false, filters = undefined, accessibility = Accessibility.ALL })=>{
|
|
2409
|
+
query: ({ type, mainField, termsFields = undefined, missingFields = undefined, numericAggAsText = false, filters = undefined, accessibility = Accessibility.ALL, indexPrefix = '' })=>{
|
|
2353
2410
|
const nestedAggFields = {
|
|
2354
2411
|
termsFields: termsFields,
|
|
2355
2412
|
missingFields: missingFields
|
|
2356
2413
|
};
|
|
2357
2414
|
const query = `query getSubAggs ( ${filters ?? '$filter: JSON,'} $nestedAggFields: JSON) {
|
|
2358
|
-
_aggregation {
|
|
2415
|
+
${indexPrefix}_aggregation {
|
|
2359
2416
|
${type} ( ${filters ?? 'filter: $filter, filterSelf: false,'} nestedAggFields: $nestedAggFields, accessibility: ${accessibility}) {
|
|
2360
2417
|
_totalCounts
|
|
2361
2418
|
${nestedHistogramQueryStrForEachField(mainField, numericAggAsText)}
|
|
@@ -2371,18 +2428,18 @@ const explorerTags = guppyApi.enhanceEndpoints({
|
|
|
2371
2428
|
};
|
|
2372
2429
|
},
|
|
2373
2430
|
transformResponse: (response, _meta, args)=>{
|
|
2374
|
-
return processHistogramResponse(response?.data?._aggregation[args.type] ?? {});
|
|
2431
|
+
return processHistogramResponse(response?.data?.[`${args?.indexPrefix ?? ''}_aggregation`][args.type] ?? {});
|
|
2375
2432
|
},
|
|
2376
2433
|
providesTags: [
|
|
2377
2434
|
'AGGS'
|
|
2378
2435
|
]
|
|
2379
2436
|
}),
|
|
2380
2437
|
getCounts: builder.query({
|
|
2381
|
-
query: ({ type, filters, accessibility = Accessibility.ALL, queryId = undefined })=>{
|
|
2438
|
+
query: ({ type, filters, accessibility = Accessibility.ALL, queryId = undefined, indexPrefix = '' })=>{
|
|
2382
2439
|
const gqlFilters = convertFilterSetToGqlFilter(filters);
|
|
2383
|
-
const queryLine = `query totalCounts${queryId ?
|
|
2440
|
+
const queryLine = `query totalCounts${queryId ? `${indexPrefix}_${queryId}` : ''} ${gqlFilters ? '($filter: JSON)' : ''}{`;
|
|
2384
2441
|
const typeAggsLine = `${type} ${gqlFilters ? '(filter: $filter, ' : '('} accessibility: ${accessibility}) {`;
|
|
2385
|
-
const query = `${queryLine} _aggregation {
|
|
2442
|
+
const query = `${queryLine} ${indexPrefix}_aggregation {
|
|
2386
2443
|
${typeAggsLine}
|
|
2387
2444
|
_totalCount
|
|
2388
2445
|
}
|
|
@@ -2398,23 +2455,23 @@ const explorerTags = guppyApi.enhanceEndpoints({
|
|
|
2398
2455
|
};
|
|
2399
2456
|
},
|
|
2400
2457
|
transformResponse: (response, _meta, args)=>{
|
|
2401
|
-
if (!response.data || !response.data
|
|
2458
|
+
if (!response.data || !response.data[`${args?.indexPrefix ?? ''}_aggregation`]) {
|
|
2402
2459
|
throw new Error('Invalid response: Missing data or _aggregation field');
|
|
2403
2460
|
}
|
|
2404
|
-
if (!(args.type in response.data
|
|
2461
|
+
if (!(args.type in response.data[`${args?.indexPrefix ?? ''}_aggregation`])) {
|
|
2405
2462
|
throw new Error(`Invalid response: Missing expected key '${args.type}' in _aggregation`);
|
|
2406
2463
|
}
|
|
2407
|
-
return response.data
|
|
2464
|
+
return response.data[`${args?.indexPrefix ?? ''}_aggregation`][args.type]._totalCount ?? 0;
|
|
2408
2465
|
},
|
|
2409
2466
|
providesTags: [
|
|
2410
2467
|
'COUNTS'
|
|
2411
2468
|
]
|
|
2412
2469
|
}),
|
|
2413
2470
|
getFieldCountSummary: builder.query({
|
|
2414
|
-
query: ({ type, field, filters, accessibility = Accessibility.ALL })=>{
|
|
2471
|
+
query: ({ type, field, filters, accessibility = Accessibility.ALL, indexPrefix = '' })=>{
|
|
2415
2472
|
const gqlFilters = convertFilterSetToGqlFilter(filters);
|
|
2416
2473
|
const query = `query summary ($filter: JSON) {
|
|
2417
|
-
_aggregation {
|
|
2474
|
+
${indexPrefix}_aggregation {
|
|
2418
2475
|
${type} (filter: $filter, accessibility: ${accessibility}) {
|
|
2419
2476
|
${field} {
|
|
2420
2477
|
histogram {
|
|
@@ -2435,15 +2492,15 @@ const explorerTags = guppyApi.enhanceEndpoints({
|
|
|
2435
2492
|
}
|
|
2436
2493
|
}),
|
|
2437
2494
|
getFieldsForIndex: builder.query({
|
|
2438
|
-
query: (index)=>{
|
|
2495
|
+
query: ({ index, indexPrefix = '' })=>{
|
|
2439
2496
|
return {
|
|
2440
2497
|
query: `{
|
|
2441
|
-
_mapping { ${index} }
|
|
2498
|
+
${indexPrefix}_mapping { ${index} }
|
|
2442
2499
|
}`
|
|
2443
2500
|
};
|
|
2444
2501
|
},
|
|
2445
|
-
transformResponse: (response)=>{
|
|
2446
|
-
return response[
|
|
2502
|
+
transformResponse: (response, _meta, args)=>{
|
|
2503
|
+
return response[`${args.indexPrefix}_mapping`];
|
|
2447
2504
|
}
|
|
2448
2505
|
}),
|
|
2449
2506
|
getSharedFieldsForIndex: builder.query({
|
|
@@ -2480,16 +2537,18 @@ const useGetArrayTypes = ()=>{
|
|
|
2480
2537
|
return data ? data['indices'] : {};
|
|
2481
2538
|
}
|
|
2482
2539
|
};
|
|
2483
|
-
const useGetIndexFields = (index)=>{
|
|
2484
|
-
const { data } = useGetFieldsForIndexQuery(
|
|
2540
|
+
const useGetIndexFields = (index, indexPrefix = '')=>{
|
|
2541
|
+
const { data } = useGetFieldsForIndexQuery({
|
|
2542
|
+
index: index,
|
|
2543
|
+
indexPrefix: indexPrefix
|
|
2544
|
+
});
|
|
2485
2545
|
return data ?? [];
|
|
2486
2546
|
};
|
|
2487
|
-
const buildGetAggregationQuery = (type, fields, filters, accessibility = Accessibility.ALL, filterSelf = false, queryId = undefined)=>{
|
|
2488
|
-
const queryStart = isFilterEmpty(filters) ? `
|
|
2489
|
-
|
|
2490
|
-
_aggregation {
|
|
2547
|
+
const buildGetAggregationQuery = (type, fields, filters, accessibility = Accessibility.ALL, filterSelf = false, queryId = undefined, indexPrefix = '')=>{
|
|
2548
|
+
const queryStart = isFilterEmpty(filters) ? `query getAggs${queryId ? `_${queryId}` : ''} {
|
|
2549
|
+
${indexPrefix}_aggregation {
|
|
2491
2550
|
${type} (accessibility: ${accessibility}) {` : `query getAggs ($filter: JSON) {
|
|
2492
|
-
_aggregation {
|
|
2551
|
+
${indexPrefix}_aggregation {
|
|
2493
2552
|
|
|
2494
2553
|
${type} (filter: $filter, filterSelf: ${filterSelf ? 'true' : 'false'}, accessibility: ${accessibility}) { _totalCount`;
|
|
2495
2554
|
const query = `${queryStart}
|
|
@@ -2505,12 +2564,12 @@ const buildGetAggregationQuery = (type, fields, filters, accessibility = Accessi
|
|
|
2505
2564
|
};
|
|
2506
2565
|
return queryBody;
|
|
2507
2566
|
};
|
|
2508
|
-
const buildGetStatsAggregationQuery = (type, fields, filters, accessibility = Accessibility.ALL, filterSelf = false, queryId = undefined)=>{
|
|
2567
|
+
const buildGetStatsAggregationQuery = (type, fields, filters, accessibility = Accessibility.ALL, filterSelf = false, queryId = undefined, indexPrefix = '')=>{
|
|
2509
2568
|
const queryStart = isFilterEmpty(filters) ? `
|
|
2510
2569
|
query getStatsAggs${queryId ? `_${queryId}` : ''} {
|
|
2511
|
-
_aggregation {
|
|
2570
|
+
${indexPrefix}_aggregation {
|
|
2512
2571
|
${type} (accessibility: ${accessibility}) {` : `query getStatsAggs${queryId ? `_${queryId}` : ''} ($filter: JSON) {
|
|
2513
|
-
_aggregation {
|
|
2572
|
+
${indexPrefix}_aggregation {
|
|
2514
2573
|
${type} (filter: $filter, filterSelf: ${filterSelf ? 'true' : 'false'}, accessibility: ${accessibility}) { _totalCount`;
|
|
2515
2574
|
const query = `${queryStart}
|
|
2516
2575
|
${fields.map((field)=>statsQueryStrForEachField(field))}
|
|
@@ -2574,7 +2633,8 @@ const persistConfig = {
|
|
|
2574
2633
|
storage,
|
|
2575
2634
|
whitelist: [
|
|
2576
2635
|
'cohorts',
|
|
2577
|
-
'activeWorkspace'
|
|
2636
|
+
'activeWorkspace',
|
|
2637
|
+
'cart'
|
|
2578
2638
|
]
|
|
2579
2639
|
};
|
|
2580
2640
|
const persistedReducer = reduxPersist.persistReducer(persistConfig, rootReducer);
|
|
@@ -5759,6 +5819,7 @@ const isWorkspaceActive = (status)=>status === WorkspaceStatus.Running || status
|
|
|
5759
5819
|
const isWorkspaceRunningOrStopping = (status)=>status === WorkspaceStatus.Running || status === WorkspaceStatus.Terminating;
|
|
5760
5820
|
|
|
5761
5821
|
exports.Accessibility = Accessibility;
|
|
5822
|
+
exports.CART_LIMIT = CART_LIMIT;
|
|
5762
5823
|
exports.CohortStorage = CohortStorage;
|
|
5763
5824
|
exports.CoreProvider = CoreProvider;
|
|
5764
5825
|
exports.DAYS_IN_YEAR = DAYS_IN_YEAR;
|
|
@@ -5792,6 +5853,7 @@ exports.RequestedWorkspaceStatus = RequestedWorkspaceStatus;
|
|
|
5792
5853
|
exports.ToGqlHandler = ToGqlHandler;
|
|
5793
5854
|
exports.ValueExtractorHandler = ValueExtractorHandler;
|
|
5794
5855
|
exports.WorkspaceStatus = WorkspaceStatus;
|
|
5856
|
+
exports.addItemsToCart = addItemsToCart;
|
|
5795
5857
|
exports.ageDisplay = ageDisplay;
|
|
5796
5858
|
exports.appendFilterToOperation = appendFilterToOperation;
|
|
5797
5859
|
exports.buildGetAggregationQuery = buildGetAggregationQuery;
|
|
@@ -5801,6 +5863,8 @@ exports.buildNestedGQLFilter = buildNestedGQLFilter;
|
|
|
5801
5863
|
exports.calculatePercentageAsNumber = calculatePercentageAsNumber;
|
|
5802
5864
|
exports.calculatePercentageAsString = calculatePercentageAsString;
|
|
5803
5865
|
exports.capitalize = capitalize;
|
|
5866
|
+
exports.cartReducer = cartReducer;
|
|
5867
|
+
exports.cartReducerPath = cartReducerPath;
|
|
5804
5868
|
exports.clearActiveWorkspaceId = clearActiveWorkspaceId;
|
|
5805
5869
|
exports.clearCohortFilters = clearCohortFilters;
|
|
5806
5870
|
exports.cohortReducer = cohortReducer;
|
|
@@ -5828,6 +5892,7 @@ exports.extractEnumFilterValue = extractEnumFilterValue;
|
|
|
5828
5892
|
exports.extractFieldNameFromFullFieldName = extractFieldNameFromFullFieldName;
|
|
5829
5893
|
exports.extractFileDatasetsInRecords = extractFileDatasetsInRecords;
|
|
5830
5894
|
exports.extractFilterValue = extractFilterValue;
|
|
5895
|
+
exports.extractFiltersWithPrefixFromFilterSet = extractFiltersWithPrefixFromFilterSet;
|
|
5831
5896
|
exports.extractIndexAndFieldNameFromFullFieldName = extractIndexAndFieldNameFromFullFieldName;
|
|
5832
5897
|
exports.extractIndexFromDataLibraryCohort = extractIndexFromDataLibraryCohort;
|
|
5833
5898
|
exports.extractIndexFromFullFieldName = extractIndexFromFullFieldName;
|
|
@@ -5885,10 +5950,12 @@ exports.isHistogramRangeData = isHistogramRangeData;
|
|
|
5885
5950
|
exports.isHttpStatusError = isHttpStatusError;
|
|
5886
5951
|
exports.isIndexedFilterSetEmpty = isIndexedFilterSetEmpty;
|
|
5887
5952
|
exports.isIntersection = isIntersection;
|
|
5953
|
+
exports.isIntersectionOrUnion = isIntersectionOrUnion;
|
|
5888
5954
|
exports.isJSONObject = isJSONObject;
|
|
5889
5955
|
exports.isJSONValue = isJSONValue;
|
|
5890
5956
|
exports.isJSONValueArray = isJSONValueArray;
|
|
5891
5957
|
exports.isNameUnique = isNameUnique;
|
|
5958
|
+
exports.isNestedFilter = isNestedFilter;
|
|
5892
5959
|
exports.isNotDefined = isNotDefined;
|
|
5893
5960
|
exports.isObject = isObject;
|
|
5894
5961
|
exports.isOperandsType = isOperandsType;
|
|
@@ -5918,6 +5985,7 @@ exports.rawDataQueryStrForEachField = rawDataQueryStrForEachField;
|
|
|
5918
5985
|
exports.registerDefaultRemoteSupport = registerDefaultRemoteSupport;
|
|
5919
5986
|
exports.removeCohort = removeCohort;
|
|
5920
5987
|
exports.removeCohortFilter = removeCohortFilter;
|
|
5988
|
+
exports.removeItemsFromCart = removeItemsFromCart;
|
|
5921
5989
|
exports.requestorApi = requestorApi;
|
|
5922
5990
|
exports.resetUserState = resetUserState;
|
|
5923
5991
|
exports.resourcePathFromProjectID = resourcePathFromProjectID;
|
|
@@ -5931,6 +5999,10 @@ exports.selectAvailableCohortByName = selectAvailableCohortByName;
|
|
|
5931
5999
|
exports.selectAvailableCohorts = selectAvailableCohorts;
|
|
5932
6000
|
exports.selectCSRFToken = selectCSRFToken;
|
|
5933
6001
|
exports.selectCSRFTokenData = selectCSRFTokenData;
|
|
6002
|
+
exports.selectCart = selectCart;
|
|
6003
|
+
exports.selectCartCount = selectCartCount;
|
|
6004
|
+
exports.selectCartItem = selectCartItem;
|
|
6005
|
+
exports.selectCartItems = selectCartItems;
|
|
5934
6006
|
exports.selectCohortById = selectCohortById;
|
|
5935
6007
|
exports.selectCohortFilterCombineMode = selectCohortFilterCombineMode;
|
|
5936
6008
|
exports.selectCohortFilterExpanded = selectCohortFilterExpanded;
|