@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.
Files changed (39) hide show
  1. package/dist/cjs/constants.js +1 -0
  2. package/dist/cjs/constants.js.map +1 -1
  3. package/dist/cjs/index.js +1117 -891
  4. package/dist/cjs/index.js.map +1 -1
  5. package/dist/cjs/server.js +1 -0
  6. package/dist/cjs/server.js.map +1 -1
  7. package/dist/constants.d.ts +2 -1
  8. package/dist/dts/constants.d.ts +1 -0
  9. package/dist/dts/constants.d.ts.map +1 -1
  10. package/dist/dts/features/cohortComparison/cohortFacetSlice.d.ts +201 -0
  11. package/dist/dts/features/cohortComparison/cohortFacetSlice.d.ts.map +1 -0
  12. package/dist/dts/features/cohortComparison/index.d.ts +7 -0
  13. package/dist/dts/features/cohortComparison/index.d.ts.map +1 -0
  14. package/dist/dts/features/cohortComparison/pValueApi.d.ts +186 -0
  15. package/dist/dts/features/cohortComparison/pValueApi.d.ts.map +1 -0
  16. package/dist/dts/features/cohortComparison/types.d.ts +74 -0
  17. package/dist/dts/features/cohortComparison/types.d.ts.map +1 -0
  18. package/dist/dts/features/cohortComparison/vennDiagramSlice.d.ts +198 -0
  19. package/dist/dts/features/cohortComparison/vennDiagramSlice.d.ts.map +1 -0
  20. package/dist/dts/features/filters/index.d.ts +1 -0
  21. package/dist/dts/features/filters/index.d.ts.map +1 -1
  22. package/dist/dts/features/filters/nestedFilters.d.ts +0 -2
  23. package/dist/dts/features/filters/nestedFilters.d.ts.map +1 -1
  24. package/dist/dts/features/filters/utils.d.ts +2 -2
  25. package/dist/dts/features/guppy/guppySlice.d.ts +566 -0
  26. package/dist/dts/features/guppy/guppySlice.d.ts.map +1 -1
  27. package/dist/dts/index.d.ts +1 -0
  28. package/dist/dts/index.d.ts.map +1 -1
  29. package/dist/dts/types/types.d.ts +15 -13
  30. package/dist/dts/types/types.d.ts.map +1 -1
  31. package/dist/esm/constants.js +1 -0
  32. package/dist/esm/constants.js.map +1 -1
  33. package/dist/esm/index.js +1103 -890
  34. package/dist/esm/index.js.map +1 -1
  35. package/dist/esm/server.js +1 -0
  36. package/dist/esm/server.js.map +1 -1
  37. package/dist/index.d.ts +7633 -6431
  38. package/package.json +2 -2
  39. 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 trimFirstFieldNameToTitle = (fieldName, trim = false)=>{
1764
+ const trimFirstfieldNameToLabel = (fieldName, trim = false)=>{
1764
1765
  if (trim) {
1765
1766
  const source = fieldName.slice(fieldName.indexOf('.') + 1);
1766
- return fieldNameToTitle(source ? source : fieldName, 0);
1767
+ return fieldNameToLabel(source ? source : fieldName, 0);
1767
1768
  }
1768
- return fieldNameToTitle(fieldName);
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 fieldNameToTitle = (fieldName, sections = 1)=>{
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
- * This function takes a FilterSet object and a prefix string as input.
1826
- * It filters the root property of the FilterSet object and returns a
1827
- * new FilterSet object that only contains filters with field names
1828
- * that start with the specified prefix.
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
- * @param fs - The FilterSet object to filter
1831
- * @param prefix - The prefix to filter by
1832
- * @returns - A new FilterSet object that only contains filters with field names that start with the specified prefix
1833
- * @category Filters
1834
- */ const extractFiltersWithPrefixFromFilterSet = (fs, prefix)=>{
1835
- if (fs === undefined || fs.root === undefined) {
1836
- return {
1837
- mode: 'and',
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
- return Object.values(fs.root).reduce((acc, filter)=>{
1842
- if (isIntersectionOrUnion(filter) || isNestedFilter(filter)) return acc;
1843
- if (filter.field.startsWith(prefix)) {
1844
- acc.root[filter.field] = filter;
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
- return acc;
1847
- }, {
1848
- mode: 'and',
1849
- root: {}
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
- * Cohorts in Gen3 are defined as a set of filters for each index in the data.
1855
- * This means one cohort id defined for all "tabs" in CohortBuilder (explorer)
1856
- * Switching a cohort id means all the cohorts for the index are changed.
1857
- */ const DEFAULT_COHORT_NAME = 'Cohort';
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
- name: newName,
1864
- id: newId,
1865
- filters: filters ?? {},
1866
- modified: false,
1867
- saved: false,
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 nanoid = customAlphabet('1234567890abcdef', 16);
1874
- const createCohortId = ()=>nanoid();
1875
- const cohortsAdapter = createEntityAdapter({
1876
- sortComparer: (a, b)=>{
1877
- if (a.modifiedDatetime <= b.modifiedDatetime) return 1;
1878
- else return -1;
1879
- },
1880
- selectId: (cohort)=>cohort.id
1881
- });
1882
- // Create an initial unsaved cohort
1883
- const initialCohort = newCohort({
1884
- customName: DEFAULT_COHORT_NAME
1885
- });
1886
- const emptyInitialState = cohortsAdapter.getInitialState({
1887
- currentCohortId: initialCohort.id,
1888
- message: undefined
1889
- });
1890
- // Set the initial cohort in the adapter state
1891
- const initialState$3 = cohortsAdapter.setOne(emptyInitialState, initialCohort);
1892
- const getCurrentCohortId = (state)=>state.currentCohortId;
1893
- /**
1894
- * Redux slice for cohort filters
1895
- */ const cohortManagerSlice = createSlice({
1896
- name: 'cohort',
1897
- initialState: initialState$3,
1898
- reducers: {
1899
- createNewCohort: (state, action)=>{
1900
- const baseName = action.payload.name || `Cohort`;
1901
- const uniqueName = generateUniqueName(Object.values(state.entities), baseName);
1902
- const cohort = newCohort({
1903
- filters: action.payload.filters,
1904
- customName: uniqueName
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
- updateCohortName: (state, action)=>{
1912
- const { id, name } = action.payload;
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
- removeCohort: (state, action)=>{
1923
- const { id: cohortId } = action.payload;
1924
- const removedCohortName = state.entities[cohortId].name;
1925
- const totalCohorts = Object.keys(state.entities).length;
1926
- if (totalCohorts <= 1) {
1927
- cohortsAdapter.removeAll(state);
1928
- const defaultCohort = newCohort({
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
- cohortsAdapter.removeOne(state, cohortId);
1942
- // deleted the current cohort so set to the most recent cohort
1943
- if (state.currentCohortId === cohortId) {
1944
- const remainingIds = Object.keys(state.entities);
1945
- state.currentCohortId = remainingIds[0];
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
- if (action?.payload.shouldShowMessage) {
1948
- state.message = [
1949
- `deleteCohort|${removedCohortName}|${state.currentCohortId}`
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
- // adds a filter to the cohort filter set at the given index
1954
- updateCohortFilter: (state, action)=>{
1955
- const { index, field, filter } = action.payload;
1956
- const currentCohortId = getCurrentCohortId(state);
1957
- if (!state.entities[currentCohortId]) {
1958
- return;
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
- cohortsAdapter.updateOne(state, {
1961
- id: currentCohortId,
1962
- changes: {
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
- setCohortFilter: (state, action)=>{
1979
- const { index, filters } = action.payload;
1980
- const currentCohortId = getCurrentCohortId(state);
1981
- if (!state.entities[currentCohortId]) {
1982
- console.error(`no cohort with id=${currentCohortId} defined`);
1983
- return;
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
- cohortsAdapter.updateOne(state, {
1986
- id: currentCohortId,
1987
- changes: {
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
- setCohortIndexFilters: (state, action)=>{
1998
- const currentCohortId = getCurrentCohortId(state);
1999
- if (!state.entities[currentCohortId]) {
2000
- console.error(`no cohort with id=${currentCohortId} defined`);
2001
- return;
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
- cohortsAdapter.updateOne(state, {
2004
- id: currentCohortId,
2005
- changes: {
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
- // removes a filter to the cohort filter set at the given index
2013
- removeCohortFilter: (state, action)=>{
2014
- const { index, field } = action.payload;
2015
- const currentCohortId = getCurrentCohortId(state);
2016
- if (!state.entities[currentCohortId]) {
2017
- console.error(`no cohort with id=${currentCohortId} defined`);
2018
- return;
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
- const filters = state.entities[currentCohortId]?.filters[index]?.root;
2021
- if (!filters) {
2022
- return;
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
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
2025
- const { [field]: _a, ...updated } = filters;
2026
- cohortsAdapter.updateOne(state, {
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
- duplicateCohort: (state)=>{
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
- state.currentCohortId = duplicatedCohort.id;
2058
- },
2059
- // removes all filters from the cohort filter set at the given index
2060
- clearCohortFilters: (state, action)=>{
2061
- const { index } = action.payload;
2062
- const currentCohortId = getCurrentCohortId(state);
2063
- if (!state.entities[currentCohortId]) {
2064
- console.error(`no cohort with id=${currentCohortId} defined`);
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
- cohortsAdapter.updateOne(state, {
2072
- id: currentCohortId,
2073
- changes: {
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
- updateCohortCounts: (state, action)=>{
2087
- const currentCohortId = getCurrentCohortId(state);
2088
- const currentCohort = state.entities[currentCohortId];
2089
- cohortsAdapter.updateOne(state, {
2090
- id: currentCohortId,
2091
- changes: {
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
- updateCohortIndexCountById: (state, action)=>{
2100
- const { index, cohortId, counts } = action.payload;
2101
- const cohort = state.entities[cohortId];
2102
- cohortsAdapter.updateOne(state, {
2103
- id: cohortId,
2104
- changes: {
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
- * Returns the selectors for the cohorts EntityAdapter
2130
- * @param state - the CoreState
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
- * @hidden
2133
- */ const cohortSelectors = cohortsAdapter.getSelectors((state)=>state.cohorts.cohortManager);
2134
- // Filter actions: addFilter, removeFilter, updateFilter
2135
- const { createNewCohort, updateCohortFilter, setCohortFilter, setCohortIndexFilters, duplicateCohort, removeCohortFilter, clearCohortFilters, removeCohort, setCurrentCohortId, updateCohortName, updateCohortCounts, updateCohortIndexCountById, setCohortList } = cohortManagerSlice.actions;
2136
- const cohortReducer = cohortManagerSlice.reducer;
2137
-
2138
- const initialState$2 = {};
2139
- const expandSlice$1 = createSlice({
2140
- name: 'CohortBuilder/filterExpand',
2141
- initialState: initialState$2,
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
- const cohortBuilderFiltersExpandedReducer = expandSlice$1.reducer;
2164
- const { toggleCohortBuilderCategoryFilter, toggleCohortBuilderAllFilters } = expandSlice$1.actions;
2165
- const selectCohortFilterExpanded = (state, index, field)=>state.cohorts.filtersExpanded?.[index]?.[field];
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
- const cohortBuilderFiltersCombineModeReducer = expandSlice.reducer;
2185
- const { setCohortFilterCombineMode } = expandSlice.actions;
2186
- const selectCohortFilterCombineMode = (state, index, field)=>state.cohorts.filtersCombineMode?.[index]?.[field] ?? 'or';
2163
+ return acc;
2164
+ }, {
2165
+ mode: 'and',
2166
+ root: {}
2167
+ });
2168
+ };
2187
2169
 
2188
- const initialState = {
2189
- shouldShareFilters: false,
2190
- sharedFiltersMap: {}
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 cohortSharedFiltersSlice = createSlice({
2193
- name: 'cohortSharedFilters',
2194
- initialState: initialState,
2195
- reducers: {
2196
- setShouldShareFilters: (state, action)=>{
2197
- state.shouldShareFilters = action.payload;
2198
- return state;
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
- const selectShouldShareFilters = (state)=>state.cohorts.sharedFilters.shouldShareFilters;
2206
- const selectSharedFilters = (state)=>state.cohorts.sharedFilters.sharedFiltersMap;
2207
- const selectSharedFiltersForFields = (state, field)=>state.cohorts.sharedFilters.sharedFiltersMap?.[field] ?? [
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
- const rootReducer = combineReducers({
2221
- gen3Services: gen3ServicesReducer,
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
- * Flattens a deep nested JSON object skipping
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
- * Converts JSON to a specified file format.
2256
- * Defaults to JSON if file format is not supported.
2257
- * @param {JSON} json
2258
- * @param {string} format
2259
- */ async function jsonToFormat(json, format) {
2260
- if (Object.keys(FILE_DELIMITERS).includes(format)) {
2261
- const flatJson = flattenJson(json);
2262
- const data = await conversion(flatJson, {
2263
- delimiter: FILE_DELIMITERS[format]
2264
- });
2265
- return data;
2266
- }
2267
- return json;
2268
- }
2269
-
2270
- // type guard functions
2271
- const isHistogramRangeData = (key)=>{
2272
- return Array.isArray(key) && key.length === 2 && key.every((item)=>typeof item === 'number');
2273
- };
2274
- const isJSONObject = (data)=>{
2275
- return typeof data === 'object' && data !== null && !Array.isArray(data);
2276
- };
2277
- const isJSONValue = (data)=>{
2278
- return typeof data === 'string' || typeof data === 'number' || typeof data === 'boolean' || Array.isArray(data) && data.every(isJSONValue) || isJSONObject(data);
2279
- };
2280
- const isJSONValueArray = (data)=>{
2281
- return Array.isArray(data) && data.every(isJSONValue);
2282
- };
2283
- const isValidObject = (input)=>typeof input === 'object' && input !== null;
2284
- const isHistogramData = (data)=>{
2285
- return isValidObject(data) && 'key' in data && 'count' in data;
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
- for (const field of numericFields){
2325
- if (field in obj && typeof obj[field] !== 'number') {
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
- * Returns all the cohorts in the state
2782
- * @param state - the CoreState
2783
- *
2784
- * @category Cohort
2785
- * @category Selectors
2786
- */ const selectAvailableCohorts = (state)=>cohortSelectors.selectAll(state);
2787
- /**
2788
- * Returns if the current cohort is modified
2789
- * @param state - the CoreState
2790
- * @category Cohort
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
- * Returns if the current cohort has been saved
2799
- * @param state - the CoreState
2800
- * @category Cohort
2801
- * @category Selectors
2802
- * @hidden
2803
- */ const selectCurrentCohortSaved = (state)=>{
2804
- const cohort = cohortSelectors.selectById(state, getCurrentCohortFromCoreState(state));
2805
- return cohort?.saved;
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
- * Select a filter by its name from the current cohort. If the filter is not found
2809
- * returns undefined.
2810
- * @param state - Core
2811
- * @param name name of the filter to select
2812
- */ const selectAvailableCohortByName = (state, name)=>cohortSelectors.selectAll(state).find((cohort)=>cohort.name === name);
2813
- /**
2814
- * Select a filter from the index.
2815
- * returns undefined.
2816
- * @param state - Core
2817
- * @param index which cohort index to select from
2818
- */ const selectIndexFilters = (state, index)=>{
2819
- const cohort = cohortSelectors.selectById(state, getCurrentCohortFromCoreState(state));
2820
- if (!cohort) {
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 cohort?.filters?.[index] ?? EmptyFilterSet;
2941
+ return `
2942
+ ${splittedField} {
2943
+ ${statsQueryStrForEachField(splittedFieldArray.join('.'))}
2944
+ }`;
2824
2945
  };
2825
-
2826
- class ToGqlAllNested {
2827
- constructor(){
2828
- this.handleEquals = (op)=>{
2829
- if (op.field.includes('.')) {
2830
- const leafField = op.field.split('.').at(-1) ?? 'unset';
2831
- return buildNestedGQLFilter(op.field, {
2832
- '=': {
2833
- [leafField]: op.operand
2834
- }
2835
- });
2836
- }
2837
- return {
2838
- '=': {
2839
- [op.field]: op.operand
2840
- }
2841
- };
2842
- };
2843
- this.handleNotEquals = (op)=>{
2844
- if (op.field.includes('.')) {
2845
- const leafField = op.field.split('.').at(-1) ?? 'unset';
2846
- return buildNestedGQLFilter(op.field, {
2847
- '!=': {
2848
- [leafField]: op.operand
2849
- }
2850
- });
2851
- }
2852
- return {
2853
- '!=': {
2854
- [op.field]: op.operand
2855
- }
2856
- };
2857
- };
2858
- this.handleLessThan = (op)=>{
2859
- if (op.field.includes('.')) {
2860
- const leafField = op.field.split('.').at(-1) ?? 'unset';
2861
- return buildNestedGQLFilter(op.field, {
2862
- '<': {
2863
- [leafField]: op.operand
2864
- }
2865
- });
2866
- }
2867
- return {
2868
- '<': {
2869
- [op.field]: op.operand
2870
- }
2871
- };
2872
- };
2873
- this.handleLessThanOrEquals = (op)=>{
2874
- if (op.field.includes('.')) {
2875
- const leafField = op.field.split('.').at(-1) ?? 'unset';
2876
- return buildNestedGQLFilter(op.field, {
2877
- '<=': {
2878
- [leafField]: op.operand
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
- return {
2979
- is: {
2980
- [op.field]: 'MISSING'
2981
- }
2982
- };
2983
- };
2984
- this.handleExists = (op)=>{
2985
- if (op.field.includes('.')) {
2986
- const leafField = op.field.split('.').at(-1) ?? 'unset';
2987
- return buildNestedGQLFilter(op.field, {
2988
- not: {
2989
- [leafField]: op?.operand ?? null
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 convertFilterSetToNestedGqlFilter = (fs, toplevelOp = 'and')=>{
3015
- const fsKeys = Object.keys(fs.root);
3016
- // if no keys return undefined
3017
- if (fsKeys.length === 0) return {
3018
- and: []
3019
- };
3020
- return toplevelOp === 'and' ? {
3021
- and: fsKeys.map((key)=>convertFilterToNestedGqlFilter(fs.root[key]))
3022
- } : {
3023
- or: fsKeys.map((key)=>convertFilterToNestedGqlFilter(fs.root[key]))
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
- 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, ToGqlHandler, ValueExtractorHandler, WorkspaceStatus, addItemsToCart, ageDisplay, appendFilterToOperation, buildGetAggregationQuery, buildGetStatsAggregationQuery, buildListItemsGroupedByDataset, buildNestedFilterForOperation, buildNestedGQLFilter, buildRangeQuery, calculatePercentageAsNumber, calculatePercentageAsString, capitalize$1 as capitalize, cartReducer, cartReducerPath, clearActiveWorkspaceId, clearCohortFilters, cohortReducer, configRegistry, conversion, convertFilterSetToGqlFilter, convertFilterToGqlFilter, convertGqlFilterToFilter, convertToHistogramDataAsStringKey, convertToQueryString, coreStore, createAppApiForRTKQ, createAppStore, createGen3App, createGen3AppWithOwnStore, createNewCohort, createUseCoreDataHook, customQueryStrForField, defaultCohortNameGenerator, downloadFromGuppyToBlob, downloadJSONDataFromGuppy, drsHostnamesReducer, duplicateCohort, explorerApi, explorerTags, extractEnumFilterValue, extractFieldNameFromFullFieldName, extractFileDatasetsInRecords, extractFilterValue, extractFiltersWithPrefixFromFilterSet, extractIndexAndFieldNameFromFullFieldName, extractIndexFromDataLibraryCohort, extractIndexFromFullFieldName, fetchArboristResources, fetchFence, fetchFencePresignedURL, fetchJSONDataFromURL, fetchJson, fetchUserState, fieldNameToTitle, 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, 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, trimFirstFieldNameToTitle, updateCohortFilter, updateCohortName, useAddCohortManifestMutation, useAddFileManifestMutation, useAddMetadataManifestMutation, useAddNewCredentialMutation, useAskQuestionMutation, useAuthorizeFromCredentialsMutation, 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, 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, useLazyGetPresignedUrlQuery, useLazyGetProjectsQuery, useLazyGetSowerJobListQuery, useLazyGetStatsAggregationsQuery, useLazyGetSubmissionGraphQLQuery, useLazyIsExternalConnectedQuery, useLazyRequestQuery, usePrevious, useRemoveCredentialMutation, useRequestByIdQuery, useRequestQuery, useRequestorStatusQuery, useSetCurrentPayModelMutation, useSubmitSowerJobMutation, useTerminateWorkspaceMutation, useUserAuth, useUserRequestQuery, userHasCreateOrUpdateOnAnyProject, userHasDataUpload, userHasMethodForServiceOnProject, userHasMethodForServiceOnResource, userHasMethodOnAnyProject, userHasSheepdogProgramAdmin, userHasSheepdogProjectAdmin };
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