Skip to content

Commit

Permalink
Merge pull request #929 from opencb/TASK-6095
Browse files Browse the repository at this point in the history
TASK-6095 - Variant Browser Sample Filter interaction issues  with Study Filter
  • Loading branch information
jmjuanes authored Jun 17, 2024
2 parents e3b4749 + 5a0ce26 commit 1b16566
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 62 deletions.
149 changes: 92 additions & 57 deletions src/webcomponents/commons/filters/study-filter.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

import {LitElement, html} from "lit";
import {LitElement, html, nothing} from "lit";
import UtilsNew from "../../../core/utils-new.js";
import LitUtils from "../utils/lit-utils.js";
import "../forms/select-field-filter.js";
Expand All @@ -24,7 +24,6 @@ export default class StudyFilter extends LitElement {

constructor() {
super();

this.#init();
}

Expand All @@ -35,103 +34,139 @@ export default class StudyFilter extends LitElement {
static get properties() {
return {
opencgaSession: {
type: Object
type: Object,
},
value: {
type: String,
},
config: {
type: Object,
},
};
}

#init() {
this._prefix = UtilsNew.randomString(8);
this.operator = ",";
this.selectedStudies = [];
this.differentStudies = [];
this._studies = [];
this._operator = ",";
this._selection = [];
this._config = this.getDefaultConfig();
}

update(changedProperties) {
if (changedProperties.has("opencgaSession")) {
if (this.opencgaSession?.project?.studies?.length) {
this.differentStudies = this.opencgaSession.project.studies.filter(study => this.opencgaSession.study.id !== study.id);
}
this.opencgaSessionObserver();
}

if (changedProperties.has("opencgaSession") || changedProperties.has("value")) {
this.selectedStudies = Array.from(new Set([
this.opencgaSession.study.fqn,
...(this.value || "").split(this.operator).filter(v => !!v),
]));
this.valueObserver();
}
if (changedProperties.has("config")) {
this._config = {
...this.getDefaultConfig(),
...this.config,
};
}

super.update(changedProperties);
}

updated(changedProperties) {
if (changedProperties.has("opencgaSession")) {
$(".selectpicker", this).selectpicker("refresh");
opencgaSessionObserver() {
this._studies = [];
if (this.opencgaSession?.project?.studies?.length) {
// 1. Add current study as the first element and mark it as disabled
this._studies.push({
name: this.opencgaSession.study.name,
id: this.opencgaSession.study.fqn,
selected: true,
disabled: true,
});
// 2. Add other studies to the studies dropdown
this.opencgaSession.project.studies.forEach(study => {
if (study.fqn !== this.opencgaSession.study.fqn) {
this._studies.push({
name: study.name,
id: study.fqn,
});
}
});
}
$(".selectpicker", this).selectpicker("val", this.selectedStudies);
}

filterChange() {
let querystring;
// AND or OR operators
if (this.operator !== "!") {
querystring = [...this.selectedStudies.map(study => `${study}`)].join(this.operator);
} else {
// NOT operator (not visible/not implemented)
querystring = [...this.selectedStudies.map(study => `${this.operator}${study}`)].join(";");
}
LitUtils.dispatchCustomEvent(this, "filterChange", querystring);
valueObserver() {
// 1. Reset the operator value. If the current value does not contain ';', maintain the current selected operator
this._operator = (this.value || "").indexOf(";") > -1 ? ";" : this._operator;
// 2. Reset the selection
this._selection = Array.from(new Set([
this.opencgaSession.study.fqn,
...(this.value || "").split(this._operator).filter(v => !!v),
]));
}

onChangeOperator(e) {
this.operator = e.target.value;
this.filterChange();
onStudyChange(event) {
// 1. Split values returned from select-field-filter and remove empty items
// Note: select-field-filter returns values joined with a comma character
const values = (event.detail.value || "")
.split(",")
.filter(value => !!value);
// 2. Trigger 'filterChange' event with the values joined with the current operator
LitUtils.dispatchCustomEvent(this, "filterChange", values.join(this._operator));
}

onChangeSelectedStudy() {
const selected = $(".selectpicker", this).selectpicker("val");
// Active study is always the first element
this.selectedStudies = [this.opencgaSession.study.fqn, ...selected];
this.requestUpdate();
this.filterChange();
onOperatorChange(event) {
// 1. Save the new operator value
this._operator = event.target.value || ",";
// 2. Trigger the 'filterChange' event
LitUtils.dispatchCustomEvent(this, "filterChange", this._selection.join(this._operator));
}

render() {
// Check Project exists
if (!this.opencgaSession && !this.opencgaSession.project) {
return html`
<div class="guard-page">
<i class="fas fa-lock fa-5x"></i>
<h3>No project available to browse. Please login to continue</h3>
</div>
`;
if (!this.opencgaSession || !this.opencgaSession.project) {
return nothing;
}

return html`
<div id="${this._prefix}DifferentStudies" class="form-group">
<select multiple class="form-control input-sm selectpicker" id="${this._prefix}includeOtherStudy"
@change="${this.onChangeSelectedStudy}">
<option value="${this.opencgaSession.study.fqn}" selected="selected" disabled>${this.opencgaSession.study.name}</option>
${(this.differentStudies || []).map(study => html`
<option value="${study.fqn}">${study.name}</option>
`)}
</select>
<div class="form-group">
<select-field-filter
.data="${this._studies}"
.value="${this._selection}"
.multiple="${true}"
.disabled="${this._config?.disabled}"
@filterChange="${event => this.onStudyChange(event)}">
</select-field-filter>
<fieldset class="switch-toggle-wrapper">
<div class="switch-toggle text-white alert alert-light">
<input id="${this._prefix}orInput" name="pss" type="radio" value="," checked ?disabled="${this.selectedStudies.length < 2}" @change="${this.onChangeOperator}" />
<input
id="${this._prefix}orInput"
name="studyFilterOperator"
type="radio"
value=","
?checked="${this._operator === ","}"
?disabled="${this._selection.length < 2}"
@change="${event => this.onOperatorChange(event)}"
/>
<label for="${this._prefix}orInput" class="rating-label rating-label-or">In any of (OR)</label>
<input id="${this._prefix}andInput" name="pss" type="radio" value=";" ?disabled="${this.selectedStudies.length < 2}" @change="${this.onChangeOperator}"/>
<input
id="${this._prefix}andInput"
name="studyFilterOperator"
type="radio"
value=";"
?checked="${this._operator === ";"}"
?disabled="${this._selection.length < 2}"
@change="${event => this.onOperatorChange(event)}"
/>
<label for="${this._prefix}andInput" class="rating-label rating-label-and">In all (AND)</label>
<a class="btn btn-primary ripple btn-small"></a>
<a class="btn btn-primary btn-small"></a>
</div>
</fieldset>
</div>
`;
}

getDefaultConfig() {
return {
disabled: false,
};
}

}

customElements.define("study-filter", StudyFilter);
22 changes: 17 additions & 5 deletions src/webcomponents/variant/variant-browser-filter.js
Original file line number Diff line number Diff line change
Expand Up @@ -338,26 +338,38 @@ export default class VariantBrowserFilter extends LitElement {
} else {
switch (subsection.id) {
case "study":
const sampleSelected = !!this.preparedQuery?.sample;
content = html`
${sampleSelected ? html`
<div class="alert alert-warning" role="alert">
You can not select multiple studies if at least one sample has been selected in <b>Sample Filter</b>.
</div>
` : nothing}
<study-filter
.value="${this.preparedQuery.study}"
.opencgaSession="${this.opencgaSession}"
.config="${{disabled: sampleSelected}}"
@filterChange="${e => this.onFilterChange("study", e.detail.value)}">
</study-filter>`;
</study-filter>
`;
break;
case "sample":
const multiStudySelected = this.preparedQuery?.study?.split(",")?.length > 1;
const multiStudySelected = this.preparedQuery?.study?.split(/[,;]/)?.length > 1;
content = html`
${multiStudySelected ? html`
<div class="alert alert-warning" role="alert">You cannot select samples with more than one study</div>
<div class="alert alert-warning" role="alert">
You cannot select samples if more than one study has been selected in <b>Study Filter</b>.
</div>
` : nothing}
<catalog-search-autocomplete title=${multiStudySelected ? "You cannot select samples with more than one study" : null}
<catalog-search-autocomplete
title="${multiStudySelected ? "You cannot select samples with more than one study" : ""}"
.value="${this.preparedQuery.sample}"
.opencgaSession="${this.opencgaSession}"
.resource="${"SAMPLE"}"
.config="${{multiple: true, maxItems: 3, disabled: multiStudySelected}}"
@filterChange="${e => this.onFilterChange("sample", e.detail.value)}">
</catalog-search-autocomplete>`;
</catalog-search-autocomplete>
`;
break;
case "cohort":
// FIXME subsection.cohorts must be renamed to subsection.studies
Expand Down

0 comments on commit 1b16566

Please sign in to comment.