@gen3/core 0.12.23 → 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/esm/index.js
CHANGED
|
@@ -44,6 +44,7 @@ const GEN3_CROSSWALK_API = process.env.NEXT_PUBLIC_GEN3_CROSSWALK_API || `${GEN3
|
|
|
44
44
|
const GEN3_SOWER_API = process.env.NEXT_PUBLIC_GEN3_SOWER_API || `${GEN3_API}/jobs`;
|
|
45
45
|
const GEN3_MANIFEST_API = process.env.NEXT_PUBLIC_GEN3_MANIFEST_API || `${GEN3_API}/manifests`;
|
|
46
46
|
const GEN3_REQUESTOR_API = process.env.NEXT_PUBLIC_GEN3_REQUESTOR_API || `${GEN3_API}/requestor`;
|
|
47
|
+
const GEN3_ANALYSIS_API = process.env.NEXT_PUBLIC_GEN3_ANALYSIS_API || `${GEN3_API}/analysis/v0`;
|
|
47
48
|
var Accessibility = /*#__PURE__*/ function(Accessibility) {
|
|
48
49
|
Accessibility["ACCESSIBLE"] = "accessible";
|
|
49
50
|
Accessibility["UNACCESSIBLE"] = "unaccessible";
|
|
@@ -1760,12 +1761,12 @@ const COMMON_PREPOSITIONS = [
|
|
|
1760
1761
|
'yet'
|
|
1761
1762
|
];
|
|
1762
1763
|
const capitalize = (s)=>s.length > 0 ? s[0].toUpperCase() + s.slice(1) : '';
|
|
1763
|
-
const
|
|
1764
|
+
const trimFirstfieldNameToLabel = (fieldName, trim = false)=>{
|
|
1764
1765
|
if (trim) {
|
|
1765
1766
|
const source = fieldName.slice(fieldName.indexOf('.') + 1);
|
|
1766
|
-
return
|
|
1767
|
+
return fieldNameToLabel(source ? source : fieldName, 0);
|
|
1767
1768
|
}
|
|
1768
|
-
return
|
|
1769
|
+
return fieldNameToLabel(fieldName);
|
|
1769
1770
|
};
|
|
1770
1771
|
/**
|
|
1771
1772
|
* Converts a filter name to a title,
|
|
@@ -1773,7 +1774,7 @@ const trimFirstFieldNameToTitle = (fieldName, trim = false)=>{
|
|
|
1773
1774
|
* if sections == 2 then the output would be Input Experimental Strategy
|
|
1774
1775
|
* @param fieldName input filter expected to be: string.firstpart_secondpart
|
|
1775
1776
|
* @param sections number of "sections" string.string.string to got back from the end of the field
|
|
1776
|
-
*/ const
|
|
1777
|
+
*/ const fieldNameToLabel = (fieldName, sections = 1)=>{
|
|
1777
1778
|
if (fieldName === undefined) return 'No Title';
|
|
1778
1779
|
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(' ');
|
|
1779
1780
|
};
|
|
@@ -1797,492 +1798,808 @@ const trimFirstFieldNameToTitle = (fieldName, trim = false)=>{
|
|
|
1797
1798
|
];
|
|
1798
1799
|
};
|
|
1799
1800
|
|
|
1800
|
-
const defaultCohortNameGenerator = ()=>`Custom cohort ${new Date().toLocaleString('en-CA', {
|
|
1801
|
-
timeZone: 'America/Chicago',
|
|
1802
|
-
hour12: false
|
|
1803
|
-
}).replace(',', '')}`;
|
|
1804
|
-
const isNameUnique = (entities, name, excludeId)=>{
|
|
1805
|
-
const trimmedName = name.trim();
|
|
1806
|
-
if (!trimmedName) return false;
|
|
1807
|
-
return !entities.some((cohort)=>cohort && cohort.id !== excludeId && cohort.name.trim().toLowerCase() === trimmedName.toLowerCase());
|
|
1808
|
-
};
|
|
1809
|
-
const generateUniqueName = (entities, baseName)=>{
|
|
1810
|
-
const trimmedBaseName = baseName.trim();
|
|
1811
|
-
// If base name is unique, use it
|
|
1812
|
-
if (isNameUnique(entities, trimmedBaseName)) {
|
|
1813
|
-
return trimmedBaseName;
|
|
1814
|
-
}
|
|
1815
|
-
// Find a unique name by appending numbers
|
|
1816
|
-
let counter = 1;
|
|
1817
|
-
let uniqueName;
|
|
1818
|
-
do {
|
|
1819
|
-
uniqueName = `${trimmedBaseName} (${counter})`;
|
|
1820
|
-
counter++;
|
|
1821
|
-
}while (!isNameUnique(entities, uniqueName))
|
|
1822
|
-
return uniqueName;
|
|
1823
|
-
};
|
|
1824
1801
|
/**
|
|
1825
|
-
*
|
|
1826
|
-
*
|
|
1827
|
-
*
|
|
1828
|
-
*
|
|
1802
|
+
* Constructs a nested operation object based on the provided field and leaf operand.
|
|
1803
|
+
* If the field does not contain a dot '.', it either assigns the field to the leaf operand (if applicable)
|
|
1804
|
+
* or returns the leaf operand as is. When the field contains dots, it splits the field into parts,
|
|
1805
|
+
* creates a "nested" operation for the root field, and recursively constructs the nested structure
|
|
1806
|
+
* for the remaining portion of the field.
|
|
1829
1807
|
*
|
|
1830
|
-
*
|
|
1831
|
-
*
|
|
1832
|
-
*
|
|
1833
|
-
*
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
root: {}
|
|
1839
|
-
};
|
|
1808
|
+
* @param {string} field - The hierarchical field path, with segments separated by dots (e.g., "root.child").
|
|
1809
|
+
* @param {Operation} leafOperand - The operation to be nested within the specified path.
|
|
1810
|
+
* @param parentPath - The parent path of the current field. Guppy nested filters require a parent path.
|
|
1811
|
+
* @param depth
|
|
1812
|
+
* @returns {Operation} A nested operation object that represents the structured path and operand.
|
|
1813
|
+
*/ const buildNestedWithParentPathGQLFilter = (field, leafOperand, parentPath = undefined)=>{
|
|
1814
|
+
if (!field.includes('.')) {
|
|
1815
|
+
return leafOperand;
|
|
1840
1816
|
}
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1817
|
+
const splitFieldArray = field.split('.');
|
|
1818
|
+
const nextField = splitFieldArray.shift();
|
|
1819
|
+
if (!nextField) {
|
|
1820
|
+
console.warn('Invalid field path:', field);
|
|
1821
|
+
return leafOperand;
|
|
1822
|
+
}
|
|
1823
|
+
const currentPath = parentPath ? `${parentPath}.${nextField}` : nextField;
|
|
1824
|
+
return {
|
|
1825
|
+
nested: {
|
|
1826
|
+
path: currentPath,
|
|
1827
|
+
...buildNestedGQLFilter(splitFieldArray.join('.'), leafOperand, currentPath)
|
|
1845
1828
|
}
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1829
|
+
};
|
|
1830
|
+
};
|
|
1831
|
+
const buildCohortGqlOperator = (fs)=>{
|
|
1832
|
+
if (!fs || !fs.root) return undefined;
|
|
1833
|
+
const fsKeys = Object.keys(fs.root);
|
|
1834
|
+
// if no keys return undefined
|
|
1835
|
+
if (fsKeys.length === 0) return undefined;
|
|
1836
|
+
// TODO consider changing FilterSet: mode to support joinOrToAll as FilterSet mode
|
|
1837
|
+
// find key using keyword "joinOrToAll"
|
|
1838
|
+
const joinOrToAllKey = fsKeys.filter((x)=>x.includes('joinOrToAll'));
|
|
1839
|
+
switch(fs.mode){
|
|
1840
|
+
case 'and':
|
|
1841
|
+
if (joinOrToAllKey.length === 1) {
|
|
1842
|
+
const firstJoinOrToAllKey = joinOrToAllKey[0];
|
|
1843
|
+
// Remove firstJoinOrToAllKey from Array
|
|
1844
|
+
fsKeys.splice(fsKeys.indexOf(firstJoinOrToAllKey), 1);
|
|
1845
|
+
const firstJoinOrToAllObj = fs.root[firstJoinOrToAllKey];
|
|
1846
|
+
// make sure type is or/ Union
|
|
1847
|
+
if (firstJoinOrToAllObj.operator === 'or') {
|
|
1848
|
+
return {
|
|
1849
|
+
or: firstJoinOrToAllObj?.operands.map((orObj)=>{
|
|
1850
|
+
// go through each or statement and add all other filters to it
|
|
1851
|
+
return {
|
|
1852
|
+
and: [
|
|
1853
|
+
convertFilterToNestedGqlFilter(orObj),
|
|
1854
|
+
...fsKeys.map((k)=>{
|
|
1855
|
+
return convertFilterToNestedGqlFilter(fs.root[k]);
|
|
1856
|
+
})
|
|
1857
|
+
]
|
|
1858
|
+
};
|
|
1859
|
+
})
|
|
1860
|
+
};
|
|
1861
|
+
} else {
|
|
1862
|
+
console.error(`function buildCohortGqlOperator expecting "or" received "${firstJoinOrToAllObj.operator}" on key "${firstJoinOrToAllKey}"`);
|
|
1863
|
+
}
|
|
1864
|
+
} else if (joinOrToAllKey.length > 1) {
|
|
1865
|
+
console.error(`function buildCohortGqlOperator expecting only one joinOrToAll received: ${joinOrToAllKey.length}`, fsKeys);
|
|
1866
|
+
}
|
|
1867
|
+
return {
|
|
1868
|
+
// TODO: Replace fixed AND with cohort top level operation like Union or Intersection
|
|
1869
|
+
[fs.mode]: fsKeys.map((k)=>{
|
|
1870
|
+
return convertFilterToGqlFilter(fs.root[k]);
|
|
1871
|
+
})
|
|
1872
|
+
};
|
|
1873
|
+
case 'or':
|
|
1874
|
+
return {
|
|
1875
|
+
[fs.mode]: fsKeys.map((k)=>{
|
|
1876
|
+
return convertFilterToGqlFilter(fs.root[k]);
|
|
1877
|
+
})
|
|
1878
|
+
};
|
|
1879
|
+
}
|
|
1851
1880
|
};
|
|
1852
|
-
|
|
1853
1881
|
/**
|
|
1854
|
-
*
|
|
1855
|
-
*
|
|
1856
|
-
*
|
|
1857
|
-
*/ const
|
|
1858
|
-
const newCohort = ({ filters = {}, customName })=>{
|
|
1859
|
-
const ts = new Date().toISOString();
|
|
1860
|
-
const newName = customName ?? defaultCohortNameGenerator();
|
|
1861
|
-
const newId = createCohortId();
|
|
1882
|
+
* Merged two FilterSets returning the merged pair.
|
|
1883
|
+
* @param a - first FilterSet
|
|
1884
|
+
* @param b - other FilterSet
|
|
1885
|
+
*/ const joinFilters = (a, b)=>{
|
|
1862
1886
|
return {
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
createdDatetime: ts,
|
|
1869
|
-
modifiedDatetime: ts,
|
|
1870
|
-
counts: {}
|
|
1887
|
+
mode: a.mode,
|
|
1888
|
+
root: {
|
|
1889
|
+
...a.root,
|
|
1890
|
+
...b.root
|
|
1891
|
+
}
|
|
1871
1892
|
};
|
|
1872
1893
|
};
|
|
1873
|
-
const
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
})
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
}
|
|
1886
|
-
const
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
}
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
});
|
|
1906
|
-
cohortsAdapter.addOne(state, cohort);
|
|
1907
|
-
if (action.payload?.setAsCurrent) {
|
|
1908
|
-
state.currentCohortId = cohort.id;
|
|
1894
|
+
const convertFilterSetToOperation = (fs)=>{
|
|
1895
|
+
if (!fs) return undefined;
|
|
1896
|
+
switch(fs.mode){
|
|
1897
|
+
case 'and':
|
|
1898
|
+
return Object.keys(fs.root).length == 0 ? undefined : {
|
|
1899
|
+
operator: fs.mode,
|
|
1900
|
+
operands: Object.keys(fs.root).map((k)=>{
|
|
1901
|
+
return fs.root[k];
|
|
1902
|
+
})
|
|
1903
|
+
};
|
|
1904
|
+
}
|
|
1905
|
+
return undefined;
|
|
1906
|
+
};
|
|
1907
|
+
const extractContents = (filter)=>{
|
|
1908
|
+
if (isGQLUnion(filter)) {
|
|
1909
|
+
return filter.or;
|
|
1910
|
+
}
|
|
1911
|
+
if (isGQLIntersection(filter)) {
|
|
1912
|
+
return filter.and;
|
|
1913
|
+
}
|
|
1914
|
+
return undefined;
|
|
1915
|
+
};
|
|
1916
|
+
class ToGqlAllNested {
|
|
1917
|
+
constructor(){
|
|
1918
|
+
this.handleEquals = (op)=>{
|
|
1919
|
+
if (op.field.includes('.')) {
|
|
1920
|
+
const leafField = op.field.split('.').at(-1) ?? 'unset';
|
|
1921
|
+
return buildNestedGQLFilter(op.field, {
|
|
1922
|
+
'=': {
|
|
1923
|
+
[leafField]: op.operand
|
|
1924
|
+
}
|
|
1925
|
+
});
|
|
1909
1926
|
}
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
cohortsAdapter.updateOne(state, {
|
|
1914
|
-
id: id,
|
|
1915
|
-
changes: {
|
|
1916
|
-
name: name,
|
|
1917
|
-
modified: true,
|
|
1918
|
-
modifiedDatetime: new Date().toISOString()
|
|
1927
|
+
return {
|
|
1928
|
+
'=': {
|
|
1929
|
+
[op.field]: op.operand
|
|
1919
1930
|
}
|
|
1920
|
-
}
|
|
1921
|
-
}
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
filters: {},
|
|
1930
|
-
customName: DEFAULT_COHORT_NAME
|
|
1931
|
+
};
|
|
1932
|
+
};
|
|
1933
|
+
this.handleNotEquals = (op)=>{
|
|
1934
|
+
if (op.field.includes('.')) {
|
|
1935
|
+
const leafField = op.field.split('.').at(-1) ?? 'unset';
|
|
1936
|
+
return buildNestedGQLFilter(op.field, {
|
|
1937
|
+
'!=': {
|
|
1938
|
+
[leafField]: op.operand
|
|
1939
|
+
}
|
|
1931
1940
|
});
|
|
1932
|
-
cohortsAdapter.addOne(state, defaultCohort);
|
|
1933
|
-
state.currentCohortId = defaultCohort.id;
|
|
1934
|
-
if (action?.payload.shouldShowMessage) {
|
|
1935
|
-
state.message = [
|
|
1936
|
-
`deleteCohort|${removedCohortName}|${state.currentCohortId}`
|
|
1937
|
-
];
|
|
1938
|
-
}
|
|
1939
|
-
return;
|
|
1940
1941
|
}
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1942
|
+
return {
|
|
1943
|
+
'!=': {
|
|
1944
|
+
[op.field]: op.operand
|
|
1945
|
+
}
|
|
1946
|
+
};
|
|
1947
|
+
};
|
|
1948
|
+
this.handleLessThan = (op)=>{
|
|
1949
|
+
if (op.field.includes('.')) {
|
|
1950
|
+
const leafField = op.field.split('.').at(-1) ?? 'unset';
|
|
1951
|
+
return buildNestedGQLFilter(op.field, {
|
|
1952
|
+
'<': {
|
|
1953
|
+
[leafField]: op.operand
|
|
1954
|
+
}
|
|
1955
|
+
});
|
|
1946
1956
|
}
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1957
|
+
return {
|
|
1958
|
+
'<': {
|
|
1959
|
+
[op.field]: op.operand
|
|
1960
|
+
}
|
|
1961
|
+
};
|
|
1962
|
+
};
|
|
1963
|
+
this.handleLessThanOrEquals = (op)=>{
|
|
1964
|
+
if (op.field.includes('.')) {
|
|
1965
|
+
const leafField = op.field.split('.').at(-1) ?? 'unset';
|
|
1966
|
+
return buildNestedGQLFilter(op.field, {
|
|
1967
|
+
'<=': {
|
|
1968
|
+
[leafField]: op.operand
|
|
1969
|
+
}
|
|
1970
|
+
});
|
|
1951
1971
|
}
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1972
|
+
return {
|
|
1973
|
+
'<=': {
|
|
1974
|
+
[op.field]: op.operand
|
|
1975
|
+
}
|
|
1976
|
+
};
|
|
1977
|
+
};
|
|
1978
|
+
this.handleGreaterThan = (op)=>{
|
|
1979
|
+
if (op.field.includes('.')) {
|
|
1980
|
+
const leafField = op.field.split('.').at(-1) ?? 'unset';
|
|
1981
|
+
return buildNestedGQLFilter(op.field, {
|
|
1982
|
+
'>': {
|
|
1983
|
+
[leafField]: op.operand
|
|
1984
|
+
}
|
|
1985
|
+
});
|
|
1959
1986
|
}
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
filters: {
|
|
1964
|
-
...state.entities[currentCohortId].filters,
|
|
1965
|
-
[index]: {
|
|
1966
|
-
mode: state.entities[currentCohortId]?.filters[index]?.mode ?? 'and',
|
|
1967
|
-
root: {
|
|
1968
|
-
...state.entities[currentCohortId]?.filters[index]?.root ?? {},
|
|
1969
|
-
[field]: filter
|
|
1970
|
-
}
|
|
1971
|
-
}
|
|
1972
|
-
},
|
|
1973
|
-
modified: true,
|
|
1974
|
-
modifiedDatetime: new Date().toISOString()
|
|
1987
|
+
return {
|
|
1988
|
+
'>': {
|
|
1989
|
+
[op.field]: op.operand
|
|
1975
1990
|
}
|
|
1976
|
-
}
|
|
1977
|
-
}
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1991
|
+
};
|
|
1992
|
+
};
|
|
1993
|
+
this.handleGreaterThanOrEquals = (op)=>{
|
|
1994
|
+
if (op.field.includes('.')) {
|
|
1995
|
+
const leafField = op.field.split('.').at(-1) ?? 'unset';
|
|
1996
|
+
return buildNestedGQLFilter(op.field, {
|
|
1997
|
+
'>=': {
|
|
1998
|
+
[leafField]: op.operand
|
|
1999
|
+
}
|
|
2000
|
+
});
|
|
1984
2001
|
}
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
filters: {
|
|
1989
|
-
...state.entities[currentCohortId].filters,
|
|
1990
|
-
[index]: filters
|
|
1991
|
-
},
|
|
1992
|
-
modified: true,
|
|
1993
|
-
modifiedDatetime: new Date().toISOString()
|
|
2002
|
+
return {
|
|
2003
|
+
'>=': {
|
|
2004
|
+
[op.field]: op.operand
|
|
1994
2005
|
}
|
|
1995
|
-
}
|
|
1996
|
-
}
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2006
|
+
};
|
|
2007
|
+
};
|
|
2008
|
+
this.handleIncludes = (op)=>{
|
|
2009
|
+
if (op.field.includes('.')) {
|
|
2010
|
+
const leafField = op.field.split('.').at(-1) ?? 'unset';
|
|
2011
|
+
return buildNestedGQLFilter(op.field, {
|
|
2012
|
+
in: {
|
|
2013
|
+
[leafField]: op.operands
|
|
2014
|
+
}
|
|
2015
|
+
});
|
|
2002
2016
|
}
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
filters: action.payload.filters,
|
|
2007
|
-
modified: true,
|
|
2008
|
-
modifiedDatetime: new Date().toISOString()
|
|
2017
|
+
return {
|
|
2018
|
+
in: {
|
|
2019
|
+
[op.field]: op.operands
|
|
2009
2020
|
}
|
|
2010
|
-
}
|
|
2011
|
-
}
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2021
|
+
};
|
|
2022
|
+
};
|
|
2023
|
+
this.handleExcludes = (op)=>{
|
|
2024
|
+
if (op.field.includes('.')) {
|
|
2025
|
+
const leafField = op.field.split('.').at(-1) ?? 'unset';
|
|
2026
|
+
return buildNestedGQLFilter(op.field, {
|
|
2027
|
+
exclude: {
|
|
2028
|
+
[leafField]: op.operands
|
|
2029
|
+
}
|
|
2030
|
+
});
|
|
2019
2031
|
}
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2032
|
+
return {
|
|
2033
|
+
exclude: {
|
|
2034
|
+
[op.field]: op.operands
|
|
2035
|
+
}
|
|
2036
|
+
};
|
|
2037
|
+
};
|
|
2038
|
+
this.handleExcludeIfAny = (op)=>{
|
|
2039
|
+
if (op.field.includes('.')) {
|
|
2040
|
+
const leafField = op.field.split('.').at(-1) ?? 'unset';
|
|
2041
|
+
return buildNestedGQLFilter(op.field, {
|
|
2042
|
+
excludeifany: {
|
|
2043
|
+
[leafField]: op.operands
|
|
2044
|
+
}
|
|
2045
|
+
});
|
|
2023
2046
|
}
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
id: currentCohortId,
|
|
2028
|
-
changes: {
|
|
2029
|
-
filters: {
|
|
2030
|
-
...state.entities[currentCohortId]?.filters,
|
|
2031
|
-
[index]: {
|
|
2032
|
-
mode: state.entities[currentCohortId].filters[index].mode,
|
|
2033
|
-
root: updated
|
|
2034
|
-
}
|
|
2035
|
-
},
|
|
2036
|
-
modified: true,
|
|
2037
|
-
modifiedDatetime: new Date().toISOString()
|
|
2047
|
+
return {
|
|
2048
|
+
excludeifany: {
|
|
2049
|
+
[op.field]: op.operands
|
|
2038
2050
|
}
|
|
2051
|
+
};
|
|
2052
|
+
};
|
|
2053
|
+
this.handleIntersection = (op)=>({
|
|
2054
|
+
and: op.operands.map((x)=>convertFilterToGqlFilter(x))
|
|
2039
2055
|
});
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
const currentCohortId = getCurrentCohortId(state);
|
|
2043
|
-
const currentCohort = state.entities[currentCohortId];
|
|
2044
|
-
const newName = generateUniqueName(Object.values(state.entities), currentCohort.name);
|
|
2045
|
-
const duplicatedCohort = newCohort({
|
|
2046
|
-
filters: {
|
|
2047
|
-
...currentCohort.filters
|
|
2048
|
-
},
|
|
2049
|
-
customName: newName
|
|
2050
|
-
});
|
|
2051
|
-
cohortsAdapter.addOne(state, {
|
|
2052
|
-
...duplicatedCohort,
|
|
2053
|
-
counts: {
|
|
2054
|
-
...currentCohort.counts
|
|
2055
|
-
}
|
|
2056
|
+
this.handleUnion = (op)=>({
|
|
2057
|
+
or: op.operands.map((x)=>convertFilterToGqlFilter(x))
|
|
2056
2058
|
});
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
return;
|
|
2066
|
-
}
|
|
2067
|
-
const filters = state.entities[currentCohortId]?.filters[index]?.root;
|
|
2068
|
-
if (!filters) {
|
|
2069
|
-
return;
|
|
2059
|
+
this.handleMissing = (op)=>{
|
|
2060
|
+
if (op.field.includes('.')) {
|
|
2061
|
+
const leafField = op.field.split('.').at(-1) ?? 'unset';
|
|
2062
|
+
return buildNestedGQLFilter(op.field, {
|
|
2063
|
+
is: {
|
|
2064
|
+
[leafField]: 'MISSING'
|
|
2065
|
+
}
|
|
2066
|
+
});
|
|
2070
2067
|
}
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
filters: {
|
|
2075
|
-
...state.entities[currentCohortId]?.filters,
|
|
2076
|
-
[index]: {
|
|
2077
|
-
mode: 'and',
|
|
2078
|
-
root: {}
|
|
2079
|
-
}
|
|
2080
|
-
},
|
|
2081
|
-
modified: true,
|
|
2082
|
-
modifiedDatetime: new Date().toISOString()
|
|
2068
|
+
return {
|
|
2069
|
+
is: {
|
|
2070
|
+
[op.field]: 'MISSING'
|
|
2083
2071
|
}
|
|
2084
|
-
}
|
|
2085
|
-
}
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
counts: {
|
|
2093
|
-
...currentCohort.counts,
|
|
2094
|
-
...action.payload
|
|
2072
|
+
};
|
|
2073
|
+
};
|
|
2074
|
+
this.handleExists = (op)=>{
|
|
2075
|
+
if (op.field.includes('.')) {
|
|
2076
|
+
const leafField = op.field.split('.').at(-1) ?? 'unset';
|
|
2077
|
+
return buildNestedGQLFilter(op.field, {
|
|
2078
|
+
not: {
|
|
2079
|
+
[leafField]: op?.operand ?? null
|
|
2095
2080
|
}
|
|
2081
|
+
});
|
|
2082
|
+
}
|
|
2083
|
+
return {
|
|
2084
|
+
not: {
|
|
2085
|
+
[op.field]: op?.operand ?? null
|
|
2096
2086
|
}
|
|
2097
|
-
}
|
|
2098
|
-
}
|
|
2099
|
-
|
|
2100
|
-
const
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
counts: {
|
|
2106
|
-
...cohort.counts,
|
|
2107
|
-
...{
|
|
2108
|
-
[index]: counts
|
|
2109
|
-
}
|
|
2110
|
-
}
|
|
2087
|
+
};
|
|
2088
|
+
};
|
|
2089
|
+
this.handleNestedFilter = (op)=>{
|
|
2090
|
+
const child = convertFilterToGqlFilter(op.operand);
|
|
2091
|
+
return {
|
|
2092
|
+
nested: {
|
|
2093
|
+
path: op.path,
|
|
2094
|
+
...child
|
|
2111
2095
|
}
|
|
2112
|
-
}
|
|
2113
|
-
}
|
|
2114
|
-
setCurrentCohortId: (state, action)=>{
|
|
2115
|
-
state.currentCohortId = action.payload;
|
|
2116
|
-
},
|
|
2117
|
-
/** @hidden */ setCohortList: (state, action)=>{
|
|
2118
|
-
if (!action.payload) {
|
|
2119
|
-
cohortsAdapter.removeMany(state, state.ids);
|
|
2120
|
-
} else {
|
|
2121
|
-
cohortsAdapter.upsertMany(state, [
|
|
2122
|
-
...action.payload
|
|
2123
|
-
]);
|
|
2124
|
-
}
|
|
2125
|
-
}
|
|
2096
|
+
};
|
|
2097
|
+
};
|
|
2126
2098
|
}
|
|
2127
|
-
}
|
|
2099
|
+
}
|
|
2100
|
+
const convertFilterToNestedGqlFilter = (filter)=>{
|
|
2101
|
+
const handler = new ToGqlAllNested();
|
|
2102
|
+
return handleOperation(handler, filter);
|
|
2103
|
+
};
|
|
2104
|
+
const convertFilterSetToNestedGqlFilter = (fs, toplevelOp = 'and')=>{
|
|
2105
|
+
const fsKeys = Object.keys(fs.root);
|
|
2106
|
+
// if no keys return undefined
|
|
2107
|
+
if (fsKeys.length === 0) return {
|
|
2108
|
+
and: []
|
|
2109
|
+
};
|
|
2110
|
+
return toplevelOp === 'and' ? {
|
|
2111
|
+
and: fsKeys.map((key)=>convertFilterToNestedGqlFilter(fs.root[key]))
|
|
2112
|
+
} : {
|
|
2113
|
+
or: fsKeys.map((key)=>convertFilterToNestedGqlFilter(fs.root[key]))
|
|
2114
|
+
};
|
|
2115
|
+
};
|
|
2116
|
+
|
|
2117
|
+
const defaultCohortNameGenerator = ()=>`Custom cohort ${new Date().toLocaleString('en-CA', {
|
|
2118
|
+
timeZone: 'America/Chicago',
|
|
2119
|
+
hour12: false
|
|
2120
|
+
}).replace(',', '')}`;
|
|
2121
|
+
const isNameUnique = (entities, name, excludeId)=>{
|
|
2122
|
+
const trimmedName = name.trim();
|
|
2123
|
+
if (!trimmedName) return false;
|
|
2124
|
+
return !entities.some((cohort)=>cohort && cohort.id !== excludeId && cohort.name.trim().toLowerCase() === trimmedName.toLowerCase());
|
|
2125
|
+
};
|
|
2126
|
+
const generateUniqueName = (entities, baseName)=>{
|
|
2127
|
+
const trimmedBaseName = baseName.trim();
|
|
2128
|
+
// If base name is unique, use it
|
|
2129
|
+
if (isNameUnique(entities, trimmedBaseName)) {
|
|
2130
|
+
return trimmedBaseName;
|
|
2131
|
+
}
|
|
2132
|
+
// Find a unique name by appending numbers
|
|
2133
|
+
let counter = 1;
|
|
2134
|
+
let uniqueName;
|
|
2135
|
+
do {
|
|
2136
|
+
uniqueName = `${trimmedBaseName} (${counter})`;
|
|
2137
|
+
counter++;
|
|
2138
|
+
}while (!isNameUnique(entities, uniqueName))
|
|
2139
|
+
return uniqueName;
|
|
2140
|
+
};
|
|
2128
2141
|
/**
|
|
2129
|
-
*
|
|
2130
|
-
*
|
|
2142
|
+
* This function takes a FilterSet object and a prefix string as input.
|
|
2143
|
+
* It filters the root property of the FilterSet object and returns a
|
|
2144
|
+
* new FilterSet object that only contains filters with field names
|
|
2145
|
+
* that start with the specified prefix.
|
|
2131
2146
|
*
|
|
2132
|
-
*
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
const
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
reducers: {
|
|
2143
|
-
toggleCohortBuilderCategoryFilter: (state, action)=>{
|
|
2144
|
-
return {
|
|
2145
|
-
...state,
|
|
2146
|
-
[action.payload.index]: {
|
|
2147
|
-
...state[action.payload.index],
|
|
2148
|
-
[action.payload.field]: action.payload.expanded
|
|
2149
|
-
}
|
|
2150
|
-
};
|
|
2151
|
-
},
|
|
2152
|
-
toggleCohortBuilderAllFilters: (state, action)=>{
|
|
2153
|
-
return {
|
|
2154
|
-
...state,
|
|
2155
|
-
[action.payload.index]: Object.keys(state[action.payload.index]).reduce((acc, k)=>{
|
|
2156
|
-
acc[k] = action.payload.expand;
|
|
2157
|
-
return acc;
|
|
2158
|
-
}, {})
|
|
2159
|
-
};
|
|
2160
|
-
}
|
|
2147
|
+
* @param fs - The FilterSet object to filter
|
|
2148
|
+
* @param prefix - The prefix to filter by
|
|
2149
|
+
* @returns - A new FilterSet object that only contains filters with field names that start with the specified prefix
|
|
2150
|
+
* @category Filters
|
|
2151
|
+
*/ const extractFiltersWithPrefixFromFilterSet = (fs, prefix)=>{
|
|
2152
|
+
if (fs === undefined || fs.root === undefined) {
|
|
2153
|
+
return {
|
|
2154
|
+
mode: 'and',
|
|
2155
|
+
root: {}
|
|
2156
|
+
};
|
|
2161
2157
|
}
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
const selectAllCohortFiltersCollapsed = (state, index)=>index in state.cohorts.filtersExpanded ? Object.values(state.cohorts.filtersExpanded?.[index]).every((e)=>!e) : false;
|
|
2167
|
-
|
|
2168
|
-
const initialState$1 = {};
|
|
2169
|
-
const expandSlice = createSlice({
|
|
2170
|
-
name: 'CohortBuilder/filterCombineMode',
|
|
2171
|
-
initialState: initialState$1,
|
|
2172
|
-
reducers: {
|
|
2173
|
-
setCohortFilterCombineMode: (state, action)=>{
|
|
2174
|
-
return {
|
|
2175
|
-
...state,
|
|
2176
|
-
[action.payload.index]: {
|
|
2177
|
-
...state[action.payload.index],
|
|
2178
|
-
[action.payload.field]: action.payload.mode
|
|
2179
|
-
}
|
|
2180
|
-
};
|
|
2158
|
+
return Object.values(fs.root).reduce((acc, filter)=>{
|
|
2159
|
+
if (isIntersectionOrUnion(filter) || isNestedFilter(filter)) return acc;
|
|
2160
|
+
if (filter.field.startsWith(prefix)) {
|
|
2161
|
+
acc.root[filter.field] = filter;
|
|
2181
2162
|
}
|
|
2182
|
-
|
|
2183
|
-
}
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2163
|
+
return acc;
|
|
2164
|
+
}, {
|
|
2165
|
+
mode: 'and',
|
|
2166
|
+
root: {}
|
|
2167
|
+
});
|
|
2168
|
+
};
|
|
2187
2169
|
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2170
|
+
/**
|
|
2171
|
+
* Cohorts in Gen3 are defined as a set of filters for each index in the data.
|
|
2172
|
+
* This means one cohort id defined for all "tabs" in CohortBuilder (explorer)
|
|
2173
|
+
* Switching a cohort id means all the cohorts for the index are changed.
|
|
2174
|
+
*/ const DEFAULT_COHORT_NAME = 'Cohort';
|
|
2175
|
+
const newCohort = ({ filters = {}, customName })=>{
|
|
2176
|
+
const ts = new Date().toISOString();
|
|
2177
|
+
const newName = customName ?? defaultCohortNameGenerator();
|
|
2178
|
+
const newId = createCohortId();
|
|
2179
|
+
return {
|
|
2180
|
+
name: newName,
|
|
2181
|
+
id: newId,
|
|
2182
|
+
filters: filters ?? {},
|
|
2183
|
+
modified: false,
|
|
2184
|
+
saved: false,
|
|
2185
|
+
createdDatetime: ts,
|
|
2186
|
+
modifiedDatetime: ts,
|
|
2187
|
+
counts: {}
|
|
2188
|
+
};
|
|
2191
2189
|
};
|
|
2192
|
-
const
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
setSharedFilters: (state, action)=>{
|
|
2201
|
-
state.sharedFiltersMap = action.payload;
|
|
2202
|
-
}
|
|
2203
|
-
}
|
|
2190
|
+
const nanoid = customAlphabet('1234567890abcdef', 16);
|
|
2191
|
+
const createCohortId = ()=>nanoid();
|
|
2192
|
+
const cohortsAdapter = createEntityAdapter({
|
|
2193
|
+
sortComparer: (a, b)=>{
|
|
2194
|
+
if (a.modifiedDatetime <= b.modifiedDatetime) return 1;
|
|
2195
|
+
else return -1;
|
|
2196
|
+
},
|
|
2197
|
+
selectId: (cohort)=>cohort.id
|
|
2204
2198
|
});
|
|
2205
|
-
|
|
2206
|
-
const
|
|
2207
|
-
|
|
2208
|
-
field
|
|
2209
|
-
];
|
|
2210
|
-
const { setShouldShareFilters, setSharedFilters } = cohortSharedFiltersSlice.actions;
|
|
2211
|
-
const cohortSharedFiltersReducer = cohortSharedFiltersSlice.reducer;
|
|
2212
|
-
|
|
2213
|
-
const cohortReducers = combineReducers({
|
|
2214
|
-
filtersExpanded: cohortBuilderFiltersExpandedReducer,
|
|
2215
|
-
filtersCombineMode: cohortBuilderFiltersCombineModeReducer,
|
|
2216
|
-
sharedFilters: cohortSharedFiltersReducer,
|
|
2217
|
-
cohortManager: cohortReducer
|
|
2199
|
+
// Create an initial unsaved cohort
|
|
2200
|
+
const initialCohort = newCohort({
|
|
2201
|
+
customName: DEFAULT_COHORT_NAME
|
|
2218
2202
|
});
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
user: userReducer,
|
|
2223
|
-
gen3Apps: gen3AppReducer,
|
|
2224
|
-
drsHostnames: drsHostnamesReducer,
|
|
2225
|
-
modals: modalReducer,
|
|
2226
|
-
cohorts: cohortReducers,
|
|
2227
|
-
activeWorkspace: activeWorkspaceReducer,
|
|
2228
|
-
[guppyApiSliceReducerPath]: guppyApiReducer,
|
|
2229
|
-
[userAuthApiReducerPath]: userAuthApiReducer,
|
|
2230
|
-
[cartReducerPath]: cartReducer
|
|
2203
|
+
const emptyInitialState = cohortsAdapter.getInitialState({
|
|
2204
|
+
currentCohortId: initialCohort.id,
|
|
2205
|
+
message: undefined
|
|
2231
2206
|
});
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
* the first level to avoid potentially flattening
|
|
2236
|
-
* non-nested data.
|
|
2237
|
-
* @param {JSON} json
|
|
2238
|
-
*/ function flattenJson(json) {
|
|
2239
|
-
const flattenedJson = [];
|
|
2240
|
-
Object.keys(json).forEach((key)=>{
|
|
2241
|
-
flattenedJson.push(flatten(json[key], {
|
|
2242
|
-
delimiter: '_'
|
|
2243
|
-
}));
|
|
2244
|
-
});
|
|
2245
|
-
return flattenedJson;
|
|
2246
|
-
}
|
|
2247
|
-
/**
|
|
2248
|
-
* Converts JSON based on a config.
|
|
2249
|
-
* @param {JSON} json
|
|
2250
|
-
* @param {Object} config
|
|
2251
|
-
*/ async function conversion(json, config) {
|
|
2252
|
-
return Papa.unparse(json, config);
|
|
2253
|
-
}
|
|
2207
|
+
// Set the initial cohort in the adapter state
|
|
2208
|
+
const initialState$3 = cohortsAdapter.setOne(emptyInitialState, initialCohort);
|
|
2209
|
+
const getCurrentCohortId = (state)=>state.currentCohortId;
|
|
2254
2210
|
/**
|
|
2255
|
-
*
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
};
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
}
|
|
2283
|
-
|
|
2284
|
-
const
|
|
2285
|
-
|
|
2211
|
+
* Redux slice for cohort filters
|
|
2212
|
+
*/ const cohortManagerSlice = createSlice({
|
|
2213
|
+
name: 'cohort',
|
|
2214
|
+
initialState: initialState$3,
|
|
2215
|
+
reducers: {
|
|
2216
|
+
createNewCohort: (state, action)=>{
|
|
2217
|
+
const baseName = action.payload.name || `Cohort`;
|
|
2218
|
+
const uniqueName = generateUniqueName(Object.values(state.entities), baseName);
|
|
2219
|
+
const cohort = newCohort({
|
|
2220
|
+
filters: action.payload.filters,
|
|
2221
|
+
customName: uniqueName
|
|
2222
|
+
});
|
|
2223
|
+
cohortsAdapter.addOne(state, cohort);
|
|
2224
|
+
if (action.payload?.setAsCurrent) {
|
|
2225
|
+
state.currentCohortId = cohort.id;
|
|
2226
|
+
}
|
|
2227
|
+
},
|
|
2228
|
+
updateCohortName: (state, action)=>{
|
|
2229
|
+
const { id, name } = action.payload;
|
|
2230
|
+
cohortsAdapter.updateOne(state, {
|
|
2231
|
+
id: id,
|
|
2232
|
+
changes: {
|
|
2233
|
+
name: name,
|
|
2234
|
+
modified: true,
|
|
2235
|
+
modifiedDatetime: new Date().toISOString()
|
|
2236
|
+
}
|
|
2237
|
+
});
|
|
2238
|
+
},
|
|
2239
|
+
removeCohort: (state, action)=>{
|
|
2240
|
+
const { id: cohortId } = action.payload;
|
|
2241
|
+
const removedCohortName = state.entities[cohortId].name;
|
|
2242
|
+
const totalCohorts = Object.keys(state.entities).length;
|
|
2243
|
+
if (totalCohorts <= 1) {
|
|
2244
|
+
cohortsAdapter.removeAll(state);
|
|
2245
|
+
const defaultCohort = newCohort({
|
|
2246
|
+
filters: {},
|
|
2247
|
+
customName: DEFAULT_COHORT_NAME
|
|
2248
|
+
});
|
|
2249
|
+
cohortsAdapter.addOne(state, defaultCohort);
|
|
2250
|
+
state.currentCohortId = defaultCohort.id;
|
|
2251
|
+
if (action?.payload.shouldShowMessage) {
|
|
2252
|
+
state.message = [
|
|
2253
|
+
`deleteCohort|${removedCohortName}|${state.currentCohortId}`
|
|
2254
|
+
];
|
|
2255
|
+
}
|
|
2256
|
+
return;
|
|
2257
|
+
}
|
|
2258
|
+
cohortsAdapter.removeOne(state, cohortId);
|
|
2259
|
+
// deleted the current cohort so set to the most recent cohort
|
|
2260
|
+
if (state.currentCohortId === cohortId) {
|
|
2261
|
+
const remainingIds = Object.keys(state.entities);
|
|
2262
|
+
state.currentCohortId = remainingIds[0];
|
|
2263
|
+
}
|
|
2264
|
+
if (action?.payload.shouldShowMessage) {
|
|
2265
|
+
state.message = [
|
|
2266
|
+
`deleteCohort|${removedCohortName}|${state.currentCohortId}`
|
|
2267
|
+
];
|
|
2268
|
+
}
|
|
2269
|
+
},
|
|
2270
|
+
// adds a filter to the cohort filter set at the given index
|
|
2271
|
+
updateCohortFilter: (state, action)=>{
|
|
2272
|
+
const { index, field, filter } = action.payload;
|
|
2273
|
+
const currentCohortId = getCurrentCohortId(state);
|
|
2274
|
+
if (!state.entities[currentCohortId]) {
|
|
2275
|
+
return;
|
|
2276
|
+
}
|
|
2277
|
+
cohortsAdapter.updateOne(state, {
|
|
2278
|
+
id: currentCohortId,
|
|
2279
|
+
changes: {
|
|
2280
|
+
filters: {
|
|
2281
|
+
...state.entities[currentCohortId].filters,
|
|
2282
|
+
[index]: {
|
|
2283
|
+
mode: state.entities[currentCohortId]?.filters[index]?.mode ?? 'and',
|
|
2284
|
+
root: {
|
|
2285
|
+
...state.entities[currentCohortId]?.filters[index]?.root ?? {},
|
|
2286
|
+
[field]: filter
|
|
2287
|
+
}
|
|
2288
|
+
}
|
|
2289
|
+
},
|
|
2290
|
+
modified: true,
|
|
2291
|
+
modifiedDatetime: new Date().toISOString()
|
|
2292
|
+
}
|
|
2293
|
+
});
|
|
2294
|
+
},
|
|
2295
|
+
setCohortFilter: (state, action)=>{
|
|
2296
|
+
const { index, filters } = action.payload;
|
|
2297
|
+
const currentCohortId = getCurrentCohortId(state);
|
|
2298
|
+
if (!state.entities[currentCohortId]) {
|
|
2299
|
+
console.error(`no cohort with id=${currentCohortId} defined`);
|
|
2300
|
+
return;
|
|
2301
|
+
}
|
|
2302
|
+
cohortsAdapter.updateOne(state, {
|
|
2303
|
+
id: currentCohortId,
|
|
2304
|
+
changes: {
|
|
2305
|
+
filters: {
|
|
2306
|
+
...state.entities[currentCohortId].filters,
|
|
2307
|
+
[index]: filters
|
|
2308
|
+
},
|
|
2309
|
+
modified: true,
|
|
2310
|
+
modifiedDatetime: new Date().toISOString()
|
|
2311
|
+
}
|
|
2312
|
+
});
|
|
2313
|
+
},
|
|
2314
|
+
setCohortIndexFilters: (state, action)=>{
|
|
2315
|
+
const currentCohortId = getCurrentCohortId(state);
|
|
2316
|
+
if (!state.entities[currentCohortId]) {
|
|
2317
|
+
console.error(`no cohort with id=${currentCohortId} defined`);
|
|
2318
|
+
return;
|
|
2319
|
+
}
|
|
2320
|
+
cohortsAdapter.updateOne(state, {
|
|
2321
|
+
id: currentCohortId,
|
|
2322
|
+
changes: {
|
|
2323
|
+
filters: action.payload.filters,
|
|
2324
|
+
modified: true,
|
|
2325
|
+
modifiedDatetime: new Date().toISOString()
|
|
2326
|
+
}
|
|
2327
|
+
});
|
|
2328
|
+
},
|
|
2329
|
+
// removes a filter to the cohort filter set at the given index
|
|
2330
|
+
removeCohortFilter: (state, action)=>{
|
|
2331
|
+
const { index, field } = action.payload;
|
|
2332
|
+
const currentCohortId = getCurrentCohortId(state);
|
|
2333
|
+
if (!state.entities[currentCohortId]) {
|
|
2334
|
+
console.error(`no cohort with id=${currentCohortId} defined`);
|
|
2335
|
+
return;
|
|
2336
|
+
}
|
|
2337
|
+
const filters = state.entities[currentCohortId]?.filters[index]?.root;
|
|
2338
|
+
if (!filters) {
|
|
2339
|
+
return;
|
|
2340
|
+
}
|
|
2341
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
2342
|
+
const { [field]: _a, ...updated } = filters;
|
|
2343
|
+
cohortsAdapter.updateOne(state, {
|
|
2344
|
+
id: currentCohortId,
|
|
2345
|
+
changes: {
|
|
2346
|
+
filters: {
|
|
2347
|
+
...state.entities[currentCohortId]?.filters,
|
|
2348
|
+
[index]: {
|
|
2349
|
+
mode: state.entities[currentCohortId].filters[index].mode,
|
|
2350
|
+
root: updated
|
|
2351
|
+
}
|
|
2352
|
+
},
|
|
2353
|
+
modified: true,
|
|
2354
|
+
modifiedDatetime: new Date().toISOString()
|
|
2355
|
+
}
|
|
2356
|
+
});
|
|
2357
|
+
},
|
|
2358
|
+
duplicateCohort: (state)=>{
|
|
2359
|
+
const currentCohortId = getCurrentCohortId(state);
|
|
2360
|
+
const currentCohort = state.entities[currentCohortId];
|
|
2361
|
+
const newName = generateUniqueName(Object.values(state.entities), currentCohort.name);
|
|
2362
|
+
const duplicatedCohort = newCohort({
|
|
2363
|
+
filters: {
|
|
2364
|
+
...currentCohort.filters
|
|
2365
|
+
},
|
|
2366
|
+
customName: newName
|
|
2367
|
+
});
|
|
2368
|
+
cohortsAdapter.addOne(state, {
|
|
2369
|
+
...duplicatedCohort,
|
|
2370
|
+
counts: {
|
|
2371
|
+
...currentCohort.counts
|
|
2372
|
+
}
|
|
2373
|
+
});
|
|
2374
|
+
state.currentCohortId = duplicatedCohort.id;
|
|
2375
|
+
},
|
|
2376
|
+
// removes all filters from the cohort filter set at the given index
|
|
2377
|
+
clearCohortFilters: (state, action)=>{
|
|
2378
|
+
const { index } = action.payload;
|
|
2379
|
+
const currentCohortId = getCurrentCohortId(state);
|
|
2380
|
+
if (!state.entities[currentCohortId]) {
|
|
2381
|
+
console.error(`no cohort with id=${currentCohortId} defined`);
|
|
2382
|
+
return;
|
|
2383
|
+
}
|
|
2384
|
+
const filters = state.entities[currentCohortId]?.filters[index]?.root;
|
|
2385
|
+
if (!filters) {
|
|
2386
|
+
return;
|
|
2387
|
+
}
|
|
2388
|
+
cohortsAdapter.updateOne(state, {
|
|
2389
|
+
id: currentCohortId,
|
|
2390
|
+
changes: {
|
|
2391
|
+
filters: {
|
|
2392
|
+
...state.entities[currentCohortId]?.filters,
|
|
2393
|
+
[index]: {
|
|
2394
|
+
mode: 'and',
|
|
2395
|
+
root: {}
|
|
2396
|
+
}
|
|
2397
|
+
},
|
|
2398
|
+
modified: true,
|
|
2399
|
+
modifiedDatetime: new Date().toISOString()
|
|
2400
|
+
}
|
|
2401
|
+
});
|
|
2402
|
+
},
|
|
2403
|
+
updateCohortCounts: (state, action)=>{
|
|
2404
|
+
const currentCohortId = getCurrentCohortId(state);
|
|
2405
|
+
const currentCohort = state.entities[currentCohortId];
|
|
2406
|
+
cohortsAdapter.updateOne(state, {
|
|
2407
|
+
id: currentCohortId,
|
|
2408
|
+
changes: {
|
|
2409
|
+
counts: {
|
|
2410
|
+
...currentCohort.counts,
|
|
2411
|
+
...action.payload
|
|
2412
|
+
}
|
|
2413
|
+
}
|
|
2414
|
+
});
|
|
2415
|
+
},
|
|
2416
|
+
updateCohortIndexCountById: (state, action)=>{
|
|
2417
|
+
const { index, cohortId, counts } = action.payload;
|
|
2418
|
+
const cohort = state.entities[cohortId];
|
|
2419
|
+
cohortsAdapter.updateOne(state, {
|
|
2420
|
+
id: cohortId,
|
|
2421
|
+
changes: {
|
|
2422
|
+
counts: {
|
|
2423
|
+
...cohort.counts,
|
|
2424
|
+
...{
|
|
2425
|
+
[index]: counts
|
|
2426
|
+
}
|
|
2427
|
+
}
|
|
2428
|
+
}
|
|
2429
|
+
});
|
|
2430
|
+
},
|
|
2431
|
+
setCurrentCohortId: (state, action)=>{
|
|
2432
|
+
state.currentCohortId = action.payload;
|
|
2433
|
+
},
|
|
2434
|
+
/** @hidden */ setCohortList: (state, action)=>{
|
|
2435
|
+
if (!action.payload) {
|
|
2436
|
+
cohortsAdapter.removeMany(state, state.ids);
|
|
2437
|
+
} else {
|
|
2438
|
+
cohortsAdapter.upsertMany(state, [
|
|
2439
|
+
...action.payload
|
|
2440
|
+
]);
|
|
2441
|
+
}
|
|
2442
|
+
}
|
|
2443
|
+
}
|
|
2444
|
+
});
|
|
2445
|
+
/**
|
|
2446
|
+
* Returns the selectors for the cohorts EntityAdapter
|
|
2447
|
+
* @param state - the CoreState
|
|
2448
|
+
*
|
|
2449
|
+
* @hidden
|
|
2450
|
+
*/ const cohortSelectors = cohortsAdapter.getSelectors((state)=>state.cohorts.cohortManager);
|
|
2451
|
+
// Filter actions: addFilter, removeFilter, updateFilter
|
|
2452
|
+
const { createNewCohort, updateCohortFilter, setCohortFilter, setCohortIndexFilters, duplicateCohort, removeCohortFilter, clearCohortFilters, removeCohort, setCurrentCohortId, updateCohortName, updateCohortCounts, updateCohortIndexCountById, setCohortList } = cohortManagerSlice.actions;
|
|
2453
|
+
const cohortReducer = cohortManagerSlice.reducer;
|
|
2454
|
+
|
|
2455
|
+
const initialState$2 = {};
|
|
2456
|
+
const expandSlice$1 = createSlice({
|
|
2457
|
+
name: 'CohortBuilder/filterExpand',
|
|
2458
|
+
initialState: initialState$2,
|
|
2459
|
+
reducers: {
|
|
2460
|
+
toggleCohortBuilderCategoryFilter: (state, action)=>{
|
|
2461
|
+
return {
|
|
2462
|
+
...state,
|
|
2463
|
+
[action.payload.index]: {
|
|
2464
|
+
...state[action.payload.index],
|
|
2465
|
+
[action.payload.field]: action.payload.expanded
|
|
2466
|
+
}
|
|
2467
|
+
};
|
|
2468
|
+
},
|
|
2469
|
+
toggleCohortBuilderAllFilters: (state, action)=>{
|
|
2470
|
+
return {
|
|
2471
|
+
...state,
|
|
2472
|
+
[action.payload.index]: Object.keys(state[action.payload.index]).reduce((acc, k)=>{
|
|
2473
|
+
acc[k] = action.payload.expand;
|
|
2474
|
+
return acc;
|
|
2475
|
+
}, {})
|
|
2476
|
+
};
|
|
2477
|
+
}
|
|
2478
|
+
}
|
|
2479
|
+
});
|
|
2480
|
+
const cohortBuilderFiltersExpandedReducer = expandSlice$1.reducer;
|
|
2481
|
+
const { toggleCohortBuilderCategoryFilter, toggleCohortBuilderAllFilters } = expandSlice$1.actions;
|
|
2482
|
+
const selectCohortFilterExpanded = (state, index, field)=>state.cohorts.filtersExpanded?.[index]?.[field];
|
|
2483
|
+
const selectAllCohortFiltersCollapsed = (state, index)=>index in state.cohorts.filtersExpanded ? Object.values(state.cohorts.filtersExpanded?.[index]).every((e)=>!e) : false;
|
|
2484
|
+
|
|
2485
|
+
const initialState$1 = {};
|
|
2486
|
+
const expandSlice = createSlice({
|
|
2487
|
+
name: 'CohortBuilder/filterCombineMode',
|
|
2488
|
+
initialState: initialState$1,
|
|
2489
|
+
reducers: {
|
|
2490
|
+
setCohortFilterCombineMode: (state, action)=>{
|
|
2491
|
+
return {
|
|
2492
|
+
...state,
|
|
2493
|
+
[action.payload.index]: {
|
|
2494
|
+
...state[action.payload.index],
|
|
2495
|
+
[action.payload.field]: action.payload.mode
|
|
2496
|
+
}
|
|
2497
|
+
};
|
|
2498
|
+
}
|
|
2499
|
+
}
|
|
2500
|
+
});
|
|
2501
|
+
const cohortBuilderFiltersCombineModeReducer = expandSlice.reducer;
|
|
2502
|
+
const { setCohortFilterCombineMode } = expandSlice.actions;
|
|
2503
|
+
const selectCohortFilterCombineMode = (state, index, field)=>state.cohorts.filtersCombineMode?.[index]?.[field] ?? 'or';
|
|
2504
|
+
|
|
2505
|
+
const initialState = {
|
|
2506
|
+
shouldShareFilters: false,
|
|
2507
|
+
sharedFiltersMap: {}
|
|
2508
|
+
};
|
|
2509
|
+
const cohortSharedFiltersSlice = createSlice({
|
|
2510
|
+
name: 'cohortSharedFilters',
|
|
2511
|
+
initialState: initialState,
|
|
2512
|
+
reducers: {
|
|
2513
|
+
setShouldShareFilters: (state, action)=>{
|
|
2514
|
+
state.shouldShareFilters = action.payload;
|
|
2515
|
+
return state;
|
|
2516
|
+
},
|
|
2517
|
+
setSharedFilters: (state, action)=>{
|
|
2518
|
+
state.sharedFiltersMap = action.payload;
|
|
2519
|
+
}
|
|
2520
|
+
}
|
|
2521
|
+
});
|
|
2522
|
+
const selectShouldShareFilters = (state)=>state.cohorts.sharedFilters.shouldShareFilters;
|
|
2523
|
+
const selectSharedFilters = (state)=>state.cohorts.sharedFilters.sharedFiltersMap;
|
|
2524
|
+
const selectSharedFiltersForFields = (state, field)=>state.cohorts.sharedFilters.sharedFiltersMap?.[field] ?? [
|
|
2525
|
+
field
|
|
2526
|
+
];
|
|
2527
|
+
const { setShouldShareFilters, setSharedFilters } = cohortSharedFiltersSlice.actions;
|
|
2528
|
+
const cohortSharedFiltersReducer = cohortSharedFiltersSlice.reducer;
|
|
2529
|
+
|
|
2530
|
+
const cohortReducers = combineReducers({
|
|
2531
|
+
filtersExpanded: cohortBuilderFiltersExpandedReducer,
|
|
2532
|
+
filtersCombineMode: cohortBuilderFiltersCombineModeReducer,
|
|
2533
|
+
sharedFilters: cohortSharedFiltersReducer,
|
|
2534
|
+
cohortManager: cohortReducer
|
|
2535
|
+
});
|
|
2536
|
+
|
|
2537
|
+
const rootReducer = combineReducers({
|
|
2538
|
+
gen3Services: gen3ServicesReducer,
|
|
2539
|
+
user: userReducer,
|
|
2540
|
+
gen3Apps: gen3AppReducer,
|
|
2541
|
+
drsHostnames: drsHostnamesReducer,
|
|
2542
|
+
modals: modalReducer,
|
|
2543
|
+
cohorts: cohortReducers,
|
|
2544
|
+
activeWorkspace: activeWorkspaceReducer,
|
|
2545
|
+
[guppyApiSliceReducerPath]: guppyApiReducer,
|
|
2546
|
+
[userAuthApiReducerPath]: userAuthApiReducer,
|
|
2547
|
+
[cartReducerPath]: cartReducer
|
|
2548
|
+
});
|
|
2549
|
+
|
|
2550
|
+
/**
|
|
2551
|
+
* Flattens a deep nested JSON object skipping
|
|
2552
|
+
* the first level to avoid potentially flattening
|
|
2553
|
+
* non-nested data.
|
|
2554
|
+
* @param {JSON} json
|
|
2555
|
+
*/ function flattenJson(json) {
|
|
2556
|
+
const flattenedJson = [];
|
|
2557
|
+
Object.keys(json).forEach((key)=>{
|
|
2558
|
+
flattenedJson.push(flatten(json[key], {
|
|
2559
|
+
delimiter: '_'
|
|
2560
|
+
}));
|
|
2561
|
+
});
|
|
2562
|
+
return flattenedJson;
|
|
2563
|
+
}
|
|
2564
|
+
/**
|
|
2565
|
+
* Converts JSON based on a config.
|
|
2566
|
+
* @param {JSON} json
|
|
2567
|
+
* @param {Object} config
|
|
2568
|
+
*/ async function conversion(json, config) {
|
|
2569
|
+
return Papa.unparse(json, config);
|
|
2570
|
+
}
|
|
2571
|
+
/**
|
|
2572
|
+
* Converts JSON to a specified file format.
|
|
2573
|
+
* Defaults to JSON if file format is not supported.
|
|
2574
|
+
* @param {JSON} json
|
|
2575
|
+
* @param {string} format
|
|
2576
|
+
*/ async function jsonToFormat(json, format) {
|
|
2577
|
+
if (Object.keys(FILE_DELIMITERS).includes(format)) {
|
|
2578
|
+
const flatJson = flattenJson(json);
|
|
2579
|
+
const data = await conversion(flatJson, {
|
|
2580
|
+
delimiter: FILE_DELIMITERS[format]
|
|
2581
|
+
});
|
|
2582
|
+
return data;
|
|
2583
|
+
}
|
|
2584
|
+
return json;
|
|
2585
|
+
}
|
|
2586
|
+
|
|
2587
|
+
// type guard functions
|
|
2588
|
+
const isHistogramRangeData = (key)=>{
|
|
2589
|
+
return Array.isArray(key) && key.length === 2 && key.every((item)=>typeof item === 'number');
|
|
2590
|
+
};
|
|
2591
|
+
const isJSONObject = (data)=>{
|
|
2592
|
+
return typeof data === 'object' && data !== null && !Array.isArray(data);
|
|
2593
|
+
};
|
|
2594
|
+
const isJSONValue = (data)=>{
|
|
2595
|
+
return typeof data === 'string' || typeof data === 'number' || typeof data === 'boolean' || Array.isArray(data) && data.every(isJSONValue) || isJSONObject(data);
|
|
2596
|
+
};
|
|
2597
|
+
const isJSONValueArray = (data)=>{
|
|
2598
|
+
return Array.isArray(data) && data.every(isJSONValue);
|
|
2599
|
+
};
|
|
2600
|
+
const isValidObject = (input)=>typeof input === 'object' && input !== null;
|
|
2601
|
+
const isHistogramData = (data)=>{
|
|
2602
|
+
return isValidObject(data) && 'key' in data && 'count' in data;
|
|
2286
2603
|
};
|
|
2287
2604
|
const isHistogramDataArray = (input)=>{
|
|
2288
2605
|
if (!isValidObject(input) || !Array.isArray(input.histogram)) {
|
|
@@ -2321,10 +2638,8 @@ const isStatsValue = (item)=>{
|
|
|
2321
2638
|
'stddev',
|
|
2322
2639
|
'median'
|
|
2323
2640
|
];
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
return false;
|
|
2327
|
-
}
|
|
2641
|
+
if (!numericFields.some((field)=>field in obj && typeof obj[field] !== 'number')) {
|
|
2642
|
+
return false;
|
|
2328
2643
|
}
|
|
2329
2644
|
// Check percentiles structure if present
|
|
2330
2645
|
if ('percentiles' in obj) {
|
|
@@ -2332,17 +2647,6 @@ const isStatsValue = (item)=>{
|
|
|
2332
2647
|
if (typeof percentiles !== 'object' || percentiles === null) {
|
|
2333
2648
|
return false;
|
|
2334
2649
|
}
|
|
2335
|
-
const pObj = percentiles;
|
|
2336
|
-
const requiredPercentiles = [
|
|
2337
|
-
'p25',
|
|
2338
|
-
'p50',
|
|
2339
|
-
'p75'
|
|
2340
|
-
];
|
|
2341
|
-
for (const p of requiredPercentiles){
|
|
2342
|
-
if (p in pObj && typeof pObj[p] !== 'number') {
|
|
2343
|
-
return false;
|
|
2344
|
-
}
|
|
2345
|
-
}
|
|
2346
2650
|
}
|
|
2347
2651
|
return true;
|
|
2348
2652
|
};
|
|
@@ -2587,443 +2891,168 @@ const groupSharedFields = (data)=>{
|
|
|
2587
2891
|
x.count = x.count < minValue ? -1 : x.count;
|
|
2588
2892
|
});
|
|
2589
2893
|
});
|
|
2590
|
-
return data;
|
|
2591
|
-
};
|
|
2592
|
-
|
|
2593
|
-
const customQueryStrForField = (field, query, depth = 0)=>{
|
|
2594
|
-
const indent = ' '.repeat(depth);
|
|
2595
|
-
const splittedFieldArray = field.split('.');
|
|
2596
|
-
const splittedField = splittedFieldArray.shift();
|
|
2597
|
-
if (splittedFieldArray.length === 0) {
|
|
2598
|
-
return `${indent}${splittedField} ${query}`;
|
|
2599
|
-
}
|
|
2600
|
-
return `${indent}${splittedField} {
|
|
2601
|
-
${customQueryStrForField(splittedFieldArray.join('.'), query, depth + 1)}
|
|
2602
|
-
${indent}}`;
|
|
2603
|
-
};
|
|
2604
|
-
// TODO: refactor the function below using customQueryStrForEachField and a wrapper function that passes the query
|
|
2605
|
-
const histogramQueryStrForEachField = (field)=>{
|
|
2606
|
-
const splittedFieldArray = field.split('.');
|
|
2607
|
-
const splittedField = splittedFieldArray.shift();
|
|
2608
|
-
if (splittedFieldArray.length === 0) {
|
|
2609
|
-
return `
|
|
2610
|
-
${splittedField} {
|
|
2611
|
-
histogram {
|
|
2612
|
-
key
|
|
2613
|
-
count
|
|
2614
|
-
}
|
|
2615
|
-
}`;
|
|
2616
|
-
}
|
|
2617
|
-
return `
|
|
2618
|
-
${splittedField} {
|
|
2619
|
-
${histogramQueryStrForEachField(splittedFieldArray.join('.'))}
|
|
2620
|
-
}`;
|
|
2621
|
-
};
|
|
2622
|
-
const statsQueryStrForEachField = (field)=>{
|
|
2623
|
-
const splittedFieldArray = field.split('.');
|
|
2624
|
-
const splittedField = splittedFieldArray.shift();
|
|
2625
|
-
if (splittedFieldArray.length === 0) {
|
|
2626
|
-
return `
|
|
2627
|
-
${splittedField} {
|
|
2628
|
-
histogram {
|
|
2629
|
-
count
|
|
2630
|
-
min
|
|
2631
|
-
max
|
|
2632
|
-
avg
|
|
2633
|
-
sum
|
|
2634
|
-
}
|
|
2635
|
-
}`;
|
|
2636
|
-
}
|
|
2637
|
-
return `
|
|
2638
|
-
${splittedField} {
|
|
2639
|
-
${statsQueryStrForEachField(splittedFieldArray.join('.'))}
|
|
2640
|
-
}`;
|
|
2641
|
-
};
|
|
2642
|
-
const nestedHistogramQueryStrForEachField = (mainField, numericAggAsText)=>`
|
|
2643
|
-
${mainField} {
|
|
2644
|
-
${numericAggAsText ? 'asTextHistogram' : 'histogram'} {
|
|
2645
|
-
key
|
|
2646
|
-
count
|
|
2647
|
-
missingFields {
|
|
2648
|
-
field
|
|
2649
|
-
count
|
|
2650
|
-
}
|
|
2651
|
-
termsFields {
|
|
2652
|
-
field
|
|
2653
|
-
count
|
|
2654
|
-
terms {
|
|
2655
|
-
key
|
|
2656
|
-
count
|
|
2657
|
-
}
|
|
2658
|
-
}
|
|
2659
|
-
}
|
|
2660
|
-
}`;
|
|
2661
|
-
const rawDataQueryStrForEachField$1 = (field)=>{
|
|
2662
|
-
const splitFieldArray = field.split('.');
|
|
2663
|
-
const splitField = splitFieldArray.shift();
|
|
2664
|
-
if (splitFieldArray.length === 0) {
|
|
2665
|
-
return `
|
|
2666
|
-
${splitField}
|
|
2667
|
-
`;
|
|
2668
|
-
}
|
|
2669
|
-
return `
|
|
2670
|
-
${splitField} {
|
|
2671
|
-
${rawDataQueryStrForEachField$1(splitFieldArray.join('.'))}
|
|
2672
|
-
}`;
|
|
2673
|
-
};
|
|
2674
|
-
|
|
2675
|
-
const convertNumericFromToArrayToFilters = (field, range, isNested = true)=>{
|
|
2676
|
-
const { from, to } = range;
|
|
2677
|
-
return {
|
|
2678
|
-
operator: 'and',
|
|
2679
|
-
operands: [
|
|
2680
|
-
isNested ? buildNestedFilterForOperation(field, {
|
|
2681
|
-
operator: '>=',
|
|
2682
|
-
field,
|
|
2683
|
-
operand: from
|
|
2684
|
-
}) : {
|
|
2685
|
-
operator: '>=',
|
|
2686
|
-
field,
|
|
2687
|
-
operand: from
|
|
2688
|
-
},
|
|
2689
|
-
isNested ? buildNestedFilterForOperation(field, {
|
|
2690
|
-
operator: '<',
|
|
2691
|
-
field,
|
|
2692
|
-
operand: to
|
|
2693
|
-
}) : {
|
|
2694
|
-
operator: '<',
|
|
2695
|
-
field,
|
|
2696
|
-
operand: to
|
|
2697
|
-
}
|
|
2698
|
-
]
|
|
2699
|
-
};
|
|
2700
|
-
};
|
|
2701
|
-
const rawDataQueryStrForEachField = (field, asTextHistogram = false)=>{
|
|
2702
|
-
const splitFieldArray = field.split('.');
|
|
2703
|
-
const splitField = splitFieldArray.shift();
|
|
2704
|
-
let middleQuery = '';
|
|
2705
|
-
if (splitFieldArray.length === 0) {
|
|
2706
|
-
middleQuery = `${splitField} { ${asTextHistogram ? 'histogram: asTextHistogram' : 'histogram'} { count } }`;
|
|
2707
|
-
} else {
|
|
2708
|
-
middleQuery = `${splitField} { ${rawDataQueryStrForEachField(splitFieldArray.join('.'), asTextHistogram)} }`;
|
|
2709
|
-
}
|
|
2710
|
-
return middleQuery;
|
|
2711
|
-
};
|
|
2712
|
-
const buildAliasedNestedCountsQuery = ({ type, field, rangeName, asTextHistogram = false })=>{
|
|
2713
|
-
const dataParams = [
|
|
2714
|
-
`filter: $${rangeName}`
|
|
2715
|
-
];
|
|
2716
|
-
const dataTypeLine = `${rangeName} : ${type} (accessibility: $accessibility ${dataParams}) {`;
|
|
2717
|
-
const processedFields = rawDataQueryStrForEachField(field, asTextHistogram);
|
|
2718
|
-
return `${dataTypeLine} ${processedFields} }`;
|
|
2719
|
-
};
|
|
2720
|
-
const buildRangeFilters = (field, ranges, filters, rangeBaseName, isNested = true)=>{
|
|
2721
|
-
return Object.entries(ranges).reduce((acc, [, rangeValue], idx)=>{
|
|
2722
|
-
acc[`${rangeBaseName}_${idx}`] = {
|
|
2723
|
-
mode: filters.mode,
|
|
2724
|
-
root: {
|
|
2725
|
-
...filters.root,
|
|
2726
|
-
[field]: convertNumericFromToArrayToFilters(field, rangeValue, isNested)
|
|
2727
|
-
}
|
|
2728
|
-
};
|
|
2729
|
-
return acc;
|
|
2730
|
-
}, {});
|
|
2731
|
-
};
|
|
2732
|
-
const buildRangeQuery = (field, ranges, filters, rangeBaseName = 'range', index = 'cases', indexPrefix = '', isNested = true, asTextHistogram = false)=>{
|
|
2733
|
-
const rangeFilters = buildRangeFilters(field, ranges, filters, rangeBaseName, isNested);
|
|
2734
|
-
let query = `query rangeQuery ($accessibility: Accessibility, ${Object.keys(rangeFilters).map((rangeKey)=>`$${rangeKey}: JSON`).join(',')} ) { ${indexPrefix}_aggregation {`;
|
|
2735
|
-
Object.keys(rangeFilters).forEach((rangeKey)=>{
|
|
2736
|
-
const rangeQuery = buildAliasedNestedCountsQuery({
|
|
2737
|
-
type: index,
|
|
2738
|
-
field,
|
|
2739
|
-
rangeName: rangeKey,
|
|
2740
|
-
asTextHistogram
|
|
2741
|
-
});
|
|
2742
|
-
query += rangeQuery + ' \n';
|
|
2743
|
-
});
|
|
2744
|
-
query += `}}`;
|
|
2745
|
-
return {
|
|
2746
|
-
query: query,
|
|
2747
|
-
filters: rangeFilters
|
|
2748
|
-
};
|
|
2749
|
-
};
|
|
2750
|
-
|
|
2751
|
-
const { selectAll: selectAllCohorts, selectTotal: selectTotalCohorts, selectById: selectCohortById, selectIds: selectCohortIds } = cohortsAdapter.getSelectors((state)=>state.cohorts.cohortManager);
|
|
2752
|
-
/**
|
|
2753
|
-
* Internally used selector for the exported selectora
|
|
2754
|
-
* @param state
|
|
2755
|
-
*/ const getCurrentCohortFromCoreState = (state)=>{
|
|
2756
|
-
return state.cohorts.cohortManager.currentCohortId;
|
|
2757
|
-
};
|
|
2758
|
-
const selectCohortFilters = (state)=>{
|
|
2759
|
-
const currentCohortId = getCurrentCohortFromCoreState(state);
|
|
2760
|
-
return state.cohorts.cohortManager.entities[currentCohortId]?.filters;
|
|
2761
|
-
};
|
|
2762
|
-
const selectCurrentCohortFilters = (state)=>{
|
|
2763
|
-
const currentCohortId = getCurrentCohortFromCoreState(state);
|
|
2764
|
-
return state.cohorts.cohortManager.entities[currentCohortId]?.filters;
|
|
2765
|
-
};
|
|
2766
|
-
const selectCurrentCohortId = (state)=>{
|
|
2767
|
-
return state.cohorts.cohortManager.currentCohortId;
|
|
2768
|
-
};
|
|
2769
|
-
const selectCurrentCohort = (state)=>cohortSelectors.selectById(state, getCurrentCohortFromCoreState(state));
|
|
2770
|
-
const selectCurrentCohortName = (state)=>cohortSelectors.selectById(state, getCurrentCohortFromCoreState(state)).name;
|
|
2771
|
-
/**
|
|
2772
|
-
* Select a filter by its name from the current cohort. If the filter is not found
|
|
2773
|
-
* returns undefined.
|
|
2774
|
-
* @param state - Core
|
|
2775
|
-
* @param index which cohort index to select from
|
|
2776
|
-
* @param name name of the filter to select
|
|
2777
|
-
*/ const selectIndexedFilterByName = (state, index, name)=>{
|
|
2778
|
-
return cohortSelectors.selectById(state, getCurrentCohortFromCoreState(state)).filters[index]?.root[name];
|
|
2894
|
+
return data;
|
|
2779
2895
|
};
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
* @category Selectors
|
|
2792
|
-
* @hidden
|
|
2793
|
-
*/ const selectCurrentCohortModified = (state)=>{
|
|
2794
|
-
const cohort = cohortSelectors.selectById(state, getCurrentCohortFromCoreState(state));
|
|
2795
|
-
return cohort?.modified;
|
|
2896
|
+
|
|
2897
|
+
const customQueryStrForField = (field, query, depth = 0)=>{
|
|
2898
|
+
const indent = ' '.repeat(depth);
|
|
2899
|
+
const splittedFieldArray = field.split('.');
|
|
2900
|
+
const splittedField = splittedFieldArray.shift();
|
|
2901
|
+
if (splittedFieldArray.length === 0) {
|
|
2902
|
+
return `${indent}${splittedField} ${query}`;
|
|
2903
|
+
}
|
|
2904
|
+
return `${indent}${splittedField} {
|
|
2905
|
+
${customQueryStrForField(splittedFieldArray.join('.'), query, depth + 1)}
|
|
2906
|
+
${indent}}`;
|
|
2796
2907
|
};
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2908
|
+
// TODO: refactor the function below using customQueryStrForEachField and a wrapper function that passes the query
|
|
2909
|
+
const histogramQueryStrForEachField = (field)=>{
|
|
2910
|
+
const splittedFieldArray = field.split('.');
|
|
2911
|
+
const splittedField = splittedFieldArray.shift();
|
|
2912
|
+
if (splittedFieldArray.length === 0) {
|
|
2913
|
+
return `
|
|
2914
|
+
${splittedField} {
|
|
2915
|
+
histogram {
|
|
2916
|
+
key
|
|
2917
|
+
count
|
|
2918
|
+
}
|
|
2919
|
+
}`;
|
|
2920
|
+
}
|
|
2921
|
+
return `
|
|
2922
|
+
${splittedField} {
|
|
2923
|
+
${histogramQueryStrForEachField(splittedFieldArray.join('.'))}
|
|
2924
|
+
}`;
|
|
2806
2925
|
};
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
console.error('No Cohort Defined');
|
|
2926
|
+
const statsQueryStrForEachField = (field)=>{
|
|
2927
|
+
const splittedFieldArray = field.split('.');
|
|
2928
|
+
const splittedField = splittedFieldArray.shift();
|
|
2929
|
+
if (splittedFieldArray.length === 0) {
|
|
2930
|
+
return `
|
|
2931
|
+
${splittedField} {
|
|
2932
|
+
histogram {
|
|
2933
|
+
count
|
|
2934
|
+
min
|
|
2935
|
+
max
|
|
2936
|
+
avg
|
|
2937
|
+
sum
|
|
2938
|
+
}
|
|
2939
|
+
}`;
|
|
2822
2940
|
}
|
|
2823
|
-
return
|
|
2941
|
+
return `
|
|
2942
|
+
${splittedField} {
|
|
2943
|
+
${statsQueryStrForEachField(splittedFieldArray.join('.'))}
|
|
2944
|
+
}`;
|
|
2824
2945
|
};
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
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
|
-
return {
|
|
2883
|
-
'<=': {
|
|
2884
|
-
[op.field]: op.operand
|
|
2885
|
-
}
|
|
2886
|
-
};
|
|
2887
|
-
};
|
|
2888
|
-
this.handleGreaterThan = (op)=>{
|
|
2889
|
-
if (op.field.includes('.')) {
|
|
2890
|
-
const leafField = op.field.split('.').at(-1) ?? 'unset';
|
|
2891
|
-
return buildNestedGQLFilter(op.field, {
|
|
2892
|
-
'>': {
|
|
2893
|
-
[leafField]: op.operand
|
|
2894
|
-
}
|
|
2895
|
-
});
|
|
2896
|
-
}
|
|
2897
|
-
return {
|
|
2898
|
-
'>': {
|
|
2899
|
-
[op.field]: op.operand
|
|
2900
|
-
}
|
|
2901
|
-
};
|
|
2902
|
-
};
|
|
2903
|
-
this.handleGreaterThanOrEquals = (op)=>{
|
|
2904
|
-
if (op.field.includes('.')) {
|
|
2905
|
-
const leafField = op.field.split('.').at(-1) ?? 'unset';
|
|
2906
|
-
return buildNestedGQLFilter(op.field, {
|
|
2907
|
-
'>=': {
|
|
2908
|
-
[leafField]: op.operand
|
|
2909
|
-
}
|
|
2910
|
-
});
|
|
2911
|
-
}
|
|
2912
|
-
return {
|
|
2913
|
-
'>=': {
|
|
2914
|
-
[op.field]: op.operand
|
|
2915
|
-
}
|
|
2916
|
-
};
|
|
2917
|
-
};
|
|
2918
|
-
this.handleIncludes = (op)=>{
|
|
2919
|
-
if (op.field.includes('.')) {
|
|
2920
|
-
const leafField = op.field.split('.').at(-1) ?? 'unset';
|
|
2921
|
-
return buildNestedGQLFilter(op.field, {
|
|
2922
|
-
in: {
|
|
2923
|
-
[leafField]: op.operands
|
|
2924
|
-
}
|
|
2925
|
-
});
|
|
2926
|
-
}
|
|
2927
|
-
return {
|
|
2928
|
-
in: {
|
|
2929
|
-
[op.field]: op.operands
|
|
2930
|
-
}
|
|
2931
|
-
};
|
|
2932
|
-
};
|
|
2933
|
-
this.handleExcludes = (op)=>{
|
|
2934
|
-
if (op.field.includes('.')) {
|
|
2935
|
-
const leafField = op.field.split('.').at(-1) ?? 'unset';
|
|
2936
|
-
return buildNestedGQLFilter(op.field, {
|
|
2937
|
-
exclude: {
|
|
2938
|
-
[leafField]: op.operands
|
|
2939
|
-
}
|
|
2940
|
-
});
|
|
2941
|
-
}
|
|
2942
|
-
return {
|
|
2943
|
-
exclude: {
|
|
2944
|
-
[op.field]: op.operands
|
|
2945
|
-
}
|
|
2946
|
-
};
|
|
2947
|
-
};
|
|
2948
|
-
this.handleExcludeIfAny = (op)=>{
|
|
2949
|
-
if (op.field.includes('.')) {
|
|
2950
|
-
const leafField = op.field.split('.').at(-1) ?? 'unset';
|
|
2951
|
-
return buildNestedGQLFilter(op.field, {
|
|
2952
|
-
excludeifany: {
|
|
2953
|
-
[leafField]: op.operands
|
|
2954
|
-
}
|
|
2955
|
-
});
|
|
2956
|
-
}
|
|
2957
|
-
return {
|
|
2958
|
-
excludeifany: {
|
|
2959
|
-
[op.field]: op.operands
|
|
2960
|
-
}
|
|
2961
|
-
};
|
|
2962
|
-
};
|
|
2963
|
-
this.handleIntersection = (op)=>({
|
|
2964
|
-
and: op.operands.map((x)=>convertFilterToGqlFilter(x))
|
|
2965
|
-
});
|
|
2966
|
-
this.handleUnion = (op)=>({
|
|
2967
|
-
or: op.operands.map((x)=>convertFilterToGqlFilter(x))
|
|
2968
|
-
});
|
|
2969
|
-
this.handleMissing = (op)=>{
|
|
2970
|
-
if (op.field.includes('.')) {
|
|
2971
|
-
const leafField = op.field.split('.').at(-1) ?? 'unset';
|
|
2972
|
-
return buildNestedGQLFilter(op.field, {
|
|
2973
|
-
is: {
|
|
2974
|
-
[leafField]: 'MISSING'
|
|
2975
|
-
}
|
|
2976
|
-
});
|
|
2946
|
+
const nestedHistogramQueryStrForEachField = (mainField, numericAggAsText)=>`
|
|
2947
|
+
${mainField} {
|
|
2948
|
+
${numericAggAsText ? 'asTextHistogram' : 'histogram'} {
|
|
2949
|
+
key
|
|
2950
|
+
count
|
|
2951
|
+
missingFields {
|
|
2952
|
+
field
|
|
2953
|
+
count
|
|
2954
|
+
}
|
|
2955
|
+
termsFields {
|
|
2956
|
+
field
|
|
2957
|
+
count
|
|
2958
|
+
terms {
|
|
2959
|
+
key
|
|
2960
|
+
count
|
|
2961
|
+
}
|
|
2962
|
+
}
|
|
2963
|
+
}
|
|
2964
|
+
}`;
|
|
2965
|
+
const rawDataQueryStrForEachField$1 = (field)=>{
|
|
2966
|
+
const splitFieldArray = field.split('.');
|
|
2967
|
+
const splitField = splitFieldArray.shift();
|
|
2968
|
+
if (splitFieldArray.length === 0) {
|
|
2969
|
+
return `
|
|
2970
|
+
${splitField}
|
|
2971
|
+
`;
|
|
2972
|
+
}
|
|
2973
|
+
return `
|
|
2974
|
+
${splitField} {
|
|
2975
|
+
${rawDataQueryStrForEachField$1(splitFieldArray.join('.'))}
|
|
2976
|
+
}`;
|
|
2977
|
+
};
|
|
2978
|
+
|
|
2979
|
+
const convertNumericFromToArrayToFilters = (field, range, isNested = true)=>{
|
|
2980
|
+
const { from, to } = range;
|
|
2981
|
+
return {
|
|
2982
|
+
operator: 'and',
|
|
2983
|
+
operands: [
|
|
2984
|
+
isNested ? buildNestedFilterForOperation(field, {
|
|
2985
|
+
operator: '>=',
|
|
2986
|
+
field,
|
|
2987
|
+
operand: from
|
|
2988
|
+
}) : {
|
|
2989
|
+
operator: '>=',
|
|
2990
|
+
field,
|
|
2991
|
+
operand: from
|
|
2992
|
+
},
|
|
2993
|
+
isNested ? buildNestedFilterForOperation(field, {
|
|
2994
|
+
operator: '<',
|
|
2995
|
+
field,
|
|
2996
|
+
operand: to
|
|
2997
|
+
}) : {
|
|
2998
|
+
operator: '<',
|
|
2999
|
+
field,
|
|
3000
|
+
operand: to
|
|
2977
3001
|
}
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
3002
|
+
]
|
|
3003
|
+
};
|
|
3004
|
+
};
|
|
3005
|
+
const rawDataQueryStrForEachField = (field, asTextHistogram = false)=>{
|
|
3006
|
+
const splitFieldArray = field.split('.');
|
|
3007
|
+
const splitField = splitFieldArray.shift();
|
|
3008
|
+
let middleQuery = '';
|
|
3009
|
+
if (splitFieldArray.length === 0) {
|
|
3010
|
+
middleQuery = `${splitField} { ${asTextHistogram ? 'histogram: asTextHistogram' : 'histogram'} { count } }`;
|
|
3011
|
+
} else {
|
|
3012
|
+
middleQuery = `${splitField} { ${rawDataQueryStrForEachField(splitFieldArray.join('.'), asTextHistogram)} }`;
|
|
3013
|
+
}
|
|
3014
|
+
return middleQuery;
|
|
3015
|
+
};
|
|
3016
|
+
const buildAliasedNestedCountsQuery = ({ type, field, rangeName, asTextHistogram = false })=>{
|
|
3017
|
+
const dataParams = [
|
|
3018
|
+
`filter: $${rangeName}`
|
|
3019
|
+
];
|
|
3020
|
+
const dataTypeLine = `${rangeName} : ${type} (accessibility: $accessibility ${dataParams}) {`;
|
|
3021
|
+
const processedFields = rawDataQueryStrForEachField(field, asTextHistogram);
|
|
3022
|
+
return `${dataTypeLine} ${processedFields} }`;
|
|
3023
|
+
};
|
|
3024
|
+
const buildRangeFilters = (field, ranges, filters, rangeBaseName, isNested = true)=>{
|
|
3025
|
+
return Object.entries(ranges).reduce((acc, [, rangeValue], idx)=>{
|
|
3026
|
+
acc[`${rangeBaseName}_${idx}`] = {
|
|
3027
|
+
mode: filters.mode,
|
|
3028
|
+
root: {
|
|
3029
|
+
...filters.root,
|
|
3030
|
+
[field]: convertNumericFromToArrayToFilters(field, rangeValue, isNested)
|
|
2992
3031
|
}
|
|
2993
|
-
return {
|
|
2994
|
-
not: {
|
|
2995
|
-
[op.field]: op?.operand ?? null
|
|
2996
|
-
}
|
|
2997
|
-
};
|
|
2998
|
-
};
|
|
2999
|
-
this.handleNestedFilter = (op)=>{
|
|
3000
|
-
const child = convertFilterToGqlFilter(op.operand);
|
|
3001
|
-
return {
|
|
3002
|
-
nested: {
|
|
3003
|
-
path: op.path,
|
|
3004
|
-
...child
|
|
3005
|
-
}
|
|
3006
|
-
};
|
|
3007
3032
|
};
|
|
3008
|
-
|
|
3009
|
-
}
|
|
3010
|
-
const convertFilterToNestedGqlFilter = (filter)=>{
|
|
3011
|
-
const handler = new ToGqlAllNested();
|
|
3012
|
-
return handleOperation(handler, filter);
|
|
3033
|
+
return acc;
|
|
3034
|
+
}, {});
|
|
3013
3035
|
};
|
|
3014
|
-
const
|
|
3015
|
-
const
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3036
|
+
const buildRangeQuery = (field, ranges, filters, rangeBaseName = 'range', index = 'cases', indexPrefix = '', isNested = true, asTextHistogram = false)=>{
|
|
3037
|
+
const rangeFilters = buildRangeFilters(field, ranges, filters, rangeBaseName, isNested);
|
|
3038
|
+
let query = `query rangeQuery ($accessibility: Accessibility, ${Object.keys(rangeFilters).map((rangeKey)=>`$${rangeKey}: JSON`).join(',')} ) { ${indexPrefix}_aggregation {`;
|
|
3039
|
+
Object.keys(rangeFilters).forEach((rangeKey)=>{
|
|
3040
|
+
const rangeQuery = buildAliasedNestedCountsQuery({
|
|
3041
|
+
type: index,
|
|
3042
|
+
field,
|
|
3043
|
+
rangeName: rangeKey,
|
|
3044
|
+
asTextHistogram
|
|
3045
|
+
});
|
|
3046
|
+
query += rangeQuery + ' \n';
|
|
3047
|
+
});
|
|
3048
|
+
query += `}}`;
|
|
3049
|
+
return {
|
|
3050
|
+
query: query,
|
|
3051
|
+
filters: rangeFilters
|
|
3024
3052
|
};
|
|
3025
3053
|
};
|
|
3026
3054
|
|
|
3055
|
+
const GUPPY_MAX_ITEMS = 10000;
|
|
3027
3056
|
const statusEndpoint = '/_status';
|
|
3028
3057
|
const fetchJson = async (url)=>{
|
|
3029
3058
|
const res = await fetch(url, {
|
|
@@ -3375,6 +3404,34 @@ const explorerTags = guppyApi.enhanceEndpoints({
|
|
|
3375
3404
|
};
|
|
3376
3405
|
}
|
|
3377
3406
|
}),
|
|
3407
|
+
getObjectIds: builder.query({
|
|
3408
|
+
query: ({ filters, field, index, indexPrefix = '', accessibility = Accessibility.ALL, limit = GUPPY_MAX_ITEMS })=>{
|
|
3409
|
+
const gqlFilter = convertFilterSetToGqlFilter(filters);
|
|
3410
|
+
const query = `query getObjectIds ($filter: JSON) {
|
|
3411
|
+
${indexPrefix}${index} (filter: $filter, accessibility: ${accessibility}, first: ${limit}) {
|
|
3412
|
+
${rawDataQueryStrForEachField$1(field)}
|
|
3413
|
+
}
|
|
3414
|
+
}`;
|
|
3415
|
+
return {
|
|
3416
|
+
query,
|
|
3417
|
+
variables: {
|
|
3418
|
+
filter: gqlFilter,
|
|
3419
|
+
accessibility
|
|
3420
|
+
}
|
|
3421
|
+
};
|
|
3422
|
+
},
|
|
3423
|
+
transformResponse: (response, _, args)=>{
|
|
3424
|
+
const valueData = JSONPath({
|
|
3425
|
+
json: response?.data ?? [],
|
|
3426
|
+
path: `$..${args.field}`,
|
|
3427
|
+
resultType: 'value'
|
|
3428
|
+
});
|
|
3429
|
+
return {
|
|
3430
|
+
ids: valueData,
|
|
3431
|
+
index: args.index
|
|
3432
|
+
};
|
|
3433
|
+
}
|
|
3434
|
+
}),
|
|
3378
3435
|
generalGQL: builder.query({
|
|
3379
3436
|
query: ({ query, variables })=>{
|
|
3380
3437
|
return {
|
|
@@ -3440,7 +3497,7 @@ const buildGetStatsAggregationQuery = (type, fields, filters, accessibility = Ac
|
|
|
3440
3497
|
};
|
|
3441
3498
|
return queryBody;
|
|
3442
3499
|
};
|
|
3443
|
-
const { useGetRawDataAndTotalCountsQuery, useGetAccessibleDataQuery, useGetAllFieldsForTypeQuery, useGetAggsQuery, useLazyGetAggsQuery, useGetStatsAggregationsQuery, useLazyGetStatsAggregationsQuery, useGetSubAggsQuery, useGetCountsQuery, useLazyGetCountsQuery, useGetFieldCountSummaryQuery, useGetFieldsForIndexQuery, useGetSharedFieldsForIndexQuery, useGeneralGQLQuery, useLazyGeneralGQLQuery, useCustomRangeQuery, useLazyCustomRangeQuery } = explorerApi;
|
|
3500
|
+
const { useGetRawDataAndTotalCountsQuery, useGetAccessibleDataQuery, useGetAllFieldsForTypeQuery, useGetAggsQuery, useLazyGetAggsQuery, useGetStatsAggregationsQuery, useLazyGetStatsAggregationsQuery, useGetSubAggsQuery, useGetCountsQuery, useLazyGetCountsQuery, useGetFieldCountSummaryQuery, useGetFieldsForIndexQuery, useGetSharedFieldsForIndexQuery, useGeneralGQLQuery, useLazyGeneralGQLQuery, useCustomRangeQuery, useLazyCustomRangeQuery, useGetObjectIdsQuery, useLazyGetObjectIdsQuery } = explorerApi;
|
|
3444
3501
|
|
|
3445
3502
|
/**
|
|
3446
3503
|
* Defines coreListeners for adding middleware.
|
|
@@ -4010,6 +4067,81 @@ class CohortStorage {
|
|
|
4010
4067
|
}
|
|
4011
4068
|
}
|
|
4012
4069
|
|
|
4070
|
+
const { selectAll: selectAllCohorts, selectTotal: selectTotalCohorts, selectById: selectCohortById, selectIds: selectCohortIds } = cohortsAdapter.getSelectors((state)=>state.cohorts.cohortManager);
|
|
4071
|
+
/**
|
|
4072
|
+
* Internally used selector for the exported selectora
|
|
4073
|
+
* @param state
|
|
4074
|
+
*/ const getCurrentCohortFromCoreState = (state)=>{
|
|
4075
|
+
return state.cohorts.cohortManager.currentCohortId;
|
|
4076
|
+
};
|
|
4077
|
+
const selectCohortFilters = (state)=>{
|
|
4078
|
+
const currentCohortId = getCurrentCohortFromCoreState(state);
|
|
4079
|
+
return state.cohorts.cohortManager.entities[currentCohortId]?.filters;
|
|
4080
|
+
};
|
|
4081
|
+
const selectCurrentCohortFilters = (state)=>{
|
|
4082
|
+
const currentCohortId = getCurrentCohortFromCoreState(state);
|
|
4083
|
+
return state.cohorts.cohortManager.entities[currentCohortId]?.filters;
|
|
4084
|
+
};
|
|
4085
|
+
const selectCurrentCohortId = (state)=>{
|
|
4086
|
+
return state.cohorts.cohortManager.currentCohortId;
|
|
4087
|
+
};
|
|
4088
|
+
const selectCurrentCohort = (state)=>cohortSelectors.selectById(state, getCurrentCohortFromCoreState(state));
|
|
4089
|
+
const selectCurrentCohortName = (state)=>cohortSelectors.selectById(state, getCurrentCohortFromCoreState(state)).name;
|
|
4090
|
+
/**
|
|
4091
|
+
* Select a filter by its name from the current cohort. If the filter is not found
|
|
4092
|
+
* returns undefined.
|
|
4093
|
+
* @param state - Core
|
|
4094
|
+
* @param index which cohort index to select from
|
|
4095
|
+
* @param name name of the filter to select
|
|
4096
|
+
*/ const selectIndexedFilterByName = (state, index, name)=>{
|
|
4097
|
+
return cohortSelectors.selectById(state, getCurrentCohortFromCoreState(state)).filters[index]?.root[name];
|
|
4098
|
+
};
|
|
4099
|
+
/**
|
|
4100
|
+
* Returns all the cohorts in the state
|
|
4101
|
+
* @param state - the CoreState
|
|
4102
|
+
*
|
|
4103
|
+
* @category Cohort
|
|
4104
|
+
* @category Selectors
|
|
4105
|
+
*/ const selectAvailableCohorts = (state)=>cohortSelectors.selectAll(state);
|
|
4106
|
+
/**
|
|
4107
|
+
* Returns if the current cohort is modified
|
|
4108
|
+
* @param state - the CoreState
|
|
4109
|
+
* @category Cohort
|
|
4110
|
+
* @category Selectors
|
|
4111
|
+
* @hidden
|
|
4112
|
+
*/ const selectCurrentCohortModified = (state)=>{
|
|
4113
|
+
const cohort = cohortSelectors.selectById(state, getCurrentCohortFromCoreState(state));
|
|
4114
|
+
return cohort?.modified;
|
|
4115
|
+
};
|
|
4116
|
+
/**
|
|
4117
|
+
* Returns if the current cohort has been saved
|
|
4118
|
+
* @param state - the CoreState
|
|
4119
|
+
* @category Cohort
|
|
4120
|
+
* @category Selectors
|
|
4121
|
+
* @hidden
|
|
4122
|
+
*/ const selectCurrentCohortSaved = (state)=>{
|
|
4123
|
+
const cohort = cohortSelectors.selectById(state, getCurrentCohortFromCoreState(state));
|
|
4124
|
+
return cohort?.saved;
|
|
4125
|
+
};
|
|
4126
|
+
/**
|
|
4127
|
+
* Select a filter by its name from the current cohort. If the filter is not found
|
|
4128
|
+
* returns undefined.
|
|
4129
|
+
* @param state - Core
|
|
4130
|
+
* @param name name of the filter to select
|
|
4131
|
+
*/ const selectAvailableCohortByName = (state, name)=>cohortSelectors.selectAll(state).find((cohort)=>cohort.name === name);
|
|
4132
|
+
/**
|
|
4133
|
+
* Select a filter from the index.
|
|
4134
|
+
* returns undefined.
|
|
4135
|
+
* @param state - Core
|
|
4136
|
+
* @param index which cohort index to select from
|
|
4137
|
+
*/ const selectIndexFilters = (state, index)=>{
|
|
4138
|
+
const cohort = cohortSelectors.selectById(state, getCurrentCohortFromCoreState(state));
|
|
4139
|
+
if (!cohort) {
|
|
4140
|
+
console.error('No Cohort Defined');
|
|
4141
|
+
}
|
|
4142
|
+
return cohort?.filters?.[index] ?? EmptyFilterSet;
|
|
4143
|
+
};
|
|
4144
|
+
|
|
4013
4145
|
const isFileItem = (item)=>{
|
|
4014
4146
|
return item && 'guid' in item;
|
|
4015
4147
|
};
|
|
@@ -6278,5 +6410,86 @@ class ConfigRegistry {
|
|
|
6278
6410
|
}
|
|
6279
6411
|
const configRegistry = new ConfigRegistry();
|
|
6280
6412
|
|
|
6281
|
-
|
|
6413
|
+
const DAYS_IN_DECADE = 3652; // Note: an approximation
|
|
6414
|
+
const cohortFacetSlice = graphQLAPI.injectEndpoints({
|
|
6415
|
+
endpoints: (builder)=>({
|
|
6416
|
+
cohortFacets: builder.query({
|
|
6417
|
+
query: ({ index, facetFields, continuousFacets, primaryCohort, comparisonCohort })=>({
|
|
6418
|
+
url: `${GEN3_ANALYSIS_API}/compare/facets`,
|
|
6419
|
+
method: 'POST',
|
|
6420
|
+
body: {
|
|
6421
|
+
doc_type: index,
|
|
6422
|
+
cohort1: primaryCohort,
|
|
6423
|
+
cohort2: comparisonCohort,
|
|
6424
|
+
facets: facetFields,
|
|
6425
|
+
interval: continuousFacets.reduce((acc, x)=>{
|
|
6426
|
+
acc[x] = DAYS_IN_DECADE;
|
|
6427
|
+
return acc;
|
|
6428
|
+
}, {})
|
|
6429
|
+
}
|
|
6430
|
+
}),
|
|
6431
|
+
transformResponse: (response)=>{
|
|
6432
|
+
const facets1 = response?.cohort1?.facets;
|
|
6433
|
+
const facets2 = response?.cohort2?.facets;
|
|
6434
|
+
return {
|
|
6435
|
+
aggregations: [
|
|
6436
|
+
facets1,
|
|
6437
|
+
facets2
|
|
6438
|
+
]
|
|
6439
|
+
};
|
|
6440
|
+
}
|
|
6441
|
+
})
|
|
6442
|
+
})
|
|
6443
|
+
});
|
|
6444
|
+
const { useCohortFacetsQuery } = cohortFacetSlice;
|
|
6445
|
+
|
|
6446
|
+
const vennDiagramApiSlice = graphQLAPI.injectEndpoints({
|
|
6447
|
+
endpoints: (builder)=>({
|
|
6448
|
+
vennDiagram: builder.query({
|
|
6449
|
+
query: (queryParameters)=>{
|
|
6450
|
+
return {
|
|
6451
|
+
url: `${GEN3_ANALYSIS_API}/compare/intersection`,
|
|
6452
|
+
method: 'POST',
|
|
6453
|
+
body: JSON.stringify({
|
|
6454
|
+
cohort1: queryParameters.set1Filters,
|
|
6455
|
+
cohort2: queryParameters.set2Filters,
|
|
6456
|
+
doc_type: queryParameters.index
|
|
6457
|
+
})
|
|
6458
|
+
};
|
|
6459
|
+
},
|
|
6460
|
+
transformResponse: (response)=>({
|
|
6461
|
+
set1: response?.cohort1,
|
|
6462
|
+
set2: response?.cohort2,
|
|
6463
|
+
intersection: response?.intersection
|
|
6464
|
+
})
|
|
6465
|
+
})
|
|
6466
|
+
})
|
|
6467
|
+
});
|
|
6468
|
+
const { useVennDiagramQuery } = vennDiagramApiSlice;
|
|
6469
|
+
|
|
6470
|
+
const graphQLQuery = `
|
|
6471
|
+
query pValue($data: [[Int]]!) {
|
|
6472
|
+
analysis {
|
|
6473
|
+
pvalue(data: $data)
|
|
6474
|
+
}
|
|
6475
|
+
}
|
|
6476
|
+
`;
|
|
6477
|
+
const pValueSlice = graphQLAPI.injectEndpoints({
|
|
6478
|
+
endpoints: (builder)=>({
|
|
6479
|
+
pValue: builder.query({
|
|
6480
|
+
query: (data)=>({
|
|
6481
|
+
url: `${GEN3_ANALYSIS_API}/pvalue`,
|
|
6482
|
+
method: 'POST',
|
|
6483
|
+
body: {
|
|
6484
|
+
query: graphQLQuery,
|
|
6485
|
+
variables: data
|
|
6486
|
+
}
|
|
6487
|
+
}),
|
|
6488
|
+
transformResponse: (response)=>response?.data?.analysis.pvalue
|
|
6489
|
+
})
|
|
6490
|
+
})
|
|
6491
|
+
});
|
|
6492
|
+
const { usePValueQuery } = pValueSlice;
|
|
6493
|
+
|
|
6494
|
+
export { Accessibility, CART_LIMIT, CohortStorage, CoreProvider, DAYS_IN_YEAR, DataLibraryStoreMode, EmptyFilterSet, EmptyWorkspaceStatusResponse, EnumValueExtractorHandler, ExtractValueFromObject, FILE_DELIMITERS, FILE_FORMATS, GEN3_API, GEN3_AUTHZ_API, GEN3_AUTHZ_SERVICE, GEN3_COMMONS_NAME, GEN3_CROSSWALK_API, GEN3_DOMAIN, GEN3_DOWNLOADS_ENDPOINT, GEN3_FENCE_API, GEN3_FENCE_SERVICE, GEN3_GUPPY_API, GEN3_MANIFEST_API, GEN3_MDS_API, GEN3_REDIRECT_URL, GEN3_SOWER_API, GEN3_SUBMISSION_API, GEN3_WORKSPACE_API, HTTPError, HTTPErrorMessages, HttpMethod, MissingServiceConfigurationError, Modals, PodConditionType, PodStatus, RequestedWorkspaceStatus, ToGqlAllNested, ToGqlHandler, ValueExtractorHandler, WorkspaceStatus, addItemsToCart, ageDisplay, appendFilterToOperation, buildCohortGqlOperator, buildGetAggregationQuery, buildGetStatsAggregationQuery, buildListItemsGroupedByDataset, buildNestedFilterForOperation, buildNestedGQLFilter, buildNestedWithParentPathGQLFilter, buildRangeQuery, calculatePercentageAsNumber, calculatePercentageAsString, capitalize$1 as capitalize, cartReducer, cartReducerPath, clearActiveWorkspaceId, clearCohortFilters, cohortReducer, configRegistry, conversion, convertFilterSetToGqlFilter, convertFilterSetToNestedGqlFilter, convertFilterSetToOperation, convertFilterToGqlFilter, convertFilterToNestedGqlFilter, convertGqlFilterToFilter, convertToHistogramDataAsStringKey, convertToQueryString, coreStore, createAppApiForRTKQ, createAppStore, createGen3App, createGen3AppWithOwnStore, createNewCohort, createUseCoreDataHook, customQueryStrForField, defaultCohortNameGenerator, downloadFromGuppyToBlob, downloadJSONDataFromGuppy, drsHostnamesReducer, duplicateCohort, explorerApi, explorerTags, extractContents, extractEnumFilterValue, extractFieldNameFromFullFieldName, extractFileDatasetsInRecords, extractFilterValue, extractFiltersWithPrefixFromFilterSet, extractIndexAndFieldNameFromFullFieldName, extractIndexFromDataLibraryCohort, extractIndexFromFullFieldName, fetchArboristResources, fetchFence, fetchFencePresignedURL, fetchJSONDataFromURL, fetchJson, fetchUserState, fieldNameToLabel, filterSetToOperation, gen3Api, generateUniqueName, getCurrentTimestamp, getFederatedLoginStatus, getGen3AppId, getNumberOfItemsInDatalist, getRemoteSupportServiceRegistry, getTimestamp, graphQLAPI, graphQLWithTags, groupSharedFields, guppyAPISliceMiddleware, guppyApi, guppyApiReducer, guppyApiSliceReducerPath, guppyDownloadApi, handleGqlOperation, handleOperation, hideModal, histogramQueryStrForEachField, humanify, ifOperationWithField, isAdditionalDataItem, isArray, isAuthenticated, isCohortItem, isDataLibraryAPIResponse, isDatalistAPI, isErrorWithMessage, isFetchBaseQueryError, isFetchError, isFetchParseError, isFileItem, isFilterEmpty, isFilterSet, isGQLIntersection, isGQLUnion, isGuppyAggregationData, isHistogramData, isHistogramDataAArray, isHistogramDataAnEnum, isHistogramDataArray, isHistogramDataArrayARange, isHistogramDataArrayAnEnum, isHistogramDataCollection, isHistogramRangeData, isHttpStatusError, isIncludes, isIndexedFilterSetEmpty, isIntersection, isIntersectionOrUnion, isJSONObject, isJSONValue, isJSONValueArray, isNameUnique, isNestedFilter, isNotDefined, isObject, isOperandsType, isOperationWithField, isOperatorWithFieldAndArrayOfOperands, isPending, isProgramUrl, isRootUrl, isStatsValue, isStatsValuesArray, isString, isTimeGreaterThan, isUnion, isWorkspaceActive, isWorkspaceRunningOrStopping, joinFilters, jsonToFormat, listifyMethodsFromMapping, logoutFence, manifestApi, manifestTags, nestedHistogramQueryStrForEachField, prepareUrl$1 as prepareUrl, prependIndexToFieldName, processHistogramResponse, projectCodeFromResourcePath, queryMultipleMDSRecords, rawDataQueryStrForEachField$1 as rawDataQueryStrForEachField, registerDefaultRemoteSupport, removeCohort, removeCohortFilter, removeItemsFromCart, requestorApi, resetUserState, resourcePathFromProjectID, roundHistogramResponse, selectActiveWorkspaceId, selectActiveWorkspaceStatus, selectAllCohortFiltersCollapsed, selectAllCohorts, selectAuthzMappingData, selectAvailableCohortByName, selectAvailableCohorts, selectCSRFToken, selectCSRFTokenData, selectCart, selectCartCount, selectCartItem, selectCartItems, selectCohortById, selectCohortFilterCombineMode, selectCohortFilterExpanded, selectCohortFilters, selectCohortIds, selectCurrentCohort, selectCurrentCohortFilters, selectCurrentCohortId, selectCurrentCohortModified, selectCurrentCohortName, selectCurrentCohortSaved, selectCurrentMessage, selectCurrentModal, selectGen3AppByName, selectGen3AppMetadataByName, selectHeadersWithCSRFToken, selectIndexFilters, selectIndexedFilterByName, selectPaymodelStatus, selectRequestedWorkspaceStatus, selectRequestedWorkspaceStatusTimestamp, selectSharedFilters, selectSharedFiltersForFields, selectShouldShareFilters, selectTotalCohorts, selectUser, selectUserAuthStatus, selectUserData, selectUserDetails, selectUserLoginStatus, selectWorkspaceStatus, selectWorkspaceStatusFromService, setActiveWorkspace, setActiveWorkspaceId, setActiveWorkspaceStatus, setCohortFilter, setCohortFilterCombineMode, setCohortIndexFilters, setCohortList, setCurrentCohortId, setDRSHostnames, setRequestedWorkspaceStatus, setSharedFilters, setShouldShareFilters, setupCoreStore, showModal, statsQueryStrForEachField, stringifyJSONParam, submissionApi, toggleCohortBuilderAllFilters, toggleCohortBuilderCategoryFilter, trimFirstfieldNameToLabel, updateCohortFilter, updateCohortName, useAddCohortManifestMutation, useAddFileManifestMutation, useAddMetadataManifestMutation, useAddNewCredentialMutation, useAskQuestionMutation, useAuthorizeFromCredentialsMutation, useCohortFacetsQuery, useCoreDispatch, useCoreSelector, useCreateAuthzResourceMutation, useCreateRequestMutation, useCustomRangeQuery, useDataLibrary, useDownloadFromGuppyQuery, useFetchUserDetailsQuery, useGeneralGQLQuery, useGetAISearchStatusQuery, useGetAISearchVersionQuery, useGetAccessibleDataQuery, useGetActivePayModelQuery, useGetAggMDSQuery, useGetAggsQuery, useGetAllFieldsForTypeQuery, useGetArrayTypes, useGetAuthzMappingsQuery, useGetAuthzResourcesQuery, useGetCSRFQuery, useGetCohortManifestQuery, useGetCountsQuery, useGetCredentialsQuery, useGetCrosswalkDataQuery, useGetDataQuery, useGetDictionaryQuery, useGetDownloadQuery, useGetExternalLoginsQuery, useGetFederatedLoginStatus, useGetFieldCountSummaryQuery, useGetFieldsForIndexQuery, useGetFileFromManifestQuery, useGetFileManifestQuery, useGetIndexAggMDSQuery, useGetIndexFields, useGetJWKKeysQuery, useGetLoginProvidersQuery, useGetMDSQuery, useGetManifestServiceStatusQuery, useGetMetadataByIdQuery, useGetMetadataFromManifestQuery, useGetMetadataManifestQuery, useGetObjectIdsQuery, useGetPresignedUrlQuery, useGetProjectsDetailsQuery, useGetProjectsQuery, useGetRawDataAndTotalCountsQuery, useGetSharedFieldsForIndexQuery, useGetSowerJobListQuery, useGetSowerJobStatusQuery, useGetSowerOutputQuery, useGetSowerServiceStatusQuery, useGetStatsAggregationsQuery, useGetStatus, useGetSubAggsQuery, useGetSubmissionGraphQLQuery, useGetSubmissionsQuery, useGetTagsQuery, useGetWorkspaceOptionsQuery, useGetWorkspacePayModelsQuery, useGetWorkspaceStatusQuery, useGraphQLQuery, useIsExternalConnectedQuery, useIsUserLoggedIn, useLaunchWorkspaceMutation, useLazyCustomRangeQuery, useLazyDownloadFromGuppyQuery, useLazyFetchUserDetailsQuery, useLazyGeneralGQLQuery, useLazyGetAggsQuery, useLazyGetAuthzMappingsQuery, useLazyGetAuthzResourcesQuery, useLazyGetCSRFQuery, useLazyGetCountsQuery, useLazyGetCrosswalkDataQuery, useLazyGetDownloadQuery, useLazyGetExternalLoginsQuery, useLazyGetManifestServiceStatusQuery, useLazyGetObjectIdsQuery, useLazyGetPresignedUrlQuery, useLazyGetProjectsQuery, useLazyGetSowerJobListQuery, useLazyGetStatsAggregationsQuery, useLazyGetSubmissionGraphQLQuery, useLazyIsExternalConnectedQuery, useLazyRequestQuery, usePValueQuery, usePrevious, useRemoveCredentialMutation, useRequestByIdQuery, useRequestQuery, useRequestorStatusQuery, useSetCurrentPayModelMutation, useSubmitSowerJobMutation, useTerminateWorkspaceMutation, useUserAuth, useUserRequestQuery, useVennDiagramQuery, userHasCreateOrUpdateOnAnyProject, userHasDataUpload, userHasMethodForServiceOnProject, userHasMethodForServiceOnResource, userHasMethodOnAnyProject, userHasSheepdogProgramAdmin, userHasSheepdogProjectAdmin };
|
|
6282
6495
|
//# sourceMappingURL=index.js.map
|