Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
1d5d504
fix: disappearing filter bug
ZakirG Dec 13, 2019
42adcdf
hay
ZakirG Dec 13, 2019
dd2ca8b
hehe
ZakirG Dec 13, 2019
b77dc46
-
ZakirG Dec 13, 2019
35da973
hehe
ZakirG Dec 13, 2019
8db7a74
ok
ZakirG Dec 13, 2019
306112e
yeah
ZakirG Dec 18, 2019
7d693af
hay
ZakirG Dec 18, 2019
2103936
whoa
ZakirG Dec 18, 2019
040d36a
wow
ZakirG Dec 18, 2019
d1f09ef
hey
ZakirG Dec 18, 2019
b3fd0e7
o
ZakirG Dec 18, 2019
950a6ab
o
ZakirG Dec 18, 2019
5838ab5
o
ZakirG Dec 18, 2019
e9374f9
o
ZakirG Dec 18, 2019
bf4a065
o
ZakirG Dec 18, 2019
f1c9102
oo
ZakirG Dec 20, 2019
c5dad64
wrote unit test got it passing
ZakirG Dec 20, 2019
f8a3ef5
-
ZakirG Dec 20, 2019
cd5c2f2
chore: eslint
ZakirG Dec 20, 2019
28b07bd
-
ZakirG Dec 20, 2019
96802f4
-
ZakirG Dec 20, 2019
c2f18c6
hey
ZakirG Dec 20, 2019
6ca5f08
revert this commit
ZakirG Dec 20, 2019
8fac895
reverted that commit
ZakirG Dec 20, 2019
04a568c
turns out hideZero is necessary
ZakirG Dec 20, 2019
7745902
sorting tab options, added unit test
ZakirG Jan 2, 2020
01cd5fd
testing
ZakirG Jan 2, 2020
cfd6cdd
fixed sort problem
ZakirG Jan 2, 2020
befca0d
package update
ZakirG Jan 2, 2020
aeb264b
mak zero hiding configurable
ZakirG Jan 3, 2020
2564b8a
mak zero hiding configurable
ZakirG Jan 3, 2020
4ec8dd9
PR feedback in progress
ZakirG Jan 27, 2020
fdb6ce3
whoa
ZakirG Jan 27, 2020
aedcdff
-
ZakirG Jan 28, 2020
65dfded
-
ZakirG Jan 28, 2020
a2e07f7
-
ZakirG Jan 28, 2020
208abab
-
ZakirG Jan 28, 2020
d286a02
-
ZakirG Jan 28, 2020
9fc8e0c
-
ZakirG Jan 28, 2020
0cffdf1
-
ZakirG Jan 28, 2020
32c8b36
-
ZakirG Jan 28, 2020
61c8516
-
ZakirG Jan 29, 2020
4d875ce
-
ZakirG Jan 29, 2020
357a136
-
ZakirG Jan 29, 2020
90aedc1
-
ZakirG Jan 29, 2020
a672740
-
ZakirG Jan 29, 2020
7a1522f
-
ZakirG Jan 29, 2020
4485590
eslint
ZakirG Jan 29, 2020
8af8a5a
tests passing
ZakirG Jan 29, 2020
f6023b4
revert package
ZakirG Feb 5, 2020
087a5fa
Merge branch 'master' of https://github.com/uc-cdis/guppy into fix/fi…
ZakirG Feb 5, 2020
71989c1
PR feedback
ZakirG Feb 5, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 18 additions & 5 deletions src/components/ConnectedFilter/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
askGuppyForAggregationData,
getAllFieldsFromFilterConfigs,
} from '../Utils/queries';
import { mergeFilters } from '../Utils/filters';
import { mergeFilters, updateCountsInInitialTabsOptions, sortTabsOptions } from '../Utils/filters';

