@gen3/core 0.12.22 → 0.12.24
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/constants.js +1 -0
- package/dist/cjs/constants.js.map +1 -1
- package/dist/cjs/index.js +1117 -891
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/server.js +1 -0
- package/dist/cjs/server.js.map +1 -1
- package/dist/constants.d.ts +2 -1
- package/dist/dts/constants.d.ts +1 -0
- package/dist/dts/constants.d.ts.map +1 -1
- package/dist/dts/features/cohortComparison/cohortFacetSlice.d.ts +201 -0
- package/dist/dts/features/cohortComparison/cohortFacetSlice.d.ts.map +1 -0
- package/dist/dts/features/cohortComparison/index.d.ts +7 -0
- package/dist/dts/features/cohortComparison/index.d.ts.map +1 -0
- package/dist/dts/features/cohortComparison/pValueApi.d.ts +186 -0
- package/dist/dts/features/cohortComparison/pValueApi.d.ts.map +1 -0
- package/dist/dts/features/cohortComparison/types.d.ts +74 -0
- package/dist/dts/features/cohortComparison/types.d.ts.map +1 -0
- package/dist/dts/features/cohortComparison/vennDiagramSlice.d.ts +198 -0
- package/dist/dts/features/cohortComparison/vennDiagramSlice.d.ts.map +1 -0
- package/dist/dts/features/filters/index.d.ts +1 -0
- package/dist/dts/features/filters/index.d.ts.map +1 -1
- package/dist/dts/features/filters/nestedFilters.d.ts +0 -2
- package/dist/dts/features/filters/nestedFilters.d.ts.map +1 -1
- package/dist/dts/features/filters/utils.d.ts +2 -2
- package/dist/dts/features/guppy/guppySlice.d.ts +566 -0
- package/dist/dts/features/guppy/guppySlice.d.ts.map +1 -1
- package/dist/dts/index.d.ts +1 -0
- package/dist/dts/index.d.ts.map +1 -1
- package/dist/dts/types/types.d.ts +15 -13
- package/dist/dts/types/types.d.ts.map +1 -1
- package/dist/esm/constants.js +1 -0
- package/dist/esm/constants.js.map +1 -1
- package/dist/esm/index.js +1103 -890
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/server.js +1 -0
- package/dist/esm/server.js.map +1 -1
- package/dist/index.d.ts +7633 -6431
- package/package.json +2 -2
- package/LICENSE +0 -201
package/dist/cjs/index.js
CHANGED
|
@@ -64,6 +64,7 @@ const GEN3_CROSSWALK_API = process.env.NEXT_PUBLIC_GEN3_CROSSWALK_API || `${GEN3
|
|
|
64
64
|
const GEN3_SOWER_API = process.env.NEXT_PUBLIC_GEN3_SOWER_API || `${GEN3_API}/jobs`;
|
|
65
65
|
const GEN3_MANIFEST_API = process.env.NEXT_PUBLIC_GEN3_MANIFEST_API || `${GEN3_API}/manifests`;
|
|
66
66
|
const GEN3_REQUESTOR_API = process.env.NEXT_PUBLIC_GEN3_REQUESTOR_API || `${GEN3_API}/requestor`;
|
|
67
|
+
const GEN3_ANALYSIS_API = process.env.NEXT_PUBLIC_GEN3_ANALYSIS_API || `${GEN3_API}/analysis/v0`;
|
|
67
68
|
var Accessibility = /*#__PURE__*/ function(Accessibility) {
|
|
68
69
|
Accessibility["ACCESSIBLE"] = "accessible";
|
|
69
70
|
Accessibility["UNACCESSIBLE"] = "unaccessible";
|
|
@@ -1780,12 +1781,12 @@ const COMMON_PREPOSITIONS = [
|
|
|
1780
1781
|
'yet'
|
|
1781
1782
|
];
|
|
1782
1783
|
const capitalize = (s)=>s.length > 0 ? s[0].toUpperCase() + s.slice(1) : '';
|
|
1783
|
-
const
|
|
1784
|
+
const trimFirstfieldNameToLabel = (fieldName, trim = false)=>{
|
|
1784
1785
|
if (trim) {
|
|
1785
1786
|
const source = fieldName.slice(fieldName.indexOf('.') + 1);
|
|
1786
|
-
return
|
|
1787
|
+
return fieldNameToLabel(source ? source : fieldName, 0);
|
|
1787
1788
|
}
|
|
1788
|
-
return
|
|
1789
|
+
return fieldNameToLabel(fieldName);
|
|
1789
1790
|
};
|
|
1790
1791
|
/**
|
|
1791
1792
|
* Converts a filter name to a title,
|
|
@@ -1793,7 +1794,7 @@ const trimFirstFieldNameToTitle = (fieldName, trim = false)=>{
|
|
|
1793
1794
|
* if sections == 2 then the output would be Input Experimental Strategy
|
|
1794
1795
|
* @param fieldName input filter expected to be: string.firstpart_secondpart
|
|
1795
1796
|
* @param sections number of "sections" string.string.string to got back from the end of the field
|
|
1796
|
-
*/ const
|
|
1797
|
+
*/ const fieldNameToLabel = (fieldName, sections = 1)=>{
|
|
1797
1798
|
if (fieldName === undefined) return 'No Title';
|
|
1798
1799
|
return fieldName.split('.').slice(-sections).map((s)=>s.split('_')).flat().map((word)=>COMMON_PREPOSITIONS.includes(word) ? word : capitalize(word)).map((word)=>word in FieldNameOverrides ? FieldNameOverrides[word] : word).join(' ');
|
|
1799
1800
|
};
|
|
@@ -1817,492 +1818,808 @@ const trimFirstFieldNameToTitle = (fieldName, trim = false)=>{
|
|
|
1817
1818
|
];
|
|
1818
1819
|
};
|
|
1819
1820
|
|
|
1820
|
-
const defaultCohortNameGenerator = ()=>`Custom cohort ${new Date().toLocaleString('en-CA', {
|
|
1821
|
-
timeZone: 'America/Chicago',
|
|
1822
|
-
hour12: false
|
|
1823
|
-
}).replace(',', '')}`;
|
|
1824
|
-
const isNameUnique = (entities, name, excludeId)=>{
|
|
1825
|
-
const trimmedName = name.trim();
|
|
1826
|
-
if (!trimmedName) return false;
|
|
1827
|
-
return !entities.some((cohort)=>cohort && cohort.id !== excludeId && cohort.name.trim().toLowerCase() === trimmedName.toLowerCase());
|
|
1828
|
-
};
|
|
1829
|
-
const generateUniqueName = (entities, baseName)=>{
|
|
1830
|
-
const trimmedBaseName = baseName.trim();
|
|
1831
|
-
// If base name is unique, use it
|
|
1832
|
-
if (isNameUnique(entities, trimmedBaseName)) {
|
|
1833
|
-
return trimmedBaseName;
|
|
1834
|
-
}
|
|
1835
|
-
// Find a unique name by appending numbers
|
|
1836
|
-
let counter = 1;
|
|
1837
|
-
let uniqueName;
|
|
1838
|
-
do {
|
|
1839
|
-
uniqueName = `${trimmedBaseName} (${counter})`;
|
|
1840
|
-
counter++;
|
|
1841
|
-
}while (!isNameUnique(entities, uniqueName))
|
|
1842
|
-
return uniqueName;
|
|
1843
|
-
};
|
|
1844
1821
|
/**
|
|
1845
|
-
*
|
|
1846
|
-
*
|
|
1847
|
-
*
|
|
1848
|
-
*
|
|
1822
|
+
* Constructs a nested operation object based on the provided field and leaf operand.
|
|
1823
|
+
* If the field does not contain a dot '.', it either assigns the field to the leaf operand (if applicable)
|
|
1824
|
+
* or returns the leaf operand as is. When the field contains dots, it splits the field into parts,
|
|
1825
|
+
* creates a "nested" operation for the root field, and recursively constructs the nested structure
|
|
1826
|
+
* for the remaining portion of the field.
|
|
1849
1827
|
*
|
|
1850
|
-
*
|
|
1851
|
-
*
|
|
1852
|
-
*
|
|
1853
|
-
*
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
root: {}
|
|
1859
|
-
};
|
|
1828
|
+
* @param {string} field - The hierarchical field path, with segments separated by dots (e.g., "root.child").
|
|
1829
|
+
* @param {Operation} leafOperand - The operation to be nested within the specified path.
|
|
1830
|
+
* @param parentPath - The parent path of the current field. Guppy nested filters require a parent path.
|
|
1831
|
+
* @param depth
|
|
1832
|
+
* @returns {Operation} A nested operation object that represents the structured path and operand.
|
|
1833
|
+
*/ const buildNestedWithParentPathGQLFilter = (field, leafOperand, parentPath = undefined)=>{
|
|
1834
|
+
if (!field.includes('.')) {
|
|
1835
|
+
return leafOperand;
|
|
1860
1836
|
}
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1837
|
+
const splitFieldArray = field.split('.');
|
|
1838
|
+
const nextField = splitFieldArray.shift();
|
|
1839
|
+
if (!nextField) {
|
|
1840
|
+
console.warn('Invalid field path:', field);
|
|
1841
|
+
return leafOperand;
|
|
1842
|
+
}
|
|
1843
|
+
const currentPath = parentPath ? `${parentPath}.${nextField}` : nextField;
|
|
1844
|
+
return {
|
|
1845
|
+
nested: {
|
|
1846
|
+
path: currentPath,
|
|
1847
|
+
...buildNestedGQLFilter(splitFieldArray.join('.'), leafOperand, currentPath)
|
|
1865
1848
|
}
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1849
|
+
};
|
|
1850
|
+
};
|
|
1851
|
+
const buildCohortGqlOperator = (fs)=>{
|
|
1852
|
+
if (!fs || !fs.root) return undefined;
|
|
1853
|
+
const fsKeys = Object.keys(fs.root);
|
|
1854
|
+
// if no keys return undefined
|
|
1855
|
+
if (fsKeys.length === 0) return undefined;
|
|
1856
|
+
// TODO consider changing FilterSet: mode to support joinOrToAll as FilterSet mode
|
|
1857
|
+
// find key using keyword "joinOrToAll"
|
|
1858
|
+
const joinOrToAllKey = fsKeys.filter((x)=>x.includes('joinOrToAll'));
|
|
1859
|
+
switch(fs.mode){
|
|
1860
|
+
case 'and':
|
|
1861
|
+
if (joinOrToAllKey.length === 1) {
|
|
1862
|
+
const firstJoinOrToAllKey = joinOrToAllKey[0];
|
|
1863
|
+
// Remove firstJoinOrToAllKey from Array
|
|
1864
|
+
fsKeys.splice(fsKeys.indexOf(firstJoinOrToAllKey), 1);
|
|
1865
|
+
const firstJoinOrToAllObj = fs.root[firstJoinOrToAllKey];
|
|
1866
|
+
// make sure type is or/ Union
|
|
1867
|
+
if (firstJoinOrToAllObj.operator === 'or') {
|
|
1868
|
+
return {
|
|
1869
|
+
or: firstJoinOrToAllObj?.operands.map((orObj)=>{
|
|
1870
|
+
// go through each or statement and add all other filters to it
|
|
1871
|
+
return {
|
|
1872
|
+
and: [
|
|
1873
|
+
convertFilterToNestedGqlFilter(orObj),
|
|
1874
|
+
...fsKeys.map((k)=>{
|
|
1875
|
+
return convertFilterToNestedGqlFilter(fs.root[k]);
|
|
1876
|
+
})
|
|
1877
|
+
]
|
|
1878
|
+
};
|
|
1879
|
+
})
|
|
1880
|
+
};
|
|
1881
|
+
} else {
|
|
1882
|
+
console.error(`function buildCohortGqlOperator expecting "or" received "${firstJoinOrToAllObj.operator}" on key "${firstJoinOrToAllKey}"`);
|
|
1883
|
+
}
|
|
1884
|
+
} else if (joinOrToAllKey.length > 1) {
|
|
1885
|
+
console.error(`function buildCohortGqlOperator expecting only one joinOrToAll received: ${joinOrToAllKey.length}`, fsKeys);
|
|
1886
|
+
}
|
|
1887
|
+
return {
|
|
1888
|
+
// TODO: Replace fixed AND with cohort top level operation like Union or Intersection
|
|
1889
|
+
[fs.mode]: fsKeys.map((k)=>{
|
|
1890
|
+
return convertFilterToGqlFilter(fs.root[k]);
|
|
1891
|
+
})
|
|
1892
|
+
};
|
|
1893
|
+
case 'or':
|
|
1894
|
+
return {
|
|
1895
|
+
[fs.mode]: fsKeys.map((k)=>{
|
|
1896
|
+
return convertFilterToGqlFilter(fs.root[k]);
|
|
1897
|
+
})
|
|
1898
|
+
};
|
|
1899
|
+
}
|
|
1871
1900
|
};
|
|
1872
|
-
|
|
1873
1901
|
/**
|
|
1874
|
-
*
|
|
1875
|
-
*
|
|
1876
|
-
*
|
|
1877
|
-
*/ const
|
|
1878
|
-
const newCohort = ({ filters = {}, customName })=>{
|
|
1879
|
-
const ts = new Date().toISOString();
|
|
1880
|
-
const newName = customName ?? defaultCohortNameGenerator();
|
|
1881
|
-
const newId = createCohortId();
|
|
1902
|
+
* Merged two FilterSets returning the merged pair.
|
|
1903
|
+
* @param a - first FilterSet
|
|
1904
|
+
* @param b - other FilterSet
|
|
1905
|
+
*/ const joinFilters = (a, b)=>{
|
|
1882
1906
|
return {
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
createdDatetime: ts,
|
|
1889
|
-
modifiedDatetime: ts,
|
|
1890
|
-
counts: {}
|
|
1907
|
+
mode: a.mode,
|
|
1908
|
+
root: {
|
|
1909
|
+
...a.root,
|
|
1910
|
+
...b.root
|
|
1911
|
+
}
|
|
1891
1912
|
};
|
|
1892
1913
|
};
|
|
1893
|
-
const
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
})
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
}
|
|
1906
|
-
const
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
}
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
});
|
|
1926
|
-
cohortsAdapter.addOne(state, cohort);
|
|
1927
|
-
if (action.payload?.setAsCurrent) {
|
|
1928
|
-
state.currentCohortId = cohort.id;
|
|
1914
|
+
const convertFilterSetToOperation = (fs)=>{
|
|
1915
|
+
if (!fs) return undefined;
|
|
1916
|
+
switch(fs.mode){
|
|
1917
|
+
case 'and':
|
|
1918
|
+
return Object.keys(fs.root).length == 0 ? undefined : {
|
|
1919
|
+
operator: fs.mode,
|
|
1920
|
+
operands: Object.keys(fs.root).map((k)=>{
|
|
1921
|
+
return fs.root[k];
|
|
1922
|
+
})
|
|
1923
|
+
};
|
|
1924
|
+
}
|
|
1925
|
+
return undefined;
|
|
1926
|
+
};
|
|
1927
|
+
const extractContents = (filter)=>{
|
|
1928
|
+
if (isGQLUnion(filter)) {
|
|
1929
|
+
return filter.or;
|
|
1930
|
+
}
|
|
1931
|
+
if (isGQLIntersection(filter)) {
|
|
1932
|
+
return filter.and;
|
|
1933
|
+
}
|
|
1934
|
+
return undefined;
|
|
1935
|
+
};
|
|
1936
|
+
class ToGqlAllNested {
|
|
1937
|
+
constructor(){
|
|
1938
|
+
this.handleEquals = (op)=>{
|
|
1939
|
+
if (op.field.includes('.')) {
|
|
1940
|
+
const leafField = op.field.split('.').at(-1) ?? 'unset';
|
|
1941
|
+
return buildNestedGQLFilter(op.field, {
|
|
1942
|
+
'=': {
|
|
1943
|
+
[leafField]: op.operand
|
|
1944
|
+
}
|
|
1945
|
+
});
|
|
1929
1946
|
}
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
cohortsAdapter.updateOne(state, {
|
|
1934
|
-
id: id,
|
|
1935
|
-
changes: {
|
|
1936
|
-
name: name,
|
|
1937
|
-
modified: true,
|
|
1938
|
-
modifiedDatetime: new Date().toISOString()
|
|
1947
|
+
return {
|
|
1948
|
+
'=': {
|
|
1949
|
+
[op.field]: op.operand
|
|
1939
1950
|
}
|
|
1940
|
-
}
|
|
1941
|
-
}
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
filters: {},
|
|
1950
|
-
customName: DEFAULT_COHORT_NAME
|
|
1951
|
+
};
|
|
1952
|
+
};
|
|
1953
|
+
this.handleNotEquals = (op)=>{
|
|
1954
|
+
if (op.field.includes('.')) {
|
|
1955
|
+
const leafField = op.field.split('.').at(-1) ?? 'unset';
|
|
1956
|
+
return buildNestedGQLFilter(op.field, {
|
|
1957
|
+
'!=': {
|
|
1958
|
+
[leafField]: op.operand
|
|
1959
|
+
}
|
|
1951
1960
|
});
|
|
1952
|
-
cohortsAdapter.addOne(state, defaultCohort);
|
|
1953
|
-
state.currentCohortId = defaultCohort.id;
|
|
1954
|
-
if (action?.payload.shouldShowMessage) {
|
|
1955
|
-
state.message = [
|
|
1956
|
-
`deleteCohort|${removedCohortName}|${state.currentCohortId}`
|
|
1957
|
-
];
|
|
1958
|
-
}
|
|
1959
|
-
return;
|
|
1960
1961
|
}
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1962
|
+
return {
|
|
1963
|
+
'!=': {
|
|
1964
|
+
[op.field]: op.operand
|
|
1965
|
+
}
|
|
1966
|
+
};
|
|
1967
|
+
};
|
|
1968
|
+
this.handleLessThan = (op)=>{
|
|
1969
|
+
if (op.field.includes('.')) {
|
|
1970
|
+
const leafField = op.field.split('.').at(-1) ?? 'unset';
|
|
1971
|
+
return buildNestedGQLFilter(op.field, {
|
|
1972
|
+
'<': {
|
|
1973
|
+
[leafField]: op.operand
|
|
1974
|
+
}
|
|
1975
|
+
});
|
|
1966
1976
|
}
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1977
|
+
return {
|
|
1978
|
+
'<': {
|
|
1979
|
+
[op.field]: op.operand
|
|
1980
|
+
}
|
|
1981
|
+
};
|
|
1982
|
+
};
|
|
1983
|
+
this.handleLessThanOrEquals = (op)=>{
|
|
1984
|
+
if (op.field.includes('.')) {
|
|
1985
|
+
const leafField = op.field.split('.').at(-1) ?? 'unset';
|
|
1986
|
+
return buildNestedGQLFilter(op.field, {
|
|
1987
|
+
'<=': {
|
|
1988
|
+
[leafField]: op.operand
|
|
1989
|
+
}
|
|
1990
|
+
});
|
|
1971
1991
|
}
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1992
|
+
return {
|
|
1993
|
+
'<=': {
|
|
1994
|
+
[op.field]: op.operand
|
|
1995
|
+
}
|
|
1996
|
+
};
|
|
1997
|
+
};
|
|
1998
|
+
this.handleGreaterThan = (op)=>{
|
|
1999
|
+
if (op.field.includes('.')) {
|
|
2000
|
+
const leafField = op.field.split('.').at(-1) ?? 'unset';
|
|
2001
|
+
return buildNestedGQLFilter(op.field, {
|
|
2002
|
+
'>': {
|
|
2003
|
+
[leafField]: op.operand
|
|
2004
|
+
}
|
|
2005
|
+
});
|
|
1979
2006
|
}
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
filters: {
|
|
1984
|
-
...state.entities[currentCohortId].filters,
|
|
1985
|
-
[index]: {
|
|
1986
|
-
mode: state.entities[currentCohortId]?.filters[index]?.mode ?? 'and',
|
|
1987
|
-
root: {
|
|
1988
|
-
...state.entities[currentCohortId]?.filters[index]?.root ?? {},
|
|
1989
|
-
[field]: filter
|
|
1990
|
-
}
|
|
1991
|
-
}
|
|
1992
|
-
},
|
|
1993
|
-
modified: true,
|
|
1994
|
-
modifiedDatetime: new Date().toISOString()
|
|
2007
|
+
return {
|
|
2008
|
+
'>': {
|
|
2009
|
+
[op.field]: op.operand
|
|
1995
2010
|
}
|
|
1996
|
-
}
|
|
1997
|
-
}
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2011
|
+
};
|
|
2012
|
+
};
|
|
2013
|
+
this.handleGreaterThanOrEquals = (op)=>{
|
|
2014
|
+
if (op.field.includes('.')) {
|
|
2015
|
+
const leafField = op.field.split('.').at(-1) ?? 'unset';
|
|
2016
|
+
return buildNestedGQLFilter(op.field, {
|
|
2017
|
+
'>=': {
|
|
2018
|
+
[leafField]: op.operand
|
|
2019
|
+
}
|
|
2020
|
+
});
|
|
2004
2021
|
}
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
filters: {
|
|
2009
|
-
...state.entities[currentCohortId].filters,
|
|
2010
|
-
[index]: filters
|
|
2011
|
-
},
|
|
2012
|
-
modified: true,
|
|
2013
|
-
modifiedDatetime: new Date().toISOString()
|
|
2022
|
+
return {
|
|
2023
|
+
'>=': {
|
|
2024
|
+
[op.field]: op.operand
|
|
2014
2025
|
}
|
|
2015
|
-
}
|
|
2016
|
-
}
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2026
|
+
};
|
|
2027
|
+
};
|
|
2028
|
+
this.handleIncludes = (op)=>{
|
|
2029
|
+
if (op.field.includes('.')) {
|
|
2030
|
+
const leafField = op.field.split('.').at(-1) ?? 'unset';
|
|
2031
|
+
return buildNestedGQLFilter(op.field, {
|
|
2032
|
+
in: {
|
|
2033
|
+
[leafField]: op.operands
|
|
2034
|
+
}
|
|
2035
|
+
});
|
|
2022
2036
|
}
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
filters: action.payload.filters,
|
|
2027
|
-
modified: true,
|
|
2028
|
-
modifiedDatetime: new Date().toISOString()
|
|
2037
|
+
return {
|
|
2038
|
+
in: {
|
|
2039
|
+
[op.field]: op.operands
|
|
2029
2040
|
}
|
|
2030
|
-
}
|
|
2031
|
-
}
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2041
|
+
};
|
|
2042
|
+
};
|
|
2043
|
+
this.handleExcludes = (op)=>{
|
|
2044
|
+
if (op.field.includes('.')) {
|
|
2045
|
+
const leafField = op.field.split('.').at(-1) ?? 'unset';
|
|
2046
|
+
return buildNestedGQLFilter(op.field, {
|
|
2047
|
+
exclude: {
|
|
2048
|
+
[leafField]: op.operands
|
|
2049
|
+
}
|
|
2050
|
+
});
|
|
2039
2051
|
}
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2052
|
+
return {
|
|
2053
|
+
exclude: {
|
|
2054
|
+
[op.field]: op.operands
|
|
2055
|
+
}
|
|
2056
|
+
};
|
|
2057
|
+
};
|
|
2058
|
+
this.handleExcludeIfAny = (op)=>{
|
|
2059
|
+
if (op.field.includes('.')) {
|
|
2060
|
+
const leafField = op.field.split('.').at(-1) ?? 'unset';
|
|
2061
|
+
return buildNestedGQLFilter(op.field, {
|
|
2062
|
+
excludeifany: {
|
|
2063
|
+
[leafField]: op.operands
|
|
2064
|
+
}
|
|
2065
|
+
});
|
|
2043
2066
|
}
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
id: currentCohortId,
|
|
2048
|
-
changes: {
|
|
2049
|
-
filters: {
|
|
2050
|
-
...state.entities[currentCohortId]?.filters,
|
|
2051
|
-
[index]: {
|
|
2052
|
-
mode: state.entities[currentCohortId].filters[index].mode,
|
|
2053
|
-
root: updated
|
|
2054
|
-
}
|
|
2055
|
-
},
|
|
2056
|
-
modified: true,
|
|
2057
|
-
modifiedDatetime: new Date().toISOString()
|
|
2067
|
+
return {
|
|
2068
|
+
excludeifany: {
|
|
2069
|
+
[op.field]: op.operands
|
|
2058
2070
|
}
|
|
2071
|
+
};
|
|
2072
|
+
};
|
|
2073
|
+
this.handleIntersection = (op)=>({
|
|
2074
|
+
and: op.operands.map((x)=>convertFilterToGqlFilter(x))
|
|
2059
2075
|
});
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
const currentCohortId = getCurrentCohortId(state);
|
|
2063
|
-
const currentCohort = state.entities[currentCohortId];
|
|
2064
|
-
const newName = generateUniqueName(Object.values(state.entities), currentCohort.name);
|
|
2065
|
-
const duplicatedCohort = newCohort({
|
|
2066
|
-
filters: {
|
|
2067
|
-
...currentCohort.filters
|
|
2068
|
-
},
|
|
2069
|
-
customName: newName
|
|
2070
|
-
});
|
|
2071
|
-
cohortsAdapter.addOne(state, {
|
|
2072
|
-
...duplicatedCohort,
|
|
2073
|
-
counts: {
|
|
2074
|
-
...currentCohort.counts
|
|
2075
|
-
}
|
|
2076
|
+
this.handleUnion = (op)=>({
|
|
2077
|
+
or: op.operands.map((x)=>convertFilterToGqlFilter(x))
|
|
2076
2078
|
});
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
return;
|
|
2086
|
-
}
|
|
2087
|
-
const filters = state.entities[currentCohortId]?.filters[index]?.root;
|
|
2088
|
-
if (!filters) {
|
|
2089
|
-
return;
|
|
2079
|
+
this.handleMissing = (op)=>{
|
|
2080
|
+
if (op.field.includes('.')) {
|
|
2081
|
+
const leafField = op.field.split('.').at(-1) ?? 'unset';
|
|
2082
|
+
return buildNestedGQLFilter(op.field, {
|
|
2083
|
+
is: {
|
|
2084
|
+
[leafField]: 'MISSING'
|
|
2085
|
+
}
|
|
2086
|
+
});
|
|
2090
2087
|
}
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
filters: {
|
|
2095
|
-
...state.entities[currentCohortId]?.filters,
|
|
2096
|
-
[index]: {
|
|
2097
|
-
mode: 'and',
|
|
2098
|
-
root: {}
|
|
2099
|
-
}
|
|
2100
|
-
},
|
|
2101
|
-
modified: true,
|
|
2102
|
-
modifiedDatetime: new Date().toISOString()
|
|
2088
|
+
return {
|
|
2089
|
+
is: {
|
|
2090
|
+
[op.field]: 'MISSING'
|
|
2103
2091
|
}
|
|
2104
|
-
}
|
|
2105
|
-
}
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
counts: {
|
|
2113
|
-
...currentCohort.counts,
|
|
2114
|
-
...action.payload
|
|
2092
|
+
};
|
|
2093
|
+
};
|
|
2094
|
+
this.handleExists = (op)=>{
|
|
2095
|
+
if (op.field.includes('.')) {
|
|
2096
|
+
const leafField = op.field.split('.').at(-1) ?? 'unset';
|
|
2097
|
+
return buildNestedGQLFilter(op.field, {
|
|
2098
|
+
not: {
|
|
2099
|
+
[leafField]: op?.operand ?? null
|
|
2115
2100
|
}
|
|
2101
|
+
});
|
|
2102
|
+
}
|
|
2103
|
+
return {
|
|
2104
|
+
not: {
|
|
2105
|
+
[op.field]: op?.operand ?? null
|
|
2116
2106
|
}
|
|
2117
|
-
}
|
|
2118
|
-
}
|
|
2119
|
-
|
|
2120
|
-
const
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
counts: {
|
|
2126
|
-
...cohort.counts,
|
|
2127
|
-
...{
|
|
2128
|
-
[index]: counts
|
|
2129
|
-
}
|
|
2130
|
-
}
|
|
2107
|
+
};
|
|
2108
|
+
};
|
|
2109
|
+
this.handleNestedFilter = (op)=>{
|
|
2110
|
+
const child = convertFilterToGqlFilter(op.operand);
|
|
2111
|
+
return {
|
|
2112
|
+
nested: {
|
|
2113
|
+
path: op.path,
|
|
2114
|
+
...child
|
|
2131
2115
|
}
|
|
2132
|
-
}
|
|
2133
|
-
}
|
|
2134
|
-
setCurrentCohortId: (state, action)=>{
|
|
2135
|
-
state.currentCohortId = action.payload;
|
|
2136
|
-
},
|
|
2137
|
-
/** @hidden */ setCohortList: (state, action)=>{
|
|
2138
|
-
if (!action.payload) {
|
|
2139
|
-
cohortsAdapter.removeMany(state, state.ids);
|
|
2140
|
-
} else {
|
|
2141
|
-
cohortsAdapter.upsertMany(state, [
|
|
2142
|
-
...action.payload
|
|
2143
|
-
]);
|
|
2144
|
-
}
|
|
2145
|
-
}
|
|
2116
|
+
};
|
|
2117
|
+
};
|
|
2146
2118
|
}
|
|
2147
|
-
}
|
|
2119
|
+
}
|
|
2120
|
+
const convertFilterToNestedGqlFilter = (filter)=>{
|
|
2121
|
+
const handler = new ToGqlAllNested();
|
|
2122
|
+
return handleOperation(handler, filter);
|
|
2123
|
+
};
|
|
2124
|
+
const convertFilterSetToNestedGqlFilter = (fs, toplevelOp = 'and')=>{
|
|
2125
|
+
const fsKeys = Object.keys(fs.root);
|
|
2126
|
+
// if no keys return undefined
|
|
2127
|
+
if (fsKeys.length === 0) return {
|
|
2128
|
+
and: []
|
|
2129
|
+
};
|
|
2130
|
+
return toplevelOp === 'and' ? {
|
|
2131
|
+
and: fsKeys.map((key)=>convertFilterToNestedGqlFilter(fs.root[key]))
|
|
2132
|
+
} : {
|
|
2133
|
+
or: fsKeys.map((key)=>convertFilterToNestedGqlFilter(fs.root[key]))
|
|
2134
|
+
};
|
|
2135
|
+
};
|
|
2136
|
+
|
|
2137
|
+
const defaultCohortNameGenerator = ()=>`Custom cohort ${new Date().toLocaleString('en-CA', {
|
|
2138
|
+
timeZone: 'America/Chicago',
|
|
2139
|
+
hour12: false
|
|
2140
|
+
}).replace(',', '')}`;
|
|
2141
|
+
const isNameUnique = (entities, name, excludeId)=>{
|
|
2142
|
+
const trimmedName = name.trim();
|
|
2143
|
+
if (!trimmedName) return false;
|
|
2144
|
+
return !entities.some((cohort)=>cohort && cohort.id !== excludeId && cohort.name.trim().toLowerCase() === trimmedName.toLowerCase());
|
|
2145
|
+
};
|
|
2146
|
+
const generateUniqueName = (entities, baseName)=>{
|
|
2147
|
+
const trimmedBaseName = baseName.trim();
|
|
2148
|
+
// If base name is unique, use it
|
|
2149
|
+
if (isNameUnique(entities, trimmedBaseName)) {
|
|
2150
|
+
return trimmedBaseName;
|
|
2151
|
+
}
|
|
2152
|
+
// Find a unique name by appending numbers
|
|
2153
|
+
let counter = 1;
|
|
2154
|
+
let uniqueName;
|
|
2155
|
+
do {
|
|
2156
|
+
uniqueName = `${trimmedBaseName} (${counter})`;
|
|
2157
|
+
counter++;
|
|
2158
|
+
}while (!isNameUnique(entities, uniqueName))
|
|
2159
|
+
return uniqueName;
|
|
2160
|
+
};
|
|
2148
2161
|
/**
|
|
2149
|
-
*
|
|
2150
|
-
*
|
|
2162
|
+
* This function takes a FilterSet object and a prefix string as input.
|
|
2163
|
+
* It filters the root property of the FilterSet object and returns a
|
|
2164
|
+
* new FilterSet object that only contains filters with field names
|
|
2165
|
+
* that start with the specified prefix.
|
|
2151
2166
|
*
|
|
2152
|
-
*
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
const
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
reducers: {
|
|
2163
|
-
toggleCohortBuilderCategoryFilter: (state, action)=>{
|
|
2164
|
-
return {
|
|
2165
|
-
...state,
|
|
2166
|
-
[action.payload.index]: {
|
|
2167
|
-
...state[action.payload.index],
|
|
2168
|
-
[action.payload.field]: action.payload.expanded
|
|
2169
|
-
}
|
|
2170
|
-
};
|
|
2171
|
-
},
|
|
2172
|
-
toggleCohortBuilderAllFilters: (state, action)=>{
|
|
2173
|
-
return {
|
|
2174
|
-
...state,
|
|
2175
|
-
[action.payload.index]: Object.keys(state[action.payload.index]).reduce((acc, k)=>{
|
|
2176
|
-
acc[k] = action.payload.expand;
|
|
2177
|
-
return acc;
|
|
2178
|
-
}, {})
|
|
2179
|
-
};
|
|
2180
|
-
}
|
|
2167
|
+
* @param fs - The FilterSet object to filter
|
|
2168
|
+
* @param prefix - The prefix to filter by
|
|
2169
|
+
* @returns - A new FilterSet object that only contains filters with field names that start with the specified prefix
|
|
2170
|
+
* @category Filters
|
|
2171
|
+
*/ const extractFiltersWithPrefixFromFilterSet = (fs, prefix)=>{
|
|
2172
|
+
if (fs === undefined || fs.root === undefined) {
|
|
2173
|
+
return {
|
|
2174
|
+
mode: 'and',
|
|
2175
|
+
root: {}
|
|
2176
|
+
};
|
|
2181
2177
|
}
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
const selectAllCohortFiltersCollapsed = (state, index)=>index in state.cohorts.filtersExpanded ? Object.values(state.cohorts.filtersExpanded?.[index]).every((e)=>!e) : false;
|
|
2187
|
-
|
|
2188
|
-
const initialState$1 = {};
|
|
2189
|
-
const expandSlice = toolkit.createSlice({
|
|
2190
|
-
name: 'CohortBuilder/filterCombineMode',
|
|
2191
|
-
initialState: initialState$1,
|
|
2192
|
-
reducers: {
|
|
2193
|
-
setCohortFilterCombineMode: (state, action)=>{
|
|
2194
|
-
return {
|
|
2195
|
-
...state,
|
|
2196
|
-
[action.payload.index]: {
|
|
2197
|
-
...state[action.payload.index],
|
|
2198
|
-
[action.payload.field]: action.payload.mode
|
|
2199
|
-
}
|
|
2200
|
-
};
|
|
2178
|
+
return Object.values(fs.root).reduce((acc, filter)=>{
|
|
2179
|
+
if (isIntersectionOrUnion(filter) || isNestedFilter(filter)) return acc;
|
|
2180
|
+
if (filter.field.startsWith(prefix)) {
|
|
2181
|
+
acc.root[filter.field] = filter;
|
|
2201
2182
|
}
|
|
2202
|
-
|
|
2203
|
-
}
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2183
|
+
return acc;
|
|
2184
|
+
}, {
|
|
2185
|
+
mode: 'and',
|
|
2186
|
+
root: {}
|
|
2187
|
+
});
|
|
2188
|
+
};
|
|
2207
2189
|
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2190
|
+
/**
|
|
2191
|
+
* Cohorts in Gen3 are defined as a set of filters for each index in the data.
|
|
2192
|
+
* This means one cohort id defined for all "tabs" in CohortBuilder (explorer)
|
|
2193
|
+
* Switching a cohort id means all the cohorts for the index are changed.
|
|
2194
|
+
*/ const DEFAULT_COHORT_NAME = 'Cohort';
|
|
2195
|
+
const newCohort = ({ filters = {}, customName })=>{
|
|
2196
|
+
const ts = new Date().toISOString();
|
|
2197
|
+
const newName = customName ?? defaultCohortNameGenerator();
|
|
2198
|
+
const newId = createCohortId();
|
|
2199
|
+
return {
|
|
2200
|
+
name: newName,
|
|
2201
|
+
id: newId,
|
|
2202
|
+
filters: filters ?? {},
|
|
2203
|
+
modified: false,
|
|
2204
|
+
saved: false,
|
|
2205
|
+
createdDatetime: ts,
|
|
2206
|
+
modifiedDatetime: ts,
|
|
2207
|
+
counts: {}
|
|
2208
|
+
};
|
|
2211
2209
|
};
|
|
2212
|
-
const
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
setSharedFilters: (state, action)=>{
|
|
2221
|
-
state.sharedFiltersMap = action.payload;
|
|
2222
|
-
}
|
|
2223
|
-
}
|
|
2210
|
+
const nanoid = nanoid$1.customAlphabet('1234567890abcdef', 16);
|
|
2211
|
+
const createCohortId = ()=>nanoid();
|
|
2212
|
+
const cohortsAdapter = toolkit.createEntityAdapter({
|
|
2213
|
+
sortComparer: (a, b)=>{
|
|
2214
|
+
if (a.modifiedDatetime <= b.modifiedDatetime) return 1;
|
|
2215
|
+
else return -1;
|
|
2216
|
+
},
|
|
2217
|
+
selectId: (cohort)=>cohort.id
|
|
2224
2218
|
});
|
|
2225
|
-
|
|
2226
|
-
const
|
|
2227
|
-
|
|
2228
|
-
field
|
|
2229
|
-
];
|
|
2230
|
-
const { setShouldShareFilters, setSharedFilters } = cohortSharedFiltersSlice.actions;
|
|
2231
|
-
const cohortSharedFiltersReducer = cohortSharedFiltersSlice.reducer;
|
|
2232
|
-
|
|
2233
|
-
const cohortReducers = toolkit.combineReducers({
|
|
2234
|
-
filtersExpanded: cohortBuilderFiltersExpandedReducer,
|
|
2235
|
-
filtersCombineMode: cohortBuilderFiltersCombineModeReducer,
|
|
2236
|
-
sharedFilters: cohortSharedFiltersReducer,
|
|
2237
|
-
cohortManager: cohortReducer
|
|
2219
|
+
// Create an initial unsaved cohort
|
|
2220
|
+
const initialCohort = newCohort({
|
|
2221
|
+
customName: DEFAULT_COHORT_NAME
|
|
2238
2222
|
});
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
user: userReducer,
|
|
2243
|
-
gen3Apps: gen3AppReducer,
|
|
2244
|
-
drsHostnames: drsHostnamesReducer,
|
|
2245
|
-
modals: modalReducer,
|
|
2246
|
-
cohorts: cohortReducers,
|
|
2247
|
-
activeWorkspace: activeWorkspaceReducer,
|
|
2248
|
-
[guppyApiSliceReducerPath]: guppyApiReducer,
|
|
2249
|
-
[userAuthApiReducerPath]: userAuthApiReducer,
|
|
2250
|
-
[cartReducerPath]: cartReducer
|
|
2223
|
+
const emptyInitialState = cohortsAdapter.getInitialState({
|
|
2224
|
+
currentCohortId: initialCohort.id,
|
|
2225
|
+
message: undefined
|
|
2251
2226
|
});
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
* the first level to avoid potentially flattening
|
|
2256
|
-
* non-nested data.
|
|
2257
|
-
* @param {JSON} json
|
|
2258
|
-
*/ function flattenJson(json) {
|
|
2259
|
-
const flattenedJson = [];
|
|
2260
|
-
Object.keys(json).forEach((key)=>{
|
|
2261
|
-
flattenedJson.push(flat.flatten(json[key], {
|
|
2262
|
-
delimiter: '_'
|
|
2263
|
-
}));
|
|
2264
|
-
});
|
|
2265
|
-
return flattenedJson;
|
|
2266
|
-
}
|
|
2267
|
-
/**
|
|
2268
|
-
* Converts JSON based on a config.
|
|
2269
|
-
* @param {JSON} json
|
|
2270
|
-
* @param {Object} config
|
|
2271
|
-
*/ async function conversion(json, config) {
|
|
2272
|
-
return Papa.unparse(json, config);
|
|
2273
|
-
}
|
|
2227
|
+
// Set the initial cohort in the adapter state
|
|
2228
|
+
const initialState$3 = cohortsAdapter.setOne(emptyInitialState, initialCohort);
|
|
2229
|
+
const getCurrentCohortId = (state)=>state.currentCohortId;
|
|
2274
2230
|
/**
|
|
2275
|
-
*
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
};
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
}
|
|
2303
|
-
|
|
2304
|
-
const
|
|
2305
|
-
|
|
2231
|
+
* Redux slice for cohort filters
|
|
2232
|
+
*/ const cohortManagerSlice = toolkit.createSlice({
|
|
2233
|
+
name: 'cohort',
|
|
2234
|
+
initialState: initialState$3,
|
|
2235
|
+
reducers: {
|
|
2236
|
+
createNewCohort: (state, action)=>{
|
|
2237
|
+
const baseName = action.payload.name || `Cohort`;
|
|
2238
|
+
const uniqueName = generateUniqueName(Object.values(state.entities), baseName);
|
|
2239
|
+
const cohort = newCohort({
|
|
2240
|
+
filters: action.payload.filters,
|
|
2241
|
+
customName: uniqueName
|
|
2242
|
+
});
|
|
2243
|
+
cohortsAdapter.addOne(state, cohort);
|
|
2244
|
+
if (action.payload?.setAsCurrent) {
|
|
2245
|
+
state.currentCohortId = cohort.id;
|
|
2246
|
+
}
|
|
2247
|
+
},
|
|
2248
|
+
updateCohortName: (state, action)=>{
|
|
2249
|
+
const { id, name } = action.payload;
|
|
2250
|
+
cohortsAdapter.updateOne(state, {
|
|
2251
|
+
id: id,
|
|
2252
|
+
changes: {
|
|
2253
|
+
name: name,
|
|
2254
|
+
modified: true,
|
|
2255
|
+
modifiedDatetime: new Date().toISOString()
|
|
2256
|
+
}
|
|
2257
|
+
});
|
|
2258
|
+
},
|
|
2259
|
+
removeCohort: (state, action)=>{
|
|
2260
|
+
const { id: cohortId } = action.payload;
|
|
2261
|
+
const removedCohortName = state.entities[cohortId].name;
|
|
2262
|
+
const totalCohorts = Object.keys(state.entities).length;
|
|
2263
|
+
if (totalCohorts <= 1) {
|
|
2264
|
+
cohortsAdapter.removeAll(state);
|
|
2265
|
+
const defaultCohort = newCohort({
|
|
2266
|
+
filters: {},
|
|
2267
|
+
customName: DEFAULT_COHORT_NAME
|
|
2268
|
+
});
|
|
2269
|
+
cohortsAdapter.addOne(state, defaultCohort);
|
|
2270
|
+
state.currentCohortId = defaultCohort.id;
|
|
2271
|
+
if (action?.payload.shouldShowMessage) {
|
|
2272
|
+
state.message = [
|
|
2273
|
+
`deleteCohort|${removedCohortName}|${state.currentCohortId}`
|
|
2274
|
+
];
|
|
2275
|
+
}
|
|
2276
|
+
return;
|
|
2277
|
+
}
|
|
2278
|
+
cohortsAdapter.removeOne(state, cohortId);
|
|
2279
|
+
// deleted the current cohort so set to the most recent cohort
|
|
2280
|
+
if (state.currentCohortId === cohortId) {
|
|
2281
|
+
const remainingIds = Object.keys(state.entities);
|
|
2282
|
+
state.currentCohortId = remainingIds[0];
|
|
2283
|
+
}
|
|
2284
|
+
if (action?.payload.shouldShowMessage) {
|
|
2285
|
+
state.message = [
|
|
2286
|
+
`deleteCohort|${removedCohortName}|${state.currentCohortId}`
|
|
2287
|
+
];
|
|
2288
|
+
}
|
|
2289
|
+
},
|
|
2290
|
+
// adds a filter to the cohort filter set at the given index
|
|
2291
|
+
updateCohortFilter: (state, action)=>{
|
|
2292
|
+
const { index, field, filter } = action.payload;
|
|
2293
|
+
const currentCohortId = getCurrentCohortId(state);
|
|
2294
|
+
if (!state.entities[currentCohortId]) {
|
|
2295
|
+
return;
|
|
2296
|
+
}
|
|
2297
|
+
cohortsAdapter.updateOne(state, {
|
|
2298
|
+
id: currentCohortId,
|
|
2299
|
+
changes: {
|
|
2300
|
+
filters: {
|
|
2301
|
+
...state.entities[currentCohortId].filters,
|
|
2302
|
+
[index]: {
|
|
2303
|
+
mode: state.entities[currentCohortId]?.filters[index]?.mode ?? 'and',
|
|
2304
|
+
root: {
|
|
2305
|
+
...state.entities[currentCohortId]?.filters[index]?.root ?? {},
|
|
2306
|
+
[field]: filter
|
|
2307
|
+
}
|
|
2308
|
+
}
|
|
2309
|
+
},
|
|
2310
|
+
modified: true,
|
|
2311
|
+
modifiedDatetime: new Date().toISOString()
|
|
2312
|
+
}
|
|
2313
|
+
});
|
|
2314
|
+
},
|
|
2315
|
+
setCohortFilter: (state, action)=>{
|
|
2316
|
+
const { index, filters } = action.payload;
|
|
2317
|
+
const currentCohortId = getCurrentCohortId(state);
|
|
2318
|
+
if (!state.entities[currentCohortId]) {
|
|
2319
|
+
console.error(`no cohort with id=${currentCohortId} defined`);
|
|
2320
|
+
return;
|
|
2321
|
+
}
|
|
2322
|
+
cohortsAdapter.updateOne(state, {
|
|
2323
|
+
id: currentCohortId,
|
|
2324
|
+
changes: {
|
|
2325
|
+
filters: {
|
|
2326
|
+
...state.entities[currentCohortId].filters,
|
|
2327
|
+
[index]: filters
|
|
2328
|
+
},
|
|
2329
|
+
modified: true,
|
|
2330
|
+
modifiedDatetime: new Date().toISOString()
|
|
2331
|
+
}
|
|
2332
|
+
});
|
|
2333
|
+
},
|
|
2334
|
+
setCohortIndexFilters: (state, action)=>{
|
|
2335
|
+
const currentCohortId = getCurrentCohortId(state);
|
|
2336
|
+
if (!state.entities[currentCohortId]) {
|
|
2337
|
+
console.error(`no cohort with id=${currentCohortId} defined`);
|
|
2338
|
+
return;
|
|
2339
|
+
}
|
|
2340
|
+
cohortsAdapter.updateOne(state, {
|
|
2341
|
+
id: currentCohortId,
|
|
2342
|
+
changes: {
|
|
2343
|
+
filters: action.payload.filters,
|
|
2344
|
+
modified: true,
|
|
2345
|
+
modifiedDatetime: new Date().toISOString()
|
|
2346
|
+
}
|
|
2347
|
+
});
|
|
2348
|
+
},
|
|
2349
|
+
// removes a filter to the cohort filter set at the given index
|
|
2350
|
+
removeCohortFilter: (state, action)=>{
|
|
2351
|
+
const { index, field } = action.payload;
|
|
2352
|
+
const currentCohortId = getCurrentCohortId(state);
|
|
2353
|
+
if (!state.entities[currentCohortId]) {
|
|
2354
|
+
console.error(`no cohort with id=${currentCohortId} defined`);
|
|
2355
|
+
return;
|
|
2356
|
+
}
|
|
2357
|
+
const filters = state.entities[currentCohortId]?.filters[index]?.root;
|
|
2358
|
+
if (!filters) {
|
|
2359
|
+
return;
|
|
2360
|
+
}
|
|
2361
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
2362
|
+
const { [field]: _a, ...updated } = filters;
|
|
2363
|
+
cohortsAdapter.updateOne(state, {
|
|
2364
|
+
id: currentCohortId,
|
|
2365
|
+
changes: {
|
|
2366
|
+
filters: {
|
|
2367
|
+
...state.entities[currentCohortId]?.filters,
|
|
2368
|
+
[index]: {
|
|
2369
|
+
mode: state.entities[currentCohortId].filters[index].mode,
|
|
2370
|
+
root: updated
|
|
2371
|
+
}
|
|
2372
|
+
},
|
|
2373
|
+
modified: true,
|
|
2374
|
+
modifiedDatetime: new Date().toISOString()
|
|
2375
|
+
}
|
|
2376
|
+
});
|
|
2377
|
+
},
|
|
2378
|
+
duplicateCohort: (state)=>{
|
|
2379
|
+
const currentCohortId = getCurrentCohortId(state);
|
|
2380
|
+
const currentCohort = state.entities[currentCohortId];
|
|
2381
|
+
const newName = generateUniqueName(Object.values(state.entities), currentCohort.name);
|
|
2382
|
+
const duplicatedCohort = newCohort({
|
|
2383
|
+
filters: {
|
|
2384
|
+
...currentCohort.filters
|
|
2385
|
+
},
|
|
2386
|
+
customName: newName
|
|
2387
|
+
});
|
|
2388
|
+
cohortsAdapter.addOne(state, {
|
|
2389
|
+
...duplicatedCohort,
|
|
2390
|
+
counts: {
|
|
2391
|
+
...currentCohort.counts
|
|
2392
|
+
}
|
|
2393
|
+
});
|
|
2394
|
+
state.currentCohortId = duplicatedCohort.id;
|
|
2395
|
+
},
|
|
2396
|
+
// removes all filters from the cohort filter set at the given index
|
|
2397
|
+
clearCohortFilters: (state, action)=>{
|
|
2398
|
+
const { index } = action.payload;
|
|
2399
|
+
const currentCohortId = getCurrentCohortId(state);
|
|
2400
|
+
if (!state.entities[currentCohortId]) {
|
|
2401
|
+
console.error(`no cohort with id=${currentCohortId} defined`);
|
|
2402
|
+
return;
|
|
2403
|
+
}
|
|
2404
|
+
const filters = state.entities[currentCohortId]?.filters[index]?.root;
|
|
2405
|
+
if (!filters) {
|
|
2406
|
+
return;
|
|
2407
|
+
}
|
|
2408
|
+
cohortsAdapter.updateOne(state, {
|
|
2409
|
+
id: currentCohortId,
|
|
2410
|
+
changes: {
|
|
2411
|
+
filters: {
|
|
2412
|
+
...state.entities[currentCohortId]?.filters,
|
|
2413
|
+
[index]: {
|
|
2414
|
+
mode: 'and',
|
|
2415
|
+
root: {}
|
|
2416
|
+
}
|
|
2417
|
+
},
|
|
2418
|
+
modified: true,
|
|
2419
|
+
modifiedDatetime: new Date().toISOString()
|
|
2420
|
+
}
|
|
2421
|
+
});
|
|
2422
|
+
},
|
|
2423
|
+
updateCohortCounts: (state, action)=>{
|
|
2424
|
+
const currentCohortId = getCurrentCohortId(state);
|
|
2425
|
+
const currentCohort = state.entities[currentCohortId];
|
|
2426
|
+
cohortsAdapter.updateOne(state, {
|
|
2427
|
+
id: currentCohortId,
|
|
2428
|
+
changes: {
|
|
2429
|
+
counts: {
|
|
2430
|
+
...currentCohort.counts,
|
|
2431
|
+
...action.payload
|
|
2432
|
+
}
|
|
2433
|
+
}
|
|
2434
|
+
});
|
|
2435
|
+
},
|
|
2436
|
+
updateCohortIndexCountById: (state, action)=>{
|
|
2437
|
+
const { index, cohortId, counts } = action.payload;
|
|
2438
|
+
const cohort = state.entities[cohortId];
|
|
2439
|
+
cohortsAdapter.updateOne(state, {
|
|
2440
|
+
id: cohortId,
|
|
2441
|
+
changes: {
|
|
2442
|
+
counts: {
|
|
2443
|
+
...cohort.counts,
|
|
2444
|
+
...{
|
|
2445
|
+
[index]: counts
|
|
2446
|
+
}
|
|
2447
|
+
}
|
|
2448
|
+
}
|
|
2449
|
+
});
|
|
2450
|
+
},
|
|
2451
|
+
setCurrentCohortId: (state, action)=>{
|
|
2452
|
+
state.currentCohortId = action.payload;
|
|
2453
|
+
},
|
|
2454
|
+
/** @hidden */ setCohortList: (state, action)=>{
|
|
2455
|
+
if (!action.payload) {
|
|
2456
|
+
cohortsAdapter.removeMany(state, state.ids);
|
|
2457
|
+
} else {
|
|
2458
|
+
cohortsAdapter.upsertMany(state, [
|
|
2459
|
+
...action.payload
|
|
2460
|
+
]);
|
|
2461
|
+
}
|
|
2462
|
+
}
|
|
2463
|
+
}
|
|
2464
|
+
});
|
|
2465
|
+
/**
|
|
2466
|
+
* Returns the selectors for the cohorts EntityAdapter
|
|
2467
|
+
* @param state - the CoreState
|
|
2468
|
+
*
|
|
2469
|
+
* @hidden
|
|
2470
|
+
*/ const cohortSelectors = cohortsAdapter.getSelectors((state)=>state.cohorts.cohortManager);
|
|
2471
|
+
// Filter actions: addFilter, removeFilter, updateFilter
|
|
2472
|
+
const { createNewCohort, updateCohortFilter, setCohortFilter, setCohortIndexFilters, duplicateCohort, removeCohortFilter, clearCohortFilters, removeCohort, setCurrentCohortId, updateCohortName, updateCohortCounts, updateCohortIndexCountById, setCohortList } = cohortManagerSlice.actions;
|
|
2473
|
+
const cohortReducer = cohortManagerSlice.reducer;
|
|
2474
|
+
|
|
2475
|
+
const initialState$2 = {};
|
|
2476
|
+
const expandSlice$1 = toolkit.createSlice({
|
|
2477
|
+
name: 'CohortBuilder/filterExpand',
|
|
2478
|
+
initialState: initialState$2,
|
|
2479
|
+
reducers: {
|
|
2480
|
+
toggleCohortBuilderCategoryFilter: (state, action)=>{
|
|
2481
|
+
return {
|
|
2482
|
+
...state,
|
|
2483
|
+
[action.payload.index]: {
|
|
2484
|
+
...state[action.payload.index],
|
|
2485
|
+
[action.payload.field]: action.payload.expanded
|
|
2486
|
+
}
|
|
2487
|
+
};
|
|
2488
|
+
},
|
|
2489
|
+
toggleCohortBuilderAllFilters: (state, action)=>{
|
|
2490
|
+
return {
|
|
2491
|
+
...state,
|
|
2492
|
+
[action.payload.index]: Object.keys(state[action.payload.index]).reduce((acc, k)=>{
|
|
2493
|
+
acc[k] = action.payload.expand;
|
|
2494
|
+
return acc;
|
|
2495
|
+
}, {})
|
|
2496
|
+
};
|
|
2497
|
+
}
|
|
2498
|
+
}
|
|
2499
|
+
});
|
|
2500
|
+
const cohortBuilderFiltersExpandedReducer = expandSlice$1.reducer;
|
|
2501
|
+
const { toggleCohortBuilderCategoryFilter, toggleCohortBuilderAllFilters } = expandSlice$1.actions;
|
|
2502
|
+
const selectCohortFilterExpanded = (state, index, field)=>state.cohorts.filtersExpanded?.[index]?.[field];
|
|
2503
|
+
const selectAllCohortFiltersCollapsed = (state, index)=>index in state.cohorts.filtersExpanded ? Object.values(state.cohorts.filtersExpanded?.[index]).every((e)=>!e) : false;
|
|
2504
|
+
|
|
2505
|
+
const initialState$1 = {};
|
|
2506
|
+
const expandSlice = toolkit.createSlice({
|
|
2507
|
+
name: 'CohortBuilder/filterCombineMode',
|
|
2508
|
+
initialState: initialState$1,
|
|
2509
|
+
reducers: {
|
|
2510
|
+
setCohortFilterCombineMode: (state, action)=>{
|
|
2511
|
+
return {
|
|
2512
|
+
...state,
|
|
2513
|
+
[action.payload.index]: {
|
|
2514
|
+
...state[action.payload.index],
|
|
2515
|
+
[action.payload.field]: action.payload.mode
|
|
2516
|
+
}
|
|
2517
|
+
};
|
|
2518
|
+
}
|
|
2519
|
+
}
|
|
2520
|
+
});
|
|
2521
|
+
const cohortBuilderFiltersCombineModeReducer = expandSlice.reducer;
|
|
2522
|
+
const { setCohortFilterCombineMode } = expandSlice.actions;
|
|
2523
|
+
const selectCohortFilterCombineMode = (state, index, field)=>state.cohorts.filtersCombineMode?.[index]?.[field] ?? 'or';
|
|
2524
|
+
|
|
2525
|
+
const initialState = {
|
|
2526
|
+
shouldShareFilters: false,
|
|
2527
|
+
sharedFiltersMap: {}
|
|
2528
|
+
};
|
|
2529
|
+
const cohortSharedFiltersSlice = toolkit.createSlice({
|
|
2530
|
+
name: 'cohortSharedFilters',
|
|
2531
|
+
initialState: initialState,
|
|
2532
|
+
reducers: {
|
|
2533
|
+
setShouldShareFilters: (state, action)=>{
|
|
2534
|
+
state.shouldShareFilters = action.payload;
|
|
2535
|
+
return state;
|
|
2536
|
+
},
|
|
2537
|
+
setSharedFilters: (state, action)=>{
|
|
2538
|
+
state.sharedFiltersMap = action.payload;
|
|
2539
|
+
}
|
|
2540
|
+
}
|
|
2541
|
+
});
|
|
2542
|
+
const selectShouldShareFilters = (state)=>state.cohorts.sharedFilters.shouldShareFilters;
|
|
2543
|
+
const selectSharedFilters = (state)=>state.cohorts.sharedFilters.sharedFiltersMap;
|
|
2544
|
+
const selectSharedFiltersForFields = (state, field)=>state.cohorts.sharedFilters.sharedFiltersMap?.[field] ?? [
|
|
2545
|
+
field
|
|
2546
|
+
];
|
|
2547
|
+
const { setShouldShareFilters, setSharedFilters } = cohortSharedFiltersSlice.actions;
|
|
2548
|
+
const cohortSharedFiltersReducer = cohortSharedFiltersSlice.reducer;
|
|
2549
|
+
|
|
2550
|
+
const cohortReducers = toolkit.combineReducers({
|
|
2551
|
+
filtersExpanded: cohortBuilderFiltersExpandedReducer,
|
|
2552
|
+
filtersCombineMode: cohortBuilderFiltersCombineModeReducer,
|
|
2553
|
+
sharedFilters: cohortSharedFiltersReducer,
|
|
2554
|
+
cohortManager: cohortReducer
|
|
2555
|
+
});
|
|
2556
|
+
|
|
2557
|
+
const rootReducer = toolkit.combineReducers({
|
|
2558
|
+
gen3Services: gen3ServicesReducer,
|
|
2559
|
+
user: userReducer,
|
|
2560
|
+
gen3Apps: gen3AppReducer,
|
|
2561
|
+
drsHostnames: drsHostnamesReducer,
|
|
2562
|
+
modals: modalReducer,
|
|
2563
|
+
cohorts: cohortReducers,
|
|
2564
|
+
activeWorkspace: activeWorkspaceReducer,
|
|
2565
|
+
[guppyApiSliceReducerPath]: guppyApiReducer,
|
|
2566
|
+
[userAuthApiReducerPath]: userAuthApiReducer,
|
|
2567
|
+
[cartReducerPath]: cartReducer
|
|
2568
|
+
});
|
|
2569
|
+
|
|
2570
|
+
/**
|
|
2571
|
+
* Flattens a deep nested JSON object skipping
|
|
2572
|
+
* the first level to avoid potentially flattening
|
|
2573
|
+
* non-nested data.
|
|
2574
|
+
* @param {JSON} json
|
|
2575
|
+
*/ function flattenJson(json) {
|
|
2576
|
+
const flattenedJson = [];
|
|
2577
|
+
Object.keys(json).forEach((key)=>{
|
|
2578
|
+
flattenedJson.push(flat.flatten(json[key], {
|
|
2579
|
+
delimiter: '_'
|
|
2580
|
+
}));
|
|
2581
|
+
});
|
|
2582
|
+
return flattenedJson;
|
|
2583
|
+
}
|
|
2584
|
+
/**
|
|
2585
|
+
* Converts JSON based on a config.
|
|
2586
|
+
* @param {JSON} json
|
|
2587
|
+
* @param {Object} config
|
|
2588
|
+
*/ async function conversion(json, config) {
|
|
2589
|
+
return Papa.unparse(json, config);
|
|
2590
|
+
}
|
|
2591
|
+
/**
|
|
2592
|
+
* Converts JSON to a specified file format.
|
|
2593
|
+
* Defaults to JSON if file format is not supported.
|
|
2594
|
+
* @param {JSON} json
|
|
2595
|
+
* @param {string} format
|
|
2596
|
+
*/ async function jsonToFormat(json, format) {
|
|
2597
|
+
if (Object.keys(FILE_DELIMITERS).includes(format)) {
|
|
2598
|
+
const flatJson = flattenJson(json);
|
|
2599
|
+
const data = await conversion(flatJson, {
|
|
2600
|
+
delimiter: FILE_DELIMITERS[format]
|
|
2601
|
+
});
|
|
2602
|
+
return data;
|
|
2603
|
+
}
|
|
2604
|
+
return json;
|
|
2605
|
+
}
|
|
2606
|
+
|
|
2607
|
+
// type guard functions
|
|
2608
|
+
const isHistogramRangeData = (key)=>{
|
|
2609
|
+
return Array.isArray(key) && key.length === 2 && key.every((item)=>typeof item === 'number');
|
|
2610
|
+
};
|
|
2611
|
+
const isJSONObject = (data)=>{
|
|
2612
|
+
return typeof data === 'object' && data !== null && !Array.isArray(data);
|
|
2613
|
+
};
|
|
2614
|
+
const isJSONValue = (data)=>{
|
|
2615
|
+
return typeof data === 'string' || typeof data === 'number' || typeof data === 'boolean' || Array.isArray(data) && data.every(isJSONValue) || isJSONObject(data);
|
|
2616
|
+
};
|
|
2617
|
+
const isJSONValueArray = (data)=>{
|
|
2618
|
+
return Array.isArray(data) && data.every(isJSONValue);
|
|
2619
|
+
};
|
|
2620
|
+
const isValidObject = (input)=>typeof input === 'object' && input !== null;
|
|
2621
|
+
const isHistogramData = (data)=>{
|
|
2622
|
+
return isValidObject(data) && 'key' in data && 'count' in data;
|
|
2306
2623
|
};
|
|
2307
2624
|
const isHistogramDataArray = (input)=>{
|
|
2308
2625
|
if (!isValidObject(input) || !Array.isArray(input.histogram)) {
|
|
@@ -2341,10 +2658,8 @@ const isStatsValue = (item)=>{
|
|
|
2341
2658
|
'stddev',
|
|
2342
2659
|
'median'
|
|
2343
2660
|
];
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
return false;
|
|
2347
|
-
}
|
|
2661
|
+
if (!numericFields.some((field)=>field in obj && typeof obj[field] !== 'number')) {
|
|
2662
|
+
return false;
|
|
2348
2663
|
}
|
|
2349
2664
|
// Check percentiles structure if present
|
|
2350
2665
|
if ('percentiles' in obj) {
|
|
@@ -2352,17 +2667,6 @@ const isStatsValue = (item)=>{
|
|
|
2352
2667
|
if (typeof percentiles !== 'object' || percentiles === null) {
|
|
2353
2668
|
return false;
|
|
2354
2669
|
}
|
|
2355
|
-
const pObj = percentiles;
|
|
2356
|
-
const requiredPercentiles = [
|
|
2357
|
-
'p25',
|
|
2358
|
-
'p50',
|
|
2359
|
-
'p75'
|
|
2360
|
-
];
|
|
2361
|
-
for (const p of requiredPercentiles){
|
|
2362
|
-
if (p in pObj && typeof pObj[p] !== 'number') {
|
|
2363
|
-
return false;
|
|
2364
|
-
}
|
|
2365
|
-
}
|
|
2366
2670
|
}
|
|
2367
2671
|
return true;
|
|
2368
2672
|
};
|
|
@@ -2607,443 +2911,168 @@ const groupSharedFields = (data)=>{
|
|
|
2607
2911
|
x.count = x.count < minValue ? -1 : x.count;
|
|
2608
2912
|
});
|
|
2609
2913
|
});
|
|
2610
|
-
return data;
|
|
2611
|
-
};
|
|
2612
|
-
|
|
2613
|
-
const customQueryStrForField = (field, query, depth = 0)=>{
|
|
2614
|
-
const indent = ' '.repeat(depth);
|
|
2615
|
-
const splittedFieldArray = field.split('.');
|
|
2616
|
-
const splittedField = splittedFieldArray.shift();
|
|
2617
|
-
if (splittedFieldArray.length === 0) {
|
|
2618
|
-
return `${indent}${splittedField} ${query}`;
|
|
2619
|
-
}
|
|
2620
|
-
return `${indent}${splittedField} {
|
|
2621
|
-
${customQueryStrForField(splittedFieldArray.join('.'), query, depth + 1)}
|
|
2622
|
-
${indent}}`;
|
|
2623
|
-
};
|
|
2624
|
-
// TODO: refactor the function below using customQueryStrForEachField and a wrapper function that passes the query
|
|
2625
|
-
const histogramQueryStrForEachField = (field)=>{
|
|
2626
|
-
const splittedFieldArray = field.split('.');
|
|
2627
|
-
const splittedField = splittedFieldArray.shift();
|
|
2628
|
-
if (splittedFieldArray.length === 0) {
|
|
2629
|
-
return `
|
|
2630
|
-
${splittedField} {
|
|
2631
|
-
histogram {
|
|
2632
|
-
key
|
|
2633
|
-
count
|
|
2634
|
-
}
|
|
2635
|
-
}`;
|
|
2636
|
-
}
|
|
2637
|
-
return `
|
|
2638
|
-
${splittedField} {
|
|
2639
|
-
${histogramQueryStrForEachField(splittedFieldArray.join('.'))}
|
|
2640
|
-
}`;
|
|
2641
|
-
};
|
|
2642
|
-
const statsQueryStrForEachField = (field)=>{
|
|
2643
|
-
const splittedFieldArray = field.split('.');
|
|
2644
|
-
const splittedField = splittedFieldArray.shift();
|
|
2645
|
-
if (splittedFieldArray.length === 0) {
|
|
2646
|
-
return `
|
|
2647
|
-
${splittedField} {
|
|
2648
|
-
histogram {
|
|
2649
|
-
count
|
|
2650
|
-
min
|
|
2651
|
-
max
|
|
2652
|
-
avg
|
|
2653
|
-
sum
|
|
2654
|
-
}
|
|
2655
|
-
}`;
|
|
2656
|
-
}
|
|
2657
|
-
return `
|
|
2658
|
-
${splittedField} {
|
|
2659
|
-
${statsQueryStrForEachField(splittedFieldArray.join('.'))}
|
|
2660
|
-
}`;
|
|
2661
|
-
};
|
|
2662
|
-
const nestedHistogramQueryStrForEachField = (mainField, numericAggAsText)=>`
|
|
2663
|
-
${mainField} {
|
|
2664
|
-
${numericAggAsText ? 'asTextHistogram' : 'histogram'} {
|
|
2665
|
-
key
|
|
2666
|
-
count
|
|
2667
|
-
missingFields {
|
|
2668
|
-
field
|
|
2669
|
-
count
|
|
2670
|
-
}
|
|
2671
|
-
termsFields {
|
|
2672
|
-
field
|
|
2673
|
-
count
|
|
2674
|
-
terms {
|
|
2675
|
-
key
|
|
2676
|
-
count
|
|
2677
|
-
}
|
|
2678
|
-
}
|
|
2679
|
-
}
|
|
2680
|
-
}`;
|
|
2681
|
-
const rawDataQueryStrForEachField$1 = (field)=>{
|
|
2682
|
-
const splitFieldArray = field.split('.');
|
|
2683
|
-
const splitField = splitFieldArray.shift();
|
|
2684
|
-
if (splitFieldArray.length === 0) {
|
|
2685
|
-
return `
|
|
2686
|
-
${splitField}
|
|
2687
|
-
`;
|
|
2688
|
-
}
|
|
2689
|
-
return `
|
|
2690
|
-
${splitField} {
|
|
2691
|
-
${rawDataQueryStrForEachField$1(splitFieldArray.join('.'))}
|
|
2692
|
-
}`;
|
|
2693
|
-
};
|
|
2694
|
-
|
|
2695
|
-
const convertNumericFromToArrayToFilters = (field, range, isNested = true)=>{
|
|
2696
|
-
const { from, to } = range;
|
|
2697
|
-
return {
|
|
2698
|
-
operator: 'and',
|
|
2699
|
-
operands: [
|
|
2700
|
-
isNested ? buildNestedFilterForOperation(field, {
|
|
2701
|
-
operator: '>=',
|
|
2702
|
-
field,
|
|
2703
|
-
operand: from
|
|
2704
|
-
}) : {
|
|
2705
|
-
operator: '>=',
|
|
2706
|
-
field,
|
|
2707
|
-
operand: from
|
|
2708
|
-
},
|
|
2709
|
-
isNested ? buildNestedFilterForOperation(field, {
|
|
2710
|
-
operator: '<',
|
|
2711
|
-
field,
|
|
2712
|
-
operand: to
|
|
2713
|
-
}) : {
|
|
2714
|
-
operator: '<',
|
|
2715
|
-
field,
|
|
2716
|
-
operand: to
|
|
2717
|
-
}
|
|
2718
|
-
]
|
|
2719
|
-
};
|
|
2720
|
-
};
|
|
2721
|
-
const rawDataQueryStrForEachField = (field, asTextHistogram = false)=>{
|
|
2722
|
-
const splitFieldArray = field.split('.');
|
|
2723
|
-
const splitField = splitFieldArray.shift();
|
|
2724
|
-
let middleQuery = '';
|
|
2725
|
-
if (splitFieldArray.length === 0) {
|
|
2726
|
-
middleQuery = `${splitField} { ${asTextHistogram ? 'histogram: asTextHistogram' : 'histogram'} { count } }`;
|
|
2727
|
-
} else {
|
|
2728
|
-
middleQuery = `${splitField} { ${rawDataQueryStrForEachField(splitFieldArray.join('.'), asTextHistogram)} }`;
|
|
2729
|
-
}
|
|
2730
|
-
return middleQuery;
|
|
2731
|
-
};
|
|
2732
|
-
const buildAliasedNestedCountsQuery = ({ type, field, rangeName, asTextHistogram = false })=>{
|
|
2733
|
-
const dataParams = [
|
|
2734
|
-
`filter: $${rangeName}`
|
|
2735
|
-
];
|
|
2736
|
-
const dataTypeLine = `${rangeName} : ${type} (accessibility: $accessibility ${dataParams}) {`;
|
|
2737
|
-
const processedFields = rawDataQueryStrForEachField(field, asTextHistogram);
|
|
2738
|
-
return `${dataTypeLine} ${processedFields} }`;
|
|
2739
|
-
};
|
|
2740
|
-
const buildRangeFilters = (field, ranges, filters, rangeBaseName, isNested = true)=>{
|
|
2741
|
-
return Object.entries(ranges).reduce((acc, [, rangeValue], idx)=>{
|
|
2742
|
-
acc[`${rangeBaseName}_${idx}`] = {
|
|
2743
|
-
mode: filters.mode,
|
|
2744
|
-
root: {
|
|
2745
|
-
...filters.root,
|
|
2746
|
-
[field]: convertNumericFromToArrayToFilters(field, rangeValue, isNested)
|
|
2747
|
-
}
|
|
2748
|
-
};
|
|
2749
|
-
return acc;
|
|
2750
|
-
}, {});
|
|
2751
|
-
};
|
|
2752
|
-
const buildRangeQuery = (field, ranges, filters, rangeBaseName = 'range', index = 'cases', indexPrefix = '', isNested = true, asTextHistogram = false)=>{
|
|
2753
|
-
const rangeFilters = buildRangeFilters(field, ranges, filters, rangeBaseName, isNested);
|
|
2754
|
-
let query = `query rangeQuery ($accessibility: Accessibility, ${Object.keys(rangeFilters).map((rangeKey)=>`$${rangeKey}: JSON`).join(',')} ) { ${indexPrefix}_aggregation {`;
|
|
2755
|
-
Object.keys(rangeFilters).forEach((rangeKey)=>{
|
|
2756
|
-
const rangeQuery = buildAliasedNestedCountsQuery({
|
|
2757
|
-
type: index,
|
|
2758
|
-
field,
|
|
2759
|
-
rangeName: rangeKey,
|
|
2760
|
-
asTextHistogram
|
|
2761
|
-
});
|
|
2762
|
-
query += rangeQuery + ' \n';
|
|
2763
|
-
});
|
|
2764
|
-
query += `}}`;
|
|
2765
|
-
return {
|
|
2766
|
-
query: query,
|
|
2767
|
-
filters: rangeFilters
|
|
2768
|
-
};
|
|
2769
|
-
};
|
|
2770
|
-
|
|
2771
|
-
const { selectAll: selectAllCohorts, selectTotal: selectTotalCohorts, selectById: selectCohortById, selectIds: selectCohortIds } = cohortsAdapter.getSelectors((state)=>state.cohorts.cohortManager);
|
|
2772
|
-
/**
|
|
2773
|
-
* Internally used selector for the exported selectora
|
|
2774
|
-
* @param state
|
|
2775
|
-
*/ const getCurrentCohortFromCoreState = (state)=>{
|
|
2776
|
-
return state.cohorts.cohortManager.currentCohortId;
|
|
2777
|
-
};
|
|
2778
|
-
const selectCohortFilters = (state)=>{
|
|
2779
|
-
const currentCohortId = getCurrentCohortFromCoreState(state);
|
|
2780
|
-
return state.cohorts.cohortManager.entities[currentCohortId]?.filters;
|
|
2781
|
-
};
|
|
2782
|
-
const selectCurrentCohortFilters = (state)=>{
|
|
2783
|
-
const currentCohortId = getCurrentCohortFromCoreState(state);
|
|
2784
|
-
return state.cohorts.cohortManager.entities[currentCohortId]?.filters;
|
|
2785
|
-
};
|
|
2786
|
-
const selectCurrentCohortId = (state)=>{
|
|
2787
|
-
return state.cohorts.cohortManager.currentCohortId;
|
|
2788
|
-
};
|
|
2789
|
-
const selectCurrentCohort = (state)=>cohortSelectors.selectById(state, getCurrentCohortFromCoreState(state));
|
|
2790
|
-
const selectCurrentCohortName = (state)=>cohortSelectors.selectById(state, getCurrentCohortFromCoreState(state)).name;
|
|
2791
|
-
/**
|
|
2792
|
-
* Select a filter by its name from the current cohort. If the filter is not found
|
|
2793
|
-
* returns undefined.
|
|
2794
|
-
* @param state - Core
|
|
2795
|
-
* @param index which cohort index to select from
|
|
2796
|
-
* @param name name of the filter to select
|
|
2797
|
-
*/ const selectIndexedFilterByName = (state, index, name)=>{
|
|
2798
|
-
return cohortSelectors.selectById(state, getCurrentCohortFromCoreState(state)).filters[index]?.root[name];
|
|
2914
|
+
return data;
|
|
2799
2915
|
};
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
* @category Selectors
|
|
2812
|
-
* @hidden
|
|
2813
|
-
*/ const selectCurrentCohortModified = (state)=>{
|
|
2814
|
-
const cohort = cohortSelectors.selectById(state, getCurrentCohortFromCoreState(state));
|
|
2815
|
-
return cohort?.modified;
|
|
2916
|
+
|
|
2917
|
+
const customQueryStrForField = (field, query, depth = 0)=>{
|
|
2918
|
+
const indent = ' '.repeat(depth);
|
|
2919
|
+
const splittedFieldArray = field.split('.');
|
|
2920
|
+
const splittedField = splittedFieldArray.shift();
|
|
2921
|
+
if (splittedFieldArray.length === 0) {
|
|
2922
|
+
return `${indent}${splittedField} ${query}`;
|
|
2923
|
+
}
|
|
2924
|
+
return `${indent}${splittedField} {
|
|
2925
|
+
${customQueryStrForField(splittedFieldArray.join('.'), query, depth + 1)}
|
|
2926
|
+
${indent}}`;
|
|
2816
2927
|
};
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2928
|
+
// TODO: refactor the function below using customQueryStrForEachField and a wrapper function that passes the query
|
|
2929
|
+
const histogramQueryStrForEachField = (field)=>{
|
|
2930
|
+
const splittedFieldArray = field.split('.');
|
|
2931
|
+
const splittedField = splittedFieldArray.shift();
|
|
2932
|
+
if (splittedFieldArray.length === 0) {
|
|
2933
|
+
return `
|
|
2934
|
+
${splittedField} {
|
|
2935
|
+
histogram {
|
|
2936
|
+
key
|
|
2937
|
+
count
|
|
2938
|
+
}
|
|
2939
|
+
}`;
|
|
2940
|
+
}
|
|
2941
|
+
return `
|
|
2942
|
+
${splittedField} {
|
|
2943
|
+
${histogramQueryStrForEachField(splittedFieldArray.join('.'))}
|
|
2944
|
+
}`;
|
|
2826
2945
|
};
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
console.error('No Cohort Defined');
|
|
2946
|
+
const statsQueryStrForEachField = (field)=>{
|
|
2947
|
+
const splittedFieldArray = field.split('.');
|
|
2948
|
+
const splittedField = splittedFieldArray.shift();
|
|
2949
|
+
if (splittedFieldArray.length === 0) {
|
|
2950
|
+
return `
|
|
2951
|
+
${splittedField} {
|
|
2952
|
+
histogram {
|
|
2953
|
+
count
|
|
2954
|
+
min
|
|
2955
|
+
max
|
|
2956
|
+
avg
|
|
2957
|
+
sum
|
|
2958
|
+
}
|
|
2959
|
+
}`;
|
|
2842
2960
|
}
|
|
2843
|
-
return
|
|
2961
|
+
return `
|
|
2962
|
+
${splittedField} {
|
|
2963
|
+
${statsQueryStrForEachField(splittedFieldArray.join('.'))}
|
|
2964
|
+
}`;
|
|
2844
2965
|
};
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
'
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
}
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
});
|
|
2901
|
-
}
|
|
2902
|
-
return {
|
|
2903
|
-
'<=': {
|
|
2904
|
-
[op.field]: op.operand
|
|
2905
|
-
}
|
|
2906
|
-
};
|
|
2907
|
-
};
|
|
2908
|
-
this.handleGreaterThan = (op)=>{
|
|
2909
|
-
if (op.field.includes('.')) {
|
|
2910
|
-
const leafField = op.field.split('.').at(-1) ?? 'unset';
|
|
2911
|
-
return buildNestedGQLFilter(op.field, {
|
|
2912
|
-
'>': {
|
|
2913
|
-
[leafField]: op.operand
|
|
2914
|
-
}
|
|
2915
|
-
});
|
|
2916
|
-
}
|
|
2917
|
-
return {
|
|
2918
|
-
'>': {
|
|
2919
|
-
[op.field]: op.operand
|
|
2920
|
-
}
|
|
2921
|
-
};
|
|
2922
|
-
};
|
|
2923
|
-
this.handleGreaterThanOrEquals = (op)=>{
|
|
2924
|
-
if (op.field.includes('.')) {
|
|
2925
|
-
const leafField = op.field.split('.').at(-1) ?? 'unset';
|
|
2926
|
-
return buildNestedGQLFilter(op.field, {
|
|
2927
|
-
'>=': {
|
|
2928
|
-
[leafField]: op.operand
|
|
2929
|
-
}
|
|
2930
|
-
});
|
|
2931
|
-
}
|
|
2932
|
-
return {
|
|
2933
|
-
'>=': {
|
|
2934
|
-
[op.field]: op.operand
|
|
2935
|
-
}
|
|
2936
|
-
};
|
|
2937
|
-
};
|
|
2938
|
-
this.handleIncludes = (op)=>{
|
|
2939
|
-
if (op.field.includes('.')) {
|
|
2940
|
-
const leafField = op.field.split('.').at(-1) ?? 'unset';
|
|
2941
|
-
return buildNestedGQLFilter(op.field, {
|
|
2942
|
-
in: {
|
|
2943
|
-
[leafField]: op.operands
|
|
2944
|
-
}
|
|
2945
|
-
});
|
|
2946
|
-
}
|
|
2947
|
-
return {
|
|
2948
|
-
in: {
|
|
2949
|
-
[op.field]: op.operands
|
|
2950
|
-
}
|
|
2951
|
-
};
|
|
2952
|
-
};
|
|
2953
|
-
this.handleExcludes = (op)=>{
|
|
2954
|
-
if (op.field.includes('.')) {
|
|
2955
|
-
const leafField = op.field.split('.').at(-1) ?? 'unset';
|
|
2956
|
-
return buildNestedGQLFilter(op.field, {
|
|
2957
|
-
exclude: {
|
|
2958
|
-
[leafField]: op.operands
|
|
2959
|
-
}
|
|
2960
|
-
});
|
|
2961
|
-
}
|
|
2962
|
-
return {
|
|
2963
|
-
exclude: {
|
|
2964
|
-
[op.field]: op.operands
|
|
2965
|
-
}
|
|
2966
|
-
};
|
|
2967
|
-
};
|
|
2968
|
-
this.handleExcludeIfAny = (op)=>{
|
|
2969
|
-
if (op.field.includes('.')) {
|
|
2970
|
-
const leafField = op.field.split('.').at(-1) ?? 'unset';
|
|
2971
|
-
return buildNestedGQLFilter(op.field, {
|
|
2972
|
-
excludeifany: {
|
|
2973
|
-
[leafField]: op.operands
|
|
2974
|
-
}
|
|
2975
|
-
});
|
|
2976
|
-
}
|
|
2977
|
-
return {
|
|
2978
|
-
excludeifany: {
|
|
2979
|
-
[op.field]: op.operands
|
|
2980
|
-
}
|
|
2981
|
-
};
|
|
2982
|
-
};
|
|
2983
|
-
this.handleIntersection = (op)=>({
|
|
2984
|
-
and: op.operands.map((x)=>convertFilterToGqlFilter(x))
|
|
2985
|
-
});
|
|
2986
|
-
this.handleUnion = (op)=>({
|
|
2987
|
-
or: op.operands.map((x)=>convertFilterToGqlFilter(x))
|
|
2988
|
-
});
|
|
2989
|
-
this.handleMissing = (op)=>{
|
|
2990
|
-
if (op.field.includes('.')) {
|
|
2991
|
-
const leafField = op.field.split('.').at(-1) ?? 'unset';
|
|
2992
|
-
return buildNestedGQLFilter(op.field, {
|
|
2993
|
-
is: {
|
|
2994
|
-
[leafField]: 'MISSING'
|
|
2995
|
-
}
|
|
2996
|
-
});
|
|
2966
|
+
const nestedHistogramQueryStrForEachField = (mainField, numericAggAsText)=>`
|
|
2967
|
+
${mainField} {
|
|
2968
|
+
${numericAggAsText ? 'asTextHistogram' : 'histogram'} {
|
|
2969
|
+
key
|
|
2970
|
+
count
|
|
2971
|
+
missingFields {
|
|
2972
|
+
field
|
|
2973
|
+
count
|
|
2974
|
+
}
|
|
2975
|
+
termsFields {
|
|
2976
|
+
field
|
|
2977
|
+
count
|
|
2978
|
+
terms {
|
|
2979
|
+
key
|
|
2980
|
+
count
|
|
2981
|
+
}
|
|
2982
|
+
}
|
|
2983
|
+
}
|
|
2984
|
+
}`;
|
|
2985
|
+
const rawDataQueryStrForEachField$1 = (field)=>{
|
|
2986
|
+
const splitFieldArray = field.split('.');
|
|
2987
|
+
const splitField = splitFieldArray.shift();
|
|
2988
|
+
if (splitFieldArray.length === 0) {
|
|
2989
|
+
return `
|
|
2990
|
+
${splitField}
|
|
2991
|
+
`;
|
|
2992
|
+
}
|
|
2993
|
+
return `
|
|
2994
|
+
${splitField} {
|
|
2995
|
+
${rawDataQueryStrForEachField$1(splitFieldArray.join('.'))}
|
|
2996
|
+
}`;
|
|
2997
|
+
};
|
|
2998
|
+
|
|
2999
|
+
const convertNumericFromToArrayToFilters = (field, range, isNested = true)=>{
|
|
3000
|
+
const { from, to } = range;
|
|
3001
|
+
return {
|
|
3002
|
+
operator: 'and',
|
|
3003
|
+
operands: [
|
|
3004
|
+
isNested ? buildNestedFilterForOperation(field, {
|
|
3005
|
+
operator: '>=',
|
|
3006
|
+
field,
|
|
3007
|
+
operand: from
|
|
3008
|
+
}) : {
|
|
3009
|
+
operator: '>=',
|
|
3010
|
+
field,
|
|
3011
|
+
operand: from
|
|
3012
|
+
},
|
|
3013
|
+
isNested ? buildNestedFilterForOperation(field, {
|
|
3014
|
+
operator: '<',
|
|
3015
|
+
field,
|
|
3016
|
+
operand: to
|
|
3017
|
+
}) : {
|
|
3018
|
+
operator: '<',
|
|
3019
|
+
field,
|
|
3020
|
+
operand: to
|
|
2997
3021
|
}
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3022
|
+
]
|
|
3023
|
+
};
|
|
3024
|
+
};
|
|
3025
|
+
const rawDataQueryStrForEachField = (field, asTextHistogram = false)=>{
|
|
3026
|
+
const splitFieldArray = field.split('.');
|
|
3027
|
+
const splitField = splitFieldArray.shift();
|
|
3028
|
+
let middleQuery = '';
|
|
3029
|
+
if (splitFieldArray.length === 0) {
|
|
3030
|
+
middleQuery = `${splitField} { ${asTextHistogram ? 'histogram: asTextHistogram' : 'histogram'} { count } }`;
|
|
3031
|
+
} else {
|
|
3032
|
+
middleQuery = `${splitField} { ${rawDataQueryStrForEachField(splitFieldArray.join('.'), asTextHistogram)} }`;
|
|
3033
|
+
}
|
|
3034
|
+
return middleQuery;
|
|
3035
|
+
};
|
|
3036
|
+
const buildAliasedNestedCountsQuery = ({ type, field, rangeName, asTextHistogram = false })=>{
|
|
3037
|
+
const dataParams = [
|
|
3038
|
+
`filter: $${rangeName}`
|
|
3039
|
+
];
|
|
3040
|
+
const dataTypeLine = `${rangeName} : ${type} (accessibility: $accessibility ${dataParams}) {`;
|
|
3041
|
+
const processedFields = rawDataQueryStrForEachField(field, asTextHistogram);
|
|
3042
|
+
return `${dataTypeLine} ${processedFields} }`;
|
|
3043
|
+
};
|
|
3044
|
+
const buildRangeFilters = (field, ranges, filters, rangeBaseName, isNested = true)=>{
|
|
3045
|
+
return Object.entries(ranges).reduce((acc, [, rangeValue], idx)=>{
|
|
3046
|
+
acc[`${rangeBaseName}_${idx}`] = {
|
|
3047
|
+
mode: filters.mode,
|
|
3048
|
+
root: {
|
|
3049
|
+
...filters.root,
|
|
3050
|
+
[field]: convertNumericFromToArrayToFilters(field, rangeValue, isNested)
|
|
3012
3051
|
}
|
|
3013
|
-
return {
|
|
3014
|
-
not: {
|
|
3015
|
-
[op.field]: op?.operand ?? null
|
|
3016
|
-
}
|
|
3017
|
-
};
|
|
3018
|
-
};
|
|
3019
|
-
this.handleNestedFilter = (op)=>{
|
|
3020
|
-
const child = convertFilterToGqlFilter(op.operand);
|
|
3021
|
-
return {
|
|
3022
|
-
nested: {
|
|
3023
|
-
path: op.path,
|
|
3024
|
-
...child
|
|
3025
|
-
}
|
|
3026
|
-
};
|
|
3027
3052
|
};
|
|
3028
|
-
|
|
3029
|
-
}
|
|
3030
|
-
const convertFilterToNestedGqlFilter = (filter)=>{
|
|
3031
|
-
const handler = new ToGqlAllNested();
|
|
3032
|
-
return handleOperation(handler, filter);
|
|
3053
|
+
return acc;
|
|
3054
|
+
}, {});
|
|
3033
3055
|
};
|
|
3034
|
-
const
|
|
3035
|
-
const
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
3056
|
+
const buildRangeQuery = (field, ranges, filters, rangeBaseName = 'range', index = 'cases', indexPrefix = '', isNested = true, asTextHistogram = false)=>{
|
|
3057
|
+
const rangeFilters = buildRangeFilters(field, ranges, filters, rangeBaseName, isNested);
|
|
3058
|
+
let query = `query rangeQuery ($accessibility: Accessibility, ${Object.keys(rangeFilters).map((rangeKey)=>`$${rangeKey}: JSON`).join(',')} ) { ${indexPrefix}_aggregation {`;
|
|
3059
|
+
Object.keys(rangeFilters).forEach((rangeKey)=>{
|
|
3060
|
+
const rangeQuery = buildAliasedNestedCountsQuery({
|
|
3061
|
+
type: index,
|
|
3062
|
+
field,
|
|
3063
|
+
rangeName: rangeKey,
|
|
3064
|
+
asTextHistogram
|
|
3065
|
+
});
|
|
3066
|
+
query += rangeQuery + ' \n';
|
|
3067
|
+
});
|
|
3068
|
+
query += `}}`;
|
|
3069
|
+
return {
|
|
3070
|
+
query: query,
|
|
3071
|
+
filters: rangeFilters
|
|
3044
3072
|
};
|
|
3045
3073
|
};
|
|
3046
3074
|
|
|
3075
|
+
const GUPPY_MAX_ITEMS = 10000;
|
|
3047
3076
|
const statusEndpoint = '/_status';
|
|
3048
3077
|
const fetchJson = async (url)=>{
|
|
3049
3078
|
const res = await fetch(url, {
|
|
@@ -3395,6 +3424,34 @@ const explorerTags = guppyApi.enhanceEndpoints({
|
|
|
3395
3424
|
};
|
|
3396
3425
|
}
|
|
3397
3426
|
}),
|
|
3427
|
+
getObjectIds: builder.query({
|
|
3428
|
+
query: ({ filters, field, index, indexPrefix = '', accessibility = Accessibility.ALL, limit = GUPPY_MAX_ITEMS })=>{
|
|
3429
|
+
const gqlFilter = convertFilterSetToGqlFilter(filters);
|
|
3430
|
+
const query = `query getObjectIds ($filter: JSON) {
|
|
3431
|
+
${indexPrefix}${index} (filter: $filter, accessibility: ${accessibility}, first: ${limit}) {
|
|
3432
|
+
${rawDataQueryStrForEachField$1(field)}
|
|
3433
|
+
}
|
|
3434
|
+
}`;
|
|
3435
|
+
return {
|
|
3436
|
+
query,
|
|
3437
|
+
variables: {
|
|
3438
|
+
filter: gqlFilter,
|
|
3439
|
+
accessibility
|
|
3440
|
+
}
|
|
3441
|
+
};
|
|
3442
|
+
},
|
|
3443
|
+
transformResponse: (response, _, args)=>{
|
|
3444
|
+
const valueData = jsonpathPlus.JSONPath({
|
|
3445
|
+
json: response?.data ?? [],
|
|
3446
|
+
path: `$..${args.field}`,
|
|
3447
|
+
resultType: 'value'
|
|
3448
|
+
});
|
|
3449
|
+
return {
|
|
3450
|
+
ids: valueData,
|
|
3451
|
+
index: args.index
|
|
3452
|
+
};
|
|
3453
|
+
}
|
|
3454
|
+
}),
|
|
3398
3455
|
generalGQL: builder.query({
|
|
3399
3456
|
query: ({ query, variables })=>{
|
|
3400
3457
|
return {
|
|
@@ -3460,7 +3517,7 @@ const buildGetStatsAggregationQuery = (type, fields, filters, accessibility = Ac
|
|
|
3460
3517
|
};
|
|
3461
3518
|
return queryBody;
|
|
3462
3519
|
};
|
|
3463
|
-
const { useGetRawDataAndTotalCountsQuery, useGetAccessibleDataQuery, useGetAllFieldsForTypeQuery, useGetAggsQuery, useLazyGetAggsQuery, useGetStatsAggregationsQuery, useLazyGetStatsAggregationsQuery, useGetSubAggsQuery, useGetCountsQuery, useLazyGetCountsQuery, useGetFieldCountSummaryQuery, useGetFieldsForIndexQuery, useGetSharedFieldsForIndexQuery, useGeneralGQLQuery, useLazyGeneralGQLQuery, useCustomRangeQuery, useLazyCustomRangeQuery } = explorerApi;
|
|
3520
|
+
const { useGetRawDataAndTotalCountsQuery, useGetAccessibleDataQuery, useGetAllFieldsForTypeQuery, useGetAggsQuery, useLazyGetAggsQuery, useGetStatsAggregationsQuery, useLazyGetStatsAggregationsQuery, useGetSubAggsQuery, useGetCountsQuery, useLazyGetCountsQuery, useGetFieldCountSummaryQuery, useGetFieldsForIndexQuery, useGetSharedFieldsForIndexQuery, useGeneralGQLQuery, useLazyGeneralGQLQuery, useCustomRangeQuery, useLazyCustomRangeQuery, useGetObjectIdsQuery, useLazyGetObjectIdsQuery } = explorerApi;
|
|
3464
3521
|
|
|
3465
3522
|
/**
|
|
3466
3523
|
* Defines coreListeners for adding middleware.
|
|
@@ -4030,6 +4087,81 @@ class CohortStorage {
|
|
|
4030
4087
|
}
|
|
4031
4088
|
}
|
|
4032
4089
|
|
|
4090
|
+
const { selectAll: selectAllCohorts, selectTotal: selectTotalCohorts, selectById: selectCohortById, selectIds: selectCohortIds } = cohortsAdapter.getSelectors((state)=>state.cohorts.cohortManager);
|
|
4091
|
+
/**
|
|
4092
|
+
* Internally used selector for the exported selectora
|
|
4093
|
+
* @param state
|
|
4094
|
+
*/ const getCurrentCohortFromCoreState = (state)=>{
|
|
4095
|
+
return state.cohorts.cohortManager.currentCohortId;
|
|
4096
|
+
};
|
|
4097
|
+
const selectCohortFilters = (state)=>{
|
|
4098
|
+
const currentCohortId = getCurrentCohortFromCoreState(state);
|
|
4099
|
+
return state.cohorts.cohortManager.entities[currentCohortId]?.filters;
|
|
4100
|
+
};
|
|
4101
|
+
const selectCurrentCohortFilters = (state)=>{
|
|
4102
|
+
const currentCohortId = getCurrentCohortFromCoreState(state);
|
|
4103
|
+
return state.cohorts.cohortManager.entities[currentCohortId]?.filters;
|
|
4104
|
+
};
|
|
4105
|
+
const selectCurrentCohortId = (state)=>{
|
|
4106
|
+
return state.cohorts.cohortManager.currentCohortId;
|
|
4107
|
+
};
|
|
4108
|
+
const selectCurrentCohort = (state)=>cohortSelectors.selectById(state, getCurrentCohortFromCoreState(state));
|
|
4109
|
+
const selectCurrentCohortName = (state)=>cohortSelectors.selectById(state, getCurrentCohortFromCoreState(state)).name;
|
|
4110
|
+
/**
|
|
4111
|
+
* Select a filter by its name from the current cohort. If the filter is not found
|
|
4112
|
+
* returns undefined.
|
|
4113
|
+
* @param state - Core
|
|
4114
|
+
* @param index which cohort index to select from
|
|
4115
|
+
* @param name name of the filter to select
|
|
4116
|
+
*/ const selectIndexedFilterByName = (state, index, name)=>{
|
|
4117
|
+
return cohortSelectors.selectById(state, getCurrentCohortFromCoreState(state)).filters[index]?.root[name];
|
|
4118
|
+
};
|
|
4119
|
+
/**
|
|
4120
|
+
* Returns all the cohorts in the state
|
|
4121
|
+
* @param state - the CoreState
|
|
4122
|
+
*
|
|
4123
|
+
* @category Cohort
|
|
4124
|
+
* @category Selectors
|
|
4125
|
+
*/ const selectAvailableCohorts = (state)=>cohortSelectors.selectAll(state);
|
|
4126
|
+
/**
|
|
4127
|
+
* Returns if the current cohort is modified
|
|
4128
|
+
* @param state - the CoreState
|
|
4129
|
+
* @category Cohort
|
|
4130
|
+
* @category Selectors
|
|
4131
|
+
* @hidden
|
|
4132
|
+
*/ const selectCurrentCohortModified = (state)=>{
|
|
4133
|
+
const cohort = cohortSelectors.selectById(state, getCurrentCohortFromCoreState(state));
|
|
4134
|
+
return cohort?.modified;
|
|
4135
|
+
};
|
|
4136
|
+
/**
|
|
4137
|
+
* Returns if the current cohort has been saved
|
|
4138
|
+
* @param state - the CoreState
|
|
4139
|
+
* @category Cohort
|
|
4140
|
+
* @category Selectors
|
|
4141
|
+
* @hidden
|
|
4142
|
+
*/ const selectCurrentCohortSaved = (state)=>{
|
|
4143
|
+
const cohort = cohortSelectors.selectById(state, getCurrentCohortFromCoreState(state));
|
|
4144
|
+
return cohort?.saved;
|
|
4145
|
+
};
|
|
4146
|
+
/**
|
|
4147
|
+
* Select a filter by its name from the current cohort. If the filter is not found
|
|
4148
|
+
* returns undefined.
|
|
4149
|
+
* @param state - Core
|
|
4150
|
+
* @param name name of the filter to select
|
|
4151
|
+
*/ const selectAvailableCohortByName = (state, name)=>cohortSelectors.selectAll(state).find((cohort)=>cohort.name === name);
|
|
4152
|
+
/**
|
|
4153
|
+
* Select a filter from the index.
|
|
4154
|
+
* returns undefined.
|
|
4155
|
+
* @param state - Core
|
|
4156
|
+
* @param index which cohort index to select from
|
|
4157
|
+
*/ const selectIndexFilters = (state, index)=>{
|
|
4158
|
+
const cohort = cohortSelectors.selectById(state, getCurrentCohortFromCoreState(state));
|
|
4159
|
+
if (!cohort) {
|
|
4160
|
+
console.error('No Cohort Defined');
|
|
4161
|
+
}
|
|
4162
|
+
return cohort?.filters?.[index] ?? EmptyFilterSet;
|
|
4163
|
+
};
|
|
4164
|
+
|
|
4033
4165
|
const isFileItem = (item)=>{
|
|
4034
4166
|
return item && 'guid' in item;
|
|
4035
4167
|
};
|
|
@@ -6298,6 +6430,87 @@ class ConfigRegistry {
|
|
|
6298
6430
|
}
|
|
6299
6431
|
const configRegistry = new ConfigRegistry();
|
|
6300
6432
|
|
|
6433
|
+
const DAYS_IN_DECADE = 3652; // Note: an approximation
|
|
6434
|
+
const cohortFacetSlice = graphQLAPI.injectEndpoints({
|
|
6435
|
+
endpoints: (builder)=>({
|
|
6436
|
+
cohortFacets: builder.query({
|
|
6437
|
+
query: ({ index, facetFields, continuousFacets, primaryCohort, comparisonCohort })=>({
|
|
6438
|
+
url: `${GEN3_ANALYSIS_API}/compare/facets`,
|
|
6439
|
+
method: 'POST',
|
|
6440
|
+
body: {
|
|
6441
|
+
doc_type: index,
|
|
6442
|
+
cohort1: primaryCohort,
|
|
6443
|
+
cohort2: comparisonCohort,
|
|
6444
|
+
facets: facetFields,
|
|
6445
|
+
interval: continuousFacets.reduce((acc, x)=>{
|
|
6446
|
+
acc[x] = DAYS_IN_DECADE;
|
|
6447
|
+
return acc;
|
|
6448
|
+
}, {})
|
|
6449
|
+
}
|
|
6450
|
+
}),
|
|
6451
|
+
transformResponse: (response)=>{
|
|
6452
|
+
const facets1 = response?.cohort1?.facets;
|
|
6453
|
+
const facets2 = response?.cohort2?.facets;
|
|
6454
|
+
return {
|
|
6455
|
+
aggregations: [
|
|
6456
|
+
facets1,
|
|
6457
|
+
facets2
|
|
6458
|
+
]
|
|
6459
|
+
};
|
|
6460
|
+
}
|
|
6461
|
+
})
|
|
6462
|
+
})
|
|
6463
|
+
});
|
|
6464
|
+
const { useCohortFacetsQuery } = cohortFacetSlice;
|
|
6465
|
+
|
|
6466
|
+
const vennDiagramApiSlice = graphQLAPI.injectEndpoints({
|
|
6467
|
+
endpoints: (builder)=>({
|
|
6468
|
+
vennDiagram: builder.query({
|
|
6469
|
+
query: (queryParameters)=>{
|
|
6470
|
+
return {
|
|
6471
|
+
url: `${GEN3_ANALYSIS_API}/compare/intersection`,
|
|
6472
|
+
method: 'POST',
|
|
6473
|
+
body: JSON.stringify({
|
|
6474
|
+
cohort1: queryParameters.set1Filters,
|
|
6475
|
+
cohort2: queryParameters.set2Filters,
|
|
6476
|
+
doc_type: queryParameters.index
|
|
6477
|
+
})
|
|
6478
|
+
};
|
|
6479
|
+
},
|
|
6480
|
+
transformResponse: (response)=>({
|
|
6481
|
+
set1: response?.cohort1,
|
|
6482
|
+
set2: response?.cohort2,
|
|
6483
|
+
intersection: response?.intersection
|
|
6484
|
+
})
|
|
6485
|
+
})
|
|
6486
|
+
})
|
|
6487
|
+
});
|
|
6488
|
+
const { useVennDiagramQuery } = vennDiagramApiSlice;
|
|
6489
|
+
|
|
6490
|
+
const graphQLQuery = `
|
|
6491
|
+
query pValue($data: [[Int]]!) {
|
|
6492
|
+
analysis {
|
|
6493
|
+
pvalue(data: $data)
|
|
6494
|
+
}
|
|
6495
|
+
}
|
|
6496
|
+
`;
|
|
6497
|
+
const pValueSlice = graphQLAPI.injectEndpoints({
|
|
6498
|
+
endpoints: (builder)=>({
|
|
6499
|
+
pValue: builder.query({
|
|
6500
|
+
query: (data)=>({
|
|
6501
|
+
url: `${GEN3_ANALYSIS_API}/pvalue`,
|
|
6502
|
+
method: 'POST',
|
|
6503
|
+
body: {
|
|
6504
|
+
query: graphQLQuery,
|
|
6505
|
+
variables: data
|
|
6506
|
+
}
|
|
6507
|
+
}),
|
|
6508
|
+
transformResponse: (response)=>response?.data?.analysis.pvalue
|
|
6509
|
+
})
|
|
6510
|
+
})
|
|
6511
|
+
});
|
|
6512
|
+
const { usePValueQuery } = pValueSlice;
|
|
6513
|
+
|
|
6301
6514
|
exports.Accessibility = Accessibility;
|
|
6302
6515
|
exports.CART_LIMIT = CART_LIMIT;
|
|
6303
6516
|
exports.CohortStorage = CohortStorage;
|
|
@@ -6334,17 +6547,20 @@ exports.Modals = Modals;
|
|
|
6334
6547
|
exports.PodConditionType = PodConditionType;
|
|
6335
6548
|
exports.PodStatus = PodStatus;
|
|
6336
6549
|
exports.RequestedWorkspaceStatus = RequestedWorkspaceStatus;
|
|
6550
|
+
exports.ToGqlAllNested = ToGqlAllNested;
|
|
6337
6551
|
exports.ToGqlHandler = ToGqlHandler;
|
|
6338
6552
|
exports.ValueExtractorHandler = ValueExtractorHandler;
|
|
6339
6553
|
exports.WorkspaceStatus = WorkspaceStatus;
|
|
6340
6554
|
exports.addItemsToCart = addItemsToCart;
|
|
6341
6555
|
exports.ageDisplay = ageDisplay;
|
|
6342
6556
|
exports.appendFilterToOperation = appendFilterToOperation;
|
|
6557
|
+
exports.buildCohortGqlOperator = buildCohortGqlOperator;
|
|
6343
6558
|
exports.buildGetAggregationQuery = buildGetAggregationQuery;
|
|
6344
6559
|
exports.buildGetStatsAggregationQuery = buildGetStatsAggregationQuery;
|
|
6345
6560
|
exports.buildListItemsGroupedByDataset = buildListItemsGroupedByDataset;
|
|
6346
6561
|
exports.buildNestedFilterForOperation = buildNestedFilterForOperation;
|
|
6347
6562
|
exports.buildNestedGQLFilter = buildNestedGQLFilter;
|
|
6563
|
+
exports.buildNestedWithParentPathGQLFilter = buildNestedWithParentPathGQLFilter;
|
|
6348
6564
|
exports.buildRangeQuery = buildRangeQuery;
|
|
6349
6565
|
exports.calculatePercentageAsNumber = calculatePercentageAsNumber;
|
|
6350
6566
|
exports.calculatePercentageAsString = calculatePercentageAsString;
|
|
@@ -6357,7 +6573,10 @@ exports.cohortReducer = cohortReducer;
|
|
|
6357
6573
|
exports.configRegistry = configRegistry;
|
|
6358
6574
|
exports.conversion = conversion;
|
|
6359
6575
|
exports.convertFilterSetToGqlFilter = convertFilterSetToGqlFilter;
|
|
6576
|
+
exports.convertFilterSetToNestedGqlFilter = convertFilterSetToNestedGqlFilter;
|
|
6577
|
+
exports.convertFilterSetToOperation = convertFilterSetToOperation;
|
|
6360
6578
|
exports.convertFilterToGqlFilter = convertFilterToGqlFilter;
|
|
6579
|
+
exports.convertFilterToNestedGqlFilter = convertFilterToNestedGqlFilter;
|
|
6361
6580
|
exports.convertGqlFilterToFilter = convertGqlFilterToFilter;
|
|
6362
6581
|
exports.convertToHistogramDataAsStringKey = convertToHistogramDataAsStringKey;
|
|
6363
6582
|
exports.convertToQueryString = convertToQueryString;
|
|
@@ -6376,6 +6595,7 @@ exports.drsHostnamesReducer = drsHostnamesReducer;
|
|
|
6376
6595
|
exports.duplicateCohort = duplicateCohort;
|
|
6377
6596
|
exports.explorerApi = explorerApi;
|
|
6378
6597
|
exports.explorerTags = explorerTags;
|
|
6598
|
+
exports.extractContents = extractContents;
|
|
6379
6599
|
exports.extractEnumFilterValue = extractEnumFilterValue;
|
|
6380
6600
|
exports.extractFieldNameFromFullFieldName = extractFieldNameFromFullFieldName;
|
|
6381
6601
|
exports.extractFileDatasetsInRecords = extractFileDatasetsInRecords;
|
|
@@ -6390,7 +6610,7 @@ exports.fetchFencePresignedURL = fetchFencePresignedURL;
|
|
|
6390
6610
|
exports.fetchJSONDataFromURL = fetchJSONDataFromURL;
|
|
6391
6611
|
exports.fetchJson = fetchJson;
|
|
6392
6612
|
exports.fetchUserState = fetchUserState;
|
|
6393
|
-
exports.
|
|
6613
|
+
exports.fieldNameToLabel = fieldNameToLabel;
|
|
6394
6614
|
exports.filterSetToOperation = filterSetToOperation;
|
|
6395
6615
|
exports.gen3Api = gen3Api;
|
|
6396
6616
|
exports.generateUniqueName = generateUniqueName;
|
|
@@ -6463,6 +6683,7 @@ exports.isTimeGreaterThan = isTimeGreaterThan;
|
|
|
6463
6683
|
exports.isUnion = isUnion;
|
|
6464
6684
|
exports.isWorkspaceActive = isWorkspaceActive;
|
|
6465
6685
|
exports.isWorkspaceRunningOrStopping = isWorkspaceRunningOrStopping;
|
|
6686
|
+
exports.joinFilters = joinFilters;
|
|
6466
6687
|
exports.jsonToFormat = jsonToFormat;
|
|
6467
6688
|
exports.listifyMethodsFromMapping = listifyMethodsFromMapping;
|
|
6468
6689
|
exports.logoutFence = logoutFence;
|
|
@@ -6547,7 +6768,7 @@ exports.stringifyJSONParam = stringifyJSONParam;
|
|
|
6547
6768
|
exports.submissionApi = submissionApi;
|
|
6548
6769
|
exports.toggleCohortBuilderAllFilters = toggleCohortBuilderAllFilters;
|
|
6549
6770
|
exports.toggleCohortBuilderCategoryFilter = toggleCohortBuilderCategoryFilter;
|
|
6550
|
-
exports.
|
|
6771
|
+
exports.trimFirstfieldNameToLabel = trimFirstfieldNameToLabel;
|
|
6551
6772
|
exports.updateCohortFilter = updateCohortFilter;
|
|
6552
6773
|
exports.updateCohortName = updateCohortName;
|
|
6553
6774
|
exports.useAddCohortManifestMutation = useAddCohortManifestMutation;
|
|
@@ -6556,6 +6777,7 @@ exports.useAddMetadataManifestMutation = useAddMetadataManifestMutation;
|
|
|
6556
6777
|
exports.useAddNewCredentialMutation = useAddNewCredentialMutation;
|
|
6557
6778
|
exports.useAskQuestionMutation = useAskQuestionMutation;
|
|
6558
6779
|
exports.useAuthorizeFromCredentialsMutation = useAuthorizeFromCredentialsMutation;
|
|
6780
|
+
exports.useCohortFacetsQuery = useCohortFacetsQuery;
|
|
6559
6781
|
exports.useCoreDispatch = useCoreDispatch;
|
|
6560
6782
|
exports.useCoreSelector = useCoreSelector;
|
|
6561
6783
|
exports.useCreateAuthzResourceMutation = useCreateAuthzResourceMutation;
|
|
@@ -6598,6 +6820,7 @@ exports.useGetManifestServiceStatusQuery = useGetManifestServiceStatusQuery;
|
|
|
6598
6820
|
exports.useGetMetadataByIdQuery = useGetMetadataByIdQuery;
|
|
6599
6821
|
exports.useGetMetadataFromManifestQuery = useGetMetadataFromManifestQuery;
|
|
6600
6822
|
exports.useGetMetadataManifestQuery = useGetMetadataManifestQuery;
|
|
6823
|
+
exports.useGetObjectIdsQuery = useGetObjectIdsQuery;
|
|
6601
6824
|
exports.useGetPresignedUrlQuery = useGetPresignedUrlQuery;
|
|
6602
6825
|
exports.useGetProjectsDetailsQuery = useGetProjectsDetailsQuery;
|
|
6603
6826
|
exports.useGetProjectsQuery = useGetProjectsQuery;
|
|
@@ -6633,6 +6856,7 @@ exports.useLazyGetCrosswalkDataQuery = useLazyGetCrosswalkDataQuery;
|
|
|
6633
6856
|
exports.useLazyGetDownloadQuery = useLazyGetDownloadQuery;
|
|
6634
6857
|
exports.useLazyGetExternalLoginsQuery = useLazyGetExternalLoginsQuery;
|
|
6635
6858
|
exports.useLazyGetManifestServiceStatusQuery = useLazyGetManifestServiceStatusQuery;
|
|
6859
|
+
exports.useLazyGetObjectIdsQuery = useLazyGetObjectIdsQuery;
|
|
6636
6860
|
exports.useLazyGetPresignedUrlQuery = useLazyGetPresignedUrlQuery;
|
|
6637
6861
|
exports.useLazyGetProjectsQuery = useLazyGetProjectsQuery;
|
|
6638
6862
|
exports.useLazyGetSowerJobListQuery = useLazyGetSowerJobListQuery;
|
|
@@ -6640,6 +6864,7 @@ exports.useLazyGetStatsAggregationsQuery = useLazyGetStatsAggregationsQuery;
|
|
|
6640
6864
|
exports.useLazyGetSubmissionGraphQLQuery = useLazyGetSubmissionGraphQLQuery;
|
|
6641
6865
|
exports.useLazyIsExternalConnectedQuery = useLazyIsExternalConnectedQuery;
|
|
6642
6866
|
exports.useLazyRequestQuery = useLazyRequestQuery;
|
|
6867
|
+
exports.usePValueQuery = usePValueQuery;
|
|
6643
6868
|
exports.usePrevious = usePrevious;
|
|
6644
6869
|
exports.useRemoveCredentialMutation = useRemoveCredentialMutation;
|
|
6645
6870
|
exports.useRequestByIdQuery = useRequestByIdQuery;
|
|
@@ -6650,6 +6875,7 @@ exports.useSubmitSowerJobMutation = useSubmitSowerJobMutation;
|
|
|
6650
6875
|
exports.useTerminateWorkspaceMutation = useTerminateWorkspaceMutation;
|
|
6651
6876
|
exports.useUserAuth = useUserAuth;
|
|
6652
6877
|
exports.useUserRequestQuery = useUserRequestQuery;
|
|
6878
|
+
exports.useVennDiagramQuery = useVennDiagramQuery;
|
|
6653
6879
|
exports.userHasCreateOrUpdateOnAnyProject = userHasCreateOrUpdateOnAnyProject;
|
|
6654
6880
|
exports.userHasDataUpload = userHasDataUpload;
|
|
6655
6881
|
exports.userHasMethodForServiceOnProject = userHasMethodForServiceOnProject;
|