- {options.map((option: string) => {
- const id = `input-${option}`;
- let isChecked = checkedOptions.includes(option);
+ {options.map((option: FilterFieldOption) => {
+ const id = `input-${option.displayValue}-${option.value}`;
+ let isChecked = checkedOptions.includes(option.value);
return (
= props => {
padding: '0 1em 0 0',
}}
>
- {
- isChecked = !isChecked;
- updatePhrases(option, isChecked);
- const update = createQueryUpdate(
- toRemove,
- checkedOptions,
- props.filter
- );
- props.onChange(update);
- }}
- style={{
- display: 'inline-block',
- }}
- />
);
@@ -159,7 +163,8 @@ export function createQueryUpdate(
toAdd = [];
} else if (onlyNot || moreAnd) {
const phrase = options
- .filter(o => !optionsToAdd.includes(o))
+ .filter(o => !optionsToAdd.includes(o.value))
+ .map(toFilterFieldValue)
.join(FILTER_VALUE_SEPARATOR);
toAdd = [new NotSearchClause(createListPhrase(prefix, phrase, fields))];
} else {
diff --git a/src/shared/components/query/filteredSearch/field/FilterFieldOption.ts b/src/shared/components/query/filteredSearch/field/FilterFieldOption.ts
new file mode 100644
index 00000000000..facc45c616b
--- /dev/null
+++ b/src/shared/components/query/filteredSearch/field/FilterFieldOption.ts
@@ -0,0 +1,12 @@
+export type FilterFieldOption = {
+ value: string;
+ displayValue: string;
+};
+
+export function toFilterFieldOption(option: string) {
+ return { value: option, displayValue: option };
+}
+
+export function toFilterFieldValue(option: FilterFieldOption) {
+ return option.value;
+}
diff --git a/src/shared/components/query/filteredSearch/field/ListFormField.tsx b/src/shared/components/query/filteredSearch/field/ListFormField.tsx
index e3bba5be7f1..8bfcde3e238 100644
--- a/src/shared/components/query/filteredSearch/field/ListFormField.tsx
+++ b/src/shared/components/query/filteredSearch/field/ListFormField.tsx
@@ -5,22 +5,22 @@ import { SearchClause } from 'shared/components/query/filteredSearch/SearchClaus
import { Phrase } from 'shared/components/query/filteredSearch/Phrase';
import './ListFormField.scss';
import { toQueryString } from 'shared/lib/query/textQueryUtils';
+import { FilterFieldOption } from 'shared/components/query/filteredSearch/field/FilterFieldOption';
export type ListFilterField = {
label: string;
input: typeof FilterList;
- options: string[];
+ options: FilterFieldOption[];
};
export const FilterList: FunctionComponent
= props => {
const form = props.filter.form as ListFilterField;
const allPhrases = toUniquePhrases(props.query);
- const queryString = toQueryString(props.query);
return (
{props.filter.form.label}
{form.options.map(option => {
- const update = props.parser.parseSearchQuery(option);
+ const update = props.parser.parseSearchQuery(option.value);
return (
= props => {
});
}}
>
- {option}
+ {option.displayValue}
);
diff --git a/src/shared/lib/query/QueryParser.spec.ts b/src/shared/lib/query/QueryParser.spec.ts
index 4c655a9d60e..1192dac26a1 100644
--- a/src/shared/lib/query/QueryParser.spec.ts
+++ b/src/shared/lib/query/QueryParser.spec.ts
@@ -11,7 +11,7 @@ import { QueryParser } from 'shared/lib/query/QueryParser';
import { StringPhrase } from 'shared/components/query/filteredSearch/Phrase';
describe('QueryParser', () => {
- const parser = new QueryParser(new Set
());
+ const parser = new QueryParser(new Set(),new Set());
const referenceGenomeFields = parser.searchFilters.find(
f => f.phrasePrefix === 'reference-genome'
)!.nodeFields;
diff --git a/src/shared/lib/query/QueryParser.ts b/src/shared/lib/query/QueryParser.ts
index 965ab857591..f95fe8fc8d6 100644
--- a/src/shared/lib/query/QueryParser.ts
+++ b/src/shared/lib/query/QueryParser.ts
@@ -6,9 +6,9 @@ import {
import {
AndSearchClause,
FILTER_SEPARATOR,
- SearchClause,
NOT_PREFIX,
NotSearchClause,
+ SearchClause,
} from 'shared/components/query/filteredSearch/SearchClause';
import { FilterCheckbox } from 'shared/components/query/filteredSearch/field/CheckboxFilterField';
import { getServerConfig, ServerConfigHelpers } from 'config/config';
@@ -18,6 +18,7 @@ import {
ListPhrase,
Phrase,
} from 'shared/components/query/filteredSearch/Phrase';
+import { toFilterFieldOption } from 'shared/components/query/filteredSearch/field/FilterFieldOption';
export class QueryParser {
/**
@@ -25,7 +26,10 @@ export class QueryParser {
*/
private readonly _searchFilters: CancerTreeSearchFilter[];
- constructor(referenceGenomes: Set) {
+ constructor(referenceGenomes: Set, readPermissions: Set) {
+ console.log('readPermissions');
+ console.log(readPermissions);
+ console.log(readPermissions.size);
this._searchFilters = [
/**
* Example queries:
@@ -38,7 +42,7 @@ export class QueryParser {
input: FilterList,
options: ServerConfigHelpers.skin_example_study_queries(
getServerConfig()!.skin_example_study_queries || ''
- ),
+ ).map(toFilterFieldOption),
},
},
/**
@@ -49,10 +53,25 @@ export class QueryParser {
nodeFields: ['referenceGenome'],
form: {
input: FilterCheckbox,
- options: [...referenceGenomes],
+ options: [...referenceGenomes].map(toFilterFieldOption),
label: 'Reference genome',
},
},
+ /**
+ * Show Authorized Studies
+ */
+ {
+ phrasePrefix: 'authorized',
+ nodeFields: ['readPermission'],
+ form: {
+ input: FilterCheckbox,
+ options: readPermissions.size > 1 ? [
+ { value: 'true', displayValue: 'Authorized' },
+ { value: 'false', displayValue: 'Unauthorized' },
+ ]:[],
+ label: 'Controlled access',
+ },
+ },
];
}
diff --git a/src/shared/lib/query/textQueryUtils.spec.ts b/src/shared/lib/query/textQueryUtils.spec.ts
index b083f5546a5..4ef8b9c150f 100644
--- a/src/shared/lib/query/textQueryUtils.spec.ts
+++ b/src/shared/lib/query/textQueryUtils.spec.ts
@@ -15,7 +15,7 @@ import { QueryParser } from 'shared/lib/query/QueryParser';
import { StringPhrase } from 'shared/components/query/filteredSearch/Phrase';
describe('textQueryUtils', () => {
- const parser = new QueryParser(new Set());
+ const parser = new QueryParser(new Set(), new Set());
const referenceGenomeFields = parser.searchFilters.find(
f => f.phrasePrefix === 'reference-genome'
)!.nodeFields;
From 6c849ad844ec5fa4e6163b5a9aad068692208b5b Mon Sep 17 00:00:00 2001
From: Prasanna Kumar Jagannathan <37613906+jagnathan@users.noreply.github.com>
Date: Fri, 21 Apr 2023 13:25:15 -0400
Subject: [PATCH 2/4] Updated logic and refactoring and prettier changes
Only CancerStudy objects from treeData are filtered based on whether the readPermission field has a value. Refactoring: New const created as shownStudiesLengthstring to identify if there is a filter applied or not.
Update Phrase.tsx
conflict resolution fix due to merge
changes for prettier
prettier changes
---
.../components/query/CancerStudySelector.tsx | 52 +++----------------
src/shared/components/query/QueryStore.ts | 18 ++++---
.../query/filteredSearch/Phrase.tsx | 8 ++-
src/shared/lib/query/QueryParser.spec.ts | 2 +-
src/shared/lib/query/QueryParser.ts | 17 +++---
5 files changed, 34 insertions(+), 63 deletions(-)
diff --git a/src/shared/components/query/CancerStudySelector.tsx b/src/shared/components/query/CancerStudySelector.tsx
index 8e2b562fb17..0ff76b86e9f 100644
--- a/src/shared/components/query/CancerStudySelector.tsx
+++ b/src/shared/components/query/CancerStudySelector.tsx
@@ -202,6 +202,10 @@ export default class CancerStudySelector extends React.Component<
const quickSetButtons = this.logic.mainView.quickSelectButtons(
getServerConfig().skin_quick_select_buttons
);
+ const shownStudiesLengthstring =
+ shownStudies.length < this.store.cancerStudies.result.length
+ ? 'matching filter'
+ : '';
return (
{shownAndSelectedStudies.length ===
shownStudies.length
- ? `Deselect all listed studies ${
- shownStudies.length <
- this.store
- .cancerStudies
- .result
- .length
- ? 'matching filter'
- : ''
- } (${
- shownStudies.length
- })`
- : `Select all listed studies ${
- shownStudies.length <
- this.store
- .cancerStudies
- .result
- .length
- ? 'matching filter'
- : ''
- } (${
- shownStudies.length
- })`}
+ ? `Deselect all listed studies ${shownStudiesLengthstring} (${shownStudies.length})`
+ : `Select all listed studies ${shownStudiesLengthstring} (${shownStudies.length})`}
@@ -385,28 +369,8 @@ export default class CancerStudySelector extends React.Component<
shownAndAuthorizedStudies.length &&
shownAndAuthorizedStudies.length >
0
- ? `Deselect all authorized studies ${
- shownStudies.length <
- this.store
- .cancerStudies
- .result
- .length
- ? 'matching filter'
- : ''
- } (${
- shownAndAuthorizedStudies.length
- })`
- : `Select all authorized studies ${
- shownStudies.length <
- this.store
- .cancerStudies
- .result
- .length
- ? 'matching filter'
- : ''
- } (${
- shownAndAuthorizedStudies.length
- })`}
+ ? `Deselect all authorized studies ${shownStudiesLengthstring} (${shownAndAuthorizedStudies.length})`
+ : `Select all authorized studies ${shownStudiesLengthstring} (${shownAndAuthorizedStudies.length})`}
diff --git a/src/shared/components/query/QueryStore.ts b/src/shared/components/query/QueryStore.ts
index 574f8120c7c..25f831730fe 100644
--- a/src/shared/components/query/QueryStore.ts
+++ b/src/shared/components/query/QueryStore.ts
@@ -1236,7 +1236,12 @@ export class QueryStore {
return client
.getAllSamplesOfPatientInStudyUsingGET({ studyId, patientId })
.then(
- samples => ({ studyId, patientId, samples, error: undefined }),
+ samples => ({
+ studyId,
+ patientId,
+ samples,
+ error: undefined,
+ }),
error => ({
studyId,
patientId,
@@ -1480,11 +1485,12 @@ export class QueryStore {
}
@computed get readPermissions(): Set {
- const studies = Array.from(this.treeData.map_node_meta.keys()).filter( s => typeof((s as CancerStudy).readPermission) !== 'undefined' );
- console.log(studies);
- const readPermissions = studies
- .map(n => (!!((n as CancerStudy).readPermission)).toString())
- .filter(n => !!n);
+ const studies = Array.from(this.treeData.map_node_meta.keys()).filter(
+ s => typeof (s as CancerStudy).readPermission !== 'undefined'
+ );
+ const readPermissions = studies.map(n =>
+ (n as CancerStudy).readPermission.toString()
+ );
return new Set(readPermissions);
}
diff --git a/src/shared/components/query/filteredSearch/Phrase.tsx b/src/shared/components/query/filteredSearch/Phrase.tsx
index 58b48c65d1e..010b4096cd9 100644
--- a/src/shared/components/query/filteredSearch/Phrase.tsx
+++ b/src/shared/components/query/filteredSearch/Phrase.tsx
@@ -129,11 +129,9 @@ export class ListPhrase implements Phrase {
public match(study: FullTextSearchNode): boolean {
let anyFieldMatch = false;
for (const fieldName of this.fields) {
- if (!_.has(study, fieldName)) {
- continue;
- }
- const fieldValue = (study as any)[fieldName];
- if (typeof fieldValue !== 'undefined') {
+ let anyPhraseMatch = false;
+ const fieldValue = study[fieldName];
+ if (fieldValue) {
for (const phrase of this._phraseList) {
anyPhraseMatch =
anyPhraseMatch ||
diff --git a/src/shared/lib/query/QueryParser.spec.ts b/src/shared/lib/query/QueryParser.spec.ts
index 1192dac26a1..2e84ec80562 100644
--- a/src/shared/lib/query/QueryParser.spec.ts
+++ b/src/shared/lib/query/QueryParser.spec.ts
@@ -11,7 +11,7 @@ import { QueryParser } from 'shared/lib/query/QueryParser';
import { StringPhrase } from 'shared/components/query/filteredSearch/Phrase';
describe('QueryParser', () => {
- const parser = new QueryParser(new Set(),new Set());
+ const parser = new QueryParser(new Set(), new Set());
const referenceGenomeFields = parser.searchFilters.find(
f => f.phrasePrefix === 'reference-genome'
)!.nodeFields;
diff --git a/src/shared/lib/query/QueryParser.ts b/src/shared/lib/query/QueryParser.ts
index f95fe8fc8d6..d9a317522be 100644
--- a/src/shared/lib/query/QueryParser.ts
+++ b/src/shared/lib/query/QueryParser.ts
@@ -27,9 +27,6 @@ export class QueryParser {
private readonly _searchFilters: CancerTreeSearchFilter[];
constructor(referenceGenomes: Set, readPermissions: Set) {
- console.log('readPermissions');
- console.log(readPermissions);
- console.log(readPermissions.size);
this._searchFilters = [
/**
* Example queries:
@@ -65,10 +62,16 @@ export class QueryParser {
nodeFields: ['readPermission'],
form: {
input: FilterCheckbox,
- options: readPermissions.size > 1 ? [
- { value: 'true', displayValue: 'Authorized' },
- { value: 'false', displayValue: 'Unauthorized' },
- ]:[],
+ options:
+ readPermissions.size > 1
+ ? [
+ { value: 'true', displayValue: 'Authorized' },
+ {
+ value: 'false',
+ displayValue: 'Unauthorized',
+ },
+ ]
+ : [],
label: 'Controlled access',
},
},
From 2961c91583e69bdc83a5aecef6bb47fa3c17f099 Mon Sep 17 00:00:00 2001
From: Prasanna Kumar Jagannathan <37613906+jagnathan@users.noreply.github.com>
Date: Wed, 15 Feb 2023 12:19:12 -0500
Subject: [PATCH 3/4] fix 9915 improve search of authorized studies
fix 9915 improve search of authorized studies
add new search filter based on readPermission flag called Controlled access authorized. Modified the search algorithm to accept booleans instead of just strings esp. false value
fix 9915 improve search of authorized studies
fix 9915 improve search of authorized studies
add new search filter based on readPermission flag called Controlled access authorized. Modified the search algorithm to accept booleans instead of just strings esp. false value
Use _.toString in matchPhraseFull, and specify type
Unnest fieldName check in Phrase.match
Introduce FilterFieldOption type that includes a displayValue
Update QueryParser.ts
Update CheckboxFilterField.tsx
id has to be unique for each filter when there are multiple filters.
Modify the Select all checkbox to select only authorized studies
Update checkbox label text
Update checkbox label text when filter is applied vs not applied
fix all Authorized or Unauthorized studies scenario
fix all Authorized or Unauthorized studies scenario. Hide the option if the studies that are all authorized or all unauthorized.
---
.../components/query/CancerStudySelector.tsx | 143 +++++++++++++-----
src/shared/components/query/QueryStore.ts | 11 +-
src/shared/components/query/StudyListLogic.ts | 36 +++++
.../query/filteredSearch/Phrase.tsx | 13 +-
.../field/CheckboxFilterField.spec.ts | 12 +-
.../field/CheckboxFilterField.tsx | 59 ++++----
.../filteredSearch/field/FilterFieldOption.ts | 12 ++
.../filteredSearch/field/ListFormField.tsx | 8 +-
src/shared/lib/query/QueryParser.spec.ts | 2 +-
src/shared/lib/query/QueryParser.ts | 27 +++-
src/shared/lib/query/textQueryUtils.spec.ts | 2 +-
11 files changed, 241 insertions(+), 84 deletions(-)
create mode 100644 src/shared/components/query/filteredSearch/field/FilterFieldOption.ts
diff --git a/src/shared/components/query/CancerStudySelector.tsx b/src/shared/components/query/CancerStudySelector.tsx
index d1d1417e8a7..8e2b562fb17 100644
--- a/src/shared/components/query/CancerStudySelector.tsx
+++ b/src/shared/components/query/CancerStudySelector.tsx
@@ -57,6 +57,9 @@ export default class CancerStudySelector extends React.Component<
onCheckAllFiltered: () => {
this.logic.mainView.toggleAllFiltered();
},
+ onCheckAuthorizedFiltered: () => {
+ this.logic.mainView.toggleAllAuthorizedAndFiltered();
+ },
onClearFilter: () => {
this.store.setSearchText('');
},
@@ -193,6 +196,9 @@ export default class CancerStudySelector extends React.Component<
shownAndSelectedStudies,
} = this.logic.mainView.getSelectionReport();
+ const shownAndAuthorizedStudies = shownStudies.filter(study => {
+ return study.readPermission;
+ });
const quickSetButtons = this.logic.mainView.quickSelectButtons(
getServerConfig().skin_quick_select_buttons
);
@@ -307,45 +313,104 @@ export default class CancerStudySelector extends React.Component<
-
+
+
+
+
+
+
+
+
diff --git a/src/shared/components/query/QueryStore.ts b/src/shared/components/query/QueryStore.ts
index 8a148cf794c..574f8120c7c 100644
--- a/src/shared/components/query/QueryStore.ts
+++ b/src/shared/components/query/QueryStore.ts
@@ -129,7 +129,7 @@ export class QueryStore {
@computed
get queryParser() {
- return new QueryParser(this.referenceGenomes);
+ return new QueryParser(this.referenceGenomes, this.readPermissions);
}
initialize(urlWithInitialParams?: string) {
@@ -1479,6 +1479,15 @@ export class QueryStore {
return new Set(referenceGenomes);
}
+ @computed get readPermissions(): Set {
+ const studies = Array.from(this.treeData.map_node_meta.keys()).filter( s => typeof((s as CancerStudy).readPermission) !== 'undefined' );
+ console.log(studies);
+ const readPermissions = studies
+ .map(n => (!!((n as CancerStudy).readPermission)).toString())
+ .filter(n => !!n);
+ return new Set(readPermissions);
+ }
+
@computed get selectableSelectedStudies() {
return this.selectableSelectedStudyIds
.map(
diff --git a/src/shared/components/query/StudyListLogic.ts b/src/shared/components/query/StudyListLogic.ts
index 53b9b27f0e8..549f0b1359a 100644
--- a/src/shared/components/query/StudyListLogic.ts
+++ b/src/shared/components/query/StudyListLogic.ts
@@ -400,6 +400,42 @@ export class FilteredCancerTreeView {
);
}
+ @action toggleAllAuthorizedAndFiltered() {
+ const {
+ selectableSelectedStudyIds,
+ selectableSelectedStudies,
+ shownStudies,
+ shownAndSelectedStudies,
+ } = this.getSelectionReport();
+
+ let updatedSelectableSelectedStudyIds: string[] = [];
+ const shownAndAuthorizedStudies = shownStudies.filter(study => {
+ return study.readPermission;
+ });
+ if (
+ shownAndAuthorizedStudies.length === shownAndSelectedStudies.length
+ ) {
+ // deselect
+ updatedSelectableSelectedStudyIds = _.without(
+ this.store.selectableSelectedStudyIds,
+ ...shownAndAuthorizedStudies.map(
+ (study: CancerStudy) => study.studyId
+ )
+ );
+ } else {
+ updatedSelectableSelectedStudyIds = _.union(
+ this.store.selectableSelectedStudyIds,
+ shownAndAuthorizedStudies.map(
+ (study: CancerStudy) => study.studyId
+ )
+ );
+ }
+
+ this.store.selectableSelectedStudyIds = updatedSelectableSelectedStudyIds.filter(
+ id => !_.includes(this.store.deletedVirtualStudies, id)
+ );
+ }
+
@action selectAllMatchingStudies(match: string | string[]) {
const {
selectableSelectedStudyIds,
diff --git a/src/shared/components/query/filteredSearch/Phrase.tsx b/src/shared/components/query/filteredSearch/Phrase.tsx
index 81471833e85..58b48c65d1e 100644
--- a/src/shared/components/query/filteredSearch/Phrase.tsx
+++ b/src/shared/components/query/filteredSearch/Phrase.tsx
@@ -129,9 +129,11 @@ export class ListPhrase implements Phrase {
public match(study: FullTextSearchNode): boolean {
let anyFieldMatch = false;
for (const fieldName of this.fields) {
- let anyPhraseMatch = false;
- const fieldValue = study[fieldName];
- if (fieldValue) {
+ if (!_.has(study, fieldName)) {
+ continue;
+ }
+ const fieldValue = (study as any)[fieldName];
+ if (typeof fieldValue !== 'undefined') {
for (const phrase of this._phraseList) {
anyPhraseMatch =
anyPhraseMatch ||
@@ -167,7 +169,8 @@ function matchPhrase(phrase: string, fullText: string) {
/**
* Full match using lowercase
+ * Need to convert boolean to string before applying lowercase
*/
-function matchPhraseFull(phrase: string, fullText: string) {
- return fullText.toLowerCase() === phrase.toLowerCase();
+function matchPhraseFull(phrase: string, toMatch: boolean | string | number) {
+ return _.toString(toMatch).toLowerCase() === phrase.toLowerCase();
}
diff --git a/src/shared/components/query/filteredSearch/field/CheckboxFilterField.spec.ts b/src/shared/components/query/filteredSearch/field/CheckboxFilterField.spec.ts
index 08267d28f94..f7c98bfa681 100644
--- a/src/shared/components/query/filteredSearch/field/CheckboxFilterField.spec.ts
+++ b/src/shared/components/query/filteredSearch/field/CheckboxFilterField.spec.ts
@@ -4,6 +4,10 @@ import {
} from 'shared/components/query/filteredSearch/field/CheckboxFilterField';
import { CancerTreeSearchFilter } from 'shared/lib/query/textQueryUtils';
import { ListPhrase } from 'shared/components/query/filteredSearch/Phrase';
+import {
+ toFilterFieldOption,
+ toFilterFieldValue,
+} from 'shared/components/query/filteredSearch/field/FilterFieldOption';
describe('CheckboxFilterField', () => {
describe('createQueryUpdate', () => {
@@ -12,7 +16,7 @@ describe('CheckboxFilterField', () => {
nodeFields: ['studyId'],
form: {
input: FilterCheckbox,
- options: ['a', 'b', 'c', 'd', 'e'],
+ options: ['a', 'b', 'c', 'd', 'e'].map(toFilterFieldOption),
label: 'Test label',
},
} as CancerTreeSearchFilter;
@@ -48,7 +52,11 @@ describe('CheckboxFilterField', () => {
it('removes all update when only And', () => {
const checked = dummyFilter.form.options;
const toRemove: ListPhrase[] = [];
- const result = createQueryUpdate(toRemove, checked, dummyFilter);
+ const result = createQueryUpdate(
+ toRemove,
+ checked.map(toFilterFieldValue),
+ dummyFilter
+ );
expect(result.toAdd?.length).toEqual(0);
});
diff --git a/src/shared/components/query/filteredSearch/field/CheckboxFilterField.tsx b/src/shared/components/query/filteredSearch/field/CheckboxFilterField.tsx
index facc250cc6a..e16ba935be0 100644
--- a/src/shared/components/query/filteredSearch/field/CheckboxFilterField.tsx
+++ b/src/shared/components/query/filteredSearch/field/CheckboxFilterField.tsx
@@ -13,11 +13,15 @@ import {
} from 'shared/lib/query/textQueryUtils';
import { FieldProps } from 'shared/components/query/filteredSearch/field/FilterFormField';
import { ListPhrase } from 'shared/components/query/filteredSearch/Phrase';
+import {
+ FilterFieldOption,
+ toFilterFieldValue,
+} from 'shared/components/query/filteredSearch/field/FilterFieldOption';
export type CheckboxFilterField = {
input: typeof FilterCheckbox;
label: string;
- options: string[];
+ options: FilterFieldOption[];
};
export const FilterCheckbox: FunctionComponent = props => {
@@ -43,9 +47,9 @@ export const FilterCheckbox: FunctionComponent = props => {
});
for (const option of options) {
- const isChecked = isOptionChecked(option, relevantClauses);
+ const isChecked = isOptionChecked(option.value, relevantClauses);
if (isChecked) {
- checkedOptions.push(option);
+ checkedOptions.push(option.value);
}
}
@@ -53,9 +57,9 @@ export const FilterCheckbox: FunctionComponent = props => {
{props.filter.form.label}
- {options.map((option: string) => {
- const id = `input-${option}`;
- let isChecked = checkedOptions.includes(option);
+ {options.map((option: FilterFieldOption) => {
+ const id = `input-${option.displayValue}-${option.value}`;
+ let isChecked = checkedOptions.includes(option.value);
return (
= props => {
padding: '0 1em 0 0',
}}
>
- {
- isChecked = !isChecked;
- updatePhrases(option, isChecked);
- const update = createQueryUpdate(
- toRemove,
- checkedOptions,
- props.filter
- );
- props.onChange(update);
- }}
- style={{
- display: 'inline-block',
- }}
- />
);
@@ -159,7 +163,8 @@ export function createQueryUpdate(
toAdd = [];
} else if (onlyNot || moreAnd) {
const phrase = options
- .filter(o => !optionsToAdd.includes(o))
+ .filter(o => !optionsToAdd.includes(o.value))
+ .map(toFilterFieldValue)
.join(FILTER_VALUE_SEPARATOR);
toAdd = [new NotSearchClause(createListPhrase(prefix, phrase, fields))];
} else {
diff --git a/src/shared/components/query/filteredSearch/field/FilterFieldOption.ts b/src/shared/components/query/filteredSearch/field/FilterFieldOption.ts
new file mode 100644
index 00000000000..facc45c616b
--- /dev/null
+++ b/src/shared/components/query/filteredSearch/field/FilterFieldOption.ts
@@ -0,0 +1,12 @@
+export type FilterFieldOption = {
+ value: string;
+ displayValue: string;
+};
+
+export function toFilterFieldOption(option: string) {
+ return { value: option, displayValue: option };
+}
+
+export function toFilterFieldValue(option: FilterFieldOption) {
+ return option.value;
+}
diff --git a/src/shared/components/query/filteredSearch/field/ListFormField.tsx b/src/shared/components/query/filteredSearch/field/ListFormField.tsx
index e3bba5be7f1..8bfcde3e238 100644
--- a/src/shared/components/query/filteredSearch/field/ListFormField.tsx
+++ b/src/shared/components/query/filteredSearch/field/ListFormField.tsx
@@ -5,22 +5,22 @@ import { SearchClause } from 'shared/components/query/filteredSearch/SearchClaus
import { Phrase } from 'shared/components/query/filteredSearch/Phrase';
import './ListFormField.scss';
import { toQueryString } from 'shared/lib/query/textQueryUtils';
+import { FilterFieldOption } from 'shared/components/query/filteredSearch/field/FilterFieldOption';
export type ListFilterField = {
label: string;
input: typeof FilterList;
- options: string[];
+ options: FilterFieldOption[];
};
export const FilterList: FunctionComponent
= props => {
const form = props.filter.form as ListFilterField;
const allPhrases = toUniquePhrases(props.query);
- const queryString = toQueryString(props.query);
return (
{props.filter.form.label}
{form.options.map(option => {
- const update = props.parser.parseSearchQuery(option);
+ const update = props.parser.parseSearchQuery(option.value);
return (
= props => {
});
}}
>
- {option}
+ {option.displayValue}
);
diff --git a/src/shared/lib/query/QueryParser.spec.ts b/src/shared/lib/query/QueryParser.spec.ts
index 4c655a9d60e..1192dac26a1 100644
--- a/src/shared/lib/query/QueryParser.spec.ts
+++ b/src/shared/lib/query/QueryParser.spec.ts
@@ -11,7 +11,7 @@ import { QueryParser } from 'shared/lib/query/QueryParser';
import { StringPhrase } from 'shared/components/query/filteredSearch/Phrase';
describe('QueryParser', () => {
- const parser = new QueryParser(new Set
());
+ const parser = new QueryParser(new Set(),new Set());
const referenceGenomeFields = parser.searchFilters.find(
f => f.phrasePrefix === 'reference-genome'
)!.nodeFields;
diff --git a/src/shared/lib/query/QueryParser.ts b/src/shared/lib/query/QueryParser.ts
index 965ab857591..f95fe8fc8d6 100644
--- a/src/shared/lib/query/QueryParser.ts
+++ b/src/shared/lib/query/QueryParser.ts
@@ -6,9 +6,9 @@ import {
import {
AndSearchClause,
FILTER_SEPARATOR,
- SearchClause,
NOT_PREFIX,
NotSearchClause,
+ SearchClause,
} from 'shared/components/query/filteredSearch/SearchClause';
import { FilterCheckbox } from 'shared/components/query/filteredSearch/field/CheckboxFilterField';
import { getServerConfig, ServerConfigHelpers } from 'config/config';
@@ -18,6 +18,7 @@ import {
ListPhrase,
Phrase,
} from 'shared/components/query/filteredSearch/Phrase';
+import { toFilterFieldOption } from 'shared/components/query/filteredSearch/field/FilterFieldOption';
export class QueryParser {
/**
@@ -25,7 +26,10 @@ export class QueryParser {
*/
private readonly _searchFilters: CancerTreeSearchFilter[];
- constructor(referenceGenomes: Set) {
+ constructor(referenceGenomes: Set, readPermissions: Set) {
+ console.log('readPermissions');
+ console.log(readPermissions);
+ console.log(readPermissions.size);
this._searchFilters = [
/**
* Example queries:
@@ -38,7 +42,7 @@ export class QueryParser {
input: FilterList,
options: ServerConfigHelpers.skin_example_study_queries(
getServerConfig()!.skin_example_study_queries || ''
- ),
+ ).map(toFilterFieldOption),
},
},
/**
@@ -49,10 +53,25 @@ export class QueryParser {
nodeFields: ['referenceGenome'],
form: {
input: FilterCheckbox,
- options: [...referenceGenomes],
+ options: [...referenceGenomes].map(toFilterFieldOption),
label: 'Reference genome',
},
},
+ /**
+ * Show Authorized Studies
+ */
+ {
+ phrasePrefix: 'authorized',
+ nodeFields: ['readPermission'],
+ form: {
+ input: FilterCheckbox,
+ options: readPermissions.size > 1 ? [
+ { value: 'true', displayValue: 'Authorized' },
+ { value: 'false', displayValue: 'Unauthorized' },
+ ]:[],
+ label: 'Controlled access',
+ },
+ },
];
}
diff --git a/src/shared/lib/query/textQueryUtils.spec.ts b/src/shared/lib/query/textQueryUtils.spec.ts
index b083f5546a5..4ef8b9c150f 100644
--- a/src/shared/lib/query/textQueryUtils.spec.ts
+++ b/src/shared/lib/query/textQueryUtils.spec.ts
@@ -15,7 +15,7 @@ import { QueryParser } from 'shared/lib/query/QueryParser';
import { StringPhrase } from 'shared/components/query/filteredSearch/Phrase';
describe('textQueryUtils', () => {
- const parser = new QueryParser(new Set());
+ const parser = new QueryParser(new Set(), new Set());
const referenceGenomeFields = parser.searchFilters.find(
f => f.phrasePrefix === 'reference-genome'
)!.nodeFields;
From 9211a095b82acaa2332ff941762d8b85c52a36f0 Mon Sep 17 00:00:00 2001
From: Prasanna Kumar Jagannathan <37613906+jagnathan@users.noreply.github.com>
Date: Fri, 21 Apr 2023 13:25:15 -0400
Subject: [PATCH 4/4] Updated logic and refactoring and prettier changes
Only CancerStudy objects from treeData are filtered based on whether the readPermission field has a value. Refactoring: New const created as shownStudiesLengthstring to identify if there is a filter applied or not.
Update Phrase.tsx
conflict resolution fix due to merge
changes for prettier
prettier changes
---
.../components/query/CancerStudySelector.tsx | 52 +++----------------
src/shared/components/query/QueryStore.ts | 18 ++++---
.../query/filteredSearch/Phrase.tsx | 8 ++-
src/shared/lib/query/QueryParser.spec.ts | 2 +-
src/shared/lib/query/QueryParser.ts | 17 +++---
5 files changed, 34 insertions(+), 63 deletions(-)
diff --git a/src/shared/components/query/CancerStudySelector.tsx b/src/shared/components/query/CancerStudySelector.tsx
index 8e2b562fb17..0ff76b86e9f 100644
--- a/src/shared/components/query/CancerStudySelector.tsx
+++ b/src/shared/components/query/CancerStudySelector.tsx
@@ -202,6 +202,10 @@ export default class CancerStudySelector extends React.Component<
const quickSetButtons = this.logic.mainView.quickSelectButtons(
getServerConfig().skin_quick_select_buttons
);
+ const shownStudiesLengthstring =
+ shownStudies.length < this.store.cancerStudies.result.length
+ ? 'matching filter'
+ : '';
return (
{shownAndSelectedStudies.length ===
shownStudies.length
- ? `Deselect all listed studies ${
- shownStudies.length <
- this.store
- .cancerStudies
- .result
- .length
- ? 'matching filter'
- : ''
- } (${
- shownStudies.length
- })`
- : `Select all listed studies ${
- shownStudies.length <
- this.store
- .cancerStudies
- .result
- .length
- ? 'matching filter'
- : ''
- } (${
- shownStudies.length
- })`}
+ ? `Deselect all listed studies ${shownStudiesLengthstring} (${shownStudies.length})`
+ : `Select all listed studies ${shownStudiesLengthstring} (${shownStudies.length})`}
@@ -385,28 +369,8 @@ export default class CancerStudySelector extends React.Component<
shownAndAuthorizedStudies.length &&
shownAndAuthorizedStudies.length >
0
- ? `Deselect all authorized studies ${
- shownStudies.length <
- this.store
- .cancerStudies
- .result
- .length
- ? 'matching filter'
- : ''
- } (${
- shownAndAuthorizedStudies.length
- })`
- : `Select all authorized studies ${
- shownStudies.length <
- this.store
- .cancerStudies
- .result
- .length
- ? 'matching filter'
- : ''
- } (${
- shownAndAuthorizedStudies.length
- })`}
+ ? `Deselect all authorized studies ${shownStudiesLengthstring} (${shownAndAuthorizedStudies.length})`
+ : `Select all authorized studies ${shownStudiesLengthstring} (${shownAndAuthorizedStudies.length})`}
diff --git a/src/shared/components/query/QueryStore.ts b/src/shared/components/query/QueryStore.ts
index 574f8120c7c..25f831730fe 100644
--- a/src/shared/components/query/QueryStore.ts
+++ b/src/shared/components/query/QueryStore.ts
@@ -1236,7 +1236,12 @@ export class QueryStore {
return client
.getAllSamplesOfPatientInStudyUsingGET({ studyId, patientId })
.then(
- samples => ({ studyId, patientId, samples, error: undefined }),
+ samples => ({
+ studyId,
+ patientId,
+ samples,
+ error: undefined,
+ }),
error => ({
studyId,
patientId,
@@ -1480,11 +1485,12 @@ export class QueryStore {
}
@computed get readPermissions(): Set {
- const studies = Array.from(this.treeData.map_node_meta.keys()).filter( s => typeof((s as CancerStudy).readPermission) !== 'undefined' );
- console.log(studies);
- const readPermissions = studies
- .map(n => (!!((n as CancerStudy).readPermission)).toString())
- .filter(n => !!n);
+ const studies = Array.from(this.treeData.map_node_meta.keys()).filter(
+ s => typeof (s as CancerStudy).readPermission !== 'undefined'
+ );
+ const readPermissions = studies.map(n =>
+ (n as CancerStudy).readPermission.toString()
+ );
return new Set(readPermissions);
}
diff --git a/src/shared/components/query/filteredSearch/Phrase.tsx b/src/shared/components/query/filteredSearch/Phrase.tsx
index 58b48c65d1e..010b4096cd9 100644
--- a/src/shared/components/query/filteredSearch/Phrase.tsx
+++ b/src/shared/components/query/filteredSearch/Phrase.tsx
@@ -129,11 +129,9 @@ export class ListPhrase implements Phrase {
public match(study: FullTextSearchNode): boolean {
let anyFieldMatch = false;
for (const fieldName of this.fields) {
- if (!_.has(study, fieldName)) {
- continue;
- }
- const fieldValue = (study as any)[fieldName];
- if (typeof fieldValue !== 'undefined') {
+ let anyPhraseMatch = false;
+ const fieldValue = study[fieldName];
+ if (fieldValue) {
for (const phrase of this._phraseList) {
anyPhraseMatch =
anyPhraseMatch ||
diff --git a/src/shared/lib/query/QueryParser.spec.ts b/src/shared/lib/query/QueryParser.spec.ts
index 1192dac26a1..2e84ec80562 100644
--- a/src/shared/lib/query/QueryParser.spec.ts
+++ b/src/shared/lib/query/QueryParser.spec.ts
@@ -11,7 +11,7 @@ import { QueryParser } from 'shared/lib/query/QueryParser';
import { StringPhrase } from 'shared/components/query/filteredSearch/Phrase';
describe('QueryParser', () => {
- const parser = new QueryParser(new Set(),new Set());
+ const parser = new QueryParser(new Set(), new Set());
const referenceGenomeFields = parser.searchFilters.find(
f => f.phrasePrefix === 'reference-genome'
)!.nodeFields;
diff --git a/src/shared/lib/query/QueryParser.ts b/src/shared/lib/query/QueryParser.ts
index f95fe8fc8d6..d9a317522be 100644
--- a/src/shared/lib/query/QueryParser.ts
+++ b/src/shared/lib/query/QueryParser.ts
@@ -27,9 +27,6 @@ export class QueryParser {
private readonly _searchFilters: CancerTreeSearchFilter[];
constructor(referenceGenomes: Set, readPermissions: Set) {
- console.log('readPermissions');
- console.log(readPermissions);
- console.log(readPermissions.size);
this._searchFilters = [
/**
* Example queries:
@@ -65,10 +62,16 @@ export class QueryParser {
nodeFields: ['readPermission'],
form: {
input: FilterCheckbox,
- options: readPermissions.size > 1 ? [
- { value: 'true', displayValue: 'Authorized' },
- { value: 'false', displayValue: 'Unauthorized' },
- ]:[],
+ options:
+ readPermissions.size > 1
+ ? [
+ { value: 'true', displayValue: 'Authorized' },
+ {
+ value: 'false',
+ displayValue: 'Unauthorized',
+ },
+ ]
+ : [],
label: 'Controlled access',
},
},