class ConnectedFilter extends React.Component {
constructor(props) {
Expand All @@ -25,13 +25,15 @@ class ConnectedFilter extends React.Component {
? _.union(filterConfigsFields, props.accessibleFieldCheckList)
: filterConfigsFields;

this.initialTabsOptions = {};
this.state = {
allFields,
initialAggsData: {},
receivedAggsData: {},
accessibility: ENUM_ACCESSIBILITY.ALL,
adminAppliedPreFilters: Object.assign({}, this.props.adminAppliedPreFilters),
filter: Object.assign({}, this.props.adminAppliedPreFilters),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it seems this this.state.filter is not useful anymore, could we just remove this, and so that not having both filter and filtersApplied, you might also want to remove its only reference in componentDidMount function

filtersApplied: {},
};
this.filterGroupRef = React.createRef();
this.adminPreFiltersFrozen = JSON.stringify(this.props.adminAppliedPreFilters).slice();
Expand Down Expand Up @@ -68,7 +70,17 @@ class ConnectedFilter extends React.Component {
* component could do some pre-processing modification about filter.
*/
getFilterTabs() {
const processedTabsOptions = this.props.onProcessFilterAggsData(this.state.receivedAggsData);
let processedTabsOptions = this.props.onProcessFilterAggsData(this.state.receivedAggsData);
if (Object.keys(this.initialTabsOptions).length === 0) {
this.initialTabsOptions = processedTabsOptions;
}

processedTabsOptions = updateCountsInInitialTabsOptions(
this.initialTabsOptions, processedTabsOptions, this.state.filtersApplied,
);

processedTabsOptions = sortTabsOptions(processedTabsOptions);

if (!processedTabsOptions || Object.keys(processedTabsOptions).length === 0) return null;
const { fieldMapping } = this.props;
const tabs = this.props.filterConfig.tabs.map(({ fields }, index) => (
Expand Down Expand Up @@ -112,7 +124,8 @@ class ConnectedFilter extends React.Component {
*/
handleFilterChange(filterResults) {
this.setState({ adminAppliedPreFilters: JSON.parse(this.adminPreFiltersFrozen) });
const mergedFilterResults = mergeFilters(filterResults, this.state.adminAppliedPreFilters);
const mergedFilterResults = mergeFilters(filterResults, JSON.parse(this.adminPreFiltersFrozen));
this.setState({ filtersApplied: mergedFilterResults });
askGuppyForAggregationData(
this.props.guppyConfig.path,
this.props.guppyConfig.type,
Expand Down Expand Up @@ -172,7 +185,6 @@ ConnectedFilter.propTypes = {
}).isRequired,
onFilterChange: PropTypes.func,
onReceiveNewAggsData: PropTypes.func,
hideZero: PropTypes.bool,
className: PropTypes.string,
fieldMapping: PropTypes.arrayOf(PropTypes.shape({
field: PropTypes.string,
Expand All @@ -185,12 +197,12 @@ ConnectedFilter.propTypes = {
lockedTooltipMessage: PropTypes.string,
disabledTooltipMessage: PropTypes.string,
accessibleFieldCheckList: PropTypes.arrayOf(PropTypes.string),
hideZero: PropTypes.bool,
};

ConnectedFilter.defaultProps = {
onFilterChange: () => {},
onReceiveNewAggsData: () => {},
hideZero: true,
className: '',
fieldMapping: [],
tierAccessLimit: undefined,
Expand All @@ -200,6 +212,7 @@ ConnectedFilter.defaultProps = {
lockedTooltipMessage: '',
disabledTooltipMessage: '',
accessibleFieldCheckList: undefined,
hideZero: false,
};

export default ConnectedFilter;
1 change: 0 additions & 1 deletion src/components/ConnectedFilter/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ export const getFilterSections = (
options: defaultOptions,
};
});

return sections;
};

Expand Down
81 changes: 81 additions & 0 deletions src/components/Utils/filters.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,84 @@ export const mergeFilters = (userFilter, adminAppliedPreFilter) => {

return filterAB;
};

function isFilterOptionToBeHidden(option, filtersApplied, fieldName) {
if (option.count > 0) {
return false;
}

if (typeof filtersApplied !== 'undefined'
&& filtersApplied[fieldName]
&& filtersApplied[fieldName].selectedValues.includes(option.key)) {
return false;
}

return true;
}

/**
* This function updates the counts in the initial set of tab options
* calculated from unfiltered data.
* It is used to retain field options in the rendering if
* they are still checked but their counts are zero.
*/
export const updateCountsInInitialTabsOptions = (
initialTabsOptions, processedTabsOptions, filtersApplied,
) => {
const updatedTabsOptions = JSON.parse(JSON.stringify(initialTabsOptions));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to stringify and then parse this object here? 🤔

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

alright it took me time to understand this code block but I guess you were trying to deep clone an object here. :D

const initialFields = Object.keys(initialTabsOptions);
for (let i = 0; i < initialFields.length; i += 1) {
const fieldName = initialFields[i];
const initialFieldOptions = initialTabsOptions[fieldName].histogram.map(x => x.key);
let processedFieldOptions = [];
if (Object.prototype.hasOwnProperty.call(processedTabsOptions, fieldName)) {
processedFieldOptions = processedTabsOptions[fieldName].histogram.map(x => x.key);
}

for (let j = 0; j < initialFieldOptions.length; j += 1) {
const optionName = initialFieldOptions[j];
let newCount;
if (processedFieldOptions.includes(optionName)) {
newCount = processedTabsOptions[fieldName].histogram.filter(
x => x.key === optionName,
)[0].count;
} else {
newCount = 0;
}
for (let k = 0; k < updatedTabsOptions[fieldName].histogram.length; k += 1) {
const option = updatedTabsOptions[fieldName].histogram[k];
if (option.key === optionName) {
updatedTabsOptions[fieldName].histogram[k].count = newCount;
if (isFilterOptionToBeHidden(
updatedTabsOptions[fieldName].histogram[k], filtersApplied, fieldName,
)) {
updatedTabsOptions[fieldName].histogram.splice(k, 1);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow I finally understand this 3-level loop 👍 I think this works! except the readability, and if there's a way to use JS's built -in Array filter or map function to reduce the level of nested loops that would be great. But anyway I am fine with keeping this. Could you add a break here? I know this if statement should only satisfy once in this for loop but just in case...

break;
}
}
}
}
}

return updatedTabsOptions;
};

function sortCountThenAlpha(a, b) {
if (a.count === b.count) {
return a.key < b.key ? -1 : 1;
}
return b.count - a.count;
}

export const sortTabsOptions = (tabsOptions) => {
const fields = Object.keys(tabsOptions);
const sortedTabsOptions = Object.assign({}, tabsOptions);
for (let x = 0; x < fields.length; x += 1) {
const field = fields[x];

const optionsForThisField = sortedTabsOptions[field].histogram;
optionsForThisField.sort(sortCountThenAlpha);
sortedTabsOptions[field].histogram = optionsForThisField;
}
return sortedTabsOptions;
};
108 changes: 107 additions & 1 deletion src/components/__tests__/filters.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* eslint-disable global-require,import/no-dynamic-require */
// Tests for Utils/filters.js
import { mergeFilters } from '../Utils/filters';
import { mergeFilters, updateCountsInInitialTabsOptions, sortTabsOptions } from '../Utils/filters';

describe('can merge simple selectedValue filters', () => {
const userFilter = { data_format: { selectedValues: ['VCF'] } };
Expand Down Expand Up @@ -60,3 +60,109 @@ describe('will select user-applied filter for a given key if it is more exclusiv
.toEqual(mergedFilterExpected);
});
});


describe('can update a small set of tabs with new counts', () => {
const initialTabsOptions = {
annotated_sex: {
histogram: [
{ key: 'yellow', count: 137675 },
{ key: 'pink', count: 56270 },
{ key: 'silver', count: 2020 },
{ key: 'orange', count: 107574 },
],
},
extra_data: {
histogram: [
{ key: 'a', count: 2 },
],
},
};

const processedTabsOptions = {
annotated_sex: {
histogram: [
{ key: 'yellow', count: 1 },
{ key: 'orange', count: 107574 },
],
},
extra_data: { histogram: [] },
};

const filtersApplied = { annotated_sex: { selectedValues: ['silver'] } };

// Silver has a count of zero, but it is in the filter, so it should remain visible
const expectedUpdatedTabsOptions = {
annotated_sex: {
histogram: [
{ key: 'yellow', count: 1 },
{ key: 'silver', count: 0 },
{ key: 'orange', count: 107574 },
],
},
extra_data: {
histogram: [],
},
};

const actualUpdatedTabsOptions = updateCountsInInitialTabsOptions(
initialTabsOptions, processedTabsOptions, filtersApplied,
);

test('update tab counts', async () => {
expect(actualUpdatedTabsOptions)
.toEqual(expectedUpdatedTabsOptions);
});
});


describe('can sort tabs options', () => {
const tabsOptionsOne = {
annotated_sex: {
histogram: [
{ key: 'orange', count: 30 },
{ key: 'pink', count: 21 },
{ key: 'yellow', count: 99 },
{ key: 'zorp', count: 4162 },
{ key: 'shiny', count: 0 },
{ key: 'green', count: 0 },
{ key: 'blue', count: 0 },
],
},
extra_data: {
histogram: [
{ key: 'a', count: 0 },
{ key: 'b', count: 0 },
{ key: 'c', count: 1 },
],
},
};

const expectedSort = {
annotated_sex: {
histogram: [
{ key: 'zorp', count: 4162 },
{ key: 'yellow', count: 99 },
{ key: 'orange', count: 30 },
{ key: 'pink', count: 21 },
{ key: 'blue', count: 0 },
{ key: 'green', count: 0 },
{ key: 'shiny', count: 0 },
],
},
extra_data: {
histogram: [
{ key: 'c', count: 1 },
{ key: 'a', count: 0 },
{ key: 'b', count: 0 },
],
},
};

const actualSort = sortTabsOptions(tabsOptionsOne);

test('test sorting tabs options', async () => {
expect(actualSort)
.toEqual(expectedSort);
});
});