Skip to content

Commit

Permalink
Merged branch 'develop' into TASK-4847
Browse files Browse the repository at this point in the history
  • Loading branch information
gpveronica committed Nov 10, 2023
2 parents 42dd9b7 + 45fd56d commit 130f384
Show file tree
Hide file tree
Showing 14 changed files with 650 additions and 81 deletions.
48 changes: 45 additions & 3 deletions cypress/e2e/iva/individual-browser-grid.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,49 @@ context("Individual Browser Grid", () => {
});
});

// MODAL CREATE AUTOCOMPLETE
context("Modal Create Autocomplete", () => {
beforeEach(() => {
// eslint-disable-next-line cypress/unsafe-to-chain-command
cy.get("@container")
.find(`button[data-action="create"]`)
.click();
cy.get("@container")
.find(`div[data-cy="modal-create"]`)
.as("modal-create");
});

it("should autocomplete on searching and selecting one result", () => {
// eslint-disable-next-line cypress/unsafe-to-chain-command
cy.get("@modal-create")
.contains("ul.nav.nav-tabs > li", "Phenotypes")
.click();
cy.get("@modal-create")
.contains("button", "Add Item")
.click();
cy.get("cellbase-search-autocomplete")
.find("select-token-filter .select2-container")
.click();
cy.get("cellbase-search-autocomplete")
.find("input.select2-search__field")
.type("gli");
cy.get("cellbase-search-autocomplete")
.find("span.select2-results li")
.first()
.click();
cy.get("cellbase-search-autocomplete")
.find("span.select2-selection__rendered")
.should("contain.text", "Glioblastoma multiforme");
cy.get("@modal-create")
.find(`input[placeholder="Add phenotype ID......"]`)
.then(element => {
expect(element.val()).equal("HP:0012174");
cy.wrap(element).should("be.disabled");
});

});
});

