diff --git a/src/sites/iva/iva-app.js b/src/sites/iva/iva-app.js
index d6f222e7f9..a4c941b495 100644
--- a/src/sites/iva/iva-app.js
+++ b/src/sites/iva/iva-app.js
@@ -1268,6 +1268,7 @@ class IvaApp extends LitElement {
content = html`
@@ -1291,6 +1292,7 @@ class IvaApp extends LitElement {
content = html`
`;
@@ -1299,6 +1301,7 @@ class IvaApp extends LitElement {
content = html`
@@ -1308,6 +1311,7 @@ class IvaApp extends LitElement {
content = html`
`;
@@ -1344,7 +1348,8 @@ class IvaApp extends LitElement {
case "analysis-tools":
content = html`
+ .opencgaSession="${this.opencgaSession}"
+ .tool="${this.queries[this.tool]?.tool}">
`;
break;
diff --git a/src/webcomponents/commons/analysis/analysis-tools.js b/src/webcomponents/commons/analysis/analysis-tools.js
index c8b69c9832..ef1a1ba0b0 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();
}
+ onChangeActiveItem(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.onChangeActiveItem(event)}">
`;
}
diff --git a/src/webcomponents/commons/filters-toolbar.js b/src/webcomponents/commons/filters-toolbar.js
index a3ad6cfcb8..a9af2c2ebc 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);
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
diff --git a/src/webcomponents/commons/utils/web-utils.js b/src/webcomponents/commons/utils/web-utils.js
index 8f2be9b30b..b241346d70 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 getClinicalAnalysisPriorityColour(rank) {
@@ -100,4 +101,13 @@ 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);
+ }
+
+ static redirectTo(opencgaSession, app = "", tool = "", query = {}) {
+ window.location.hash = WebUtils.getLink(opencgaSession, app, tool, query);
+ }
}
diff --git a/src/webcomponents/commons/view/vertical-menu.js b/src/webcomponents/commons/view/vertical-menu.js
index ac8ba76732..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 {
@@ -17,6 +18,9 @@ export default class VerticalMenu extends LitElement {
opencgaSession: {
type: Object,
},
+ activeItem: {
+ type: String,
+ },
config: {
type: Object,
},
@@ -35,8 +39,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;
}
}
@@ -46,6 +57,7 @@ export default class VerticalMenu extends LitElement {
onChangeActiveItem(newActiveItem) {
this._activeItem = newActiveItem;
+ LitUtils.dispatchCustomEvent(this, "changeActiveItem", this._activeItem);
this.requestUpdate();
}
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)}">
`;
}
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)}">
`;
}
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)}">
`;
}
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)}">
`;
}
diff --git a/src/webcomponents/variant/variant-browser-grid.js b/src/webcomponents/variant/variant-browser-grid.js
index 6b43d5f23c..68c9dc3e33 100644
--- a/src/webcomponents/variant/variant-browser-grid.js
+++ b/src/webcomponents/variant/variant-browser-grid.js
@@ -903,7 +903,8 @@ export default class VariantBrowserGrid extends LitElement {
break;
case "copy-link":
// 1. Generate the URL to this variant
- const link = WebUtils.getIVALink(this.opencgaSession, this.toolId, {id: variant.id});
+ const [app, tool] = WebUtils.getApplicationAndToolFromHash();
+ const link = WebUtils.getIVALink(this.opencgaSession, app, tool, {id: variant.id});
// 2. Copy this link to the clipboard
UtilsNew.copyToClipboard(link);
// 3. Notify user that link has been copied to the clipboard