From de8425a8ab8e13d5c3a5857b778651368e6f6405 Mon Sep 17 00:00:00 2001 From: Josemi Date: Fri, 26 Sep 2025 13:08:30 +0200 Subject: [PATCH 01/15] wc: include new activeItem property in vertical-menu component #TASK-7762 --- src/webcomponents/commons/view/vertical-menu.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/webcomponents/commons/view/vertical-menu.js b/src/webcomponents/commons/view/vertical-menu.js index ac8ba76732..0481e2a83d 100644 --- a/src/webcomponents/commons/view/vertical-menu.js +++ b/src/webcomponents/commons/view/vertical-menu.js @@ -17,6 +17,9 @@ export default class VerticalMenu extends LitElement { opencgaSession: { type: Object, }, + activeItem: { + type: String, + }, config: { type: Object, }, @@ -35,8 +38,15 @@ export default class VerticalMenu extends LitElement { ...this.getDefaultConfig(), ...this.config, }; - // initialize the active item - if (!this._activeItem) { + } + + if (changedProperties.has("config") || changedProperties.has("activeItem")) { + // check if we have to change the active item + if (this.activeItem && this.activeItem !== this._activeItem) { + this._activeItem = this.activeItem; + } + // initialize the active item if not set + if (!this._activeItem && !this.activeItem) { this._activeItem = this._config.menu[0].submenu[0].id; } } From 27a8380deeb327cda5e80c9152f4e7a6bd88fbea Mon Sep 17 00:00:00 2001 From: Josemi Date: Fri, 26 Sep 2025 13:10:13 +0200 Subject: [PATCH 02/15] wc: dispatch a changeActiveItem event in vertical-menu when active item changes #TASK-7762 --- src/webcomponents/commons/view/vertical-menu.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/webcomponents/commons/view/vertical-menu.js b/src/webcomponents/commons/view/vertical-menu.js index 0481e2a83d..70930d2aac 100644 --- a/src/webcomponents/commons/view/vertical-menu.js +++ b/src/webcomponents/commons/view/vertical-menu.js @@ -1,5 +1,6 @@ import {LitElement, html, nothing} from "lit"; import UtilsNew from "../../../core/utils-new.js"; +import LitUtils from "../utils/lit-utils.js"; export default class VerticalMenu extends LitElement { @@ -56,6 +57,7 @@ export default class VerticalMenu extends LitElement { onChangeActiveItem(newActiveItem) { this._activeItem = newActiveItem; + LitUtils.dispatchCustomEvent(this, "changeActiveItem", this._activeItem); this.requestUpdate(); } From cc0465e558a71750dfa4bc49b3606d4572fe47bb Mon Sep 17 00:00:00 2001 From: Josemi Date: Fri, 26 Sep 2025 13:12:38 +0200 Subject: [PATCH 03/15] wc: add utility to extract current application and tool from hash fragment #TASK-7762 --- src/webcomponents/commons/utils/web-utils.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/webcomponents/commons/utils/web-utils.js b/src/webcomponents/commons/utils/web-utils.js index 38b3bfaa56..219d805044 100644 --- a/src/webcomponents/commons/utils/web-utils.js +++ b/src/webcomponents/commons/utils/web-utils.js @@ -123,4 +123,10 @@ export default class WebUtils { }); } + static getApplicationAndToolFromHash(hash = "") { + // '#clinical/portal/project/study' --> ['clinical', 'portal] + // '#portal/project/study' --> ['portal'] + return (hash || window.location.hash).replace("#", "").split("/").slice(0, -2); + } + } From 731b1feda13daf23a18ff1d16e8886eb37610d8c Mon Sep 17 00:00:00 2001 From: Josemi Date: Fri, 26 Sep 2025 13:20:28 +0200 Subject: [PATCH 04/15] wc: refactor methods to generate links to IVA in webutils #TASK-7762 --- src/webcomponents/commons/utils/web-utils.js | 33 +++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/src/webcomponents/commons/utils/web-utils.js b/src/webcomponents/commons/utils/web-utils.js index 219d805044..146ba9670f 100644 --- a/src/webcomponents/commons/utils/web-utils.js +++ b/src/webcomponents/commons/utils/web-utils.js @@ -60,26 +60,27 @@ export default class WebUtils { return (resource && mapResourcePermissionId[resource] && mode) ? `${mode.toUpperCase()}_${mapResourcePermissionId[resource]}` : ""; } - static getIVALink(opencgaSession, tool, query = {}) { - const baseUrl = (new URL(window.location.pathname, window.location.origin)); - let queryStr = ""; - // Check if query object has been provided - if (query) { - queryStr = "?" + (new URLSearchParams(query)).toString(); - } - return `${baseUrl}#${tool}/${opencgaSession.project.id}/${opencgaSession.study.id}${queryStr}`; - } - - static getInterpreterLink(opencgaSession, caseId = "") { + static getLink(opencgaSession, app = "", tool = "", query = null) { const hashItems = [ - // ...window.location.hash.replace("#", "").split("/").slice(0, -3), // '#clinical/portal/project/study' --> ['clinical'] - "clinical", - "interpreter", + app, + tool, opencgaSession?.project?.id || "", opencgaSession?.study?.id || "", ]; - return `#${hashItems.filter(Boolean).join("/")}${!!caseId ? "?id=" + caseId : ""}`; + // build the querystring fragment of the URL if a query object is provided + const queryStr = (query && Object.keys(query || {}).length > 0) ? "?" + (new URLSearchParams(query)).toString() : ""; + + // build and return the internal link + return `#${hashItems.filter(Boolean).join("/")}${queryStr}`; + } + + static getIVALink(opencgaSession, app, tool, query = null) { + return (new URL(window.location.pathname, window.location.origin)) + WebUtils.getLink(opencgaSession, app, tool, query); + } + + static getInterpreterLink(opencgaSession, query = null) { + return WebUtils.getLink(opencgaSession, "clinical", "interpreter", query); } static jobStatusFormatter(status, appendDescription = false) { @@ -129,4 +130,6 @@ export default class WebUtils { return (hash || window.location.hash).replace("#", "").split("/").slice(0, -2); } + + } From 15c33725349c5fbc63a5d603c7bfd5ae5e843764 Mon Sep 17 00:00:00 2001 From: Josemi Date: Fri, 26 Sep 2025 13:21:11 +0200 Subject: [PATCH 05/15] wc: add method to redirect to the provided app and tool #TASK-7762 --- src/webcomponents/commons/utils/web-utils.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/webcomponents/commons/utils/web-utils.js b/src/webcomponents/commons/utils/web-utils.js index 146ba9670f..9ada0878e0 100644 --- a/src/webcomponents/commons/utils/web-utils.js +++ b/src/webcomponents/commons/utils/web-utils.js @@ -130,6 +130,7 @@ export default class WebUtils { return (hash || window.location.hash).replace("#", "").split("/").slice(0, -2); } - - + static redirectTo(opencgaSession, app = "", tool = "", query = {}) { + window.location.hash = WebUtils.getLink(opencgaSession, app, tool, query); + } } From a34c490aa551894fd11bc5cde3fd70031074d186 Mon Sep 17 00:00:00 2001 From: Josemi Date: Fri, 26 Sep 2025 13:54:21 +0200 Subject: [PATCH 06/15] wc: fix usage of getIVALink in variant browser grid #TASK-7762 --- src/webcomponents/variant/variant-browser-grid.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/webcomponents/variant/variant-browser-grid.js b/src/webcomponents/variant/variant-browser-grid.js index 5ef2911f36..6039e52a41 100644 --- a/src/webcomponents/variant/variant-browser-grid.js +++ b/src/webcomponents/variant/variant-browser-grid.js @@ -966,7 +966,8 @@ export default class VariantBrowserGrid extends LitElement { switch (action) { case "copy-link": // 1. Generate the URL to this variant - const link = WebUtils.getIVALink(this.opencgaSession, this.toolId, {id: row.id}); + const [app, tool] = WebUtils.getApplicationAndToolFromHash(); + const link = WebUtils.getIVALink(this.opencgaSession, app, tool, {id: row.id}); // 2. Copy this link to the clipboard UtilsNew.copyToClipboard(link); // 3. Notify user that link has been copied to the clipboard From 927533891707a830466cf1461afde2916514dc45 Mon Sep 17 00:00:00 2001 From: Josemi Date: Fri, 26 Sep 2025 13:54:59 +0200 Subject: [PATCH 07/15] wc: fix usage of getIVALink in new filters toolbar #TASK-7762 --- src/webcomponents/commons/filters-toolbar.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/webcomponents/commons/filters-toolbar.js b/src/webcomponents/commons/filters-toolbar.js index f9985e9a9b..97f73ac4de 100644 --- a/src/webcomponents/commons/filters-toolbar.js +++ b/src/webcomponents/commons/filters-toolbar.js @@ -439,7 +439,8 @@ export default class FiltersToolbar extends LitElement { onCopyLink() { // 1. Generate the url to the tool with the current query - const link = WebUtils.getIVALink(this.opencgaSession, this.toolId, this.preparedQuery); + const [app, tool] = WebUtils.getApplicationAndToolFromHash(); + const link = WebUtils.getIVALink(this.opencgaSession, app, tool, this.preparedQuery); // 2. Copy this link to the user clipboard UtilsNew.copyToClipboard(link); From 10b6634fd2ab790a343df3cc221b97046135b1d3 Mon Sep 17 00:00:00 2001 From: Josemi Date: Fri, 26 Sep 2025 13:55:07 +0200 Subject: [PATCH 08/15] wc: fix usage of getIVALink in old filters toolbar #TASK-7762 --- src/webcomponents/commons/opencga-active-filters.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/webcomponents/commons/opencga-active-filters.js b/src/webcomponents/commons/opencga-active-filters.js index 14c02caf9d..9f004ddf48 100644 --- a/src/webcomponents/commons/opencga-active-filters.js +++ b/src/webcomponents/commons/opencga-active-filters.js @@ -719,7 +719,8 @@ export default class OpencgaActiveFilters extends LitElement { onCopyLink() { // 1. Generate the url to the tool with the current query - const link = WebUtils.getIVALink(this.opencgaSession, this.toolId, this.query); + const [app, tool] = WebUtils.getApplicationAndToolFromHash(); + const link = WebUtils.getIVALink(this.opencgaSession, app, tool, this.query); // 2. Copy this link to the user clipboard UtilsNew.copyToClipboard(link); // 3. Notify user that the link has been copied to the clipboard From 35dc1e9febef93362e153d35054f2b9fc1121709 Mon Sep 17 00:00:00 2001 From: Josemi Date: Fri, 26 Sep 2025 13:57:09 +0200 Subject: [PATCH 09/15] wc: fix analysis tools to listen for active item change in vertical menu #TASK-7762 --- .../commons/analysis/analysis-tools.js | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/webcomponents/commons/analysis/analysis-tools.js b/src/webcomponents/commons/analysis/analysis-tools.js index c8b69c9832..af06b1e38b 100644 --- a/src/webcomponents/commons/analysis/analysis-tools.js +++ b/src/webcomponents/commons/analysis/analysis-tools.js @@ -1,4 +1,5 @@ -import {LitElement, html, nothing, render} from "lit"; +import {LitElement, html} from "lit"; +import WebUtils from "../utils/web-utils.js"; import "../tool-header.js"; import "../view/vertical-menu.js"; import "../../clinical/analysis/mutational-signature-analysis.js"; @@ -42,6 +43,9 @@ export default class AnalysisTools extends LitElement { opencgaSession: { type: Object, }, + tool: { + type: String, + }, }; } @@ -49,12 +53,21 @@ export default class AnalysisTools extends LitElement { this._config = this.getDefaultConfig(); } + onChangeActiveTool(event) { + const [app, tool] = WebUtils.getApplicationAndToolFromHash(); + WebUtils.redirectTo(this.opencgaSession, app, tool, { + tool: event.detail.value, + }); + } + render() { return html` + .activeItem="${this.tool}" + .config="${this._config || {}}" + @changeActiveItem="${event => this.onChangeActiveTool(event)}"> `; } From 7861cb7293f11dd0c1a4acd7bb4787bca67afaf2 Mon Sep 17 00:00:00 2001 From: Josemi Date: Fri, 26 Sep 2025 14:00:10 +0200 Subject: [PATCH 10/15] wc: fix organization-admin to listen for active item change in vertical menu #TASK-7762 --- .../organization/admin/organization-admin.js | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/webcomponents/organization/admin/organization-admin.js b/src/webcomponents/organization/admin/organization-admin.js index cb19e10d88..8db5fcd3cf 100644 --- a/src/webcomponents/organization/admin/organization-admin.js +++ b/src/webcomponents/organization/admin/organization-admin.js @@ -14,6 +14,7 @@ * limitations under the License. */ import {LitElement, html} from "lit"; +import WebUtils from "../../commons/utils/web-utils.js"; import OpencgaCatalogUtils from "../../../core/clients/opencga/opencga-catalog-utils.js"; import "./group-admin-browser.js"; import "./user-admin-browser.js"; @@ -38,7 +39,10 @@ export default class OrganizationAdmin extends LitElement { static get properties() { return { opencgaSession: { - type: Object + type: Object, + }, + tool: { + type: String, }, }; } @@ -47,6 +51,13 @@ export default class OrganizationAdmin extends LitElement { this._config = this.getDefaultConfig(); } + onChangeActiveItem(event) { + const [app, tool] = WebUtils.getApplicationAndToolFromHash(); + WebUtils.redirectTo(this.opencgaSession, app, tool, { + tool: event.detail.value, + }); + } + render() { if (!this.opencgaSession?.organization || !OpencgaCatalogUtils.isOrganizationAdmin(this.opencgaSession?.organization, this.opencgaSession?.user?.id)) { return html` @@ -60,7 +71,9 @@ export default class OrganizationAdmin extends LitElement { + .activeItem="${this.tool}" + .config="${this._config || {}}" + @changeActiveItem="${event => this.onChangeActiveItem(event)}"> `; } From ab5749fe0ced088149f32b31bae7855926d6cb70 Mon Sep 17 00:00:00 2001 From: Josemi Date: Fri, 26 Sep 2025 14:00:57 +0200 Subject: [PATCH 11/15] wc: rename active item listener in analysis-tools #TASK-7762 --- src/webcomponents/commons/analysis/analysis-tools.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/webcomponents/commons/analysis/analysis-tools.js b/src/webcomponents/commons/analysis/analysis-tools.js index af06b1e38b..ef1a1ba0b0 100644 --- a/src/webcomponents/commons/analysis/analysis-tools.js +++ b/src/webcomponents/commons/analysis/analysis-tools.js @@ -53,7 +53,7 @@ export default class AnalysisTools extends LitElement { this._config = this.getDefaultConfig(); } - onChangeActiveTool(event) { + onChangeActiveItem(event) { const [app, tool] = WebUtils.getApplicationAndToolFromHash(); WebUtils.redirectTo(this.opencgaSession, app, tool, { tool: event.detail.value, @@ -67,7 +67,7 @@ export default class AnalysisTools extends LitElement { .opencgaSession="${this.opencgaSession}" .activeItem="${this.tool}" .config="${this._config || {}}" - @changeActiveItem="${event => this.onChangeActiveTool(event)}"> + @changeActiveItem="${event => this.onChangeActiveItem(event)}"> `; } From 1c69d559d20029ef0dc21df3593c99e5c18f783d Mon Sep 17 00:00:00 2001 From: Josemi Date: Fri, 26 Sep 2025 14:06:51 +0200 Subject: [PATCH 12/15] wc: fix study-admin-iva to listen for active item change in vertical menu #TASK-7762 --- .../study/admin/study-admin-iva.js | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/webcomponents/study/admin/study-admin-iva.js b/src/webcomponents/study/admin/study-admin-iva.js index 620b1ed7a3..3d761b42bc 100644 --- a/src/webcomponents/study/admin/study-admin-iva.js +++ b/src/webcomponents/study/admin/study-admin-iva.js @@ -15,9 +15,7 @@ */ import {LitElement, html} from "lit"; -import LitUtils from "../../commons/utils/lit-utils"; -import NotificationUtils from "../../commons/utils/notification-utils"; -import UtilsNew from "../../../core/utils-new"; +import WebUtils from "../../commons/utils/web-utils.js"; import OpencgaCatalogUtils from "../../../core/clients/opencga/opencga-catalog-utils"; import "../../commons/view/vertical-menu.js"; import "../../commons/pages/restricted-access-page.js"; @@ -41,6 +39,9 @@ export default class StudyAdminIva extends LitElement { opencgaSession: { type: Object, }, + tool: { + type: String, + }, settings: { type: Object, }, @@ -78,6 +79,13 @@ export default class StudyAdminIva extends LitElement { return (title === "Clinical Analysis Browser") ? "Clinical Analysis Portal" : title; } + onChangeActiveItem(event) { + const [app, tool] = WebUtils.getApplicationAndToolFromHash(); + WebUtils.redirectTo(this.opencgaSession, app, tool, { + tool: event.detail.value, + }); + } + render() { const isOrganizationAdmin = OpencgaCatalogUtils.isOrganizationAdmin(this.opencgaSession?.organization, this.opencgaSession?.user?.id); const isAdmin = OpencgaCatalogUtils.isAdmin(this.opencgaSession?.study, this.opencgaSession?.user?.id); @@ -94,7 +102,9 @@ export default class StudyAdminIva extends LitElement { + .activeItem="${this.tool}" + .config="${this._config || {}}" + @changeActiveItem="${event => this.onChangeActiveItem(event)}"> `; } From 3027bbf69b0f7adce74a425fe737f412b85206a1 Mon Sep 17 00:00:00 2001 From: Josemi Date: Fri, 26 Sep 2025 14:08:16 +0200 Subject: [PATCH 13/15] wc: fix study-admin to listen for active item change in vertical menu #TASK-7762 --- src/webcomponents/study/admin/study-admin.js | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/webcomponents/study/admin/study-admin.js b/src/webcomponents/study/admin/study-admin.js index 51f034a2e7..a59add1e4b 100644 --- a/src/webcomponents/study/admin/study-admin.js +++ b/src/webcomponents/study/admin/study-admin.js @@ -15,6 +15,7 @@ */ import {LitElement, html} from "lit"; +import WebUtils from "../../commons/utils/web-utils.js"; import OpencgaCatalogUtils from "../../../core/clients/opencga/opencga-catalog-utils.js"; import "./study-admin-users.js"; import "./study-admin-permissions.js"; @@ -44,6 +45,9 @@ export default class StudyAdmin extends LitElement { opencgaSession: { type: Object, }, + tool: { + type: String, + }, }; } @@ -51,6 +55,13 @@ export default class StudyAdmin extends LitElement { this._config = this.getDefaultConfig(); } + onChangeActiveItem(event) { + const [app, tool] = WebUtils.getApplicationAndToolFromHash(); + WebUtils.redirectTo(this.opencgaSession, app, tool, { + tool: event.detail.value, + }); + } + render() { const isOrganizationAdmin = OpencgaCatalogUtils.isOrganizationAdmin(this.opencgaSession?.organization, this.opencgaSession?.user?.id); const isAdmin = OpencgaCatalogUtils.isAdmin(this.opencgaSession?.study, this.opencgaSession?.user?.id); @@ -67,7 +78,9 @@ export default class StudyAdmin extends LitElement { + .activeItem="${this.tool}" + .config="${this._config || {}}" + @changeActiveItem="${event => this.onChangeActiveItem(event)}"> `; } From 89d394a1a35478d7167632de2c58542c2eb526ba Mon Sep 17 00:00:00 2001 From: Josemi Date: Fri, 26 Sep 2025 14:09:31 +0200 Subject: [PATCH 14/15] wc: fix operations-admin to listen for active item change in vertical menu #TASK-7762 --- .../study/admin/variant/operations-admin.js | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/webcomponents/study/admin/variant/operations-admin.js b/src/webcomponents/study/admin/variant/operations-admin.js index ea8742c0f3..d2d0a08994 100644 --- a/src/webcomponents/study/admin/variant/operations-admin.js +++ b/src/webcomponents/study/admin/variant/operations-admin.js @@ -15,6 +15,7 @@ */ import {LitElement, html} from "lit"; +import WebUtils from "../../../commons/utils/web-utils.js"; import OpencgaCatalogUtils from "../../../../core/clients/opencga/opencga-catalog-utils"; import "../../../variant/operation/variant-index-operation.js"; import "../../../variant/operation/variant-stats-index-operation.js"; @@ -40,6 +41,9 @@ export default class OperationsAdmin extends LitElement { opencgaSession: { type: Object }, + tool: { + type: String, + }, }; } @@ -48,6 +52,13 @@ export default class OperationsAdmin extends LitElement { this._config = this.getDefaultConfig(); } + onChangeActiveItem(event) { + const [app, tool] = WebUtils.getApplicationAndToolFromHash(); + WebUtils.redirectTo(this.opencgaSession, app, tool, { + tool: event.detail.value, + }); + } + render() { const isOrganizationAdmin = OpencgaCatalogUtils.isOrganizationAdmin(this.opencgaSession?.organization, this.opencgaSession?.user?.id); const isAdmin = OpencgaCatalogUtils.isAdmin(this.opencgaSession?.study, this.opencgaSession?.user?.id); @@ -64,7 +75,9 @@ export default class OperationsAdmin extends LitElement { + .activeItem="${this.tool}" + .config="${this._config || {}}" + @changeActiveItem="${event => this.onChangeActiveItem(event)}"> `; } From 7cae0fe66f89b7dc2ab5edc34d2a1443dd8ac686 Mon Sep 17 00:00:00 2001 From: Josemi Date: Fri, 26 Sep 2025 14:10:31 +0200 Subject: [PATCH 15/15] iva: add tool property in some components #TASK-7762 --- src/sites/iva/iva-app.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/sites/iva/iva-app.js b/src/sites/iva/iva-app.js index f765bacd99..e7d32545b3 100644 --- a/src/sites/iva/iva-app.js +++ b/src/sites/iva/iva-app.js @@ -1417,6 +1417,7 @@ class IvaApp extends LitElement { content = html` @@ -1448,6 +1449,7 @@ class IvaApp extends LitElement { content = html` `; @@ -1456,6 +1458,7 @@ class IvaApp extends LitElement { content = html` @@ -1465,6 +1468,7 @@ class IvaApp extends LitElement { content = html` `; @@ -1501,7 +1505,8 @@ class IvaApp extends LitElement { case "analysis-tools": content = html` + .opencgaSession="${this.opencgaSession}" + .tool="${this.queries[this.tool]?.tool}"> `; break;