diff --git a/services/static-webserver/client/source/class/osparc/dashboard/ResourceBrowserFilter.js b/services/static-webserver/client/source/class/osparc/dashboard/ResourceBrowserFilter.js index 54857e7db2d7..9f1d9528cd2e 100644 --- a/services/static-webserver/client/source/class/osparc/dashboard/ResourceBrowserFilter.js +++ b/services/static-webserver/client/source/class/osparc/dashboard/ResourceBrowserFilter.js @@ -57,8 +57,35 @@ qx.Class.define("osparc.dashboard.ResourceBrowserFilter", { __tagButtons: null, __appTypeButtons: null, + _createChildControlImpl: function(id) { + let control; + switch (id) { + case "filters-spacer": + control = new qx.ui.core.Spacer(10, 10); + this._add(control); + break; + case "shared-with-layout": + control = this.__createSharedWithFilterLayout(); + this._add(control); + break; + case "app-type-layout": + control = this.__createAppTypeFilterLayout(); + this._add(control); + break; + case "tags-layout": { + control = this.__createTagsFilterLayout(); + const scrollView = new qx.ui.container.Scroll(); + scrollView.add(control); + this._add(scrollView, { + flex: 1 + }); + break; + } + } + return control || null; + }, + __buildLayout: function() { - const filtersSpacer = new qx.ui.core.Spacer(10, 10); switch (this.__resourceType) { case "study": { this._add(this.__createWorkspacesAndFoldersTree()); @@ -72,28 +99,18 @@ qx.Class.define("osparc.dashboard.ResourceBrowserFilter", { this._add(this.__createFunctions()); } this._add(this.__createTrashBin()); - this._add(filtersSpacer); - const scrollView = new qx.ui.container.Scroll(); - scrollView.add(this.__createTagsFilterLayout()); - this._add(scrollView, { - flex: 1 - }); + this.getChildControl("filters-spacer"); break; } - case "template": { - this._add(filtersSpacer); - this._add(this.__createSharedWithFilterLayout()); - const scrollView = new qx.ui.container.Scroll(); - scrollView.add(this.__createTagsFilterLayout()); - this._add(scrollView, { - flex: 1 - }); + case "template": + this.getChildControl("filters-spacer"); + this.getChildControl("shared-with-layout"); + this.getChildControl("tags-layout"); break; - } case "service": - this._add(filtersSpacer); - this._add(this.__createSharedWithFilterLayout()); - this._add(this.__createAppTypeFilterLayout()); + this.getChildControl("filters-spacer"); + this.getChildControl("shared-with-layout"); + this.getChildControl("app-type-layout"); break; } }, @@ -354,12 +371,6 @@ qx.Class.define("osparc.dashboard.ResourceBrowserFilter", { __createTagsFilterLayout: function() { const tagsLayout = new qx.ui.container.Composite(new qx.ui.layout.VBox(2)); osparc.utils.Utils.setIdToWidget(tagsLayout, this.__resourceType + "-tagsFilter"); - - this.__populateTags(tagsLayout, []); - osparc.store.Tags.getInstance().addListener("tagsChanged", () => { - this.__populateTags(tagsLayout, this.__getSelectedTagIds()); - }, this); - return tagsLayout; }, @@ -368,11 +379,17 @@ qx.Class.define("osparc.dashboard.ResourceBrowserFilter", { return selectedTagIds; }, - __populateTags: function(tagsLayout, selectedTagIds) { - const maxTags = 5; - this.__tagButtons = []; + populateTags: function(presentTagIds = []) { + const selectedTagIds = this.__getSelectedTagIds(); + const tagsLayout = this.getChildControl("tags-layout"); tagsLayout.removeAll(); - osparc.store.Tags.getInstance().getTags().forEach((tag, idx) => { + const maxTags = 10; + this.__tagButtons = []; + presentTagIds.forEach(tagId => { + const tag = osparc.store.Tags.getInstance().getTag(tagId); + if (!tag) { + return; + } const button = new qx.ui.form.ToggleButton(null, "@FontAwesome5Solid/tag/16"); button.id = tag.getTagId(); tag.bind("name", button, "label"); @@ -391,7 +408,7 @@ qx.Class.define("osparc.dashboard.ResourceBrowserFilter", { this.fireDataEvent("changeSelectedTags", selection); }, this); - button.setVisibility(idx >= maxTags ? "excluded" : "visible"); + button.setVisibility(this.__tagButtons.length >= maxTags ? "excluded" : "visible"); this.__tagButtons.push(button); }); @@ -426,6 +443,7 @@ qx.Class.define("osparc.dashboard.ResourceBrowserFilter", { myAccountWindow.openTags(); }); tagsLayout.add(editTagsButton); + editTagsButton.exclude(); // excluded for now, they will be used as categories if (this.__resourceType === "study") { tagsLayout.getChildren().forEach(item => item.setPaddingLeft(10)); // align them with the context diff --git a/services/static-webserver/client/source/class/osparc/dashboard/TutorialBrowser.js b/services/static-webserver/client/source/class/osparc/dashboard/TutorialBrowser.js index d54097606b5a..43a15eaf17c4 100644 --- a/services/static-webserver/client/source/class/osparc/dashboard/TutorialBrowser.js +++ b/services/static-webserver/client/source/class/osparc/dashboard/TutorialBrowser.js @@ -116,6 +116,27 @@ qx.Class.define("osparc.dashboard.TutorialBrowser", { }); this.__evaluateUpdateAllButton(); osparc.filter.UIFilterController.dispatch("searchBarFilter"); + + this.__populateTags(); + }, + + __populateTags: function() { + if (this._resourceFilter) { + const presentTags = new Set(); + this._resourcesList.forEach(template => { + (template["tags"] || []).forEach(tagId => presentTags.add(tagId)); + }); + this._resourceFilter.populateTags(Array.from(presentTags)); + } + }, + + // overridden + _groupByChanged: function(groupBy) { + this.base(arguments, groupBy); + + if (this._resourceFilter) { + this._resourceFilter.getChildControl("tags-layout").setVisibility(groupBy === "tags" ? "visible" : "excluded"); + } }, __itemClicked: function(card) { @@ -143,6 +164,8 @@ qx.Class.define("osparc.dashboard.TutorialBrowser", { this._addViewModeButton(); this._addResourceFilter(); + this.__populateTags(); + osparc.store.Tags.getInstance().addListener("tagsChanged", () => this.__populateTags(), this); this._resourcesContainer.addListener("changeVisibility", () => this.__evaluateUpdateAllButton()); diff --git a/services/static-webserver/client/source/class/osparc/data/model/Node.js b/services/static-webserver/client/source/class/osparc/data/model/Node.js index d5ea36cf93fc..ce0d98d11b21 100644 --- a/services/static-webserver/client/source/class/osparc/data/model/Node.js +++ b/services/static-webserver/client/source/class/osparc/data/model/Node.js @@ -868,21 +868,35 @@ qx.Class.define("osparc.data.model.Node", { return; } - // create automatic port connections - let autoConnections = 0; - const outPorts = node1.getOutputs(); - const inPorts = node2.getInputs(); - for (const outPort in outPorts) { - for (const inPort in inPorts) { - if (await node2.addPortLink(inPort, node1.getNodeId(), outPort)) { - autoConnections++; - break; + const autoConnectPorts = async () => { + // create automatic port connections + let autoConnections = 0; + const outPorts = node1.getOutputs(); + const inPorts = node2.getInputs(); + for (const outPort in outPorts) { + for (const inPort in inPorts) { + if (await node2.addPortLink(inPort, node1.getNodeId(), outPort)) { + autoConnections++; + break; + } } } + if (autoConnections) { + const flashMessenger = osparc.FlashMessenger.getInstance(); + flashMessenger.logAs(autoConnections + this.tr(" ports auto connected"), "INFO"); + } } - if (autoConnections) { - const flashMessenger = osparc.FlashMessenger.getInstance(); - flashMessenger.logAs(autoConnections + this.tr(" ports auto connected"), "INFO"); + if (node1.getMetadata() && node2.getMetadata()) { + autoConnectPorts(); + } else { + // wait for both metadata to be loaded + const onMetadataChanged = () => { + if (node1.getMetadata() && node2.getMetadata()) { + autoConnectPorts(); + } + }; + node1.addListenerOnce("changeMetadata", onMetadataChanged, this); + node2.addListenerOnce("changeMetadata", onMetadataChanged, this); } }, diff --git a/services/static-webserver/client/source/class/osparc/desktop/organizations/MembersList.js b/services/static-webserver/client/source/class/osparc/desktop/organizations/MembersList.js index a155551492cc..9321319958ad 100644 --- a/services/static-webserver/client/source/class/osparc/desktop/organizations/MembersList.js +++ b/services/static-webserver/client/source/class/osparc/desktop/organizations/MembersList.js @@ -328,8 +328,10 @@ qx.Class.define("osparc.desktop.organizations.MembersList", { const readAccessRole = osparc.data.Roles.ORG["read"]; const newAccessRights = readAccessRole.accessRights; + const orgId = this.__currentOrg.getGroupId(); + const userId = "id" in listedMember ? listedMember["id"] : listedMember["key"]; const groupsStore = osparc.store.Groups.getInstance(); - groupsStore.patchMember(this.__currentOrg.getGroupId(), listedMember["id"], newAccessRights) + groupsStore.patchAccessRights(orgId, userId, newAccessRights) .then(() => { osparc.FlashMessenger.logAs(this.tr(`Successfully promoted to ${readAccessRole.label}`)); this.__reloadOrgMembers(); @@ -348,7 +350,7 @@ qx.Class.define("osparc.desktop.organizations.MembersList", { const noReadAccessRole = osparc.data.Roles.ORG["noRead"]; const newAccessRights = noReadAccessRole.accessRights; const orgId = this.__currentOrg.getGroupId(); - const userId = "id" in listedMember ? listedMember["id"] : listedMember["key"] + const userId = "id" in listedMember ? listedMember["id"] : listedMember["key"]; const groupsStore = osparc.store.Groups.getInstance(); groupsStore.patchAccessRights(orgId, userId, newAccessRights) .then(() => {