diff --git a/cypress/e2e/iva/cohort-browser-grid.cy.js b/cypress/e2e/iva/cohort-browser-grid.cy.js index ce32243cff..fa9d3b4602 100644 --- a/cypress/e2e/iva/cohort-browser-grid.cy.js +++ b/cypress/e2e/iva/cohort-browser-grid.cy.js @@ -214,8 +214,8 @@ context("Cohort Browser Grid", () => { }); }); - it("should hidden columns [Date,Type]",() => { - const columns = ["Cohort ID","Date","Type"]; + it("should hide columns [Cohort ID,Creation Date]",() => { + const columns = ["Cohort ID","Creation Date"]; cy.get(`${browserGrid} thead th`) .as("headerColumns"); @@ -290,49 +290,34 @@ context("Cohort Browser Grid", () => { .find("li") .contains("New Catalog Tab") .click() - .should('be.visible'); + .should("be.visible"); }); }); context("detail tab", () => { it("should render", () => { - cy.get(browserDetail) + cy.get("detail-tabs") .should("be.visible"); }); - it("should display info from the selected row",() => { - BrowserTest.getColumnIndexByHeader("Cohort ID") - cy.get("@indexColumn") - .then((indexColumn) => { - const indexRow = 2 - // eslint-disable-next-line cypress/unsafe-to-chain-command - cy.get(`tbody tr`) - .eq(indexRow) - .click() // select the row - .find("td") - .eq(indexColumn) - .invoke("text") - .as("textRow") - }); - - cy.get("@textRow") - .then((textRow) => { - cy.get("detail-tabs > div.panel") - .invoke("text") - .then((text) => { - const textTab = text.trim().split(" "); - expect(textRow).to.equal(textTab[1].trim()); - }); - }); + it("should display info from the selected row", () => { + const cohort = "FIN"; + cy.get(`tbody tr[data-uniqueid="${cohort}"]`) + .find(`td:first`) + .trigger("click"); + + cy.get(`detail-tabs h3`) + .should("contain.text", `Cohort ${cohort}`); }); it("should display 'JSON Data' Tab", () => { - // eslint-disable-next-line cypress/unsafe-to-chain-command cy.get(`detail-tabs > div.detail-tabs > ul`) .find("li") .contains("JSON Data") - .click() - .should('be.visible'); + .trigger("click"); + + cy.get("json-viewer") + .should("be.visible"); }); }); }); diff --git a/cypress/e2e/iva/disease-panel-browser-grid.cy.js b/cypress/e2e/iva/disease-panel-browser-grid.cy.js index 413f56351c..51ed666d74 100644 --- a/cypress/e2e/iva/disease-panel-browser-grid.cy.js +++ b/cypress/e2e/iva/disease-panel-browser-grid.cy.js @@ -210,7 +210,7 @@ context("Disease Panel Browser Grid", () => { }); }); - it("should hidden columns [Disorders,Source,Extra column]",() => { + it("should hide columns [Disorders,Source,Extra column]",() => { const columns = ["Disorders","Source","Extra column"]; cy.get("disease-panel-grid thead th") .as("headerColumns"); @@ -345,40 +345,23 @@ context("Disease Panel Browser Grid", () => { }); it("should display info from the selected row",() => { - BrowserTest.getColumnIndexByHeader("Panel ID"); - cy.get("@indexColumn") - .then(indexColumn => { - const indexRow = 2; - // eslint-disable-next-line cypress/unsafe-to-chain-command - cy.get("tbody tr") - .eq(indexRow) - .click() // select the row - .find("td") - .eq(indexColumn) - .invoke("text") - .as("textRow"); - }); - - cy.get("@textRow") - .then((textRow) => { - const textRowTrimmed = textRow.trim(); - cy.get("detail-tabs > div.panel") - .invoke("text") - .then((text) => { - const textTab = text.trim().split(" "); - expect(textRowTrimmed).to.equal(textTab[2].trim()); - }); - }); + const panel = "Familial_non_syndromic_congenital_heart_disease-PanelAppId-212"; + cy.get(`tbody tr[data-uniqueid="${panel}"]`) + .find(`td:first`) + .trigger("click"); + + cy.get(`detail-tabs h3`) + .should("contain.text", `Disease Panel ${panel}`); }); it("should display 'JSON Data' Tab", () => { - // eslint-disable-next-line cypress/unsafe-to-chain-command cy.get("@detail") .find("li") .contains("JSON Data") - .click() + .trigger("click"); + + cy.get("json-viewer") .should("be.visible"); }); }); - }); diff --git a/cypress/e2e/iva/family-browser-grid.cy.js b/cypress/e2e/iva/family-browser-grid.cy.js index f09a376eb7..bd355297b0 100644 --- a/cypress/e2e/iva/family-browser-grid.cy.js +++ b/cypress/e2e/iva/family-browser-grid.cy.js @@ -211,7 +211,7 @@ context("Family Browser Grid", () => { }); }); - it("should hidden columns [Case ID,Phenotypes]",() => { + it("should hide columns [Case ID,Phenotypes]",() => { const columns = ["Case ID","Phenotypes"]; cy.get(`${browserGrid} thead th`) .as("headerColumns"); @@ -298,44 +298,30 @@ context("Family Browser Grid", () => { }); }); - context("detail tab",{tags: ["@shortTask","@testTask"]}, () => { + context("detail tab", {tags: ["@shortTask","@testTask"]}, () => { it("should render", () => { cy.get(browserDetail) .should("be.visible"); }); - it("should display info from the selected row",() => { - BrowserTest.getColumnIndexByHeader("Family"); - cy.get("@indexColumn") - .then((indexColumn) => { - const indexRow = 1; - // eslint-disable-next-line cypress/unsafe-to-chain-command - cy.get("tbody tr") - .eq(indexRow) - .click() // select the row - .find("td") - .eq(indexColumn) - .invoke("text") - .as("textRow"); - }); - - cy.get("@textRow") - .then((textRow) => { - cy.get("detail-tabs > div.panel") - .invoke("text") - .then((text) => { - const textTab = text.trim().split(" "); - expect(textRow).to.equal(textTab[1].trim()); - }); - }); + it("should display info from the selected row", () => { + const family = "919278"; + cy.get(`tbody tr[data-uniqueid="${family}"]`) + .find(`td`) + .eq(1) + .trigger("click"); + + cy.get(`detail-tabs h3`) + .should("contain.text", `Family ${family}`); }); it("should display 'JSON Data' Tab", () => { - // eslint-disable-next-line cypress/unsafe-to-chain-command cy.get("detail-tabs > div.detail-tabs > ul") .find("li") .contains("JSON Data") - .click() + .trigger("click"); + + cy.get("json-viewer") .should("be.visible"); }); }); diff --git a/cypress/e2e/iva/file-browser-grid.cy.js b/cypress/e2e/iva/file-browser-grid.cy.js index 0588932068..a5e8a2140e 100644 --- a/cypress/e2e/iva/file-browser-grid.cy.js +++ b/cypress/e2e/iva/file-browser-grid.cy.js @@ -22,7 +22,7 @@ context("File Browser Grid", () => { const browserDetail = "file-detail"; beforeEach(() => { - cy.visit("#file-browser-grid") + cy.visit("#file-browser-grid"); cy.waitUntil(() => { return cy.get(browserGrid) .should("be.visible"); @@ -151,8 +151,8 @@ context("File Browser Grid", () => { }); }); - it("should hidden columns [Directory,Format,Bioformat]",() => { - const columns = ["Directory","Format","Bioformat"]; + it("should hide columns [Name,Format]",() => { + const columns = ["Name","Format"]; cy.get(`${browserGrid} thead th`) .as("headerColumns"); @@ -229,7 +229,7 @@ context("File Browser Grid", () => { it("should display 'Extra Column' column", () => { cy.get("thead th") .contains("Extra column") - .should('be.visible'); + .should("be.visible"); }); it("should display 'New Catalog Tab' Tab", () => { @@ -238,50 +238,34 @@ context("File Browser Grid", () => { .find("li") .contains("New Catalog Tab") .click() - .should('be.visible'); + .should("be.visible"); }); }); - context("detail tab", () => { it("should render", () => { cy.get(browserDetail) .should("be.visible"); }); - it("should display info from the selected row",() => { - BrowserTest.getColumnIndexByHeader("Name") - cy.get("@indexColumn") - .then((indexColumn) => { - const indexRow = 2 - // eslint-disable-next-line cypress/unsafe-to-chain-command - cy.get(`tbody tr`) - .eq(indexRow) - .click() // select the row - .find("td") - .eq(indexColumn) - .invoke("text") - .as("textRow") - }); - - cy.get("@textRow") - .then((textRow) => { - cy.get("detail-tabs > div.panel") - .invoke("text") - .then((text) => { - const textTab = text.split(":"); - expect(textRow).to.equal(textTab[1].trim()); - }); - }); + it("should display info from the selected row", () => { + const file = "chinese:HG007_GRCh38_1_22_v4.2.1_benchmark.vcf.gz"; + cy.get(`tbody tr[data-uniqueid="${file}"]`) + .find(`td:first`) + .trigger("click"); + + cy.get(`detail-tabs h3`) + .should("contain.text", `File ${file}`); }); it("should display 'Preview' Tab", () => { - // eslint-disable-next-line cypress/unsafe-to-chain-command cy.get(`detail-tabs > div.detail-tabs > ul`) .find("li") .contains("Preview") - .click() - .should('be.visible'); + .trigger("click"); + + cy.get("file-preview") + .should("be.visible"); }); }); }); diff --git a/cypress/e2e/iva/individual-browser-grid.cy.js b/cypress/e2e/iva/individual-browser-grid.cy.js index 320ce280e0..ff21ff3cf1 100644 --- a/cypress/e2e/iva/individual-browser-grid.cy.js +++ b/cypress/e2e/iva/individual-browser-grid.cy.js @@ -214,6 +214,7 @@ context("Individual Browser Grid", () => { }); }); + // MODAL SETTINGS context("Modal Setting", () => { it("should move modal setting", () => { @@ -254,7 +255,7 @@ context("Individual Browser Grid", () => { }); }); - it("should hidden columns [Disorders,Case ID,Ethnicity]",() => { + it("should hide columns [Disorders,Case ID,Ethnicity]",() => { const columns = ["Disorders","Case ID","Ethnicity"]; cy.get(`${browserGrid} thead th`) .as("headerColumns"); @@ -332,6 +333,7 @@ context("Individual Browser Grid", () => { }); }); + // 2. Data completeness in the grid context("data completeness", () => { let creationDateIndex = null; @@ -386,6 +388,7 @@ context("Individual Browser Grid", () => { }); + // 3. Data format context("data format", () => { beforeEach(() => { cy.get("@grid") @@ -394,6 +397,7 @@ context("Individual Browser Grid", () => { }); }); + // 4. Extensions context("extension", () => { it("should display 'Extra Column' column", () => { cy.get("thead th") @@ -402,10 +406,67 @@ context("Individual Browser Grid", () => { }); }); + // 5. Annotations + context("annotations", () => { + const annotations = [ + { + title: "Cardiology Tests", + position: 6, + variables: ["ecg_test", "echo_test"] + }, + { + title: "Risk Assessment", + position: 7, + variables: ["date_risk_assessment"] + } + ]; + + beforeEach(() => { + cy.get("@grid") + .find("table") + .as("table"); + }); + + // 5.1 Render each varSet title as column header + it("should render enabled varSet column titles", () => { + cy.wrap(annotations).each(annotation => { + cy.get("@table") + .contains("thead tr th", annotation.title); + }); + }); + // 5.2 Render each varSet column at the position configured in position + it("should have varSet position configured equal to the index of the corresponding column", () => { + cy.wrap(annotations).each(annotation => { + cy.get("@table") + .contains("thead tr th", annotation.title) + .invoke("index") + .then(i => { + // 1. Test index column configured equals column index rendered + expect(i-1).equal(annotation.position); + }); + }); + }); + // 5.3 Render variables correctly + it("should render annotations configured", () => { + cy.wrap(annotations).each(annotation => { + cy.get("@table") + .contains("thead tr th", annotation.title) + .invoke("index") + .then(i => { + // 1. Test index column configured equals column index rendered + cy.get("tbody tr") + .first() + .find("td") + .eq(i) + .should("contain.text", annotation.variables[0]); + }); + }); + }); + }); }); + // DETAIL TABS context("Detail", () => { - beforeEach(() => { cy.get("@container") .find(`div[data-cy="ib-detail"]`) @@ -417,40 +478,25 @@ context("Individual Browser Grid", () => { .should("be.visible"); }); - it("should display info from the selected row",() => { - BrowserTest.getColumnIndexByHeader("Individual"); - cy.get("@indexColumn") - .then(indexColumn => { - const indexRow = 2; - // eslint-disable-next-line cypress/unsafe-to-chain-command - cy.get(`tbody tr`) - .eq(indexRow) - .click() // select the row - .find("td") - .eq(indexColumn) - .invoke("text") - .as("textRow"); - }); + it("should display info from the selected row", () => { + const individual = "NA12877"; + cy.get(`tbody tr[data-uniqueid="${individual}"]`) + .find(`td`) + .eq(1) + .trigger("click"); - cy.get("@textRow") - .then((textRow) => { - cy.get("detail-tabs > div.panel") - .invoke("text") - .then((text) => { - const textTab = text.trim().split(" "); - expect(textRow).to.equal(textTab[1].trim()); - }); - }); + cy.get(`detail-tabs h3`) + .should("contain.text", `Individual ${individual}`); }); it("should display 'JSON Data' Tab", () => { - // eslint-disable-next-line cypress/unsafe-to-chain-command cy.get("@detail") .find("li") .contains("JSON Data") - .click() - .should('be.visible'); + .trigger("click"); + + cy.get("json-viewer") + .should("be.visible"); }); }); - }); diff --git a/cypress/e2e/iva/job-browser-grid.cy.js b/cypress/e2e/iva/job-browser-grid.cy.js index ff5858f123..a99bfcad91 100644 --- a/cypress/e2e/iva/job-browser-grid.cy.js +++ b/cypress/e2e/iva/job-browser-grid.cy.js @@ -151,7 +151,7 @@ context("Job Browser Grid", () => { }); }); - it("should hidden columns [Status,Output Files,Runtime]",() => { + it("should hide columns [Status,Output Files,Runtime]",() => { const columns = ["Status","Output Files","Runtime"]; cy.get(`${browserGrid} thead th`) .as("headerColumns"); @@ -243,44 +243,30 @@ context("Job Browser Grid", () => { }); }); - context("detail tab",{tags: "@shortTask"}, () => { + context("detail tabs", {tags: "@shortTask"}, () => { it("should render", () => { cy.get(browserDetail) .should("be.visible"); }); - it("should display info from the selected row",() => { - BrowserTest.getColumnIndexByHeader("Job ID"); - cy.get("@indexColumn") - .then((indexColumn) => { - const indexRow = 2; - // eslint-disable-next-line cypress/unsafe-to-chain-command - cy.get(`tbody tr`) - .eq(indexRow) - .click() // select the row - .find("td") - .eq(indexColumn) - .invoke("text") - .as("textRow"); - }); - - cy.get("@textRow") - .then((textRow) => { - cy.get("detail-tabs > div.panel") - .invoke("text") - .then((text) => { - const textTab = text.trim().split(" "); - expect(textRow).to.equal(textTab[1].trim()); - }); - }); + it("should display info from the selected row", () => { + const job = "pedigree-graph-init.20230530144950.FWjipG"; + cy.get(`tbody tr[data-uniqueid="${job}"]`) + .find(`td`) + .eq(1) + .trigger("click"); + + cy.get(`detail-tabs h3`) + .should("contain.text", `Job ${job}`); }); it("should display 'Logs' Tab", () => { - // eslint-disable-next-line cypress/unsafe-to-chain-command cy.get(`detail-tabs > div.detail-tabs > ul`) .find("li") .contains("Logs") - .click() + .trigger("click"); + + cy.get("job-detail-log") .should("be.visible"); }); }); diff --git a/cypress/e2e/iva/sample-browser-grid.cy.js b/cypress/e2e/iva/sample-browser-grid.cy.js index 8b5d5e4044..8d2af424d8 100644 --- a/cypress/e2e/iva/sample-browser-grid.cy.js +++ b/cypress/e2e/iva/sample-browser-grid.cy.js @@ -214,7 +214,7 @@ context("Sample Browser Grid", () => { }); }); - it("should hidden columns [Collection Method,Preparation Method]",() => { + it("should hide columns [Collection Method,Preparation Method]",() => { const columns = ["Collection Method", "Preparation Method"]; cy.get(`${browserGrid} thead th`) .as("headerColumns"); @@ -300,24 +300,25 @@ context("Sample Browser Grid", () => { it("should move modal setting", () => { cy.get("button[data-action='settings']") - .click() + .click(); BrowserTest.getElementByComponent({ selector: 'sample-grid opencb-grid-toolbar', tag:'div', elementId: 'SettingModal' - }).as("settingModal") + }).as("settingModal"); cy.get("@settingModal") .then(($modal) => { const startPosition = $modal.offset(); cy.log("start Position:", startPosition); // Drag the modal to a new position using Cypress's drag command + // eslint-disable-next-line cypress/unsafe-to-chain-command cy.get("@settingModal") .find('.modal-header') .trigger('mousedown', { which: 1 }) // Trigger mouse down event .trigger('mousemove', { clientX: 100, clientY: 100 }) // Move the mouse - .trigger('mouseup') // Release the mouse + .trigger('mouseup'); // Release the mouse // Get the final position of the modal cy.get(`@settingModal`) @@ -359,7 +360,7 @@ context("Sample Browser Grid", () => { .then(i => { creationDateIndex = i + 1; cy.get("@body") - .find(`td:nth-child(${i})`) + .find(`td:nth-child(${creationDateIndex})`) .each(td => { cy.wrap(td) .should("not.be.empty"); @@ -371,7 +372,7 @@ context("Sample Browser Grid", () => { cy.get("@body") .find(`td:nth-child(${creationDateIndex})`) .each(td => { - const regExp = /^(([0-9])|([0-2][0-9])|([3][0-1])) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) \d{4}$/ + const regExp = /^(([0-9])|([0-2][0-9])|([3][0-1])) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) \d{4}$/; expect(td.text()).to.match(regExp); }); }); @@ -400,14 +401,12 @@ context("Sample Browser Grid", () => { it("should display 'Extra Column' column", () => { cy.get("thead th") .contains("Extra column") - .should('be.visible') - }) - }) - + .should("be.visible"); + }); + }); }); context("Detail", () => { - beforeEach(() => { cy.get("@container") .find(`div[data-cy="sb-detail"]`) @@ -419,40 +418,24 @@ context("Sample Browser Grid", () => { .should("be.visible"); }); - it("should display info from the selected row",() => { - BrowserTest.getColumnIndexByHeader("Sample ID") - cy.get("@indexColumn") - .then(indexColumn => { - const indexRow = 2 - // eslint-disable-next-line cypress/unsafe-to-chain-command - cy.get(`tbody tr`) - .eq(indexRow) - .click() // select the row - .find("td") - .eq(indexColumn) - .invoke("text") - .as("textRow") - }); - - cy.get("@textRow") - .then((textRow) => { - cy.get("detail-tabs > div.panel") - .invoke("text") - .then((text) => { - const textTab = text.trim().split(" "); - expect(textRow).to.equal(textTab[1].trim()); - }); - }); + it("should display info from the selected row", () => { + const sample = "NA12889"; + cy.get(`tbody tr[data-uniqueid="${sample}"]`) + .find(`td:first`) + .trigger("click"); + + cy.get(`detail-tabs h3`) + .should("contain.text", `Sample ${sample}`); }); it("should display 'JSON Data' Tab", () => { - // eslint-disable-next-line cypress/unsafe-to-chain-command cy.get("@detail") .find("li") .contains("JSON Data") - .click() - .should('be.visible'); + .trigger("click"); + + cy.get("json-viewer") + .should("be.visible"); }); }); - }); diff --git a/cypress/e2e/iva/variant-browser-grid-cancer.cy.js b/cypress/e2e/iva/variant-browser-grid-cancer.cy.js index bf53596132..d1feb85e3e 100644 --- a/cypress/e2e/iva/variant-browser-grid-cancer.cy.js +++ b/cypress/e2e/iva/variant-browser-grid-cancer.cy.js @@ -69,7 +69,7 @@ context("Variant Browser Grid Cancer", () => { }); }); - it("should hidden columns [Variant,Gene,Type]",() => { + it("should hide columns [Variant,Gene,Type]",() => { const columns = ["Variant","Gene","Type"]; cy.get("variant-browser-grid thead th") .as("headerColumns"); @@ -94,13 +94,11 @@ context("Variant Browser Grid Cancer", () => { tag:"div", elementId: "SettingModal" }).as("settingModal"); + cy.get("@settingModal") .contains("button", "OK") .click(); - cy.get("@headerColumns") - .should("not.exist"); - cy.get("@headerColumns") - .should("exist"); + cy.get("@headerColumns") .should($header => { const _columns = Array.from($header, th => th.textContent?.trim()); diff --git a/cypress/e2e/iva/variant-browser-grid-germline.cy.js b/cypress/e2e/iva/variant-browser-grid-germline.cy.js index 63da1634a6..fd586c02d4 100644 --- a/cypress/e2e/iva/variant-browser-grid-germline.cy.js +++ b/cypress/e2e/iva/variant-browser-grid-germline.cy.js @@ -69,7 +69,7 @@ context("Variant Browser Grid Germline", () => { }); }); - it("should hidden columns [Type,Consequence Type,Gene]",() => { + it("should hide columns [Type,Consequence Type,Gene]",() => { const columns = ["Type","Consequence Type","Gene"]; cy.get("variant-browser-grid thead th") .as("headerColumns"); @@ -97,10 +97,6 @@ context("Variant Browser Grid Germline", () => { cy.get("@settingModal") .contains("button", "OK") .click(); - cy.get("@headerColumns") - .should("not.exist"); - cy.get("@headerColumns") - .should("exist"); cy.get("@headerColumns") .then($header => { const _columns = Array.from($header, th => th.textContent.trim()); diff --git a/cypress/e2e/iva/variant-interpreter-grid-cancer-cnv.cy.js b/cypress/e2e/iva/variant-interpreter-grid-cancer-cnv.cy.js index 5f641ec015..69a0d24e5c 100644 --- a/cypress/e2e/iva/variant-interpreter-grid-cancer-cnv.cy.js +++ b/cypress/e2e/iva/variant-interpreter-grid-cancer-cnv.cy.js @@ -64,7 +64,7 @@ context("Variant Interpreter Grid Cancer CNV", () => { }); }); - it("should hidden columns [Type,Role in Cancer,Cohort Stats]",() => { + it("should hide columns [Type,Role in Cancer,Cohort Stats]",() => { const columns = ["Type","Role in Cancer","Cohort Stats"]; cy.get("variant-interpreter-grid thead th").as("headerColumns"); columns.forEach(col => { diff --git a/cypress/e2e/iva/variant-interpreter-grid-cancer.cy.js b/cypress/e2e/iva/variant-interpreter-grid-cancer.cy.js index fcacff7031..03ba4ecceb 100644 --- a/cypress/e2e/iva/variant-interpreter-grid-cancer.cy.js +++ b/cypress/e2e/iva/variant-interpreter-grid-cancer.cy.js @@ -68,7 +68,7 @@ context("Variant Interpreter Grid Cancer", () => { }); }); - it("should hidden columns [Type,Consequence Type,Gene]",() => { + it("should hide columns [Type,Consequence Type,Gene]",() => { const columns = ["Consequence Type","Gene"]; cy.get("variant-interpreter-grid thead th") .as("headerColumns"); diff --git a/cypress/e2e/iva/variant-interpreter-grid-germline.cy.js b/cypress/e2e/iva/variant-interpreter-grid-germline.cy.js index 8ff4d37102..692c424bbf 100644 --- a/cypress/e2e/iva/variant-interpreter-grid-germline.cy.js +++ b/cypress/e2e/iva/variant-interpreter-grid-germline.cy.js @@ -70,7 +70,7 @@ context("Variant Interpreter Grid Germiline", () => { }); }); - it("should hidden columns [Type,Consequence Type,Gene]",() => { + it("should hide columns [Type,Consequence Type,Gene]",() => { const columns = ["Type","Consequence Type","Gene"]; cy.get("variant-interpreter-grid thead th") .as("headerColumns"); @@ -98,10 +98,6 @@ context("Variant Interpreter Grid Germiline", () => { cy.get("@settingModal") .contains("button", "OK") .click(); - cy.get("@headerColumns") - .should("not.exist"); - cy.get("@headerColumns") - .should("exist"); cy.get("@headerColumns") .should($header => { const _columns = Array.from($header, th => th.textContent.trim()); diff --git a/src/core/bioinfo/bioinfo-utils.js b/src/core/bioinfo/bioinfo-utils.js index 4727480824..f88f40fcab 100644 --- a/src/core/bioinfo/bioinfo-utils.js +++ b/src/core/bioinfo/bioinfo-utils.js @@ -230,6 +230,29 @@ export default class BioinfoUtils { return `https://panelapp.genomicsengland.co.uk/panels/${panelAppId}/`; } + static getOntologyLink(ontologyTermId) { + if (ontologyTermId.includes(":")) { + const [source, id] = ontologyTermId?.split(":"); + switch (source?.toUpperCase()) { + case "HP": + return this.getHpoLink(ontologyTermId); + case "SO": + return this.getSequenceOntologyLink(ontologyTermId); + case "OMIM": + return this.getOmimOntologyLink(id); + case "ORPHA": + return this.getOrphanetLink(id); + case "MONDO": + // MONDO ontology does not have a specific URL + return this.getOboLink(ontologyTermId); + default: + return ontologyTermId; + } + } else { + return ontologyTermId; + } + } + static getOboLink(ontologyId) { const ontologyShort = ontologyId.replace(":", "_"); return `http://purl.obolibrary.org/obo/${ontologyShort}`; @@ -243,4 +266,11 @@ export default class BioinfoUtils { return `http://www.sequenceontology.org/browser/current_svn/term/${soTerm}`; } + static getOmimOntologyLink(soTerm) { + return `https://omim.org/entry/${soTerm}"`; + } + + static getOrphanetLink(orphaId) { + return `https://www.orpha.net/consor/cgi-bin/OC_Exp.php?lng=EN&Expert=${orphaId}`; + } } diff --git a/src/core/clients/opencga/opencga-catalog-utils.js b/src/core/clients/opencga/opencga-catalog-utils.js index b70a341e61..5d3ae68994 100644 --- a/src/core/clients/opencga/opencga-catalog-utils.js +++ b/src/core/clients/opencga/opencga-catalog-utils.js @@ -135,16 +135,22 @@ export default class OpencgaCatalogUtils { } // Update grid configuration of the specified browser - static updateGridConfig(opencgaSession, browserName, newGridConfig) { - const newConfig = { - ...opencgaSession.user.configs?.IVA, - [browserName]: { - ...opencgaSession.user.configs?.IVA[browserName], - grid: newGridConfig, - }, + static updateGridConfig(id = "IVA", opencgaSession, toolId, gridConfig) { + const userGridSettings = { + settings: { + ...opencgaSession.user.configs?.[id]?.settings, + [toolId]: { + ...opencgaSession.user.configs?.[id][toolId], + grid: gridConfig, + }, + } + }; + const newGridConfig = { + ...opencgaSession.user.configs?.[id], + ...userGridSettings }; - return opencgaSession.opencgaClient.updateUserConfigs(newConfig) + return opencgaSession.opencgaClient.updateUserConfig(id, newGridConfig) .then(response => { // Update user configuration in opencgaSession object // eslint-disable-next-line no-param-reassign diff --git a/src/core/clients/opencga/opencga-client.js b/src/core/clients/opencga/opencga-client.js index a3ac9c9962..9e4b5416fc 100644 --- a/src/core/clients/opencga/opencga-client.js +++ b/src/core/clients/opencga/opencga-client.js @@ -32,6 +32,7 @@ import User from "./api/User.js"; import Variant from "./api/Variant.js"; import VariantOperation from "./api/VariantOperation.js"; import {CellBaseClient} from "../cellbase/cellbase-client"; +import UtilsNew from "../../utils-new"; export class OpenCGAClient { @@ -170,14 +171,6 @@ export class OpenCGAClient { return this.clients.get("meta"); } - admin() { - if (!this.clients.has("admin")) { - this.clients.set("admin", new Admin(this._config)); - } - return this.clients.get("admin"); - } - - // Analysis alignments() { if (!this.clients.has("alignments")) { this.clients.set("alignments", new Alignment(this._config)); @@ -213,6 +206,13 @@ export class OpenCGAClient { return this.clients.get("ga4gh"); } + admin() { + if (!this.clients.has("admin")) { + this.clients.set("admin", new Admin(this._config)); + } + return this.clients.get("admin"); + } + /* * Convenient function to create a client from the entity name, this is case insensitive. */ @@ -250,6 +250,8 @@ export class OpenCGAClient { return this.clinical(); case "META": return this.meta(); + case "ADMIN": + return this.admin(); default: throw new Error("Resource not recognized"); } @@ -257,7 +259,8 @@ export class OpenCGAClient { async login(userId, password) { try { - const restResponse = await this.users().login({user: userId, password: password}); + const restResponse = await this.users() + .login({user: userId, password: password}); // TODO remove userId and token from config and move it to session this._config.userId = userId; @@ -265,10 +268,9 @@ export class OpenCGAClient { // Check if cookies being used if (this._config.cookies.active) { - this.setCookies(userId, this._config.token); + this.#setCookies(userId, this._config.token); } this.clients.forEach(client => client.setToken(this._config.token)); - // this.createSession(); return restResponse; } catch (restResponse) { console.error(restResponse); @@ -276,33 +278,24 @@ export class OpenCGAClient { } } - setCookies(userId, token) { - if (userId && token) { - // eslint-disable-next-line no-undef - Cookies.set(this._config.cookies.prefix + "_userId", userId, {secure: true}); - // eslint-disable-next-line no-undef - Cookies.set(this._config.cookies.prefix + "_sid", this._config.token, {secure: true}); - } else { - // eslint-disable-next-line no-undef - Cookies.expire(this._config.cookies.prefix + "_userId"); - // eslint-disable-next-line no-undef - Cookies.expire(this._config.cookies.prefix + "_sid"); - } - } - - // refresh only works if cookies are enabled + // Refresh only works if cookies are enabled async refresh() { const userId = this._config.userId; - const response = await this.users().login({refreshToken: this._config.token}); + const response = await this.users() + .login({refreshToken: this._config.token}); this._config.token = response.getResult(0).token; - await this.updateUserConfigs({ - lastAccess: new Date().getTime() - }); + // Nacho (22/10/2023): We should not update 'lastAccess' date when token is updated automatically + // await this.updateUserConfig({ + // lastAccess: new Date().getTime() + // }); + // Update cookie with the new token if (this._config.cookies.active) { - this.setCookies(userId, this._config.token); + this.#setCookies(userId, this._config.token); } + + // Update existing clients with the new token this.clients.forEach(client => client.setToken(this._config.token)); return response; } @@ -315,11 +308,25 @@ export class OpenCGAClient { // Remove cookies if (this._config.cookies.active) { - this.setCookies(); + this.#setCookies(); } return Promise.resolve(); } + #setCookies(userId, token) { + if (userId && token) { + // eslint-disable-next-line no-undef + Cookies.set(this._config.cookies.prefix + "_userId", userId, {secure: true}); + // eslint-disable-next-line no-undef + Cookies.set(this._config.cookies.prefix + "_sid", this._config.token, {secure: true}); + } else { + // eslint-disable-next-line no-undef + Cookies.expire(this._config.cookies.prefix + "_userId"); + // eslint-disable-next-line no-undef + Cookies.expire(this._config.cookies.prefix + "_sid"); + } + } + // Creates and return an anonymous session object, it is a sync function. createAnonymousSession() { const opencgaSession = {}; @@ -342,14 +349,12 @@ export class OpenCGAClient { * opencgaClient object itself. * @returns {Promise} */ - // TODO urgent refactor createSession() { const _this = this; return new Promise((resolve, reject) => { // check that a session exists // TODO should we check the session has not expired? if (_this._config.token) { - // _this._notifySessionEvent("signingIn", "Fetching User data"); _this.users().info(_this._config.userId) .then(async response => { console.log("Creating session"); @@ -366,8 +371,7 @@ export class OpenCGAClient { // serverVersion: _this._config.serverVersion, }; session.opencgaClient = _this; - // _this._notifySessionEvent("signingIn", "Updating User config"); - const userConfig = await this.updateUserConfigs({ + const userConfig = await this.updateUserConfig("IVA", { ...session.user.configs.IVA, lastAccess: new Date().getTime() }); @@ -382,7 +386,6 @@ export class OpenCGAClient { // Fetch authorised Projects and Studies console.log("Fetching projects and studies"); - // _this._notifySessionEvent("signingIn", "Fetching Projects and Studies"); _this.projects() .search({limit: 100}) .then(async function (response) { @@ -401,7 +404,6 @@ export class OpenCGAClient { for (const study of project.studies) { // We need to store the user permission for the all the studies fetched console.log("Fetching user permissions"); - // _this._notifySessionEvent("signingIn", "Fetching User permissions"); let acl = null; const admins = study.groups.find(g => g.id === "@admins"); @@ -414,7 +416,6 @@ export class OpenCGAClient { // Fetch all the cohort console.log("Fetching cohorts"); - // _this._notifySessionEvent("signingIn", "Fetching Cohorts"); const cohortsResponse = await _this.cohorts() .search({study: study.fqn, exclude: "samples", limit: 100}); study.cohorts = cohortsResponse.responses[0].results @@ -456,7 +457,7 @@ export class OpenCGAClient { version: project.cellbase.version.startsWith("v") ? project.cellbase.version : "v" + project.cellbase.version, species: "hsapiens", }); - // https://ws.zettagenomics.com/cellbase/webservices/rest/v5.1/meta/hsapiens/dataReleases + // Call to: https://ws.zettagenomics.com/cellbase/webservices/rest/v5.1/meta/hsapiens/dataReleases const promise = cellbaseClient.getMeta("dataReleases"); cellbaseSourcesPromises.push(promise); indexesMap.push(i); @@ -477,7 +478,6 @@ export class OpenCGAClient { // Fetch the Disease Panels for each Study console.log("Fetching disease panels"); - // _this._notifySessionEvent("signingIn", "Fetching Disease Panels"); const panelPromises = []; for (const study of studies) { const promise = _this.panels().search({ @@ -517,29 +517,6 @@ export class OpenCGAClient { }); } - // async _fetchCellBaseSources(project) { - // if (project.cellbase?.url && project.cellbase.version !== "v5" && project.cellbase.version !== "v4") { - // const cellbaseClient = new CellBaseClient({ - // host: project.cellbase.url, - // version: project.cellbase.version.startsWith("v") ? project.cellbase.version : "v" + project.cellbase.version, - // species: "hsapiens", - // }); - // console.log(project.cellbase) - // // https://ws.zettagenomics.com/cellbase/webservices/rest/v5.1/meta/hsapiens/dataReleases - // return cellbaseClient.getMeta("dataReleases"); - // } - // } - - _notifySessionEvent(id, message) { - globalThis.dispatchEvent(new CustomEvent(id, - { - detail: { - value: message - } - } - )); - } - getConfig() { return this._config; } @@ -557,22 +534,18 @@ export class OpenCGAClient { return this.users().configs(this._config.userId, "IVA"); } - updateUserConfigs(data) { - // TODO remove this nasty nested bug fix - if (data?.IVA) { - delete data.IVA; - } - const userIvaConfig = this.users().updateConfigs(this._config.userId, { - id: "IVA", - configuration: { - ...data - } - }); - // Update opencgaSession object - // if (opencgaSession?.user?.configs) { - // opencgaSession.user.configs.IVA = userIvaConfig.responses[0].results[0]; - // } - return userIvaConfig; + // Nacho (22/10/2023): This method needs a config ID and VALUE now, + // different sites or apps may need to store configurations. + updateUserConfig(id, newConfig) { + return this.users() + .updateConfigs(this._config.userId, { + id: id, + configuration: { + ...newConfig, + date: UtilsNew.getDatetime(), + version: "v2" + } + }); } } diff --git a/src/sites/api/api-app.js b/src/sites/api/api-app.js index 9d30e7ef64..a1c4e8bb15 100644 --- a/src/sites/api/api-app.js +++ b/src/sites/api/api-app.js @@ -260,9 +260,9 @@ class ApiApp extends LitElement { console.error(e); this.notificationManager.error("Error creating session", e.message); }).finally(() => { - this.signingIn = false; - this.requestUpdate(); - }); + this.signingIn = false; + this.requestUpdate(); + }); } // TODO turn this into a Promise @@ -343,35 +343,6 @@ class ApiApp extends LitElement { window.clearInterval(this.intervalCheckSession); } - async saveLastStudy(newStudy) { - const userConfig = await this.opencgaClient.updateUserConfigs({ - ...this.opencgaSession.user.configs.IVA, - lastStudy: newStudy.fqn - }); - this.opencgaSession.user.configs.IVA = userConfig.responses[0].results[0]; - } - - onUrlChange(e) { - let hashFrag = e.detail.id; - if (UtilsNew.isNotUndefined(this.opencgaSession.project) && UtilsNew.isNotEmpty(this.opencgaSession.project.alias)) { - - hashFrag += "/" + this.opencgaSession.project.alias; - if (UtilsNew.isNotUndefined(this.opencgaSession.study) && UtilsNew.isNotEmpty(this.opencgaSession.study.alias)) { - hashFrag += "/" + this.opencgaSession.study.alias; - } - } - - const myQueryParams = []; - for (const key in e.detail.query) { - myQueryParams.push(key + "=" + e.detail.query[key]); - } - if (myQueryParams.length > 0) { - hashFrag += `?${myQueryParams.join("&")}`; - } - - window.location.hash = hashFrag; - } - checkSessionActive() { // We check if refresh token has updated session id cookie // let sid = Cookies.get(this.config.opencga.cookie.prefix + "_sid"); @@ -572,7 +543,7 @@ class ApiApp extends LitElement { if (studyFound) { // Update the lastStudy in config iff has changed - this.opencgaClient.updateUserConfigs({...this.opencgaSession.user.configs, lastStudy: studyFqn}); + this.opencgaClient.updateUserConfig("IVA", {...this.opencgaSession.user.configs["IVA"], lastStudy: studyFqn}); // Refresh the session this.opencgaSession = {...this.opencgaSession}; diff --git a/src/sites/iva/conf/browsers.settings.js b/src/sites/iva/conf/browsers.settings.js index dfaab64cb5..c7c7113d1e 100644 --- a/src/sites/iva/conf/browsers.settings.js +++ b/src/sites/iva/conf/browsers.settings.js @@ -22,10 +22,27 @@ const CATALOG_SETTINGS = { exportTabs: ["download", "link", "code"] }, // It is supported either columns[] or hiddenColumns[]. - columns: ["id", "samples", "father", "mother", "disorders", "phenotypes", "caseId", "sex", "ethnicity", "dateOfBirth", "creationDate", "actions"] + columns: ["id", "samples", "father", "mother", "disorders", "phenotypes", "caseId", "sex", "ethnicity", "dateOfBirth", "creationDate", "actions"], + + // Annotations Example: + // annotations: [ + // { + // title: "Cardiology Tests", + // position: 3, + // variableSetId: "cardiology_tests_checklist", + // variables: ["ecg_test", "echo_test"] + // }, + // { + // title: "Risk Assessment", + // position: 5, + // variableSetId: "risk_assessment", + // variables: ["vf_cardiac_arrest_events"] + // } + // ] + }, // merge criterium: uses this array as filter for internal 1D array. - details: ["individual-view", "clinical-analysis-grid", "individual-inferred-sex", "individual-mendelian-error", "json-view"] + details: ["individual-view", "clinical-analysis-grid", "individual-inferred-sex", "individual-mendelian-error", "json-view"], }, COHORT_BROWSER: { /** diff --git a/src/sites/iva/conf/config.js b/src/sites/iva/conf/config.js index 6c8636bd0e..04ab111996 100644 --- a/src/sites/iva/conf/config.js +++ b/src/sites/iva/conf/config.js @@ -23,7 +23,7 @@ const hosts = [ }, { id: "test", - url: "https://ws.opencb.org/opencga-test" + url: "https://demo.app.zettagenomics.com/opencga" }, { id: "testteam", diff --git a/src/sites/iva/conf/opencga-individual-browser.settings.js b/src/sites/iva/conf/opencga-individual-browser.settings.js index d772399da7..1f189424ec 100644 --- a/src/sites/iva/conf/opencga-individual-browser.settings.js +++ b/src/sites/iva/conf/opencga-individual-browser.settings.js @@ -27,6 +27,22 @@ const OPENCGA_INDIVIDUAL_BROWSER_SETTINGS = { // merge criterium: uses this array as filter for internal 1D/2D array. It handles row/col span // It is supported either columns[] or hiddenColumns[]. columns: ["id", "samples", "father", "mother", "disorders", "phenotypes", "caseId", "sex", "ethnicity", "dateOfBirth", "creationDate", "actions"] + + // Example: + // annotations: [ + // { + // title: "Cardiology Tests", + // position: 3, + // variableSetId: "cardiology_tests_checklist", + // variables: ["ecg_test", "echo_test"] + // }, + // { + // title: "Risk Assessment", + // position: 5, + // variableSetId: "risk_assessment", + // variables: ["vf_cardiac_arrest_events"] + // } + // ] }, // merge criterium: uses this array as filter for internal 1D array. details: ["individual-view", "clinical-analysis-grid", "individual-inferred-sex", "individual-mendelian-error", "json-view"] diff --git a/src/sites/iva/iva-app.js b/src/sites/iva/iva-app.js index d76fb5c4f8..d29e90d85b 100644 --- a/src/sites/iva/iva-app.js +++ b/src/sites/iva/iva-app.js @@ -659,34 +659,34 @@ class IvaApp extends LitElement { window.clearInterval(this.intervalCheckSession); } - async saveLastStudy(newStudy) { - const userConfig = await this.opencgaClient.updateUserConfigs({ - ...this.opencgaSession.user.configs.IVA, - lastStudy: newStudy.fqn - }); - this.opencgaSession.user.configs.IVA = userConfig.responses[0].results[0]; - } - - onUrlChange(e) { - let hashFrag = e.detail.id; - if (UtilsNew.isNotUndefined(this.opencgaSession.project) && UtilsNew.isNotEmpty(this.opencgaSession.project.alias)) { - - hashFrag += "/" + this.opencgaSession.project.alias; - if (UtilsNew.isNotUndefined(this.opencgaSession.study) && UtilsNew.isNotEmpty(this.opencgaSession.study.alias)) { - hashFrag += "/" + this.opencgaSession.study.alias; - } - } - - const myQueryParams = []; - for (const key in e.detail.query) { - myQueryParams.push(key + "=" + e.detail.query[key]); - } - if (myQueryParams.length > 0) { - hashFrag += `?${myQueryParams.join("&")}`; - } - - window.location.hash = hashFrag; - } + // async saveLastStudy(newStudy) { + // const userConfig = await this.opencgaClient.updateUserConfig({ + // ...this.opencgaSession.user.configs.IVA, + // lastStudy: newStudy.fqn + // }); + // this.opencgaSession.user.configs.IVA = userConfig.responses[0].results[0]; + // } + + // onUrlChange(e) { + // let hashFrag = e.detail.id; + // if (UtilsNew.isNotUndefined(this.opencgaSession.project) && UtilsNew.isNotEmpty(this.opencgaSession.project.alias)) { + // + // hashFrag += "/" + this.opencgaSession.project.alias; + // if (UtilsNew.isNotUndefined(this.opencgaSession.study) && UtilsNew.isNotEmpty(this.opencgaSession.study.alias)) { + // hashFrag += "/" + this.opencgaSession.study.alias; + // } + // } + // + // const myQueryParams = []; + // for (const key in e.detail.query) { + // myQueryParams.push(key + "=" + e.detail.query[key]); + // } + // if (myQueryParams.length > 0) { + // hashFrag += `?${myQueryParams.join("&")}`; + // } + // + // window.location.hash = hashFrag; + // } // TODO: we should move this code to an OpenCGA Utils checkSessionActive() { @@ -951,7 +951,7 @@ class IvaApp extends LitElement { if (studyFound) { // Update the lastStudy in config iff has changed - this.opencgaClient.updateUserConfigs({...this.opencgaSession.user.configs, lastStudy: studyFqn}); + this.opencgaClient.updateUserConfig("IVA", {...this.opencgaSession.user.configs["IVA"], lastStudy: studyFqn}); // Refresh the session and update cellbase this.opencgaSession = {...this.opencgaSession}; diff --git a/src/sites/test-app/clients/api-mock/Cohort.js b/src/sites/test-app/clients/api-mock/Cohort.js index 7926c8dc85..f1955826d1 100644 --- a/src/sites/test-app/clients/api-mock/Cohort.js +++ b/src/sites/test-app/clients/api-mock/Cohort.js @@ -44,7 +44,7 @@ export default class Cohort { info(cohorts, params) { if (cohorts === "ALL") { - return UtilsNew.importJSONFile(`./test-data/2.11/cohorts-1000G.json`) + return UtilsNew.importJSONFile(`./test-data/${this._config.testDataVersion}/cohorts-1000G.json`) .then(data => ({ responses: [{results: [data[0]]}] })); diff --git a/src/sites/test-app/clients/api-mock/DiseasePanel.js b/src/sites/test-app/clients/api-mock/DiseasePanel.js index cf7027d9bf..8cde94b0e1 100644 --- a/src/sites/test-app/clients/api-mock/DiseasePanel.js +++ b/src/sites/test-app/clients/api-mock/DiseasePanel.js @@ -35,7 +35,7 @@ export default class DiseasePanel { } info(panels, params) { - // Mocked response for Sample update test + // Mocked response for Disease Panel update test if (panels === "Early_onset_dystonia-PanelAppId-192") { return UtilsNew.importJSONFile(`./test-data/${this._config.testDataVersion}/disease-panels-platinum.json`) .then(data => ({ diff --git a/src/sites/test-app/clients/opencga-client-mock.js b/src/sites/test-app/clients/opencga-client-mock.js index 6f89c5db0b..2f9d7f606d 100644 --- a/src/sites/test-app/clients/opencga-client-mock.js +++ b/src/sites/test-app/clients/opencga-client-mock.js @@ -220,18 +220,16 @@ export class OpenCGAClientMock { return this.users().configs(this._config.userId, "IVA"); } - updateUserConfigs(data) { - // TODO remove this nasty nested bug fix - if (data?.IVA) { - delete data.IVA; - } - const userIvaConfig = this.users().updateConfigs(this._config.userId, { - id: "IVA", - configuration: { - ...data - } - }); - return userIvaConfig; + // Nacho (22/10/2023): This method needs a config ID and VALUE now, + // different sites or apps may need to store configurations. + updateUserConfig(id, newConfig) { + return this.users() + .updateConfigs(this._config.userId, { + id: id, + configuration: { + ...newConfig + } + }); } } diff --git a/src/sites/test-app/extensions/extensions.js b/src/sites/test-app/extensions/extensions.js index 752665dd83..48d7d73216 100644 --- a/src/sites/test-app/extensions/extensions.js +++ b/src/sites/test-app/extensions/extensions.js @@ -82,6 +82,7 @@ window.IVA_EXTENSIONS = { "individual-grid", "job-grid", "sample-grid", + "disease-panel-grid", ], maintainer: "", version: "", @@ -99,34 +100,6 @@ window.IVA_EXTENSIONS = { }, ], }, - { - id: "catalog-columns-multiple", - name: "Catalog Columns", - description: "Example columns for Catalog Grids", - type: "column", - components: [ - "disease-panel-grid", - ], - maintainer: "", - version: "", - compatibleWith: "", - columns: [ - [ - { - // position: 0, - config: { - id: "new-column-1", - title: "Extra column", - field: "", - align: "center", - rowspan: 2, - colspan: 1, - formatter: (value, row, index) => `Row ${index}`, - }, - }, - ], - ], - }, { id: "catalog-detail", name: "New Catalog Tab", diff --git a/src/sites/test-app/test-app.js b/src/sites/test-app/test-app.js index 0722eee441..22160850eb 100644 --- a/src/sites/test-app/test-app.js +++ b/src/sites/test-app/test-app.js @@ -215,7 +215,8 @@ class TestApp extends LitElement { // this.opencgaSession = content; // this.requestUpdate(); // }); - this.opencgaSession = {}; + // this.opencgaSession = {}; + this.opencgaSession = null; this.initProjectMock(); } @@ -667,10 +668,8 @@ class TestApp extends LitElement { ${this.config.enabledComponents["file-browser-grid"] ? html`
+ testDataVersion="${this.testDataVersion}" + .opencgaSession="${this.opencgaSession}">
` : nothing} @@ -678,10 +677,8 @@ class TestApp extends LitElement { ${this.config.enabledComponents["individual-browser-grid"] ? html`
+ testDataVersion="${this.testDataVersion}" + .opencgaSession="${this.opencgaSession}">
` : nothing} @@ -689,10 +686,8 @@ class TestApp extends LitElement { ${this.config.enabledComponents["family-browser-grid"] ? html`
+ testDataVersion="${this.testDataVersion}" + .opencgaSession="${this.opencgaSession}">
` : nothing} @@ -700,10 +695,8 @@ class TestApp extends LitElement { ${this.config.enabledComponents["cohort-browser-grid"] ? html`
+ testDataVersion="${this.testDataVersion}" + .opencgaSession="${this.opencgaSession}">
` : nothing} @@ -711,10 +704,8 @@ class TestApp extends LitElement { ${this.config.enabledComponents["sample-browser-grid"] ? html`
+ testDataVersion="${this.testDataVersion}" + .opencgaSession="${this.opencgaSession}">
` : nothing} @@ -722,10 +713,8 @@ class TestApp extends LitElement { ${this.config.enabledComponents["job-browser-grid"] ? html`
+ testDataVersion="${this.testDataVersion}" + .opencgaSession="${this.opencgaSession}">
` : nothing} @@ -733,10 +722,8 @@ class TestApp extends LitElement { ${this.config.enabledComponents["disease-panel-browser-grid"] ? html`
+ testDataVersion="${this.testDataVersion}" + .opencgaSession="${this.opencgaSession}">
` : nothing} diff --git a/src/sites/test-app/webcomponents/cohort-browser-grid-test.js b/src/sites/test-app/webcomponents/cohort-browser-grid-test.js index a752248944..de4960e3fe 100644 --- a/src/sites/test-app/webcomponents/cohort-browser-grid-test.js +++ b/src/sites/test-app/webcomponents/cohort-browser-grid-test.js @@ -17,7 +17,6 @@ import {html, LitElement} from "lit"; import UtilsNew from "../../../core/utils-new.js"; -import "../../../webcomponents/loading-spinner.js"; import "../../../webcomponents/cohort/cohort-grid.js"; import "../../../webcomponents/cohort/cohort-detail.js"; import "../../../webcomponents/cohort/cohort-view.js"; @@ -38,145 +37,133 @@ class CohortBrowserGridTest extends LitElement { static get properties() { return { - testFile: { - type: String - }, opencgaSession: { type: Object }, testDataVersion: { type: String }, - config: { - type: Object - }, - _selectRow: { - type: Object, - state: true - }, }; } #init() { - this.isLoading = false; - this.data = []; - this._config = {}; - } - - #setLoading(value) { - this.isLoading = value; - this.requestUpdate(); + this.COMPONENT_ID = "cohort-browser"; + this.FILES = [ + "cohorts-1000G.json", + ]; + this._data = null; + this._selectedRow = null; + this._config = this.getDefaultConfig(); } update(changedProperties) { - if (changedProperties.has("testFile") && - changedProperties.has("testDataVersion") && - changedProperties.has("opencgaSession")) { + if (changedProperties.has("testDataVersion") || changedProperties.has("opencgaSession")) { this.opencgaSessionObserver(); } + super.update(changedProperties); } opencgaSessionObserver() { - this.#setLoading(true); - UtilsNew.importJSONFile(`./test-data/${this.testDataVersion}/${this.testFile}.json`) - .then(content => { - this.cohorts = content; - this.mutate(); - }) - .catch(err => { - console.log(err); - }) - .finally(() => { - this.#setLoading(false); + if (this.opencgaSession && this.testDataVersion) { + const allPromises = this.FILES.map(file => { + return UtilsNew.importJSONFile(`./test-data/${this.testDataVersion}/${file}`); }); - } - onSettingsUpdate() { - this._config = {...this.opencgaSession?.user?.configs?.IVA?.cohortBrowser?.grid}; - this.opencgaSessionObserver(); - } - - getDefaultTabsConfig() { - return { - title: "Cohort", - showTitle: true, - items: [ - { - id: "cohort-view", - name: "Overview", - active: true, - render: (cohort, active, opencgaSession) => { - return html` - - - `; - } - }, - // { - // id: "sample-view", - // name: "Samples", - // render: (cohort, active, opencgaSession) => { - // return html` - // - // - // `; - // } - // }, - { - id: "json-view", - name: "JSON Data", - render: (cohort, active, opencgaSession) => { - return html` - - - `; - } - } - ] - }; + Promise.all(allPromises) + .then(data => { + this._data = data[0]; + this._selectedRow = this._data[0]; + this.mutate(); + this.requestUpdate(); + }) + .catch(err => { + console.log(err); + }); + } } mutate() { return null; } - selectRow(e) { - this._selectRow = {...e.detail.row}; + onSettingsUpdate() { + this._config.grid = { + ...this._config.grid, + ...this.opencgaSession?.user?.configs?.IVA?.settings?.[this.COMPONENT_ID]?.grid, + }; + this.requestUpdate(); + } + + onSelectRow(e) { + this._selectedRow = e.detail.row; + this.requestUpdate(); } render() { - if (this.isLoading) { - return html``; + if (!this._data) { + return "Loading..."; } return html` -

- Catalog Browser Grid (${this.testFile}) -

- - - - +
+

+ Cohort Browser Grid (${this.FILES[0]}) +

+ + + + +
`; } + getDefaultConfig() { + return { + grid: {}, + detail: { + title: "Cohort", + showTitle: true, + items: [ + { + id: "cohort-view", + name: "Overview", + active: true, + render: (cohort, active, opencgaSession) => { + return html` + + + `; + } + }, + { + id: "json-view", + name: "JSON Data", + render: (cohort, active) => { + return html` + + + `; + } + } + ], + }, + }; + } + } customElements.define("cohort-browser-grid-test", CohortBrowserGridTest); diff --git a/src/sites/test-app/webcomponents/disease-panel-browser-grid-test.js b/src/sites/test-app/webcomponents/disease-panel-browser-grid-test.js index 3575e1617e..e7af4241e3 100644 --- a/src/sites/test-app/webcomponents/disease-panel-browser-grid-test.js +++ b/src/sites/test-app/webcomponents/disease-panel-browser-grid-test.js @@ -15,16 +15,12 @@ */ import {html, LitElement} from "lit"; - import UtilsNew from "../../../core/utils-new.js"; - import "../../../webcomponents/disease-panel/disease-panel-grid.js"; import "../../../webcomponents/disease-panel/disease-panel-detail.js"; import "../../../webcomponents/disease-panel/disease-panel-create.js"; import "../../../webcomponents/disease-panel/disease-panel-update.js"; -import NotificationUtils from "../../../webcomponents/commons/utils/notification-utils"; - class DiseasePanelBrowserGridTest extends LitElement { @@ -45,42 +41,19 @@ class DiseasePanelBrowserGridTest extends LitElement { testDataVersion: { type: String }, - _ready: { - type: Boolean, - state: true, - } }; } #init() { - this._ready = false; + this.COMPONENT_ID = "disease-panel-browser"; this.FILES = [ "disease-panels-platinum.json", ]; - this._data = []; - this._selectedInstance = {}; - - this.configGrid = { - pageSize: 10, - pageList: [10, 25, 50], - multiSelection: false, - showSelectCheckbox: false, - toolbar: { - showColumns: true, - showDownload: false, - showExport: false, - showSettings: false, - exportTabs: ["download", "link", "code"] - }, - }; + this._data = null; + this._selectedRow = {}; + this._config = this.getDefaultConfig(); } - // TODO: The Sample Browser Test needs to test two things: - // 1. The view: - // - The sample browser: table grid and details - // - The sample browser facet - // 2. The filters - update(changedProperties) { if (changedProperties.has("testDataVersion") || changedProperties.has("opencgaSession")) { this.propertyObserver(); @@ -90,83 +63,44 @@ class DiseasePanelBrowserGridTest extends LitElement { } propertyObserver() { - if (this.opencgaSession?.cellbaseClient && this.testDataVersion) { + if (this.opencgaSession && this.testDataVersion) { const promises = this.FILES.map(file => { return UtilsNew.importJSONFile(`./test-data/${this.testDataVersion}/${file}`); }); - // Import all files Promise.all(promises) .then(data => { this._data = data[0]; - this._selectedInstance = this._data[0]; - // Mutate data and update + this._selectedRow = this._data[0]; this.mutate(); this.requestUpdate(); }) .catch(error => { - NotificationUtils.dispatch(this, NotificationUtils.NOTIFY_RESPONSE, error); - }).finally(() => { - this._ready = true; + console.error(error); }); } } - onSettingsUpdate() { - this.configGrid = {...this.configGrid, ...this.opencgaSession?.user?.configs?.IVA?.diseasePanelBrowser?.grid}; - this.propertyObserver(); + mutate() { + return null; } - - getDefaultTabsConfig() { - return { - title: "Disease Panel", - showTitle: true, - items: [ - { - id: "disease-panel-view", - name: "Summary", - active: true, - render: (diseasePanel, _active, opencgaSession) => html` - - - `, - }, - { - id: "json-view", - name: "JSON Data", - render: (diseasePanel, active) => html` - - - `, - }, - ] + onSettingsUpdate() { + this._config.grid = { + ...this._config.grid, + ...this.opencgaSession?.user?.configs?.IVA?.settings?.[this.COMPONENT_ID]?.grid, }; + this.requestUpdate(); } - mutate() { - // 1. Mutations related to date - // this._data[3].id = ""; - // this._data[1].creationDate = ""; - // this._data[2].creationDate = "20540101"; // No valid format - // this._data[2].creationDate = "20210527101416"; // Valid format - - // Finally, we update samples mem address to force a rendering - // this._data = [...this._data]; - } - - selectInstance(e) { - this._selectedInstance = e.detail.row; + onSelectRow(e) { + this._selectedRow = e.detail.row; this.requestUpdate(); } render() { - if (!this._ready) { - return html `Processing`; + if (!this._data) { + return "Loading..."; } return html` @@ -175,21 +109,67 @@ class DiseasePanelBrowserGridTest extends LitElement { Disease Panel Browser Grid (${this.FILES[0]}) + @selectrow="${e => this.onSelectRow(e)}"> + .config="${this._config.detail}"> `; } + getDefaultConfig() { + return { + grid: { + pageSize: 10, + pageList: [10, 25, 50], + multiSelection: false, + showSelectCheckbox: false, + toolbar: { + showColumns: true, + showDownload: false, + showExport: false, + showSettings: false, + exportTabs: ["download", "link", "code"] + }, + }, + detail: { + title: "Disease Panel", + showTitle: true, + items: [ + { + id: "disease-panel-view", + name: "Summary", + active: true, + render: (diseasePanel, _active, opencgaSession) => html` + + + `, + }, + { + id: "json-view", + name: "JSON Data", + render: (diseasePanel, active) => html` + + + `, + }, + ] + }, + }; + } + } customElements.define("disease-panel-browser-grid-test", DiseasePanelBrowserGridTest); diff --git a/src/sites/test-app/webcomponents/family-browser-grid-test.js b/src/sites/test-app/webcomponents/family-browser-grid-test.js index a54b0015db..f5091368e1 100644 --- a/src/sites/test-app/webcomponents/family-browser-grid-test.js +++ b/src/sites/test-app/webcomponents/family-browser-grid-test.js @@ -17,7 +17,6 @@ import {html, LitElement} from "lit"; import UtilsNew from "../../../core/utils-new.js"; -import "../../../webcomponents/loading-spinner.js"; import "../../../webcomponents/family/family-grid.js"; import "../../../webcomponents/family/family-detail.js"; import "../../../webcomponents/family/family-view.js"; @@ -38,135 +37,131 @@ class FamilyBrowserGridTest extends LitElement { static get properties() { return { - testFile: { - type: String - }, opencgaSession: { type: Object }, testDataVersion: { type: String }, - config: { - type: Object - }, - _selectRow: { - type: Object, - state: true - }, - _ready: { - type: Boolean, - state: true - } }; } #init() { - this._ready = false; - this.data = []; - this._config = {}; + this.COMPONENT_ID = "family-browser"; + this.FILES = [ + "families-platinum.json", + ]; + this._data = null; + this._selectedRow = null; + this._config = this.getDefaultConfig(); } - update(changedProperties) { - if (changedProperties.has("testFile") && - changedProperties.has("testDataVersion") && - changedProperties.has("opencgaSession")) { + if (changedProperties.has("testDataVersion") || changedProperties.has("opencgaSession")) { this.opencgaSessionObserver(); } - super.update(changedProperties); - } - #setLoading(value) { - this.isLoading = value; - this.requestUpdate(); + super.update(changedProperties); } opencgaSessionObserver() { - this.#setLoading(true); - UtilsNew.importJSONFile(`./test-data/${this.testDataVersion}/${this.testFile}.json`) - .then(content => { - this.families = content; - this.mutate(); - }) - .catch(err => { - console.log(err); - }) - .finally(() => { - this.#setLoading(false); + if (this.opencgaSession && this.testDataVersion) { + const allPromises = this.FILES.map(file => { + return UtilsNew.importJSONFile(`./test-data/${this.testDataVersion}/${file}`); }); - } - - onSettingsUpdate() { - this._config = {...this._config, ...this.opencgaSession?.user?.configs?.IVA?.familyBrowser?.grid}; - this.opencgaSessionObserver(); - } - getDefaultTabsConfig() { - return { - title: "Family", - showTitle: true, - items: [ - { - id: "family-view", - name: "Overview", - active: true, - // visible: - render: (family, active, opencgaSession) => html` - - - `, - }, - { - id: "json-view", - name: "JSON Data", - render: (family, active, opencgaSession) => html` - - - `, - } - ] - }; + Promise.all(allPromises) + .then(data => { + this._data = data[0]; + this._selectedRow = this._data[0]; + this.mutate(); + this.requestUpdate(); + }) + .catch(err => { + console.error(err); + }); + } } mutate() { return null; } - selectRow(e) { - this._selectRow = {...e.detail.row}; + onSettingsUpdate() { + this._config.grid = { + ...this._config.grid, + ...this.opencgaSession?.user?.configs?.IVA?.settings?.[this.COMPONENT_ID]?.grid, + }; + this.requestUpdate(); + } + + onSelectRow(e) { + this._selectedRow = e.detail.row; + this.requestUpdate(); } render() { - if (this.isLoading) { - return html``; + if (!this._data) { + return "Loading..."; } return html` -

- Catalog Browser Grid (${this.testFile}) -

- - - - +
+

+ Family Browser Grid (${this.FILES[0]}) +

+ + + + +
`; } + getDefaultConfig() { + return { + grid: {}, + detail: { + title: "Family", + showTitle: true, + items: [ + { + id: "family-view", + name: "Overview", + active: true, + render: (family, active, opencgaSession) => html` + + + `, + }, + { + id: "json-view", + name: "JSON Data", + render: (family, active) => html` + + + `, + } + ], + }, + }; + } + } customElements.define("family-browser-grid-test", FamilyBrowserGridTest); diff --git a/src/sites/test-app/webcomponents/file-browser-grid-test.js b/src/sites/test-app/webcomponents/file-browser-grid-test.js index de04944b5b..b9ceeadd5a 100644 --- a/src/sites/test-app/webcomponents/file-browser-grid-test.js +++ b/src/sites/test-app/webcomponents/file-browser-grid-test.js @@ -17,11 +17,8 @@ import {html, LitElement} from "lit"; import UtilsNew from "../../../core/utils-new.js"; -import "../../../webcomponents/loading-spinner.js"; import "../../../webcomponents/file/file-grid.js"; import "../../../webcomponents/file/file-detail.js"; -// import "../../../webcomponents/file/file-create.js"; -// import "../../../webcomponents/file/file-update.js"; class FileBrowserGridTest extends LitElement { @@ -37,99 +34,103 @@ class FileBrowserGridTest extends LitElement { static get properties() { return { - testFile: { - type: String - }, opencgaSession: { type: Object }, testDataVersion: { type: String }, - config: { - type: Object - }, - _selectRow: { - type: Object, - state: true - }, }; } #init() { - this.isLoading = false; - this.data = []; - this._config = {}; - } - - #setLoading(value) { - this.isLoading = value; - this.requestUpdate(); + this.COMPONENT_ID = "file-browser"; + this.FILES = [ + "files-chinese.json", + ]; + this._data = null; + this._selectedRow = null; + this._config = this.getDefaultConfig(); } update(changedProperties) { - if (changedProperties.has("testFile") && - changedProperties.has("testDataVersion") && - changedProperties.has("opencgaSession")) { + if (changedProperties.has("testDataVersion") || changedProperties.has("opencgaSession")) { this.opencgaSessionObserver(); } + super.update(changedProperties); } opencgaSessionObserver() { - this.#setLoading(true); - UtilsNew.importJSONFile(`./test-data/${this.testDataVersion}/${this.testFile}.json`) - .then(content => { - this.files = content; - this.mutate(); - }) - .catch(err => { - console.log(err); - }) - .finally(() => { - this.#setLoading(false); + if (this.opencgaSession && this.testDataVersion) { + const allPromises = this.FILES.map(file => { + return UtilsNew.importJSONFile(`./test-data/${this.testDataVersion}/${file}`); }); - } + Promise.all(allPromises) + .then(data => { + this._data = data[0]; + this._selectedRow = this._data[0]; + this.mutate(); + this.requestUpdate(); + }) + .catch(err => { + console.error(err); + }); + } + } mutate() { return null; } - selectRow(e) { - this._selectRow = {...e.detail.row}; + onSelectRow(e) { + this._selectedRow = e.detail.row; + this.requestUpdate(); } onSettingsUpdate() { - this._config = {...this.opencgaSession?.user?.configs?.IVA?.fileBrowser?.grid}; - this.opencgaSessionObserver(); + this._config.grid = { + ...this._config.grid, + ...this.opencgaSession?.user?.configs?.IVA?.settings?.[this.COMPONENT_ID]?.grid, + }; + this.requestUpdate(); } - render() { - if (this.isLoading) { - return html``; + if (!this._data) { + return "Loading..."; } return html` -

- Catalog Browser Grid (${this.testFile}) -

- - - - - +
+

+ File Browser Grid (${this.FILES[0]}) +

+ + + + +
`; } + getDefaultConfig() { + return { + grid: {}, + detail: {}, + }; + } + } customElements.define("file-browser-grid-test", FileBrowserGridTest); diff --git a/src/sites/test-app/webcomponents/individual-browser-grid-test.js b/src/sites/test-app/webcomponents/individual-browser-grid-test.js index 8d04df8499..efc9224f7d 100644 --- a/src/sites/test-app/webcomponents/individual-browser-grid-test.js +++ b/src/sites/test-app/webcomponents/individual-browser-grid-test.js @@ -17,12 +17,10 @@ import {html, LitElement} from "lit"; import UtilsNew from "../../../core/utils-new.js"; -import "../../../webcomponents/loading-spinner.js"; import "../../../webcomponents/individual/individual-grid.js"; import "../../../webcomponents/individual/individual-detail.js"; import "../../../webcomponents/individual/individual-view.js"; import "../../../webcomponents/commons/json-viewer.js"; -import NotificationUtils from "../../../webcomponents/commons/utils/notification-utils"; import "../../../webcomponents/individual/individual-update.js"; import "../../../webcomponents/individual/individual-create.js"; @@ -46,54 +44,21 @@ class IndividualBrowserGridTest extends LitElement { testDataVersion: { type: String }, - _ready: { - type: Boolean, - state: true, - }, - _selectRow: { - type: Object, - state: true - }, }; } #init() { - this._ready = false; + this.COMPONENT_ID = "individual-browser"; this.FILES = [ "individuals-platinum.json", ]; - this._data = []; - this._selectedInstance = {}; - - this.configGrid = { - pageSize: 10, - pageList: [10, 25, 50], - multiSelection: false, - showSelectCheckbox: false, - // FIXME: temporarily moved here - showColumns: false, // To clean-up? - showDownload: false, // To clean-up? - showExport: true, - showSettings: true, - showNew: true, - showCreate: true, - // FIXME\ - toolbar: { - showColumns: true, - showDownload: false, - showExport: false, - showSettings: false, - exportTabs: ["download", "link", "code"] - }, - }; + this._data = null; + this._selectedRow = {}; + + this._config = this.getDefaultConfig(); } update(changedProperties) { - /* if (changedProperties.has("testFile") && - changedProperties.has("testDataVersion") && - changedProperties.has("opencgaSession")) { - this.opencgaSessionObserver(); - } */ if (changedProperties.has("testDataVersion") || changedProperties.has("opencgaSession")) { this.propertyObserver(); } @@ -102,8 +67,7 @@ class IndividualBrowserGridTest extends LitElement { } propertyObserver() { - if (this.opencgaSession?.cellbaseClient && this.testDataVersion) { - + if (this.opencgaSession && this.testDataVersion) { const promises = this.FILES.map(file => { return UtilsNew.importJSONFile(`./test-data/${this.testDataVersion}/${file}`); }); @@ -112,67 +76,218 @@ class IndividualBrowserGridTest extends LitElement { Promise.all(promises) .then(data => { this._data = data[0]; - this._selectedInstance = this._data[0]; + this._selectedRow = this._data[0]; // Mutate data and update this.mutate(); this.requestUpdate(); }) .catch(error => { - NotificationUtils.dispatch(this, NotificationUtils.NOTIFY_RESPONSE, error); - }).finally(() => { - this._ready = true; + console.error(error); }); } } - onSettingsUpdate() { - this.configGrid = {...this.configGrid, ...this.opencgaSession?.user?.configs?.IVA?.individualBrowser?.grid}; - this.propertyObserver(); - } - - getDefaultTabsConfig() { - return { - title: "Individual", - showTitle: true, - items: [ - { - id: "individual-view", - name: "Overview", - active: true, - render: (individual, active, opencgaSession) => html` - - - `, + mutate() { + // return null; + // Mutation 1: The first individual has annotations with the variable sets defined for the study + this._data[0].annotationSets = [ + { + id: "cardiology_tests_checklist_annotationset", + name: "cariodology_tests_checklist_annotationset", + variableSetId: "cardiology_tests_checklist", + annotations: { + ecg_exercise_test: "YES", + electrophysiological_study: "YES", + echo_test: "NO", + ecg_test: "YES" }, - { - id: "json-view", - name: "JSON Data", - render: (individual, active, opencgaSession) => html` - - - `, - } - ] - }; + creationDate: "20231006101625", + release: 1, + attributes: [] + }, + { + id: "risk_assessment_annotationset", + name: "risk_assessment_annotationset", + variableSetId: "risk_assessment", + annotations: { + date_risk_assessment: "20-05-2022", + risk_score: 7, + vf_cardiac_arrest_events: "NO", + sdc_iad_family_history: "UNKNOWN", + }, + creationDate: "20231006101625", + release: 1, + attributes: [] + }, + ]; + // Mutation 2: This study has some variableSets defined + this.opencgaSession.study.variableSets = [ + { + "id": "cardiology_test_checklist", + "name": "Individual cardiology test checklist variableSet name", + "unique": true, + "confidential": false, + "internal": false, + "description": "Individual cardiology test checklist variableSet descriptino", + "variables": [ + { + "id": "echo_test", + "name": "echo_test variable name", + "category": "", + "type": "CATEGORICAL", + "required": false, + "multiValue": false, + "allowedValues": ["YES", "NO", "UNKNOWN"], + "rank": 2, + "dependsOn": "", + "description": "echo_test variable description", + "attributes": {} + }, + { + "id": "ecg_test", + "name": "ecg_test variable name", + "category": "", + "type": "CATEGORICAL", + "required": false, + "multiValue": false, + "allowedValues": ["YES", "NO", "UNKNOWN"], + "rank": 2, + "dependsOn": "", + "description": "ecg_test variable description", + "attributes": {} + }, + { + "id": "ecg_exercise_test", + "name": "ecg_exercise_test variable name", + "category": "", + "type": "CATEGORICAL", + "required": false, + "multiValue": false, + "allowedValues": ["YES", "NO", "UNKNOWN"], + "rank": 2, + "dependsOn": "", + "description": "ecg_exercise_test variable description", + "attributes": {} + }, + { + "id": "electrophysiological_study", + "name": "electrophysiological_study variable name", + "category": "", + "type": "CATEGORICAL", + "required": false, + "multiValue": false, + "allowedValues": ["YES", "NO", "UNKNOWN"], + "rank": 2, + "dependsOn": "", + "description": "electrophysiological_study variable description", + "attributes": {} + }, + + ], + + }, + { + "id": "risk_assessment", + "name": "Risk assessment variableSet name", + "unique": true, + "confidential": false, + "internal": false, + "description": "Risk assessment variableSet description", + "variables": [ + { + "id": "date_risk_assessment", + "name": "date_risk_assessment variable name", + "category": "", + "type": "DATE", + "required": false, + "multiValue": false, + "allowedValues": [], + "rank": 2, + "dependsOn": "", + "description": "date_risk_assessment variable description", + "attributes": {} + }, + { + "id": "risk_score", + "name": "risk_score variable name", + "category": "", + "type": "INTEGER", + "required": false, + "multiValue": false, + "allowedValues": [], + "rank": 2, + "dependsOn": "", + "description": "risk_score variable description", + "attributes": {} + }, + { + "id": "vf_cardiac_arrest_events", + "name": "vf_cardiac_arrest_events variable name", + "category": "", + "type": "CATEGORICAL", + "required": false, + "multiValue": false, + "allowedValues": ["YES", "NO", "UNKNOWN"], + "rank": 2, + "dependsOn": "", + "description": "vf_cardiac_arrest_events variable description", + "attributes": {} + }, + { + "id": "sdc_iad_family_history", + "name": "sdc_iad_family_history variable name", + "category": "", + "type": "CATEGORICAL", + "required": false, + "multiValue": false, + "allowedValues": ["YES", "NO", "UNKNOWN"], + "rank": 2, + "dependsOn": "", + "description": "sdc_iad_family_history variable description", + "attributes": {} + }, + + ], + + }, + ]; + + // Mutation 3: annotation columns enabled through the admin interface in filter.result.grid + // See example of use in browser.settings.js, INDIVIDUAL_BROWSER + this._config.grid.annotations = [ + { + title: "Cardiology Tests", + position: 6, + variableSetId: "cardiology_tests_checklist", + variables: ["ecg_test", "echo_test"] + }, + { + title: "Risk Assessment", + position: 7, + variableSetId: "risk_assessment", + variables: ["date_risk_assessment"] + + } + ]; + } - mutate() { - return null; + onSettingsUpdate() { + this._config.grid = { + ...this._config.grid, + ...this.opencgaSession?.user?.configs?.IVA?.settings?.[this.COMPONENT_ID]?.grid, + }; + this.requestUpdate(); } - selectInstance(e) { - this._selectedInstance = e.detail.row; + onSelectRow(e) { + this._selectedRow = e.detail.row; this.requestUpdate(); } render() { - if (!this._ready) { - return html `Processing`; + if (!this._data) { + return html`Processing`; } return html` @@ -181,21 +296,56 @@ class IndividualBrowserGridTest extends LitElement { Individual Browser Grid (${this.FILES[0]}) + @selectrow="${e => this.onSelectRow(e)}"> + .config="${this._config.detail}"> `; } + getDefaultConfig() { + return { + grid: {}, + detail: { + title: "Individual", + showTitle: true, + items: [ + { + id: "individual-view", + name: "Overview", + active: true, + render: (individual, active, opencgaSession) => html` + + + `, + }, + { + id: "json-view", + name: "JSON Data", + render: (individual, active) => html` + + + `, + } + ], + }, + }; + } + } customElements.define("individual-browser-grid-test", IndividualBrowserGridTest); diff --git a/src/sites/test-app/webcomponents/job-browser-grid-test.js b/src/sites/test-app/webcomponents/job-browser-grid-test.js index 3cdb4551f5..dd2cab1a62 100644 --- a/src/sites/test-app/webcomponents/job-browser-grid-test.js +++ b/src/sites/test-app/webcomponents/job-browser-grid-test.js @@ -17,11 +17,8 @@ import {html, LitElement} from "lit"; import UtilsNew from "../../../core/utils-new.js"; -import "../../../webcomponents/loading-spinner.js"; import "../../../webcomponents/job/job-grid.js"; import "../../../webcomponents/job/job-detail.js"; -// import "../../../webcomponents/job/job-create.js"; -// import "../../../webcomponents/job/job-update.js"; class JobBrowserGridTest extends LitElement { @@ -37,96 +34,103 @@ class JobBrowserGridTest extends LitElement { static get properties() { return { - testFile: { - type: String - }, opencgaSession: { type: Object }, testDataVersion: { type: String }, - config: { - type: Object - }, - _selectRow: { - type: Object, - state: true - }, }; } #init() { - this.isLoading = false; - this.data = []; - this._config = {}; - } - - #setLoading(value) { - this.isLoading = value; - this.requestUpdate(); + this.COMPONENT_ID = "job-browser"; + this.FILES = [ + "job-1000G.json", + ]; + this._data = null; + this._selectedRow = null; + this._config = this.getDefaultConfig(); } update(changedProperties) { - if (changedProperties.has("testFile") && - changedProperties.has("testDataVersion") && - changedProperties.has("opencgaSession")) { + if (changedProperties.has("testDataVersion") || changedProperties.has("opencgaSession")) { this.opencgaSessionObserver(); } + super.update(changedProperties); } opencgaSessionObserver() { - this.#setLoading(true); - UtilsNew.importJSONFile(`./test-data/${this.testDataVersion}/${this.testFile}.json`) - .then(content => { - this.jobs = content; - this.mutate(); - }) - .catch(err => { - console.log(err); - }) - .finally(() => { - this.#setLoading(false); + if (this.opencgaSession && this.testDataVersion) { + const allPromises = this.FILES.map(file => { + return UtilsNew.importJSONFile(`./test-data/${this.testDataVersion}/${file}`); }); + + Promise.all(allPromises) + .then(data => { + this._data = data[0]; + this._selectedRow = this._data[0]; + this.mutate(); + this.requestUpdate(); + }) + .catch(err => { + console.log(err); + }); + } } mutate() { return null; } - selectRow(e) { - this._selectRow = {...e.detail.row}; + onSelectRow(e) { + this._selectedRow = e.detail.row; + this.requestUpdate(); } onSettingsUpdate() { - this._config = {...this.opencgaSession?.user?.configs?.IVA?.jobBrowser?.grid}; - this.opencgaSessionObserver(); + this._config.grid = { + ...this._config.grid, + ...this.opencgaSession?.user?.configs?.IVA?.settings?.[this.COMPONENT_ID]?.grid, + }; + this.requestUpdate(); } render() { - if (this.isLoading) { - return html``; + if (!this._data) { + return "Loading..."; } return html` -

- Catalog Browser Grid (${this.testFile}) -

- - - - +
+

+ Job Browser Grid (${this.FILES[0]}) +

+ + + + +
`; } + getDefaultConfig() { + return { + grid: {}, + detail: {}, + }; + } + } customElements.define("job-browser-grid-test", JobBrowserGridTest); diff --git a/src/sites/test-app/webcomponents/sample-browser-grid-test.js b/src/sites/test-app/webcomponents/sample-browser-grid-test.js index 3778893b19..85e255b27b 100644 --- a/src/sites/test-app/webcomponents/sample-browser-grid-test.js +++ b/src/sites/test-app/webcomponents/sample-browser-grid-test.js @@ -20,7 +20,6 @@ import UtilsNew from "../../../core/utils-new.js"; import "../../../webcomponents/sample/sample-grid.js"; import "../../../webcomponents/sample/sample-detail.js"; -import NotificationUtils from "../../../webcomponents/commons/utils/notification-utils.js"; import "../../../webcomponents/sample/sample-update.js"; import "../../../webcomponents/sample/sample-create.js"; @@ -44,49 +43,18 @@ class SampleBrowserGridTest extends LitElement { testDataVersion: { type: String }, - _ready: { - type: Boolean, - state: true, - } }; } #init() { - this._ready = false; + this.COMPONENT_ID = "sample-browser"; this.FILES = [ "samples-platinum.json", ]; - this._data = []; - this._selectedInstance = {}; - - this.configGrid = { - pageSize: 10, - pageList: [10, 25, 50], - multiSelection: false, - showSelectCheckbox: false, - // FIXME: temporarily moved here - showColumns: false, // To clean-up? - showDownload: false, // To clean-up? - showExport: true, - showSettings: true, - showNew: true, - showCreate: true, - // FIXME\ - toolbar: { - // FIXME 20230830 Vero BUG: Toolbar configuration (and clientS configuration) is currently ignored. - // The configurations read in the following files for deciding whether the buttons are displayed or not, - // are not under the toolbar key but in the parent. I move this configuration temporarily to the parent. - // See clients browser.settings.js and getDefaultConfig() in: - // - sample-browser.js - // - sample-grid.js - // - opencb-grid-toolbar.js - showColumns: true, - showDownload: false, - showExport: false, - showSettings: false, - exportTabs: ["download", "link", "code"] - }, - }; + this._data = null; + this._selectedRow = {}; + + this._config = this.getDefaultConfig(); } // TODO: The Sample Browser Test needs to test two things: @@ -104,8 +72,7 @@ class SampleBrowserGridTest extends LitElement { } propertyObserver() { - if (this.opencgaSession?.cellbaseClient && this.testDataVersion) { - + if (this.opencgaSession && this.testDataVersion) { const promises = this.FILES.map(file => { return UtilsNew.importJSONFile(`./test-data/${this.testDataVersion}/${file}`); }); @@ -114,55 +81,17 @@ class SampleBrowserGridTest extends LitElement { Promise.all(promises) .then(data => { this._data = data[0]; - this._selectedInstance = this._data[0]; + this._selectedRow = this._data[0]; // Mutate data and update this.mutate(); this.requestUpdate(); }) .catch(error => { - NotificationUtils.dispatch(this, NotificationUtils.NOTIFY_RESPONSE, error); - }).finally(() => { - this._ready = true; + console.error(error); }); } } - onSettingsUpdate() { - this.configGrid = {...this.configGrid, ...this.opencgaSession?.user?.configs?.IVA?.sampleBrowser?.grid}; - this.propertyObserver(); - } - - getDefaultTabsConfig() { - return { - title: "Sample", - showTitle: true, - items: [ - { - id: "sample-view", - name: "Overview", - active: true, - render: (sample, active, opencgaSession) => html` - - - `, - }, - { - id: "json-view", - name: "JSON Data", - render: (sample, active) => html` - - - `, - } - ] - }; - } - mutate() { // 1. Mutations related to date // this._data[3].id = ""; @@ -174,14 +103,22 @@ class SampleBrowserGridTest extends LitElement { this._data = [...this._data]; } - selectInstance(e) { - this._selectedInstance = e.detail.row; + onSettingsUpdate() { + this._config.grid = { + ...this._config.grid, + ...this.opencgaSession?.user?.configs?.IVA?.settings?.[this.COMPONENT_ID]?.grid, + }; + this.requestUpdate(); + } + + onSelectRow(e) { + this._selectedRow = e.detail.row; this.requestUpdate(); } render() { - if (!this._ready) { - return html `Processing`; + if (!this._data) { + return html`Processing...`; } return html` @@ -190,21 +127,56 @@ class SampleBrowserGridTest extends LitElement { Sample Browser Grid (${this.FILES[0]}) + @selectrow="${e => this.onSelectRow(e)}"> + .config="${this._config?.detail}"> `; } + getDefaultConfig() { + return { + grid: {}, + detail: { + title: "Sample", + showTitle: true, + items: [ + { + id: "sample-view", + name: "Overview", + active: true, + render: (sample, active, opencgaSession) => html` + + + `, + }, + { + id: "json-view", + name: "JSON Data", + render: (sample, active) => html` + + + `, + } + ], + }, + }; + } + } customElements.define("sample-browser-grid-test", SampleBrowserGridTest); diff --git a/src/sites/test-app/webcomponents/variant-browser-grid-test.js b/src/sites/test-app/webcomponents/variant-browser-grid-test.js index cd5f50cbd4..b588654b67 100644 --- a/src/sites/test-app/webcomponents/variant-browser-grid-test.js +++ b/src/sites/test-app/webcomponents/variant-browser-grid-test.js @@ -53,25 +53,12 @@ class VariantBrowserGridTest extends LitElement { } #init() { + this.COMPONENT_ID = "variant-browser"; this.isLoading = false; this.variants = []; this._dataFormConfig = DATA_FORM_EXAMPLE; - this.configVariantGrid = { - pageSize: 10, - pageList: [10, 25, 50], - multiSelection: false, - showSelectCheckbox: false, - toolbar: { - // showNew: true, - showColumns: true, - showDownload: false, - showExport: false, - showSettings: false, - exportTabs: ["download", "link", "code"] - // columns list for the dropdown will be added in grid webcomponents based on settings.table.columns - }, - }; + this._config = {}; } #setLoading(value) { @@ -127,7 +114,10 @@ class VariantBrowserGridTest extends LitElement { } onSettingsUpdate() { - this.configVariantGrid = {...this.configVariantGrid, ...this.opencgaSession?.user?.configs?.IVA?.variantBrowser?.grid}; + this._config = { + ...this._config, + ...this.opencgaSession?.user?.configs?.IVA?.settings?.[this.COMPONENT_ID]?.grid + }; this.opencgaSessionObserver(); } @@ -140,30 +130,11 @@ class VariantBrowserGridTest extends LitElement { Variant Browser (${this.testVariantFile?.split("-")?.at(-1)}) - - diff --git a/src/sites/test-app/webcomponents/variant-interpreter-grid-test.js b/src/sites/test-app/webcomponents/variant-interpreter-grid-test.js index 95f518d9a2..5a5591720b 100644 --- a/src/sites/test-app/webcomponents/variant-interpreter-grid-test.js +++ b/src/sites/test-app/webcomponents/variant-interpreter-grid-test.js @@ -157,7 +157,10 @@ class VariantInterpreterGridTest extends LitElement { } onSettingsUpdate() { - this.configVariantInterpreterGrid = {...this.configVariantInterpreterGrid, ...this.opencgaSession?.user?.configs?.IVA?.variantInterpreterBrowser?.grid}; + this.configVariantInterpreterGrid = { + ...this.configVariantInterpreterGrid, + ...this.opencgaSession?.user?.configs?.IVA?.settings?.variantInterpreterBrowser?.grid + }; this.opencgaSessionObserver(); } diff --git a/src/webcomponents/clinical/clinical-analysis-browser.js b/src/webcomponents/clinical/clinical-analysis-browser.js index bd6cdae332..2b478b3df7 100644 --- a/src/webcomponents/clinical/clinical-analysis-browser.js +++ b/src/webcomponents/clinical/clinical-analysis-browser.js @@ -54,6 +54,7 @@ export default class ClinicalAnalysisBrowser extends LitElement { } #init() { + this.COMPONENT_ID = "clinical-analysis-browser"; this._prefix = UtilsNew.randomString(8); this._config = this.getDefaultConfig(); } @@ -92,7 +93,7 @@ export default class ClinicalAnalysisBrowser extends LitElement { // Apply user configuration UtilsNew.setObjectValue(this._config, "filter.result.grid", { ...this._config.filter?.result?.grid, - ...this.opencgaSession.user?.configs?.IVA?.[this._config.componentId]?.grid, + ...this.opencgaSession.user?.configs?.IVA?.settings?.[this.COMPONENT_ID]?.grid, }); @@ -143,7 +144,7 @@ export default class ClinicalAnalysisBrowser extends LitElement { active: true, render: params => html ` html` { const panelHtml = row.panels?.length > 0 ? CatalogGridFormatter.panelFormatter(row.panels) : "-"; return ` -
${CatalogGridFormatter.disorderFormatter(value, row)}
+
${CatalogGridFormatter.disorderFormatter([value], row)}
${panelHtml}
`; }, diff --git a/src/webcomponents/clinical/clinical-analysis-group.js b/src/webcomponents/clinical/clinical-analysis-group.js index 99c124fcc3..b5fea8e993 100644 --- a/src/webcomponents/clinical/clinical-analysis-group.js +++ b/src/webcomponents/clinical/clinical-analysis-group.js @@ -15,6 +15,9 @@ export default class ClinicalAnalysisGroup extends LitElement { static get properties() { return { + toolId: { + type: String, + }, opencgaSession: { type: Object, }, @@ -31,6 +34,7 @@ export default class ClinicalAnalysisGroup extends LitElement { } #init() { + this.COMPONENT_ID = "clinical-analysis-group"; this._prefix = UtilsNew.randomString(8); this._config = this.getDefaultConfig(); this.activeGroup = this._config.groups[0]; @@ -92,6 +96,31 @@ export default class ClinicalAnalysisGroup extends LitElement { this.updateGroups(); } + renderGroupItem(item) { + const query = { + ...this.query, + [this.activeGroup.queryField]: item, + }; + return html` +
+

+ + ${item || this.activeGroup.display.emptyTitle} + +

+ + +
+ `; + } + render() { return html`
@@ -126,26 +155,7 @@ export default class ClinicalAnalysisGroup extends LitElement {
- ${this.groups.map(item => html` -
-

- - ${item || this.activeGroup.display.emptyTitle} - -

- - -
- `)} + ${this.groups.map(item => this.renderGroupItem(item))} `; } diff --git a/src/webcomponents/clinical/clinical-analysis-summary.js b/src/webcomponents/clinical/clinical-analysis-summary.js index 6c0d41fc5f..982ef66f22 100644 --- a/src/webcomponents/clinical/clinical-analysis-summary.js +++ b/src/webcomponents/clinical/clinical-analysis-summary.js @@ -137,7 +137,7 @@ export default class ClinicalAnalysisSummary extends LitElement { field: "disorder", type: "custom", display: { - render: disorder => UtilsNew.renderHTML(CatalogGridFormatter.disorderFormatter(disorder)), + render: disorder => UtilsNew.renderHTML(CatalogGridFormatter.disorderFormatter([disorder])), } }, { diff --git a/src/webcomponents/clinical/clinical-analysis-update.js b/src/webcomponents/clinical/clinical-analysis-update.js index 3bb9e60045..df07d845e1 100644 --- a/src/webcomponents/clinical/clinical-analysis-update.js +++ b/src/webcomponents/clinical/clinical-analysis-update.js @@ -213,7 +213,7 @@ export default class ClinicalAnalysisUpdate extends LitElement { field: "disorder", type: "custom", display: { - render: disorder => UtilsNew.renderHTML(CatalogGridFormatter.disorderFormatter(disorder)), + render: disorder => UtilsNew.renderHTML(CatalogGridFormatter.disorderFormatter([disorder])), } }, { diff --git a/src/webcomponents/clinical/clinical-analysis-view.js b/src/webcomponents/clinical/clinical-analysis-view.js index af9b98d002..8a1f5bc337 100644 --- a/src/webcomponents/clinical/clinical-analysis-view.js +++ b/src/webcomponents/clinical/clinical-analysis-view.js @@ -239,7 +239,7 @@ export default class ClinicalAnalysisView extends LitElement { id: "type", type: "custom", display: { - render: disorder => UtilsNew.renderHTML(CatalogGridFormatter.disorderFormatter(disorder)), + render: disorder => UtilsNew.renderHTML(CatalogGridFormatter.disorderFormatter([disorder])), }, }, { diff --git a/src/webcomponents/clinical/interpretation/clinical-interpretation-editor.js b/src/webcomponents/clinical/interpretation/clinical-interpretation-editor.js index c291754830..09ee8fb576 100644 --- a/src/webcomponents/clinical/interpretation/clinical-interpretation-editor.js +++ b/src/webcomponents/clinical/interpretation/clinical-interpretation-editor.js @@ -221,7 +221,7 @@ class ClinicalInterpretationEditor extends LitElement { field: "disorder", type: "custom", display: { - render: disorder => UtilsNew.renderHTML(CatalogGridFormatter.disorderFormatter(disorder)) + render: disorder => UtilsNew.renderHTML(CatalogGridFormatter.disorderFormatter([disorder])) } }, { @@ -322,7 +322,13 @@ class ClinicalInterpretationEditor extends LitElement { _updateOrDeleteComments(notify) { if (this.commentsUpdate?.updated?.length > 0) { - this.opencgaSession.opencgaClient.clinical().updateInterpretation(this.clinicalAnalysis.id, this.clinicalAnalysis.interpretation.id, {comments: this.commentsUpdate.updated}, {commentsAction: "REPLACE", study: this.opencgaSession.study.fqn}) + this.opencgaSession.opencgaClient.clinical() + .updateInterpretation( + this.clinicalAnalysis.id, + this.clinicalAnalysis.interpretation.id, + {comments: this.commentsUpdate.updated}, + {commentsAction: "REPLACE", study: this.opencgaSession.study.fqn} + ) .then(response => { if (notify && this.commentsUpdate?.deleted?.length === 0) { this._postUpdate(response); @@ -333,7 +339,13 @@ class ClinicalInterpretationEditor extends LitElement { }); } if (this.commentsUpdate?.deleted?.length > 0) { - this.opencgaSession.opencgaClient.clinical().updateInterpretation(this.clinicalAnalysis.id, this.clinicalAnalysis.interpretation.id, {comments: this.commentsUpdate.deleted}, {commentsAction: "REMOVE", study: this.opencgaSession.study.fqn}) + this.opencgaSession.opencgaClient.clinical() + .updateInterpretation( + this.clinicalAnalysis.id, + this.clinicalAnalysis.interpretation.id, + {comments: this.commentsUpdate.deleted}, + {commentsAction: "REMOVE", study: this.opencgaSession.study.fqn} + ) .then(response => { if (notify) { this._postUpdate(response); diff --git a/src/webcomponents/cohort/cohort-browser.js b/src/webcomponents/cohort/cohort-browser.js index b6fc545b10..1a25c9524c 100644 --- a/src/webcomponents/cohort/cohort-browser.js +++ b/src/webcomponents/cohort/cohort-browser.js @@ -49,6 +49,7 @@ export default class CohortBrowser extends LitElement { } _init() { + this.COMPONENT_ID = "cohort-browser"; this._config = this.getDefaultConfig(); } @@ -60,37 +61,27 @@ export default class CohortBrowser extends LitElement { } settingsObserver() { - this._config = {...this.getDefaultConfig()}; - // merge filter list, canned filters, detail tabs + this._config = this.getDefaultConfig(); + + // Apply Study settings if (this.settings?.menu) { this._config.filter = UtilsNew.mergeFiltersAndDetails(this._config?.filter, this.settings); } - // if (this.settings?.table) { - // this._config.filter.result.grid = {...this._config.filter.result.grid, ...this.settings.table}; - // } + UtilsNew.setObjectValue(this._config, "filter.result.grid", { ...this._config?.filter?.result.grid, ...this.settings.table }); - // if (this.settings?.table?.toolbar) { - // this._config.filter.result.grid.toolbar = {...this._config.filter.result.grid.toolbar, ...this.settings.table.toolbar}; - // } UtilsNew.setObjectValue(this._config, "filter.result.grid.toolbar", { ...this._config.filter?.result?.grid?.toolbar, ...this.settings.table?.toolbar }); - // if (this.opencgaSession.user?.configs?.IVA?.cohortBrowserCatalog?.grid) { - // this._config.filter.result.grid = { - // ...this._config.filter.result.grid, - // ...this.opencgaSession.user.configs.IVA.cohortBrowserCatalog.grid, - // }; - // } - // Apply user configuration + // Apply User grid configuration. Only 'pageSize' and 'columns' are set UtilsNew.setObjectValue(this._config, "filter.result.grid", { ...this._config.filter?.result?.grid, - ...this.opencgaSession.user?.configs?.IVA?.cohortBrowser?.grid + ...this.opencgaSession.user?.configs?.IVA?.settings?.[this.COMPONENT_ID]?.grid }); this.requestUpdate(); @@ -127,6 +118,7 @@ export default class CohortBrowser extends LitElement { active: true, render: params => html ` ` - }/* - { - id: "comparator-tab", - name: "Comparator", - icon: "fas fa-clone", - disabled: true - }*/ + } ], filter: { searchButton: false, diff --git a/src/webcomponents/cohort/cohort-grid.js b/src/webcomponents/cohort/cohort-grid.js index 596db506c9..b8e3ce116e 100644 --- a/src/webcomponents/cohort/cohort-grid.js +++ b/src/webcomponents/cohort/cohort-grid.js @@ -38,6 +38,9 @@ export default class CohortGrid extends LitElement { static get properties() { return { + toolId: { + type: String, + }, opencgaSession: { type: Object }, @@ -66,6 +69,7 @@ export default class CohortGrid extends LitElement { updated(changedProperties) { if ((changedProperties.has("opencgaSession") || + changedProperties.has("toolId") || changedProperties.has("query") || changedProperties.has("config") || changedProperties.has("active")) && this.active) { @@ -89,7 +93,7 @@ export default class CohortGrid extends LitElement { // Config for the grid toolbar this.toolbarConfig = { - toolId: "cohortBrowser", + toolId: this.toolId, resource: "COHORT", columns: this._getDefaultColumns(), create: { @@ -217,7 +221,7 @@ export default class CohortGrid extends LitElement { limit: params.data.limit, skip: params.data.offset || 0, count: !this.table.bootstrapTable("getOptions").pageNumber || this.table.bootstrapTable("getOptions").pageNumber === 1, - include: "id,creationDate,status,type,numSamples", + include: "id,creationDate,status,type,numSamples,annotationSets", ...this.query }; // Store the current filters @@ -289,12 +293,19 @@ export default class CohortGrid extends LitElement { id: "id", title: "Cohort ID", field: "id", + formatter: (cohortId, cohort) => { + return ` +
+ ${cohortId} + ${cohort.name ? `${cohort.name}` : ""} +
`; + }, halign: this._config.header.horizontalAlign, visible: this.gridCommons.isColumnVisible("id") }, { id: "numSamples", - title: "#Samples", + title: "Number of Samples", field: "numSamples", // formatter: (value, row) => row.numSamples ?? 0, halign: this._config.header.horizontalAlign, @@ -302,20 +313,18 @@ export default class CohortGrid extends LitElement { }, { id: "creationDate", - title: "Date", + title: "Creation Date", field: "creationDate", formatter: CatalogGridFormatter.dateFormatter, halign: this._config.header.horizontalAlign, visible: this.gridCommons.isColumnVisible("creationDate") }, - { - id: "type", - title: "Type", - field: "type", - halign: this._config.header.horizontalAlign, - visible: this.gridCommons.isColumnVisible("type") - } ]; + + if (this._config.annotations?.length > 0) { + this.gridCommons.addColumnsFromAnnotations(this._columns, CatalogGridFormatter.customAnnotationFormatter, this._config); + } + if (this.opencgaSession && this._config.showActions) { this._columns.push({ id: "actions", diff --git a/src/webcomponents/commons/catalog-browser-grid-config.js b/src/webcomponents/commons/catalog-browser-grid-config.js index f2e115fb0b..35fff4dd1b 100644 --- a/src/webcomponents/commons/catalog-browser-grid-config.js +++ b/src/webcomponents/commons/catalog-browser-grid-config.js @@ -61,9 +61,14 @@ export default class CatalogBrowserGridConfig extends LitElement { this.selectedColumns = []; // get all id columns visible const isColumnVisible = col => col.visible === undefined || col.visible; const addColumnData = col => { - this.selectColumnData.push({id: col.id, name: col.title}); - if (isColumnVisible(col)) { - this.selectedColumns.push(col.id); + if (!col.excludeFromSettings) { + this.selectColumnData.push({ + id: col.id, + name: col.title + }); + if (isColumnVisible(col)) { + this.selectedColumns.push(col.id); + } } }; @@ -106,7 +111,7 @@ export default class CatalogBrowserGridConfig extends LitElement { } }); } else { - // it just one head: get a list of object + // it just one head: get a list of object columnsHead.forEach(column => { addColumnData(column); }); @@ -135,10 +140,18 @@ export default class CatalogBrowserGridConfig extends LitElement { } async onSubmit() { - // Update user configuration - // console.log("onGridConfigSave", this, "values", e.detail.value.columns); try { - await OpencgaCatalogUtils.updateGridConfig(this.opencgaSession, this.toolId, this.config); + // Update user configuration + await OpencgaCatalogUtils.updateGridConfig( + "IVA", + this.opencgaSession, + this.toolId, + { + pageSize: this.config.pageSize, + columns: this.config.columns, + highlights: this.config.highlights, + } + ); LitUtils.dispatchCustomEvent(this, "settingsUpdate"); NotificationUtils.dispatch(this, NotificationUtils.NOTIFY_SUCCESS, { diff --git a/src/webcomponents/commons/catalog-grid-formatter.js b/src/webcomponents/commons/catalog-grid-formatter.js index 1abfb3531d..3b59c1c952 100644 --- a/src/webcomponents/commons/catalog-grid-formatter.js +++ b/src/webcomponents/commons/catalog-grid-formatter.js @@ -19,72 +19,85 @@ import BioinfoUtils from "../../core/bioinfo/bioinfo-utils.js"; export default class CatalogGridFormatter { - static phenotypesFormatter(value, row) { - if (!value || !value?.length) { + static phenotypesFormatter(phenotypes) { + if (!phenotypes || phenotypes.length === 0) { return "-"; } const status = ["OBSERVED", "NOT_OBSERVED", "UNKNOWN"]; - const tooltip = [...value].sort((a, b) => status.indexOf(a.status) - status.indexOf(b.status)).map(phenotype => { - const result = []; - if (phenotype.name) { - result.push(UtilsNew.escapeHtml(phenotype.name)); - // Check if we have also the phenotype ID --> add the '-' separator + const phenotypesHtml = phenotypes + .sort((a, b) => status.indexOf(a.status) - status.indexOf(b.status)) + .map(phenotype => { + const result = []; + if (phenotype.name) { + result.push(UtilsNew.escapeHtml(phenotype.name)); + } + // Add phenotype ID if exists if (phenotype.id && phenotype.id !== phenotype.name) { - result.push("-"); + if (phenotype.source && phenotype.source.toUpperCase() === "HPO") { + result.push(` + (${phenotype.id}) + `); + } else { + result.push(phenotype.id); + } } - } - // Add phenotype ID if exists - if (phenotype.id && phenotype.id !== phenotype.name) { - if (phenotype.source && phenotype.source.toUpperCase() === "HPO") { - result.push(` - ${phenotype.id}`); + // Add phenotype status if exists + // if (phenotype.status) { + // result.push(`(${phenotype.status})`); + // } + return `
${result.join("")}
`; + }); + + if (phenotypesHtml?.length > 0) { + let html = "
"; + for (let i = 0; i < phenotypesHtml.length; i++) { + // Display first 3 phenotypes + if (i < 3) { + html += phenotypesHtml[i]; } else { - result.push(phenotype.id); + html += `... view all phenotypes (${phenotypesHtml.length})`; + break; } } - // Add phenotype status if exists - if (phenotype.status) { - result.push(`(${phenotype.status})`); - } - return `

${result.join(" ")}

`; - }).join(""); - if (value && value.length > 0) { - return ` ${value.length} term${value.length > 1 ? "s" : ""} found`; + html += "
"; + return html; } else { // TODO Think about this - return `
${tooltip}
`; + return `-`; } } - static disorderFormatter(value, row) { - if (value && value.id) { - let idHtml; - const split = value.id.split(":"); - switch (split[0]) { - case "HP": - idHtml = ` - ${value.id} - - `; - break; - case "OMIM": - idHtml = ` - ${value.id} - - `; - break; - default: - idHtml = value.id; - break; - } - if (value.name) { - return `${value.name} (${idHtml})`; - } else { - return `${idHtml}`; + static disorderFormatter(disorders) { + let html = "-"; + if (disorders?.length > 0) { + html = "
"; + for (const disorder of disorders) { + if (disorder?.id) { + // Default value if the disorder ID does not include ':' (source:ID) + let idHtml = disorder.id; + // We try to get a HTTP link + const ontologyLink = BioinfoUtils.getOntologyLink(disorder.id); + if (ontologyLink.startsWith("http")) { + // We have identified the ontology source and created a link + idHtml = `${disorder.id}`; + } + if (disorder.name && disorder.name !== disorder.id) { + html += ` +
+ ${disorder.name} (${idHtml}) +
`; + } else { + html += ` +
+ ${idHtml} +
+ `; + } + } } - } else { - return "-"; + html += "
"; } + return html; } static panelFormatter(panels) { @@ -113,21 +126,38 @@ export default class CatalogGridFormatter { // @param {String} key The property to map onto in case `files` is an array of objects. // @returns {string} html code static fileFormatter(files, extensions, key) { - let results = []; - if (files && files.length > 0) { - if (extensions && extensions.length > 0) { + let bamAndVcfFiles = []; + if (files?.length > 0) { + if (extensions?.length > 0) { files.forEach(file => { const f = key ? file[key] : file; for (const extension of extensions) { if (f.endsWith(extension)) { - results.push(f); + bamAndVcfFiles.push(f); + break; } } }); } else { - results = key ? files.map(file => file?.name) : files; + bamAndVcfFiles = key ? files.map(file => file[key]) : files; + } + + if (bamAndVcfFiles?.length > 0) { + let html = `
`; + for (let i = 0; i < bamAndVcfFiles.length; i++) { + // Display first 3 files + if (i < 3) { + html += ` +
${bamAndVcfFiles[i]}
+ `; + } else { + html += `... view all files (${bamAndVcfFiles.length})`; + break; + } + } + html += "
"; + return html; } - return results.length > 20 ? results.length + " files" : `
    ${results.map(file => `
  • ${file}
  • `).join("")}
`; } else { return "-"; } @@ -145,9 +175,9 @@ export default class CatalogGridFormatter { let result = ""; for (const clinicalAnalysis of clinicalAnalysisArray) { result += ` -
- - ${clinicalAnalysis.id} ${clinicalAnalysis.proband.id === individualId ? "(proband)" : ""} + `; @@ -158,4 +188,45 @@ export default class CatalogGridFormatter { } } + static customAnnotationFormatter(annotationSets, selectedVariableSetId, selectedVariables) { + let html = `
`; + if (selectedVariableSetId) { + // Select the first annotationSet for the selectedVariableSetId. In the future there will be only one. + const annotationSet = annotationSets?.find(v => v.variableSetId === selectedVariableSetId); + if (annotationSet) { + // If 'variables' is not provided we display all of them + const variables = (selectedVariables?.length > 0) ? selectedVariables : Object.keys(annotationSet.annotations).sort(); + for (const variable of variables) { + html += ` +
+ ${variable}: ${annotationSet.annotations[variable]} +
+ `; + } + } else { + // This entity has not this variableSetId annotated + html += `-`; + } + } else { + if (annotationSets?.length > 0) { + // We display all variableSetIds + for (const annotationSet of annotationSets) { + html += `
${annotationSet.variableSetId}
`; + for (const variable of Object.keys(annotationSet.annotations).sort()) { + html += ` +
+ ${variable}: ${annotationSet.annotations[variable]} +
+ `; + } + } + } else { + // This entity has not annotations + html += `-`; + } + } + html += `
`; + return html; + } + } diff --git a/src/webcomponents/commons/forms/data-form.js b/src/webcomponents/commons/forms/data-form.js index d8674412a7..dca24bc8a7 100644 --- a/src/webcomponents/commons/forms/data-form.js +++ b/src/webcomponents/commons/forms/data-form.js @@ -658,6 +658,8 @@ export default class DataForm extends LitElement { `; } + // ${typeof content === "string" ? UtilsNew.renderHTML(content) : content} + // content.replace(/(<([^>]+)>)/ig, '') return html`
@@ -946,7 +948,7 @@ export default class DataForm extends LitElement { return html`No template provided`; } const content = html` - + ${UtilsNew.renderHTML(this.applyTemplate(element.display.template, data, null, this._getDefaultValue(element)))} `; diff --git a/src/webcomponents/commons/grid-commons.js b/src/webcomponents/commons/grid-commons.js index 27a7ba4493..72acf5f344 100644 --- a/src/webcomponents/commons/grid-commons.js +++ b/src/webcomponents/commons/grid-commons.js @@ -18,7 +18,6 @@ import UtilsNew from "../../core/utils-new.js"; import CustomActions from "./custom-actions.js"; import ExtensionsManager from "../extensions-manager.js"; - export default class GridCommons { static GRID_ICONS_PREFIX = "fas"; @@ -298,6 +297,25 @@ export default class GridCommons { return rowStyle; } + addColumnsFromAnnotations(columns, formatter, gridConfig) { + if (gridConfig?.annotations?.length > 0) { + for (const annotation of gridConfig.annotations) { + const column = { + id: "annotations", + title: annotation.title || "Custom Annotation", + field: "annotationSets", + formatter: annotationSets => formatter(annotationSets, annotation.variableSetId, annotation.variables), + halign: gridConfig.header?.horizontalAlign || "center", + visible: true, + excludeFromSettings: true, + // visible: this.gridCommons.isColumnVisible("annotations") + }; + columns.splice(annotation.position, 0, column); + } + } + return columns; + } + addColumnsFromExtensions(columns, componentId) { if (!this.context?._config?.skipExtensions) { const id = componentId || this.context?.COMPONENT_ID; diff --git a/src/webcomponents/commons/opencga-browser-filter.js b/src/webcomponents/commons/opencga-browser-filter.js index 11d43c593f..1d8023848a 100644 --- a/src/webcomponents/commons/opencga-browser-filter.js +++ b/src/webcomponents/commons/opencga-browser-filter.js @@ -102,6 +102,7 @@ export default class OpencgaBrowserFilter extends LitElement { "genes": "genes.id", "categories": "categories.name", "source": "source.name", + "format": "format", "tags": "tags", "sex": "sex.id", "karyotypicSex": "karyotypicSex", @@ -232,6 +233,7 @@ export default class OpencgaBrowserFilter extends LitElement { case "tool": case "categories": case "genes": + case "format": case "tags": case "source": case "sex": @@ -251,7 +253,6 @@ export default class OpencgaBrowserFilter extends LitElement { break; case "affectationStatus": case "lifeStatus": - case "format": case "bioformat": case "internalVariantIndexStatus": case "internalStatus": diff --git a/src/webcomponents/disease-panel/disease-panel-browser.js b/src/webcomponents/disease-panel/disease-panel-browser.js index 5aaed0ee19..76fcf08803 100644 --- a/src/webcomponents/disease-panel/disease-panel-browser.js +++ b/src/webcomponents/disease-panel/disease-panel-browser.js @@ -17,8 +17,6 @@ import {LitElement, html} from "lit"; import UtilsNew from "../../core/utils-new.js"; import {construction} from "../commons/under-construction.js"; -import OpencgaCatalogUtils from "../../core/clients/opencga/opencga-catalog-utils.js"; -import NotificationUtils from "../commons/utils/notification-utils.js"; import "./disease-panel-gene-view.js"; import "./disease-panel-region-view.js"; import "./disease-panel-summary.js"; @@ -58,7 +56,8 @@ export default class DiseasePanelBrowser extends LitElement { } _init() { - this._config = this.getDefautlConfig(); + this.COMPONENT_ID = "disease-panel-browser"; + this._config = this.getDefaultConfig(); } update(changedProperties) { @@ -70,50 +69,29 @@ export default class DiseasePanelBrowser extends LitElement { settingsObserver() { this._config = { - ...this.getDefautlConfig(), + ...this.getDefaultConfig(), ...(this.config || {}), }; + // Apply Study settings if (this.settings?.menu) { this._config.filter = UtilsNew.mergeFiltersAndDetails(this._config?.filter, this.settings); } - // if (this.settings?.table) { - // this._config.filter.result.grid = { - // ...this._config.filter.result.grid, - // ...this.settings.table, - // }; - // } - UtilsNew.setObjectValue(this._config, "filter.result.grid", { ...this._config?.filter?.result.grid, ...this.settings?.table }); - // if (this.settings?.table?.toolbar) { - // this._config.filter.result.grid.toolbar = { - // ...this._config.filter.result.grid.toolbar, - // ...this.settings.table.toolbar, - // }; - // } - UtilsNew.setObjectValue(this._config, "filter.result.grid.toolbar", { ...this._config.filter?.result?.grid?.toolbar, ...this.settings?.table?.toolbar }); - - // if (this.opencgaSession.user?.configs?.IVA?.diseasePanelBrowser?.grid) { - // this._config.filter.result.grid = { - // ...this._config.filter.result.grid, - // ...this.opencgaSession.user.configs.IVA.diseasePanelBrowser.grid, - // }; - // } - - // Apply user configuration + // Apply User grid configuration. Only 'pageSize' and 'columns' are set UtilsNew.setObjectValue(this._config, "filter.result.grid", { ...this._config.filter?.result?.grid, - ...this.opencgaSession.user?.configs?.IVA?.diseasePanelBrowser?.grid + ...this.opencgaSession.user?.configs?.IVA?.settings?.[this.COMPONENT_ID]?.grid }); this.requestUpdate(); @@ -139,7 +117,7 @@ export default class DiseasePanelBrowser extends LitElement { `; } - getDefautlConfig() { + getDefaultConfig() { return { title: "Disease Panel Browser", icon: "fab fa-searchengin", @@ -151,6 +129,7 @@ export default class DiseasePanelBrowser extends LitElement { active: true, render: params => html` 0) { + if (this.diseasePanels?.length > 0) { this.renderLocalTable(); } else { this.renderRemoteTable(); @@ -147,7 +152,6 @@ export default class DiseasePanelGrid extends LitElement { renderRemoteTable() { if (this.opencgaSession.opencgaClient && this.opencgaSession?.study?.fqn) { - // const filters = {...this.query}; if (this.lastFilters && JSON.stringify(this.lastFilters) === JSON.stringify(this.query)) { // Abort destroying and creating again the grid. The filters have not changed return; @@ -260,11 +264,6 @@ export default class DiseasePanelGrid extends LitElement { gridContext: this, formatLoadingMessage: () => "
", onClickRow: (row, selectedElement) => this.gridCommons.onClickRow(row.id, row, selectedElement), - // onPageChange: (page, size) => { - // const result = this.gridCommons.onPageChange(page, size); - // this.from = result.from || this.from; - // this.to = result.to || this.to; - // }, onPostBody: data => { // We call onLoadSuccess to select first row this.gridCommons.onLoadSuccess({rows: data, total: data.length}, 1); @@ -285,7 +284,6 @@ export default class DiseasePanelGrid extends LitElement { await this.updateComplete; ModalUtils.show(`${this._prefix}UpdateModal`); break; - case "copy-json": UtilsNew.copyToClipboard(JSON.stringify(row, null, "\t")); break; @@ -361,144 +359,113 @@ export default class DiseasePanelGrid extends LitElement { _getDefaultColumns() { this._columns = [ - [ - { - id: "id", - title: "Panel ID", - field: "id", - rowspan: 2, - colspan: 1, - formatter: (value, row) => { - if (row?.source && row?.source?.project === "PanelApp") { - return String.raw` + { + id: "name", + title: "Panel", + field: "name", + formatter: (name, row) => { + let idLinkHtml = ""; + if (row?.source && row?.source?.project === "PanelApp") { + idLinkHtml = ` ${row?.id ?? "-"} `; - } - return row?.id ?? "-"; - }, - halign: this._config.header.horizontalAlign, - visible: this.gridCommons.isColumnVisible("id") - }, - { - id: "name", - title: "Name", - field: "name", - rowspan: 2, - colspan: 1, - formatter: (value, row) => row?.name ?? "-", - halign: this._config.header.horizontalAlign, - visible: this.gridCommons.isColumnVisible("name") - }, - { - id: "disorders", - title: "Disorders", - field: "disorders", - rowspan: 2, - colspan: 1, - formatter: disorders => { - if (disorders?.length > 0) { - const disordersHtml = []; - for (const disorder of disorders) { - let result = disorder.id; - if (disorder.name) { - result += " - " + disorder.name; - } - disordersHtml.push(`
${result}
`); - } - return disordersHtml.join(""); - } - }, - halign: this._config.header.horizontalAlign, - visible: this.gridCommons.isColumnVisible("disorders") + } + return ` +
+
${name}
+
${idLinkHtml}
+
`; }, - { - id: "stats", - title: "Stats", - field: "stats", - rowspan: 1, - colspan: 3, - align: "center", - visible: true + halign: this._config.header.horizontalAlign, + visible: this.gridCommons.isColumnVisible("name") + }, + // { + // id: "id", + // title: "Panel ID", + // field: "id", + // rowspan: 2, + // colspan: 1, + // formatter: (value, row) => { + // if (row?.source && row?.source?.project === "PanelApp") { + // return String.raw` + // + // ${row?.id ?? "-"} + // `; + // } + // return row?.id ?? "-"; + // }, + // halign: this._config.header.horizontalAlign, + // visible: this.gridCommons.isColumnVisible("id") + // }, + { + id: "disorders", + title: "Disorders", + field: "disorders", + formatter: disorders => CatalogGridFormatter.disorderFormatter(disorders), + halign: this._config.header.horizontalAlign, + visible: this.gridCommons.isColumnVisible("disorders") + }, + { + id: "stats", + title: "Stats", + field: "stats", + formatter: stats => { + return ` +
+
+ Genes: ${stats.numberOfGenes} +
+
+ Regions: ${stats.numberOfRegions} +
+
+ Variants: ${stats.numberOfVariants} +
+
+ `; }, - { - id: "source", - title: "Source", - field: "source", - rowspan: 2, - colspan: 1, - formatter: (value, row) => { - if (row?.source) { - const {id, author, project, version} = row.source; - let projectAndVersion = ""; - if (project?.toUpperCase() === "PANELAPP") { - projectAndVersion = ` + align: "center", + visible: this.gridCommons.isColumnVisible("stats") + }, + { + id: "source", + title: "Source", + field: "source", + formatter: (value, row) => { + if (row?.source) { + const {id, author, project, version} = row.source; + let projectAndVersion = ""; + if (project?.toUpperCase() === "PANELAPP") { + projectAndVersion = ` ${project} ${version} `; - } else { - projectAndVersion = `${project || ""} ${version}`; - } - return `${author ? `${author} -` : ""} ${projectAndVersion}`; + } else { + projectAndVersion = `${project || ""} ${version}`; } - return "-"; - }, - align: "center", - visible: this.gridCommons.isColumnVisible("source") - }, - ], - [ - { - id: "numberOfGenes", - title: "# genes", - field: "numberOfGenes", - rowspan: 1, - colspan: 1, - formatter: (value, row) => row?.stats?.numberOfGenes ?? "-", - halign: this._config.header.horizontalAlign, - align: "right", - visible: this.gridCommons.isColumnVisible("numberOfGenes") - }, - { - id: "numberOfRegions", - title: "# regions", - field: "numberOfRegions", - rowspan: 1, - colspan: 1, - formatter: (value, row) => row?.stats?.numberOfRegions ?? "-", - halign: this._config.header.horizontalAlign, - align: "right", - visible: this.gridCommons.isColumnVisible("numberOfRegions") + return `${author ? `${author} -` : ""} ${projectAndVersion}`; + } + return "-"; }, - { - id: "numberOfVariants", - title: "# variants", - field: "numberOfVariants", - rowspan: 1, - colspan: 1, - formatter: (value, row) => row?.stats?.numberOfVariants ?? "-", - halign: this._config.header.horizontalAlign, - align: "right", - visible: this.gridCommons.isColumnVisible("numberOfVariants") - } - ] + align: "center", + visible: this.gridCommons.isColumnVisible("source") + }, ]; if (this.opencgaSession && this._config.showActions) { - this._columns[0].push({ + this._columns.push({ id: "actions", title: "Actions", field: "actions", halign: this._config.header.horizontalAlign, - rowspan: 2, - colspan: 1, formatter: (value, row) => `