diff --git a/services/static-webserver/client/source/class/osparc/dashboard/Dashboard.js b/services/static-webserver/client/source/class/osparc/dashboard/Dashboard.js index b26b4d52e17..cc714440242 100644 --- a/services/static-webserver/client/source/class/osparc/dashboard/Dashboard.js +++ b/services/static-webserver/client/source/class/osparc/dashboard/Dashboard.js @@ -97,7 +97,8 @@ qx.Class.define("osparc.dashboard.Dashboard", { const permissions = osparc.data.Permissions.getInstance(); const tabIconSize = 20; const tabs = [{ - id: "studiesTabBtn", + id: "studiesTab", + buttonId: "studiesTabBtn", label: osparc.product.Utils.getStudyAlias({ plural: true, allUpperCase: true @@ -107,7 +108,8 @@ qx.Class.define("osparc.dashboard.Dashboard", { }]; if (permissions.canDo("dashboard.templates.read")) { tabs.push({ - id: "templatesTabBtn", + id: "templatesTab", + buttonId: "templatesTabBtn", label: osparc.product.Utils.getTemplateAlias({ plural: true, allUpperCase: true @@ -118,7 +120,8 @@ qx.Class.define("osparc.dashboard.Dashboard", { } if (permissions.canDo("dashboard.services.read")) { tabs.push({ - id: "servicesTabBtn", + id: "servicesTab", + buttonId: "servicesTabBtn", label: this.tr("SERVICES"), icon: "@FontAwesome5Solid/cogs/"+tabIconSize, buildLayout: this.__createServiceBrowser @@ -126,16 +129,18 @@ qx.Class.define("osparc.dashboard.Dashboard", { } if (permissions.canDo("dashboard.data.read") && osparc.product.Utils.isProduct("osparc")) { tabs.push({ - id: "dataTabBtn", + id: "dataTab", + buttonId: "dataTabBtn", label: this.tr("DATA"), icon: "@FontAwesome5Solid/folder/"+tabIconSize, buildLayout: this.__createDataBrowser }); } - tabs.forEach(({id, label, icon, buildLayout}) => { + tabs.forEach(({id, buttonId, label, icon, buildLayout}) => { const tabPage = new qx.ui.tabview.Page(label, icon).set({ appearance: "dashboard-page" }); + tabPage.id = id; const tabButton = tabPage.getChildControl("button"); tabButton.set({ minWidth: 50, @@ -149,7 +154,7 @@ qx.Class.define("osparc.dashboard.Dashboard", { visibility: "excluded" }); osparc.utils.Utils.centerTabIcon(tabPage); - osparc.utils.Utils.setIdToWidget(tabButton, id); + osparc.utils.Utils.setIdToWidget(tabButton, buttonId); tabPage.setLayout(new qx.ui.layout.Grow()); const viewLayout = buildLayout.call(this); @@ -158,6 +163,13 @@ qx.Class.define("osparc.dashboard.Dashboard", { viewLayout.resetSelection(); } }, this); + viewLayout.addListener("changeTab", e => { + const activeTab = e.getData(); + const tabFound = this.getSelectables().find(s => s.id === activeTab); + if (tabFound) { + this.setSelection([tabFound]); + } + }, this); const scrollerMainView = new qx.ui.container.Scroll(); scrollerMainView.add(viewLayout); tabPage.add(scrollerMainView); diff --git a/services/static-webserver/client/source/class/osparc/dashboard/ResourceBrowserBase.js b/services/static-webserver/client/source/class/osparc/dashboard/ResourceBrowserBase.js index 4982fcaefed..9082c3a5c2b 100644 --- a/services/static-webserver/client/source/class/osparc/dashboard/ResourceBrowserBase.js +++ b/services/static-webserver/client/source/class/osparc/dashboard/ResourceBrowserBase.js @@ -77,6 +77,7 @@ qx.Class.define("osparc.dashboard.ResourceBrowserBase", { }, events: { + "changeTab": "qx.event.type.Data", "publishTemplate": "qx.event.type.Data" }, @@ -222,7 +223,7 @@ qx.Class.define("osparc.dashboard.ResourceBrowserBase", { throw new Error("Abstract method called!"); }, - reloadResources: function() { + reloadMoreResources: function() { throw new Error("Abstract method called!"); }, @@ -431,7 +432,7 @@ qx.Class.define("osparc.dashboard.ResourceBrowserBase", { _moreResourcesRequired: function() { if (this._resourcesContainer && this._resourcesContainer.areMoreResourcesRequired(this._loadingResourcesBtn)) { - this.reloadResources(); + this.reloadMoreResources(); } }, @@ -456,6 +457,9 @@ qx.Class.define("osparc.dashboard.ResourceBrowserBase", { }, _startStudyById: function(studyId, openCB, cancelCB, isStudyCreation = false) { + if (isStudyCreation) { + this.fireDataEvent("changeTab", "studiesTab"); + } this.self().startStudyById(studyId, openCB, cancelCB, isStudyCreation); }, diff --git a/services/static-webserver/client/source/class/osparc/dashboard/StudyBrowser.js b/services/static-webserver/client/source/class/osparc/dashboard/StudyBrowser.js index ae1864c7514..c60730c757b 100644 --- a/services/static-webserver/client/source/class/osparc/dashboard/StudyBrowser.js +++ b/services/static-webserver/client/source/class/osparc/dashboard/StudyBrowser.js @@ -119,7 +119,6 @@ qx.Class.define("osparc.dashboard.StudyBrowser", { const isStudyCreation = false; this._startStudyById(loadStudyId, null, cancelCB, isStudyCreation); } else { - this.__reloadFolders(); this.reloadResources(); } // "Starting..." page @@ -151,12 +150,17 @@ qx.Class.define("osparc.dashboard.StudyBrowser", { osparc.data.Permissions.getInstance().canDo("studies.user.read") && osparc.auth.Manager.getInstance().isLoggedIn() ) { + this.__reloadFolders(); this.__reloadStudies(); } else { this.__resetStudiesList(); } }, + reloadMoreResources: function() { + this.__reloadStudies(); + }, + __reloadWorkspaces: function() { this.__setWorkspacesToList([]); osparc.store.Workspaces.getInstance().fetchWorkspaces() @@ -223,21 +227,11 @@ qx.Class.define("osparc.dashboard.StudyBrowser", { this._loadingResourcesBtn.setVisibility("visible"); this.__getNextStudiesRequest() .then(resp => { - const urlParams = resp["params"]["url"]; // Context might have been changed while waiting for the response. // The new call is on the way, therefore this response can be ignored. - if ("workspaceId" in urlParams) { - if ( - urlParams.workspaceId !== this.getCurrentWorkspaceId() || - urlParams.folderId !== this.getCurrentFolderId() - ) { - return; - } - } else if ("text" in urlParams) { - const currentFilterData = this._searchBarFilter.getFilterData(); - if (currentFilterData.text && urlParams.text !== encodeURIComponent(currentFilterData.text)) { - return; - } + const contextChanged = this.__didContextChange(resp["params"]["url"]); + if (contextChanged) { + return; } const studies = resp["data"]; @@ -615,26 +609,67 @@ qx.Class.define("osparc.dashboard.StudyBrowser", { }, this); }, + __didContextChange: function(reqParams) { + // not needed for the comparison + delete reqParams["type"]; + delete reqParams["limit"]; + delete reqParams["offset"]; + + // check the entries in currentParams are the same as the reqParams + const currentParams = this.__getRequestParams(); + let sameContext = true; + Object.entries(currentParams).forEach(([key, value]) => { + sameContext &= key in reqParams && reqParams[key] === value; + }); + return !sameContext; + }, + __getNextPageParams: function() { - if ("nextRequest" in this._resourcesContainer.getFlatList() && - this._resourcesContainer.getFlatList().nextRequest !== null && - osparc.utils.Utils.hasParamFromURL(this._resourcesContainer.getFlatList().nextRequest, "offset") && - osparc.utils.Utils.hasParamFromURL(this._resourcesContainer.getFlatList().nextRequest, "limit") - ) { - return { - offset: osparc.utils.Utils.getParamFromURL(this._resourcesContainer.getFlatList().nextRequest, "offset"), - limit: osparc.utils.Utils.getParamFromURL(this._resourcesContainer.getFlatList().nextRequest, "limit") - }; + if (this._resourcesContainer.getFlatList() && this._resourcesContainer.getFlatList().nextRequest) { + // Context might have been changed while waiting for the response. + // The new call is on the way, therefore this response can be ignored. + const url = new URL(this._resourcesContainer.getFlatList().nextRequest); + const urlSearchParams = new URLSearchParams(url.search); + const urlParams = {}; + for (const [snakeKey, value] of urlSearchParams.entries()) { + const key = osparc.utils.Utils.snakeToCamel(snakeKey); + urlParams[key] = value === "null" ? null : value; + } + const contextChanged = this.__didContextChange(urlParams); + if ( + !contextChanged && + osparc.utils.Utils.hasParamFromURL(this._resourcesContainer.getFlatList().nextRequest, "offset") && + osparc.utils.Utils.hasParamFromURL(this._resourcesContainer.getFlatList().nextRequest, "limit") + ) { + return { + offset: osparc.utils.Utils.getParamFromURL(this._resourcesContainer.getFlatList().nextRequest, "offset"), + limit: osparc.utils.Utils.getParamFromURL(this._resourcesContainer.getFlatList().nextRequest, "limit") + }; + } } return null; }, + __getRequestParams: function() { + const requestParams = {}; + requestParams.orderBy = JSON.stringify(this.getOrderBy()); + + const filterData = this._searchBarFilter.getFilterData(); + if (filterData.text) { + requestParams.text = encodeURIComponent(filterData.text); // name, description and uuid + return requestParams; + } + + requestParams.workspaceId = this.getCurrentWorkspaceId(); + requestParams.folderId = this.getCurrentFolderId(); + return requestParams; + }, + __getNextStudiesRequest: function() { const params = { url: { offset: 0, limit: osparc.dashboard.ResourceBrowserBase.PAGINATED_STUDIES, - orderBy: JSON.stringify(this.getOrderBy()), } }; @@ -647,14 +682,13 @@ qx.Class.define("osparc.dashboard.StudyBrowser", { resolveWResponse: true }; - const filterData = this._searchBarFilter.getFilterData(); - if (filterData.text) { - params.url.text = encodeURIComponent(filterData.text); // name, description and uuid + const requestParams = this.__getRequestParams(); + Object.entries(requestParams).forEach(([key, value]) => { + params.url[key] = value; + }); + if ("text" in requestParams) { return osparc.data.Resources.fetch("studies", "getPageSearch", params, undefined, options); } - - params.url.workspaceId = this.getCurrentWorkspaceId(); - params.url.folderId = this.getCurrentFolderId(); return osparc.data.Resources.fetch("studies", "getPage", params, undefined, options); }, diff --git a/services/static-webserver/client/source/class/osparc/utils/Utils.js b/services/static-webserver/client/source/class/osparc/utils/Utils.js index 67521f76086..7f2baa75805 100644 --- a/services/static-webserver/client/source/class/osparc/utils/Utils.js +++ b/services/static-webserver/client/source/class/osparc/utils/Utils.js @@ -1009,6 +1009,15 @@ qx.Class.define("osparc.utils.Utils", { isUrl: url => /^(http:\/\/www\.|https:\/\/www\.|http:\/\/|https:\/\/)?[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?$/gm.test(url), + snakeToCamel: str => { + return str.toLowerCase().replace(/([-_][a-z])/g, group => + group + .toUpperCase() + .replace("-", "") + .replace("_", "") + ); + }, + setIdToWidget: (qWidget, id) => { if (qWidget.getContentElement) { qWidget.getContentElement().setAttribute("osparc-test-id", id);