// MODAL UPDATE
context("Modal Update", () => {
beforeEach(() => {
Expand Down Expand Up @@ -352,7 +395,6 @@ context("Individual Browser Grid", () => {
.find(`tbody tr[data-index="0"]`)
.as("row");
});

});

// 4. Extensions
Expand Down Expand Up @@ -442,7 +484,7 @@ context("Individual Browser Grid", () => {
.find(`td`)
.eq(1)
.trigger("click");

cy.get(`detail-tabs h3`)
.should("contain.text", `Individual ${individual}`);
});
Expand All @@ -452,7 +494,7 @@ context("Individual Browser Grid", () => {
.find("li")
.contains("JSON Data")
.trigger("click");

cy.get("json-viewer")
.should("be.visible");
});
Expand Down
1 change: 1 addition & 0 deletions src/core/clients/cellbase/cellbase-client.js
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ export class CellBaseClient {

const url = this._createRestUrl(host, version, species, category, subcategory, ids, resource, params);
const k = this.generateKey({...params, species, category, subcategory, resource, params});
// FIXME: add try-catch-finally (see opencga-rest-input.js)
return this.restClient.call(url, options, k);
}

Expand Down
14 changes: 14 additions & 0 deletions src/sites/test-app/clients/cellbase-client-mock.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import UtilsNew from "../../../core/utils-new.js";
import {RestResponse} from "../../../core/clients/rest-response";

export class CellBaseClientMock {

Expand Down Expand Up @@ -42,6 +43,19 @@ export class CellBaseClientMock {
return UtilsNew.importJSONFile(`./test-data/${this._config.testDataVersion}/genome-browser-region-17-43102293-43106467-variants.json`);
}
}
}
if (category === "feature") {
if (subcategory === "ontology" && resource === "search") {
switch (params.name) {
case "~/gli/i":
return UtilsNew.importJSONFile(`./test-data/${this._config.testDataVersion}/cellbase-autocomplete-phenotypes.json`)
.then(data => new RestResponse({responses: [{results: data}]}));
default:
break;
}
}


}
// Other request
return Promise.reject(new Error("Not implemented"));
Expand Down
275 changes: 275 additions & 0 deletions src/webcomponents/commons/filters/cellbase-search-autocomplete.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,275 @@
/**
* Copyright 2015-2023 OpenCB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import {LitElement, html} from "lit";
import LitUtils from "../utils/lit-utils.js";
import "../forms/select-token-filter.js";
import UtilsNew from "../../../core/utils-new";

export default class CellbaseSearchAutocomplete extends LitElement {

constructor() {
super();

this.#init();
}

createRenderRoot() {
return this;
}

static get properties() {
return {
value: {
type: Object
},
resource: {
type: String,
},
cellbaseClient: {
type: Object,
},
classes: {
type: String
},
config: {
type: Object
},
searchField: {
type: String,
},
};
}

#init() {
this.RESOURCES = {};
this.endpoint = {};
this.defaultQueryParams = {
limit: 10,
count: false,
};
this.#initResourcesConfig();
this.searchField = "";
}

#initResourcesConfig() {
this.RESOURCES = {
"PHENOTYPE": {
category: "feature",
subcategory: "ontology",
operation: "search",
getSearchField: term => /^[^:\s]+:/.test(term) ? "id": "name",
placeholder: "Start typing a phenotype ID or name...",
queryParams: {},
// Pre-process the results of the query if needed.
},
"DISORDER": {
category: "feature",
subcategory: "ontology",
operation: "search",
getSearchField: term => /^[^:\s]+:/.test(term) ? "id": "name",
placeholder: "Start typing a disorder ID or name ...",
queryParams: {},
// Pre-process the results of the query if needed.
},
"GENE": {
// CAUTION: In feature-filter.js L71, we are autocompleting: xref, ids, gene, geneName.
category: "feature",
subcategory: "gene",
operation: "search",
getSearchField: term => {
// FIXME: Query gene by id is not working! Temporarily returning ALWAYS name
// return term.startsWith("ENSG0") ? "id" : "name";
return term.startsWith("ENSG0") ? "name" : "name";
},
valueField: "name",
placeholder: "Start typing an ensemble gene ID or name...",
queryParams: {
exclude: "transcripts,annotation",
}, // CAUTION: query params depends on the resource/operation (i.e. search, info) used
},
"VARIANT": {},
"PROTEIN": {},
"TRANSCRIPT": {},
"VARIATION": {},
"REGULATORY": {},
};
}

// Filter the fields that can be used to fill the form automatically
#filterResults(results) {
return results.map(item => ({
id: item.id,
name: item.name,
source: item.source,
description: item.description,
text: item.name || item.id,
}));
}

// Templating one option of dropdown
// TODO Vero: Style with default bootstrap
#viewResultStyle() {
return html `
<style>
.result-wrapper {
display: flex;
flex-direction: column;
}
.result-name-wrapper {
display: flex;
align-items: center;
}
.result-source {
display: flex;
align-items: center;
justify-content: center;
margin-right: 8px;
font-size: 10px;
padding: 2px 4px;
color: white;
background-color: #d91c5e;
border: 1px solid #d91c5e;
border-radius: 2px;
}
</style>
`;
}

#viewResult(option) {
return option.name ? $(`
<div class="result-wrapper">
<div class="result-name-wrapper">
<div class="result-source">${option.source}</div>
<div class="result-source-name">${option.name}</div>
</div>
<div class="dropdown-item-extra">${option.id || "-"}</div>
</div>
`) : $(`
<span>${option.text}</span>
`);
}

update(changedProperties) {
if (changedProperties.has("resource")) {
this.resourceObserver();
}

if (changedProperties.has("config")) {
this.configObserver();
}

super.update(changedProperties);
}

resourceObserver() {
if (this.resource) {
this.resource.toUpperCase();
}
this._config = {
...this.getDefaultConfig(),
...this.config,
};
}

configObserver() {
this._config = {
...this.getDefaultConfig(),
...this.config
};
}

onFilterChange(e) {
const value = e.detail.value;
const data = e.detail.data.selected ? e.detail.data : {};
if (!UtilsNew.isEmpty(data)) {
// 1. To remove internal keys from select2 that are not part of the data model.
const internalKeys = ["selected", "text"];
internalKeys.forEach(key => delete data[key]);
// 2. To filter out entries with undefined values
Object.keys(data).forEach(key => typeof data[key] === "undefined" && delete data[key]);
}
// 3. To dispatch event with value autocompleted and data filtered
LitUtils.dispatchCustomEvent(this, "filterChange", value, {
data: data,
});
}

render() {
if (!this.resource) {
return html`Resource not provided`;
}

return html`
<select-token-filter
.keyObject="${this.RESOURCES[this.resource].valueField || "id"}"
.classes="${this.classes}"
.config="${this._config}"
@filterChange="${e => this.onFilterChange(e)}">
</select-token-filter>
`;
}

getDefaultConfig() {
return {
disabled: false,
multiple: false,
freeTag: false,
limit: 10,
maxItems: 0, // No limit set
minimumInputLength: 3, // Only start searching when the user has input 3 or more characters
placeholder: this.RESOURCES[this.resource].placeholder,
filterResults: this.#filterResults,
viewResultStyle: this.#viewResultStyle,
viewResult: this.#viewResult,
viewSelection: result => result[this.searchField],
// TODO Vero: change name to fetch
source: async (params, success, failure) => {
const page = params?.data?.page || 1;
const queryParams = {
...this.defaultQueryParams,
...this.RESOURCES[this.resource].queryParams,
skip: (page - 1) * this._config.limit,
};
if (params?.data?.term) {
// Get the query param field. It will vary with the text typed by the user according to a regex
this.searchField = this.RESOURCES[this.resource].getSearchField(params.data.term);
// Set the query params
const queryParamsField = {
[this.searchField]: `~/${params?.data?.term}/i`,
...queryParams,
};
// Query cellbase with the appropriate resource params
try {
const response = await this.cellbaseClient.get(
this.RESOURCES[this.resource].category,
this.RESOURCES[this.resource].subcategory,
"",
this.RESOURCES[this.resource].operation,
queryParamsField);
success(response);
} catch (error) {
// TODO Vero 20230928: manage failure
console.log(error);
}
}
},
};
}

}

customElements.define("cellbase-search-autocomplete", CellbaseSearchAutocomplete);
Loading

0 comments on commit 130f384

Please sign in to comment.