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 77595025bc45..b40fd6fc1bef 100644
--- a/services/static-webserver/client/source/class/osparc/dashboard/Dashboard.js
+++ b/services/static-webserver/client/source/class/osparc/dashboard/Dashboard.js
@@ -38,8 +38,9 @@ qx.Class.define("osparc.dashboard.Dashboard", {
construct: function() {
this.base(arguments);
- osparc.utils.Utils.setIdToWidget(this.getChildControl("bar"), "dashboardTabs");
- osparc.utils.Utils.setIdToWidget(this, "dashboard");
+ this.getChildControl("bar").set({
+ visibility: "excluded",
+ });
this.set({
contentPadding: this.self().PADDING,
diff --git a/services/static-webserver/client/source/class/osparc/dashboard/NewPlusButton.js b/services/static-webserver/client/source/class/osparc/dashboard/NewPlusButton.js
new file mode 100644
index 000000000000..125844d2b1cc
--- /dev/null
+++ b/services/static-webserver/client/source/class/osparc/dashboard/NewPlusButton.js
@@ -0,0 +1,39 @@
+/* ************************************************************************
+
+ osparc - the simcore frontend
+
+ https://osparc.io
+
+ Copyright:
+ 2025 IT'IS Foundation, https://itis.swiss
+
+ License:
+ MIT: https://opensource.org/licenses/MIT
+
+ Authors:
+ * Odei Maiz (odeimaiz)
+
+************************************************************************ */
+
+qx.Class.define("osparc.dashboard.NewPlusButton", {
+ extend: qx.ui.form.MenuButton,
+
+ construct: function() {
+ this.base(arguments);
+
+ this.set({
+ appearance: "strong-button",
+ icon: osparc.dashboard.CardBase.NEW_ICON + "20",
+ label: this.tr("New"),
+ font: "text-16",
+ gap: 15,
+ padding: 15,
+ paddingRight: 20,
+ allowGrowX: false,
+ });
+
+ osparc.utils.Utils.setIdToWidget(this, "newPlusBtn");
+
+ this.setMenu(new osparc.dashboard.NewPlusMenu());
+ },
+});
diff --git a/services/static-webserver/client/source/class/osparc/dashboard/NewPlusMenu.js b/services/static-webserver/client/source/class/osparc/dashboard/NewPlusMenu.js
new file mode 100644
index 000000000000..fb21a72cc616
--- /dev/null
+++ b/services/static-webserver/client/source/class/osparc/dashboard/NewPlusMenu.js
@@ -0,0 +1,302 @@
+/* ************************************************************************
+
+ osparc - the simcore frontend
+
+ https://osparc.io
+
+ Copyright:
+ 2025 IT'IS Foundation, https://itis.swiss
+
+ License:
+ MIT: https://opensource.org/licenses/MIT
+
+ Authors:
+ * Odei Maiz (odeimaiz)
+
+************************************************************************ */
+
+qx.Class.define("osparc.dashboard.NewPlusMenu", {
+ extend: qx.ui.menu.Menu,
+
+ construct: function() {
+ this.base(arguments);
+
+ osparc.utils.Utils.prettifyMenu(this);
+
+ this.set({
+ position: "bottom-left",
+ spacingX: 20,
+ });
+
+ this.__categoryHeaders = [];
+
+ this.__addItems();
+ },
+
+ events: {
+ "createFolder": "qx.event.type.Data",
+ "newEmptyStudyClicked": "qx.event.type.Data",
+ "newStudyFromTemplateClicked": "qx.event.type.Data",
+ "newStudyFromServiceClicked": "qx.event.type.Data",
+ },
+
+ statics: {
+ createMenuButton: function(icon, title, infoText) {
+ title = osparc.utils.Utils.replaceTokens(
+ title,
+ "replace_me_product_name",
+ osparc.store.StaticInfo.getInstance().getDisplayName()
+ );
+ const menuButton = new qx.ui.menu.Button().set({
+ icon: icon || null,
+ label: title,
+ font: "text-16",
+ allowGrowX: true,
+ });
+ menuButton.getChildControl("icon").set({
+ alignX: "center",
+ });
+ menuButton.getChildControl("label").set({
+ rich: true,
+ marginRight: 20,
+ });
+ if (infoText) {
+ infoText = osparc.utils.Utils.replaceTokens(
+ title,
+ "replace_me_product_name",
+ osparc.store.StaticInfo.getInstance().getDisplayName()
+ );
+ const infoHint = new osparc.ui.hint.InfoHint(infoText).set({
+ source: osparc.ui.hint.InfoHint.INFO_ICON + "/16",
+ });
+ // where the shortcut is supposed to go
+ // eslint-disable-next-line no-underscore-dangle
+ menuButton._add(infoHint, {column: 2});
+ }
+ return menuButton;
+ },
+
+ createHeader: function(icon, label, infoText) {
+ return this.createMenuButton(icon, label, infoText).set({
+ anonymous: true,
+ cursor: "default",
+ font: "text-14",
+ textColor: "text-darker",
+ });
+ },
+ },
+
+ members: {
+ __categoryHeaders: null,
+
+ _createChildControlImpl: function(id) {
+ let control;
+ switch (id) {
+ case "new-folder":
+ control = this.self().createMenuButton(
+ osparc.dashboard.CardBase.NEW_ICON + "16",
+ this.tr("New Folder"),
+ );
+ osparc.utils.Utils.setIdToWidget(control, "newFolderButton");
+ control.addListener("tap", () => this.__createNewFolder());
+ this.add(control);
+ break;
+ }
+ return control || this.base(arguments, id);
+ },
+
+ __addItems: async function() {
+ this.getChildControl("new-folder");
+ this.addSeparator();
+ await this.__addNewStudyItems();
+ },
+
+ __addNewStudyItems: async function() {
+ await Promise.all([
+ osparc.store.Products.getInstance().getNewStudyConfig(),
+ osparc.data.Resources.get("templates")
+ ]).then(values => {
+ const newStudiesData = values[0];
+ const templates = values[1];
+ if (newStudiesData["categories"]) {
+ this.__addCategories(newStudiesData["categories"]);
+ }
+ newStudiesData["resources"].forEach(newStudyData => {
+ if (newStudyData["showDisabled"]) {
+ this.__addDisabledButton(newStudyData);
+ } else if (newStudyData["resourceType"] === "study") {
+ this.__addEmptyStudyButton(newStudyData);
+ } else if (newStudyData["resourceType"] === "template") {
+ this.__addFromTemplateButton(newStudyData, templates);
+ } else if (newStudyData["resourceType"] === "service") {
+ this.__addFromServiceButton(newStudyData);
+ }
+ });
+ });
+ },
+
+ __getLastIdxFromCategory: function(categoryId) {
+ for (let i=this.getChildren().length-1; i>=0; i--) {
+ const child = this.getChildren()[i];
+ if (child && child["categoryId"] && child["categoryId"] === categoryId) {
+ return i;
+ }
+ }
+ return null;
+ },
+
+ __addCategories: function(categories) {
+ categories.forEach(category => {
+ const categoryHeader = this.self().createHeader(null, category["title"], category["description"]);
+ categoryHeader["categoryId"] = category["id"];
+ if (this.__categoryHeaders.length) {
+ // add spacing between categories
+ categoryHeader.setMarginTop(10);
+ }
+ this.__categoryHeaders.push(categoryHeader);
+ this.add(categoryHeader);
+ });
+ },
+
+ __addIcon: function(menuButton, resourceInfo, resourceMetadata) {
+ let source = null;
+ if (resourceInfo && "icon" in resourceInfo) {
+ // first the one set in the new_studies
+ source = resourceInfo["icon"];
+ } else if (resourceMetadata && "thumbnail" in resourceMetadata) {
+ // second the one from the resource
+ source = resourceMetadata["thumbnail"];
+ }
+
+ if (source) {
+ const thumbnail = new osparc.ui.basic.Thumbnail(source, 24, 24).set({
+ minHeight: 24,
+ minWidth: 24,
+ });
+ thumbnail.getChildControl("image").set({
+ anonymous: true,
+ decorator: "rounded",
+ });
+ // eslint-disable-next-line no-underscore-dangle
+ menuButton._add(thumbnail, {column: 0});
+ }
+ },
+
+ __addFromResourceButton: function(menuButton, category) {
+ let idx = null;
+ if (category) {
+ idx = this.__getLastIdxFromCategory(category);
+ }
+ if (idx) {
+ menuButton["categoryId"] = category;
+ this.addAt(menuButton, idx+1);
+ } else {
+ this.add(menuButton);
+ }
+ },
+
+ __addDisabledButton: function(newStudyData) {
+ const menuButton = this.self().createMenuButton(null, newStudyData.title, newStudyData.reason);
+ osparc.utils.Utils.setIdToWidget(menuButton, newStudyData.idToWidget);
+ menuButton.setEnabled(false);
+
+ this.__addIcon(menuButton, newStudyData);
+ this.__addFromResourceButton(menuButton, newStudyData.category);
+ },
+
+ __addEmptyStudyButton: function(newStudyData) {
+ const menuButton = this.self().createMenuButton(null, newStudyData.title);
+ osparc.utils.Utils.setIdToWidget(menuButton, newStudyData.idToWidget);
+
+ menuButton.addListener("tap", () => {
+ this.fireDataEvent("newEmptyStudyClicked", {
+ newStudyLabel: newStudyData.newStudyLabel,
+ });
+ });
+
+ this.__addIcon(menuButton, newStudyData);
+ this.__addFromResourceButton(menuButton, newStudyData.category);
+ },
+
+ __addFromTemplateButton: function(newStudyData, templates) {
+ const menuButton = this.self().createMenuButton(null, newStudyData.title);
+ osparc.utils.Utils.setIdToWidget(menuButton, newStudyData.idToWidget);
+ // disable it until found in templates store
+ menuButton.setEnabled(false);
+
+ let templateMetadata = templates.find(t => t.name === newStudyData.expectedTemplateLabel);
+ if (templateMetadata) {
+ menuButton.setEnabled(true);
+ menuButton.addListener("tap", () => {
+ this.fireDataEvent("newStudyFromTemplateClicked", {
+ templateData: templateMetadata,
+ newStudyLabel: newStudyData.newStudyLabel,
+ });
+ });
+ this.__addIcon(menuButton, newStudyData, templateMetadata);
+ this.__addFromResourceButton(menuButton, newStudyData.category);
+ }
+ },
+
+ __addFromServiceButton: function(newStudyData) {
+ const menuButton = this.self().createMenuButton(null, newStudyData.title);
+ osparc.utils.Utils.setIdToWidget(menuButton, newStudyData.idToWidget);
+ // disable it until found in services store
+ menuButton.setEnabled(false);
+
+ const key = newStudyData.expectedKey;
+ // Include deprecated versions, they should all be updatable to a non deprecated version
+ const versions = osparc.service.Utils.getVersions(key, false);
+ if (versions.length && newStudyData) {
+ // scale to latest compatible
+ const latestVersion = versions[0];
+ const latestCompatible = osparc.service.Utils.getLatestCompatible(key, latestVersion);
+ osparc.store.Services.getService(latestCompatible["key"], latestCompatible["version"])
+ .then(latestMetadata => {
+ // make sure this one is not deprecated
+ if (osparc.service.Utils.isDeprecated(latestMetadata)) {
+ return;
+ }
+ menuButton.setEnabled(true);
+ menuButton.addListener("tap", () => {
+ this.fireDataEvent("newStudyFromServiceClicked", {
+ serviceMetadata: latestMetadata,
+ newStudyLabel: newStudyData.newStudyLabel,
+ });
+ });
+
+ const cb = e => {
+ this.hide();
+ // so that is not consumed by the menu button itself
+ e.stopPropagation();
+ latestMetadata["resourceType"] = "service";
+ const resourceDetails = new osparc.dashboard.ResourceDetails(latestMetadata);
+ osparc.dashboard.ResourceDetails.popUpInWindow(resourceDetails);
+ }
+ const infoButton = new osparc.ui.basic.IconButton(osparc.ui.hint.InfoHint.INFO_ICON + "/16", cb);
+ // where the shortcut is supposed to go
+ // eslint-disable-next-line no-underscore-dangle
+ menuButton._add(infoButton, {column: 2});
+
+ this.__addIcon(menuButton, newStudyData, latestMetadata);
+ this.__addFromResourceButton(menuButton, newStudyData.category);
+ })
+ }
+ },
+
+ __createNewFolder: function() {
+ const newFolder = true;
+ const folderEditor = new osparc.editor.FolderEditor(newFolder);
+ const title = this.tr("New Folder");
+ const win = osparc.ui.window.Window.popUpInWindow(folderEditor, title, 300, 120);
+ folderEditor.addListener("createFolder", () => {
+ const name = folderEditor.getLabel();
+ this.fireDataEvent("createFolder", {
+ name,
+ });
+ win.close();
+ });
+ folderEditor.addListener("cancel", () => win.close());
+ },
+ },
+});
diff --git a/services/static-webserver/client/source/class/osparc/dashboard/NewStudies.js b/services/static-webserver/client/source/class/osparc/dashboard/NewStudies.js
index 4f1c9c9d736b..a4c961b82fc7 100644
--- a/services/static-webserver/client/source/class/osparc/dashboard/NewStudies.js
+++ b/services/static-webserver/client/source/class/osparc/dashboard/NewStudies.js
@@ -82,7 +82,9 @@ qx.Class.define("osparc.dashboard.NewStudies", {
this._add(noGroupContainer);
Array.from(this.__groups).forEach(group => {
- const groupContainer = this.__createGroupContainer(group.id, group.label, "transparent");
+ let headerLabel = group.title;
+ headerLabel += "description" in group ? (". " + group["description"]) : "";
+ const groupContainer = this.__createGroupContainer(group.id, headerLabel, "transparent");
this._add(groupContainer);
});
} else {
@@ -106,7 +108,18 @@ qx.Class.define("osparc.dashboard.NewStudies", {
this.__newStudies.forEach(resourceData => {
const cards = this.__resourceToCards(resourceData);
cards.forEach(newCard => {
- newCard.setEnabled(!(resourceData.showDisabled));
+ if (resourceData.showDisabled) {
+ newCard.setEnabled(false);
+ if (resourceData.reason) {
+ const reason = osparc.utils.Utils.replaceTokens(
+ resourceData.reason,
+ "replace_me_product_name",
+ osparc.store.StaticInfo.getInstance().getDisplayName()
+ );
+ const descLabel = newCard.getChildControl("subtitle-text");
+ descLabel.setValue(reason.toString());
+ }
+ }
newCards.push(newCard);
});
});
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 8c3cfd236370..049b85416891 100644
--- a/services/static-webserver/client/source/class/osparc/dashboard/ResourceBrowserBase.js
+++ b/services/static-webserver/client/source/class/osparc/dashboard/ResourceBrowserBase.js
@@ -42,10 +42,10 @@ qx.Class.define("osparc.dashboard.ResourceBrowserBase", {
const mainLayoutWithSideSpacers = new qx.ui.container.Composite(new qx.ui.layout.HBox(spacing))
this._addToMainLayout(mainLayoutWithSideSpacers);
- this.__leftFilters = new qx.ui.container.Composite(new qx.ui.layout.VBox(15)).set({
+ this._leftFilters = new qx.ui.container.Composite(new qx.ui.layout.VBox(15)).set({
width: leftColumnWidth
});
- mainLayoutWithSideSpacers.add(this.__leftFilters);
+ mainLayoutWithSideSpacers.add(this._leftFilters);
this.__centerLayout = new qx.ui.container.Composite(new qx.ui.layout.VBox(15));
mainLayoutWithSideSpacers.add(this.__centerLayout);
@@ -95,7 +95,7 @@ qx.Class.define("osparc.dashboard.ResourceBrowserBase", {
return isLogged;
},
- startStudyById: function(studyId, openCB, cancelCB, showStudyOptions = false) {
+ startStudyById: function(studyId, openCB, cancelCB, isStudyCreation = false) {
if (!osparc.dashboard.ResourceBrowserBase.checkLoggedIn()) {
return;
}
@@ -117,12 +117,15 @@ qx.Class.define("osparc.dashboard.ResourceBrowserBase", {
osparc.data.Resources.fetch("studies", "getWallet", params)
.then(wallet => {
if (
- showStudyOptions ||
+ isStudyCreation ||
wallet === null ||
osparc.desktop.credits.Utils.getWallet(wallet["walletId"]) === null
) {
// pop up study options if the study was just created or if it has no wallet assigned or user has no access to it
const resourceSelector = new osparc.study.StudyOptions(studyId);
+ if (isStudyCreation) {
+ resourceSelector.getChildControl("open-button").setLabel(this.tr("New"));
+ }
const win = osparc.study.StudyOptions.popUpInWindow(resourceSelector);
win.moveItUp();
resourceSelector.addListener("startStudy", () => {
@@ -190,7 +193,7 @@ qx.Class.define("osparc.dashboard.ResourceBrowserBase", {
},
members: {
- __leftFilters: null,
+ _leftFilters: null,
_resourceFilter: null,
__centerLayout: null,
_resourceType: null,
@@ -395,11 +398,16 @@ qx.Class.define("osparc.dashboard.ResourceBrowserBase", {
_addResourceFilter: function() {
const resourceFilter = this._resourceFilter = new osparc.dashboard.ResourceFilter(this._resourceType).set({
- marginTop: osparc.dashboard.SearchBarFilter.HEIGHT + 10,
+ marginTop: 20,
maxWidth: this.self().SIDE_SPACER_WIDTH,
width: this.self().SIDE_SPACER_WIDTH
});
+ resourceFilter.addListener("changeTab", e => {
+ const contextTab = e.getData();
+ this.fireDataEvent("changeTab", contextTab);
+ }, this);
+
resourceFilter.addListener("changeSharedWith", e => {
const sharedWith = e.getData();
this._searchBarFilter.setSharedWithActiveFilter(sharedWith.id, sharedWith.label);
@@ -420,7 +428,7 @@ qx.Class.define("osparc.dashboard.ResourceBrowserBase", {
resourceFilter.filterChanged(filterData);
});
- this.__leftFilters.add(resourceFilter, {
+ this._leftFilters.add(resourceFilter, {
flex: 1
});
},
diff --git a/services/static-webserver/client/source/class/osparc/dashboard/ResourceDetails.js b/services/static-webserver/client/source/class/osparc/dashboard/ResourceDetails.js
index 5cd54f4b231d..5f6bb97a02e5 100644
--- a/services/static-webserver/client/source/class/osparc/dashboard/ResourceDetails.js
+++ b/services/static-webserver/client/source/class/osparc/dashboard/ResourceDetails.js
@@ -126,7 +126,9 @@ qx.Class.define("osparc.dashboard.ResourceDetails", {
toolbar.add(serviceVersionSelector);
}
- const openButton = new osparc.ui.form.FetchButton(this.tr("Open")).set({
+ const studyAlias = osparc.product.Utils.getStudyAlias({firstUpperCase: true});
+ const openText = (this.__resourceData["resourceType"] === "study") ? this.tr("Open") : this.tr("New") + " " + studyAlias;
+ const openButton = new osparc.ui.form.FetchButton(openText).set({
enabled: true
});
page.openButton = openButton;
diff --git a/services/static-webserver/client/source/class/osparc/dashboard/ResourceFilter.js b/services/static-webserver/client/source/class/osparc/dashboard/ResourceFilter.js
index c9aa77b74eb3..2b35fcad22d0 100644
--- a/services/static-webserver/client/source/class/osparc/dashboard/ResourceFilter.js
+++ b/services/static-webserver/client/source/class/osparc/dashboard/ResourceFilter.js
@@ -29,12 +29,13 @@ qx.Class.define("osparc.dashboard.ResourceFilter", {
this.__tagButtons = [];
this.__serviceTypeButtons = [];
- this._setLayout(new qx.ui.layout.VBox(20));
+ this._setLayout(new qx.ui.layout.VBox(15));
this.__buildLayout();
},
events: {
"trashContext": "qx.event.type.Event",
+ "changeTab": "qx.event.type.Data",
"trashStudyRequested": "qx.event.type.Data",
"trashFolderRequested": "qx.event.type.Data",
"changeSharedWith": "qx.event.type.Data",
@@ -51,19 +52,27 @@ qx.Class.define("osparc.dashboard.ResourceFilter", {
__serviceTypeButtons: null,
__buildLayout: function() {
- if (this.__resourceType === "study") {
- this._add(this.__createWorkspacesAndFoldersTree());
- this._add(this.__createTrashBin());
- } else {
- this._add(this.__createSharedWithFilterLayout());
- }
-
- if (this.__resourceType !== "service") {
- this._add(this.__createTagsFilterLayout());
- }
-
- if (this.__resourceType === "service") {
- this._add(this.__createServiceTypeFilterLayout());
+ const filtersSpacer = new qx.ui.core.Spacer(10, 10);
+ switch (this.__resourceType) {
+ case "study":
+ this._add(this.__createWorkspacesAndFoldersTree());
+ this._add(this.__createTrashBin());
+ this._add(this.__createResourceTypeContextButtons());
+ this._add(filtersSpacer);
+ this._add(this.__createTagsFilterLayout());
+ break;
+ case "template":
+ this._add(this.__createResourceTypeContextButtons());
+ this._add(filtersSpacer);
+ this._add(this.__createSharedWithFilterLayout());
+ this._add(this.__createTagsFilterLayout());
+ break;
+ case "service":
+ this._add(this.__createResourceTypeContextButtons());
+ this._add(filtersSpacer);
+ this._add(this.__createSharedWithFilterLayout());
+ this._add(this.__createServiceTypeFilterLayout());
+ break;
}
},
@@ -83,14 +92,14 @@ qx.Class.define("osparc.dashboard.ResourceFilter", {
osparc.utils.Utils.setIdToWidget(workspacesAndFoldersTree, "contextTree");
// Height needs to be calculated manually to make it flexible
workspacesAndFoldersTree.set({
- minHeight: 60,
+ minHeight: 60, // two entries
maxHeight: 400,
height: 60,
});
workspacesAndFoldersTree.addListener("openChanged", () => {
const rowConfig = workspacesAndFoldersTree.getPane().getRowConfig();
const totalHeight = rowConfig.itemCount * rowConfig.defaultItemSize;
- workspacesAndFoldersTree.setHeight(totalHeight + 10);
+ workspacesAndFoldersTree.setHeight(totalHeight + 2);
});
return workspacesAndFoldersTree;
},
@@ -203,9 +212,94 @@ qx.Class.define("osparc.dashboard.ResourceFilter", {
},
/* /TRASH BIN */
+ /* RESOURCE TYPE CONTEXT */
+ __createResourceTypeContextButtons: function() {
+ const resourceTypeContextButtons = new qx.ui.container.Composite(new qx.ui.layout.VBox(2));
+
+ const studiesButton = this.__createStudiesButton().set({
+ value: this.__resourceType === "study",
+ visibility: this.__resourceType === "study" ? "excluded" : "visible",
+ });
+ resourceTypeContextButtons.add(studiesButton);
+
+ const permissions = osparc.data.Permissions.getInstance();
+ const templatesButton = this.__createTemplatesButton().set({
+ value: this.__resourceType === "template",
+ });
+ if (permissions.canDo("dashboard.templates.read")) {
+ resourceTypeContextButtons.add(templatesButton);
+ }
+
+ const servicesButton = this.__createServicesButton().set({
+ value: this.__resourceType === "service",
+ });
+ if (permissions.canDo("dashboard.services.read")) {
+ resourceTypeContextButtons.add(servicesButton);
+ }
+
+ return resourceTypeContextButtons;
+ },
+
+ __createStudiesButton: function() {
+ const studyAlias = osparc.product.Utils.getStudyAlias({
+ firstUpperCase: true,
+ plural: true
+ });
+ const studiesButton = new qx.ui.toolbar.RadioButton().set({
+ value: false,
+ appearance: "filter-toggle-button",
+ label: studyAlias,
+ icon: "@FontAwesome5Solid/file/16",
+ paddingLeft: 10, // align it with the context
+ });
+ osparc.utils.Utils.setIdToWidget(studiesButton, "studiesTabBtn");
+ studiesButton.addListener("tap", () => {
+ studiesButton.setValue(this.__resourceType === "study");
+ this.fireDataEvent("changeTab", "studiesTab");
+ });
+ return studiesButton;
+ },
+
+ __createTemplatesButton: function() {
+ const templateAlias = osparc.product.Utils.getTemplateAlias({
+ firstUpperCase: true,
+ plural: true
+ });
+ const templatesButton = new qx.ui.toolbar.RadioButton().set({
+ value: false,
+ appearance: "filter-toggle-button",
+ label: templateAlias,
+ icon: "@FontAwesome5Solid/copy/16",
+ paddingLeft: 10, // align it with the context
+ });
+ osparc.utils.Utils.setIdToWidget(templatesButton, "templatesTabBtn");
+ templatesButton.addListener("tap", () => {
+ templatesButton.setValue(this.__resourceType === "template");
+ this.fireDataEvent("changeTab", "templatesTab");
+ });
+ return templatesButton;
+ },
+
+ __createServicesButton: function() {
+ const servicesButton = new qx.ui.toolbar.RadioButton().set({
+ value: false,
+ appearance: "filter-toggle-button",
+ label: this.tr("Services"),
+ icon: "@FontAwesome5Solid/cogs/16",
+ paddingLeft: 10, // align it with the context
+ });
+ osparc.utils.Utils.setIdToWidget(servicesButton, "servicesTabBtn");
+ servicesButton.addListener("tap", () => {
+ servicesButton.setValue(this.__resourceType === "service");
+ this.fireDataEvent("changeTab", "servicesTab");
+ });
+ return servicesButton;
+ },
+ /* /RESOURCE TYPE CONTEXT */
+
/* SHARED WITH */
__createSharedWithFilterLayout: function() {
- const sharedWithLayout = new qx.ui.container.Composite(new qx.ui.layout.VBox(5));
+ const sharedWithLayout = new qx.ui.container.Composite(new qx.ui.layout.VBox(2));
const sharedWithRadioGroup = new qx.ui.form.RadioGroup();
sharedWithRadioGroup.setAllowEmptySelection(false);
@@ -338,7 +432,7 @@ qx.Class.define("osparc.dashboard.ResourceFilter", {
/* SERVICE TYPE */
__createServiceTypeFilterLayout: function() {
- const layout = new qx.ui.container.Composite(new qx.ui.layout.VBox(5));
+ const layout = new qx.ui.container.Composite(new qx.ui.layout.VBox(2));
const radioGroup = new qx.ui.form.RadioGroup();
radioGroup.setAllowEmptySelection(true);
diff --git a/services/static-webserver/client/source/class/osparc/dashboard/ServiceBrowser.js b/services/static-webserver/client/source/class/osparc/dashboard/ServiceBrowser.js
index 7ae65ff0bd1e..fec523a23413 100644
--- a/services/static-webserver/client/source/class/osparc/dashboard/ServiceBrowser.js
+++ b/services/static-webserver/client/source/class/osparc/dashboard/ServiceBrowser.js
@@ -103,7 +103,9 @@ qx.Class.define("osparc.dashboard.ServiceBrowser", {
return;
}
- this._showLoadingPage(this.tr("Creating ") + osparc.product.Utils.getStudyAlias());
+ const studyAlias = osparc.product.Utils.getStudyAlias({firstUpperCase: true});
+ this._showLoadingPage(this.tr("Creating ") + studyAlias);
+
osparc.study.Utils.createStudyFromService(key, version)
.then(studyId => {
const openCB = () => this._hideLoadingPage();
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 1b4c523639ef..9c04ac3ef7d6 100644
--- a/services/static-webserver/client/source/class/osparc/dashboard/StudyBrowser.js
+++ b/services/static-webserver/client/source/class/osparc/dashboard/StudyBrowser.js
@@ -251,7 +251,10 @@ qx.Class.define("osparc.dashboard.StudyBrowser", {
})
.catch(console.error)
.finally(() => {
- this.__addNewFolderButton();
+ // In favor of the NewPlusButton
+ if (!osparc.product.Utils.hasNewPlusButton()) {
+ this.__addNewFolderButton();
+ }
this.__loadingFolders = null;
});
},
@@ -882,6 +885,45 @@ qx.Class.define("osparc.dashboard.StudyBrowser", {
}
},
+ __addNewPlusButton: function() {
+ const newPlusButton = new osparc.dashboard.NewPlusButton();
+ this._leftFilters.add(newPlusButton);
+
+ const newPlusButtonMenu = newPlusButton.getMenu();
+
+ newPlusButtonMenu.addListener("createFolder", e => {
+ const data = e.getData();
+ this.__createFolder(data);
+ }, this);
+
+ newPlusButtonMenu.addListener("newEmptyStudyClicked", e => {
+ const {
+ newStudyLabel,
+ } = e.getData();
+ this.__newEmptyStudyBtnClicked(newStudyLabel);
+ }, this);
+
+ newPlusButtonMenu.addListener("newStudyFromTemplateClicked", e => {
+ const {
+ templateData,
+ newStudyLabel,
+ } = e.getData();
+ if (templateData) {
+ this.__newPlanBtnClicked(templateData, newStudyLabel);
+ }
+ }, this);
+
+ newPlusButtonMenu.addListener("newStudyFromServiceClicked", e => {
+ const {
+ serviceMetadata,
+ newStudyLabel,
+ } = e.getData();
+ if (serviceMetadata) {
+ this.__newStudyFromServiceBtnClicked(serviceMetadata["key"], serviceMetadata["version"], newStudyLabel);
+ }
+ }, this);
+ },
+
__addNewStudyButtons: function() {
if (this.getCurrentContext() !== "studiesAndFolders") {
return;
@@ -895,19 +937,21 @@ qx.Class.define("osparc.dashboard.StudyBrowser", {
}
}
- switch (osparc.product.Utils.getProductName()) {
- case "osparc":
- this.__addEmptyStudyPlusButton();
- break;
- case "tis":
- case "tiplite":
- this.__addTIPPlusButton();
- break;
- case "s4l":
- case "s4lacad":
- case "s4llite":
- this.__addPlusButtonsFromServices();
- break;
+ if (!osparc.product.Utils.hasNewPlusButton()) {
+ switch (osparc.product.Utils.getProductName()) {
+ case "osparc":
+ this.__addEmptyStudyPlusButton();
+ break;
+ case "tis":
+ case "tiplite":
+ this.__addTIPPlusButton();
+ break;
+ case "s4l":
+ case "s4lacad":
+ case "s4llite":
+ this.__addPlusButtonsFromServices();
+ break;
+ }
}
},
@@ -917,31 +961,31 @@ qx.Class.define("osparc.dashboard.StudyBrowser", {
firstUpperCase: true
})
const desc = this.tr("Start with an empty study");
- const newStudyBtn = (mode === "grid") ? new osparc.dashboard.GridButtonNew(title, desc) : new osparc.dashboard.ListButtonNew(title, desc);
- newStudyBtn.setCardKey("new-study");
- newStudyBtn.subscribeToFilterGroup("searchBarFilter");
- osparc.utils.Utils.setIdToWidget(newStudyBtn, "newStudyBtn");
- newStudyBtn.addListener("tap", () => this.__newStudyBtnClicked(newStudyBtn));
- this._resourcesContainer.addNonResourceCard(newStudyBtn);
+ const newEmptyStudyBtn = (mode === "grid") ? new osparc.dashboard.GridButtonNew(title, desc) : new osparc.dashboard.ListButtonNew(title, desc);
+ newEmptyStudyBtn.setCardKey("new-study");
+ newEmptyStudyBtn.subscribeToFilterGroup("searchBarFilter");
+ osparc.utils.Utils.setIdToWidget(newEmptyStudyBtn, "emptyStudyBtn");
+ newEmptyStudyBtn.addListener("tap", () => this.__newEmptyStudyBtnClicked("New Study"));
+ this._resourcesContainer.addNonResourceCard(newEmptyStudyBtn);
},
__addTIPPlusButton: function() {
const mode = this._resourcesContainer.getMode();
const title = this.tr("New Plan");
- const newStudyBtn = (mode === "grid") ? new osparc.dashboard.GridButtonNew(title) : new osparc.dashboard.ListButtonNew(title);
- newStudyBtn.setCardKey("new-study");
- newStudyBtn.subscribeToFilterGroup("searchBarFilter");
- osparc.utils.Utils.setIdToWidget(newStudyBtn, "newStudyBtn");
- this._resourcesContainer.addNonResourceCard(newStudyBtn);
- newStudyBtn.setEnabled(false);
+ const newPlansBtn = (mode === "grid") ? new osparc.dashboard.GridButtonNew(title) : new osparc.dashboard.ListButtonNew(title);
+ newPlansBtn.setCardKey("new-study");
+ newPlansBtn.subscribeToFilterGroup("searchBarFilter");
+ osparc.utils.Utils.setIdToWidget(newPlansBtn, "newPlansBtn");
+ this._resourcesContainer.addNonResourceCard(newPlansBtn);
+ newPlansBtn.setEnabled(false);
osparc.utils.Utils.fetchJSON("/resource/osparc/new_studies.json")
.then(newStudiesData => {
const product = osparc.product.Utils.getProductName()
if (product in newStudiesData) {
- newStudyBtn.setEnabled(true);
+ newPlansBtn.setEnabled(true);
- newStudyBtn.addListener("tap", () => {
+ newPlansBtn.addListener("tap", () => {
osparc.data.Resources.get("templates")
.then(templates => {
if (templates) {
@@ -990,7 +1034,7 @@ qx.Class.define("osparc.dashboard.StudyBrowser", {
const newStudyFromServiceButton = (mode === "grid") ? new osparc.dashboard.GridButtonNew(title, desc) : new osparc.dashboard.ListButtonNew(title, desc);
newStudyFromServiceButton.setCardKey("new-"+key);
osparc.utils.Utils.setIdToWidget(newStudyFromServiceButton, newButtonInfo.idToWidget);
- newStudyFromServiceButton.addListener("tap", () => this.__newStudyFromServiceBtnClicked(newStudyFromServiceButton, latestMetadata["key"], latestMetadata["version"], newButtonInfo.newStudyLabel));
+ newStudyFromServiceButton.addListener("tap", () => this.__newStudyFromServiceBtnClicked(latestMetadata["key"], latestMetadata["version"], newButtonInfo.newStudyLabel));
this._resourcesContainer.addNonResourceCard(newStudyFromServiceButton);
})
}
@@ -1044,6 +1088,10 @@ qx.Class.define("osparc.dashboard.StudyBrowser", {
this.__addSortByButton();
this._addViewModeButton();
+ if (osparc.product.Utils.hasNewPlusButton()) {
+ this.__addNewPlusButton();
+ }
+
this._addResourceFilter();
this.__connectContexts();
@@ -1463,10 +1511,10 @@ qx.Class.define("osparc.dashboard.StudyBrowser", {
}
},
- __newStudyBtnClicked: function(button) {
- const minStudyData = osparc.data.model.Study.createMinStudyObject();
+ __newEmptyStudyBtnClicked: function(newStudyLabel) {
const existingNames = this._resourcesList.map(study => study["name"]);
- const title = osparc.utils.Utils.getUniqueName(minStudyData.name, existingNames);
+ const title = osparc.utils.Utils.getUniqueName(newStudyLabel, existingNames);
+ const minStudyData = osparc.data.model.Study.createMinStudyObject();
minStudyData["name"] = title;
minStudyData["workspaceId"] = this.getCurrentWorkspaceId();
minStudyData["folderId"] = this.getCurrentFolderId();
@@ -1503,7 +1551,7 @@ qx.Class.define("osparc.dashboard.StudyBrowser", {
});
},
- __newStudyFromServiceBtnClicked: function(button, key, version, newStudyLabel) {
+ __newStudyFromServiceBtnClicked: function(key, version, newStudyLabel) {
this._showLoadingPage(this.tr("Creating ") + osparc.product.Utils.getStudyAlias());
const contextProps = {
workspaceId: this.getCurrentWorkspaceId(),
diff --git a/services/static-webserver/client/source/class/osparc/dashboard/TemplateBrowser.js b/services/static-webserver/client/source/class/osparc/dashboard/TemplateBrowser.js
index fab2dc1eb94c..e9443c4ecbbc 100644
--- a/services/static-webserver/client/source/class/osparc/dashboard/TemplateBrowser.js
+++ b/services/static-webserver/client/source/class/osparc/dashboard/TemplateBrowser.js
@@ -144,6 +144,7 @@ qx.Class.define("osparc.dashboard.TemplateBrowser", {
// they will be patched once the study is created
studyOptions.setPatchStudy(false);
studyOptions.setStudyData(templateData);
+ studyOptions.getChildControl("open-button").setLabel(this.tr("New"));
const win = osparc.study.StudyOptions.popUpInWindow(studyOptions);
win.moveItUp();
const cancelStudyOptions = () => {
diff --git a/services/static-webserver/client/source/class/osparc/desktop/MainPage.js b/services/static-webserver/client/source/class/osparc/desktop/MainPage.js
index 39968f8913db..d3eff170ad6e 100644
--- a/services/static-webserver/client/source/class/osparc/desktop/MainPage.js
+++ b/services/static-webserver/client/source/class/osparc/desktop/MainPage.js
@@ -199,11 +199,6 @@ qx.Class.define("osparc.desktop.MainPage", {
__createDashboardLayout: function() {
const dashboard = this.__dashboard = new osparc.dashboard.Dashboard();
- const tabsBar = dashboard.getChildControl("bar");
- tabsBar.set({
- paddingBottom: 6
- });
- this.__navBar.addDashboardTabButtons(tabsBar);
const dashboardLayout = new qx.ui.container.Composite(new qx.ui.layout.HBox(5));
dashboardLayout.add(dashboard, {
flex: 1
diff --git a/services/static-webserver/client/source/class/osparc/form/PortInfoHint.js b/services/static-webserver/client/source/class/osparc/form/PortInfoHint.js
index 70ddcf32bf0f..112b43d3637e 100644
--- a/services/static-webserver/client/source/class/osparc/form/PortInfoHint.js
+++ b/services/static-webserver/client/source/class/osparc/form/PortInfoHint.js
@@ -40,7 +40,7 @@ qx.Class.define("osparc.form.PortInfoHint", {
}
this.setHintText(text);
this.set({
- source: errorMsg ? this.self().ERROR_ICON : osparc.ui.hint.InfoHint.INFO_ICON,
+ source: errorMsg ? this.self().ERROR_ICON : osparc.ui.hint.InfoHint.INFO_ICON + "/14",
textColor: errorMsg ? "failed-red" : "text"
});
}
diff --git a/services/static-webserver/client/source/class/osparc/navigation/NavigationBar.js b/services/static-webserver/client/source/class/osparc/navigation/NavigationBar.js
index f6e2688ae05c..e8d252a5f82c 100644
--- a/services/static-webserver/client/source/class/osparc/navigation/NavigationBar.js
+++ b/services/static-webserver/client/source/class/osparc/navigation/NavigationBar.js
@@ -330,15 +330,6 @@ qx.Class.define("osparc.navigation.NavigationBar", {
return registerButton;
},
- addDashboardTabButtons: function(tabButtons) {
- this.__tabButtons = tabButtons;
- this.getChildControl("center-items").add(tabButtons);
- this.bind("study", this.__tabButtons, "visibility", {
- converter: s => s ? "excluded" : "visible"
- });
- this.__navBarResized();
- },
-
__applyStudy: function(study) {
const readOnlyInfo = this.getChildControl("read-only-info")
if (study) {
diff --git a/services/static-webserver/client/source/class/osparc/product/Utils.js b/services/static-webserver/client/source/class/osparc/product/Utils.js
index 0a78cf5e2f04..4c77b84e0e16 100644
--- a/services/static-webserver/client/source/class/osparc/product/Utils.js
+++ b/services/static-webserver/client/source/class/osparc/product/Utils.js
@@ -114,23 +114,6 @@ qx.Class.define("osparc.product.Utils", {
return resourceType;
},
- __linkExists: function(url) {
- return new Promise((resolve, reject) => {
- const reqSvg = new XMLHttpRequest();
- reqSvg.open("GET", url, true);
- reqSvg.onreadystatechange = () => {
- if (reqSvg.readyState === 4) {
- if (reqSvg.status === 404) {
- reject();
- } else {
- resolve();
- }
- }
- };
- reqSvg.send();
- });
- },
-
getLogoPath: function(longLogo = true) {
let logosPath = null;
const colorManager = qx.theme.manager.Color.getInstance();
@@ -307,6 +290,17 @@ qx.Class.define("osparc.product.Utils", {
break;
}
return url;
- }
+ },
+
+ hasNewPlusButton: function() {
+ return [
+ "osparc",
+ "s4l",
+ "s4lacad",
+ "s4llite",
+ // "tis",
+ // "tiplite",
+ ].includes(osparc.product.Utils.getProductName());
+ },
}
});
diff --git a/services/static-webserver/client/source/class/osparc/store/Products.js b/services/static-webserver/client/source/class/osparc/store/Products.js
new file mode 100644
index 000000000000..4728bded6093
--- /dev/null
+++ b/services/static-webserver/client/source/class/osparc/store/Products.js
@@ -0,0 +1,48 @@
+/* ************************************************************************
+
+ osparc - the simcore frontend
+
+ https://osparc.io
+
+ Copyright:
+ 2025 IT'IS Foundation, https://itis.swiss
+
+ License:
+ MIT: https://opensource.org/licenses/MIT
+
+ Authors:
+ * Odei Maiz (odeimaiz)
+
+************************************************************************ */
+
+qx.Class.define("osparc.store.Products", {
+ extend: qx.core.Object,
+ type: "singleton",
+
+ members: {
+ __newStudyConfig: null,
+
+ fetchNewStudyConfig: function() {
+ return osparc.utils.Utils.fetchJSON("/resource/osparc/new_studies.json")
+ .then(newStudiesData => {
+ const product = osparc.product.Utils.getProductName()
+ if (product in newStudiesData) {
+ this.__newStudyConfig = newStudiesData[product];
+ return this.__newStudyConfig;
+ }
+ return {};
+ })
+ .catch(console.error);
+ },
+
+ getNewStudyConfig: function() {
+ return new Promise(resolve => {
+ if (this.__newStudyConfig) {
+ resolve(this.__newStudyConfig);
+ } else {
+ resolve(this.fetchNewStudyConfig())
+ }
+ });
+ },
+ }
+});
diff --git a/services/static-webserver/client/source/class/osparc/study/StudyOptions.js b/services/static-webserver/client/source/class/osparc/study/StudyOptions.js
index 70576fa6c799..1ed9a4cd961d 100644
--- a/services/static-webserver/client/source/class/osparc/study/StudyOptions.js
+++ b/services/static-webserver/client/source/class/osparc/study/StudyOptions.js
@@ -277,6 +277,7 @@ qx.Class.define("osparc.study.StudyOptions", {
walletSelector.setSelection([selectable]);
}
});
+ osparc.utils.Utils.growSelectBox(walletSelector, 220);
}
},
diff --git a/services/static-webserver/client/source/class/osparc/theme/Appearance.js b/services/static-webserver/client/source/class/osparc/theme/Appearance.js
index 82b0c9b56661..8af7db982cb1 100644
--- a/services/static-webserver/client/source/class/osparc/theme/Appearance.js
+++ b/services/static-webserver/client/source/class/osparc/theme/Appearance.js
@@ -722,13 +722,14 @@ qx.Theme.define("osparc.theme.Appearance", {
"menu-button": {
alias: "atom",
- style: function(states) {
+ style: states => {
return {
+ decorator: "rounded",
cursor: states.disabled ? "not-allowed" : "pointer",
- backgroundColor: states.selected ? "background-selected-dark" : undefined,
+ backgroundColor: states.selected || states.hovered ? "pb-new" : undefined,
textColor: states.selected ? "default-button-text" : "text",
- padding: [2, 6]
- };
+ padding: [4, 8]
+ }
}
},
diff --git a/services/static-webserver/client/source/class/osparc/ui/hint/InfoHint.js b/services/static-webserver/client/source/class/osparc/ui/hint/InfoHint.js
index 050e4a6ef570..5ec7e00ca84f 100644
--- a/services/static-webserver/client/source/class/osparc/ui/hint/InfoHint.js
+++ b/services/static-webserver/client/source/class/osparc/ui/hint/InfoHint.js
@@ -25,7 +25,7 @@ qx.Class.define("osparc.ui.hint.InfoHint", {
* @extends osparc.ui.basic.IconButton
*/
construct: function(hintText) {
- this.base(arguments, this.self().INFO_ICON);
+ this.base(arguments, this.self().INFO_ICON + "/14");
this.__createHint();
@@ -39,7 +39,7 @@ qx.Class.define("osparc.ui.hint.InfoHint", {
},
statics: {
- INFO_ICON: "@MaterialIcons/info_outline/14"
+ INFO_ICON: "@MaterialIcons/info_outline"
},
properties: {
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 6dcdffa2692d..6f8bcec17f63 100644
--- a/services/static-webserver/client/source/class/osparc/utils/Utils.js
+++ b/services/static-webserver/client/source/class/osparc/utils/Utils.js
@@ -89,7 +89,7 @@ qx.Class.define("osparc.utils.Utils", {
}
},
- FLOATING_Z_INDEX: 110000,
+ FLOATING_Z_INDEX: 1000001 + 1,
updateTabName: function(name) {
document.title = name;
@@ -958,10 +958,10 @@ qx.Class.define("osparc.utils.Utils", {
},
cookie: {
- setCookie: (cname, cvalue, exdays) => {
- if (exdays) {
+ setCookie: (cname, cvalue, expDays) => {
+ if (expDays) {
const d = new Date();
- d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000));
+ d.setTime(d.getTime() + (expDays * 24 * 60 * 60 * 1000));
document.cookie = cname + "=" + cvalue + ";Expires=" + d.toUTCString() + ";path=/";
} else {
document.cookie = cname + "=" + cvalue + ";path=/";
diff --git a/services/static-webserver/client/source/class/osparc/widget/logger/LoggerModel.js b/services/static-webserver/client/source/class/osparc/widget/logger/LoggerModel.js
index 9cb8b2249de9..edca2766438e 100644
--- a/services/static-webserver/client/source/class/osparc/widget/logger/LoggerModel.js
+++ b/services/static-webserver/client/source/class/osparc/widget/logger/LoggerModel.js
@@ -113,7 +113,12 @@ qx.Class.define("osparc.widget.logger.LoggerModel", {
newRow["level"] = this.self().getLevelIcon(newRow.logLevel);
newRow["time"] = osparc.utils.Utils.formatTime(newRow.timeStamp, true);
newRow["who"] = newRow.label;
- newRow["msgRich"] = newRow.msg.replace(/\n/g, "
");
+
+ // there might a double backslash before the n
+ let clean = newRow.msg.replace(/\\n/g, "
");
+ clean = newRow.msg.replace(/\n/g, "
");
+ newRow["msgRich"] = clean;
+
this.__rawData.push(newRow);
});
},
diff --git a/services/static-webserver/client/source/resource/osparc/new_studies.json b/services/static-webserver/client/source/resource/osparc/new_studies.json
index a13a042051f6..ed29e1145d51 100644
--- a/services/static-webserver/client/source/resource/osparc/new_studies.json
+++ b/services/static-webserver/client/source/resource/osparc/new_studies.json
@@ -1,149 +1,210 @@
{
"tis": {
- "linkedResource": "templates",
+ "categories": [{
+ "id": "precomputed",
+ "title": "Precomputed"
+ }, {
+ "id": "personalized",
+ "title": "Personalized",
+ "description": "In the process, TIP will launch simulations on AWS.
The associated resource costs will be deduced from your Credits."
+ }],
"resources": [{
+ "resourceType": "template",
"expectedTemplateLabel": "TI Planning Tool",
"title": "Classic TI",
- "description": "",
"newStudyLabel": "Classic TI",
"category": "precomputed",
"idToWidget": "newTIPlanButton"
}, {
+ "resourceType": "template",
"expectedTemplateLabel": "mcTI Planning Tool",
"title": "Multichannel TI",
- "description": "",
"newStudyLabel": "Multichannel TI",
"category": "precomputed",
"idToWidget": "newMTIPlanButton"
}, {
+ "resourceType": "template",
"expectedTemplateLabel": "pmTI Planning Tool",
"title": "Phase-modulation TI",
- "description": "",
"newStudyLabel": "Phase-modulation TI",
"category": "precomputed",
"idToWidget": "newPMTIPlanButton"
}, {
+ "resourceType": "template",
"expectedTemplateLabel": "personalized TI Planning Tool",
- "title": "Personalized
Classic TI",
- "description": "",
+ "title": "Personalized Classic TI",
"newStudyLabel": "Personalized Classic TI",
"category": "personalized",
- "idToWidget": "personalizationNewTIPlanButton",
- "billable": true
+ "idToWidget": "personalizationNewTIPlanButton"
}, {
+ "resourceType": "template",
"expectedTemplateLabel": "personalized mcTI Planning Tool",
- "title": "Personalized
Multichannel TI",
- "description": "",
+ "title": "Personalized Multichannel TI",
"newStudyLabel": "Personalized Multichannel TI",
"category": "personalized",
- "idToWidget": "personalizationNewMTIPlanButton",
- "billable": true
+ "idToWidget": "personalizationNewMTIPlanButton"
}, {
+ "resourceType": "template",
"expectedTemplateLabel": "personalized pmTI Planning Tool",
- "title": "Personalized
Phase-modulation TI",
- "description": "",
+ "title": "Personalized Phase-modulation TI",
"newStudyLabel": "Personalized Phase-modulation TI",
"category": "personalized",
- "idToWidget": "personalizationNewPMTIPlanButton",
- "billable": true
- }],
+ "idToWidget": "personalizationNewPMTIPlanButton"
+ }]
+ },
+ "tiplite": {
"categories": [{
"id": "precomputed",
- "label": "Precomputed"
+ "title": "Precomputed"
}, {
"id": "personalized",
- "label": "Personalized: In the process, TIP will launch simulations on AWS.
The associated resource costs will be deduced from your Credits."
- }]
- },
- "tiplite": {
- "linkedResource": "templates",
+ "title": "Personalized",
+ "description": "In the process, TIP will launch simulations on AWS.
The associated resource costs will be deduced from your Credits."
+ }],
"resources": [{
+ "resourceType": "template",
"expectedTemplateLabel": "TI Planning Tool",
"title": "Classic TI",
- "description": "",
"newStudyLabel": "Classic TI",
"category": "precomputed",
"idToWidget": "newTIPlanButton"
}, {
"showDisabled": true,
+ "reason": "Not available in ${replace_me_product_name}",
+ "resourceType": "template",
"expectedTemplateLabel": "mcTI Planning Tool",
"title": "Multichannel TI",
- "description": "Not available in ${replace_me_product_name}",
"newStudyLabel": "Multichannel TI",
"category": "precomputed",
"idToWidget": "newMTIPlanButton"
}, {
"showDisabled": true,
+ "reason": "Not available in ${replace_me_product_name}",
+ "resourceType": "template",
"expectedTemplateLabel": "pmTI Planning Tool",
"title": "Phase-modulation TI",
- "description": "Not available in ${replace_me_product_name}",
"newStudyLabel": "Phase-modulation TI",
"category": "precomputed",
"idToWidget": "newPMTIPlanButton"
}, {
"showDisabled": true,
+ "reason": "Not available in ${replace_me_product_name}",
+ "resourceType": "template",
"expectedTemplateLabel": "personalized TI Planning Tool",
- "title": "Personalized
Classic TI",
- "description": "Not available in ${replace_me_product_name}",
+ "title": "Personalized Classic TI",
"newStudyLabel": "Personalized Classic TI",
"category": "personalized",
- "idToWidget": "personalizationNewTIPlanButton",
- "billable": true
+ "idToWidget": "personalizationNewTIPlanButton"
}, {
"showDisabled": true,
+ "reason": "Not available in ${replace_me_product_name}",
+ "resourceType": "template",
"expectedTemplateLabel": "personalized mcTI Planning Tool",
- "title": "Personalized
Multichannel TI",
- "description": "Not available in ${replace_me_product_name}",
+ "title": "Personalized Multichannel TI",
"newStudyLabel": "Personalized Multichannel TI",
"category": "personalized",
- "idToWidget": "personalizationNewMTIPlanButton",
- "billable": true
+ "idToWidget": "personalizationNewMTIPlanButton"
}, {
"showDisabled": true,
+ "reason": "Not available in ${replace_me_product_name}",
+ "resourceType": "template",
"expectedTemplateLabel": "personalized pmTI Planning Tool",
- "title": "Personalized
Phase-modulation TI",
- "description": "Not available in ${replace_me_product_name}",
+ "title": "Personalized Phase-modulation TI",
"newStudyLabel": "Personalized Phase-modulation TI",
"category": "personalized",
- "idToWidget": "personalizationNewPMTIPlanButton",
- "billable": true
- }],
- "categories": [{
- "id": "precomputed",
- "label": "Precomputed"
- }, {
- "id": "personalized",
- "label": "Personalized: In the process, TIP will launch simulations on AWS.
The associated resource costs will be deduced from your Credits."
+ "idToWidget": "personalizationNewPMTIPlanButton"
}]
},
"s4l": {
- "linkedResource": "services",
+ "categories": [{
+ "id": "apps",
+ "title": "Apps"
+ }, {
+ "id": "osparc",
+ "title": "oSPARC"
+ }],
"resources": [{
+ "category": "apps",
+ "resourceType": "service",
"expectedKey": "simcore/services/dynamic/s4l-ui",
- "title": "Start Sim4Life",
- "description": "New Sim4Life project",
+ "title": "Sim4Life",
"newStudyLabel": "New S4L project",
"idToWidget": "startS4LButton"
+ }, {
+ "category": "apps",
+ "resourceType": "service",
+ "expectedKey": "simcore/services/dynamic/iseg-web",
+ "title": "iSEG",
+ "newStudyLabel": "New iSEG project"
+ }, {
+ "category": "apps",
+ "resourceType": "service",
+ "expectedKey": "simcore/services/dynamic/s4l-jupyter",
+ "title": "Jupyter Lab",
+ "icon": "https://upload.wikimedia.org/wikipedia/commons/3/38/Jupyter_logo.svg",
+ "newStudyLabel": "New S4L Jupyter Lab"
+ }, {
+ "category": "osparc",
+ "resourceType": "study",
+ "icon": "@FontAwesome5Solid/file/18",
+ "title": "Empty Pipeline",
+ "newStudyLabel": "New Project",
+ "idToWidget": "emptyStudyBtn"
}]
},
"s4lacad": {
- "linkedResource": "services",
+ "categories": [{
+ "id": "apps",
+ "title": "Apps"
+ }, {
+ "id": "osparc",
+ "title": "oSPARC"
+ }],
"resources": [{
+ "category": "apps",
+ "resourceType": "service",
"expectedKey": "simcore/services/dynamic/s4l-ui",
- "title": "Start Sim4Life",
- "description": "New Sim4Life project",
+ "title": "Sim4Life",
"newStudyLabel": "New S4L project",
"idToWidget": "startS4LButton"
+ }, {
+ "category": "apps",
+ "resourceType": "service",
+ "expectedKey": "simcore/services/dynamic/iseg-web",
+ "title": "iSEG",
+ "newStudyLabel": "New iSEG project"
+ }, {
+ "category": "apps",
+ "resourceType": "service",
+ "expectedKey": "simcore/services/dynamic/s4l-jupyter",
+ "icon": "https://upload.wikimedia.org/wikipedia/commons/3/38/Jupyter_logo.svg",
+ "title": "Jupyter Lab",
+ "newStudyLabel": "New S4L Jupyter Lab"
+ }, {
+ "category": "osparc",
+ "resourceType": "study",
+ "icon": "@FontAwesome5Solid/file/18",
+ "title": "Empty Pipeline",
+ "newStudyLabel": "New Project",
+ "idToWidget": "emptyStudyBtn"
}]
},
"s4llite": {
- "linkedResource": "services",
"resources": [{
+ "resourceType": "service",
"expectedKey": "simcore/services/dynamic/s4l-ui-lite",
- "title": "Start ${replace_me_product_name}",
- "description": "New project",
- "newStudyLabel": "New project",
+ "title": "${replace_me_product_name}",
+ "newStudyLabel": "New Project",
"idToWidget": "startS4LButton"
}]
+ },
+ "osparc": {
+ "resources": [{
+ "resourceType": "study",
+ "icon": "@FontAwesome5Solid/file/18",
+ "title": "Empty Study",
+ "newStudyLabel": "New Study",
+ "idToWidget": "emptyStudyBtn"
+ }]
}
}
diff --git a/tests/e2e-frontend/tests/navigationBar/navigationBar.spec.js b/tests/e2e-frontend/tests/navigationBar/navigationBar.spec.js
index 0c981ef8777a..c6bb8752f334 100644
--- a/tests/e2e-frontend/tests/navigationBar/navigationBar.spec.js
+++ b/tests/e2e-frontend/tests/navigationBar/navigationBar.spec.js
@@ -10,10 +10,6 @@ import users from '../users.json';
const expectedElements = {
"osparc": {
"poweredByOsparc": false,
- "studies": {
- "visible": true,
- "label": "STUDIES",
- },
"templates": {
"visible": true,
"label": "TEMPLATES",
@@ -33,10 +29,6 @@ const expectedElements = {
},
"s4l": {
"poweredByOsparc": true,
- "studies": {
- "visible": true,
- "label": "PROJECTS",
- },
"templates": {
"visible": true,
"label": "TUTORIALS",
@@ -55,10 +47,6 @@ const expectedElements = {
},
"s4lacad": {
"poweredByOsparc": true,
- "studies": {
- "visible": true,
- "label": "PROJECTS",
- },
"templates": {
"visible": true,
"label": "TUTORIALS",
@@ -77,10 +65,6 @@ const expectedElements = {
},
"s4llite": {
"poweredByOsparc": true,
- "studies": {
- "visible": true,
- "label": "PROJECTS",
- },
"templates": {
"visible": true,
"label": "TUTORIALS",
@@ -98,10 +82,6 @@ const expectedElements = {
},
"tis": {
"poweredByOsparc": true,
- "studies": {
- "visible": true,
- "label": "STUDIES",
- },
"templates": {
"visible": false,
},
@@ -118,10 +98,6 @@ const expectedElements = {
},
"tiplite": {
"poweredByOsparc": true,
- "studies": {
- "visible": true,
- "label": "STUDIES",
- },
"templates": {
"visible": false,
},
@@ -177,13 +153,10 @@ for (const product in products) {
});
test(`Check Dashboard tabs`, async () => {
- expect(expectedElements[product]["studies"]).toBeDefined();
expect(expectedElements[product]["templates"]).toBeDefined();
expect(expectedElements[product]["services"]).toBeDefined();
expect(expectedElements[product]["data"]).toBeDefined();
- const isStudiesVisible = expectedElements[product]["studies"]["visible"];
- const studiesLabel = expectedElements[product]["studies"]["label"];
const isTemplatesVisible = expectedElements[product]["templates"]["visible"];
const templatesLabel = expectedElements[product]["templates"]["label"];
const isServicesVisible = expectedElements[product]["services"]["visible"];
@@ -201,7 +174,6 @@ for (const product in products) {
}
};
- await checkButton("studiesTabBtn", isStudiesVisible, studiesLabel);
await checkButton("templatesTabBtn", isTemplatesVisible, templatesLabel);
await checkButton("servicesTabBtn", isServicesVisible, servicesLabel);
await checkButton("dataTabBtn", isDataVisible, dataLabel);
diff --git a/tests/e2e-frontend/tests/studyBrowser/mainView.spec.js b/tests/e2e-frontend/tests/studyBrowser/mainView.spec.js
index ff8890af5720..6c90a57c36d8 100644
--- a/tests/e2e-frontend/tests/studyBrowser/mainView.spec.js
+++ b/tests/e2e-frontend/tests/studyBrowser/mainView.spec.js
@@ -9,33 +9,51 @@ import users from '../users.json';
const expectedElements = {
"osparc": {
+ "newButton": {
+ "id": "newPlusBtn"
+ },
"plusButton": {
- "id": "newStudyBtn",
+ "id": "emptyStudyBtn",
},
},
"s4l": {
+ "newButton": {
+ "id": "newPlusBtn"
+ },
"plusButton": {
"id": "startS4LButton",
},
},
"s4lacad": {
+ "newButton": {
+ "id": "newPlusBtn"
+ },
"plusButton": {
"id": "startS4LButton",
},
},
"s4llite": {
+ "newButton": {
+ "id": "newPlusBtn"
+ },
"plusButton": {
"id": "startS4LButton",
},
},
"tis": {
+ "newButton": {
+ "id": "newPlansBtn"
+ },
"plusButton": {
- "id": "newStudyBtn",
+ "id": "newTIPlanButton",
},
},
"tiplite": {
+ "newButton": {
+ "id": "newPlansBtn"
+ },
"plusButton": {
- "id": "newStudyBtn",
+ "id": "newTIPlanButton",
},
},
};
@@ -66,9 +84,14 @@ for (const product in products) {
await browser.close();
});
- test(`Plus button`, async () => {
+ test(`Plus button after New button`, async () => {
expect(expectedElements[product]["plusButton"]).toBeDefined();
+ if (expectedElements[product]["newPlusButton"]) {
+ const newPlusButton = page.getByTestId("newPlusBtn");
+ await newPlusButton.click();
+ }
+
const plusButtonId = expectedElements[product]["plusButton"]["id"];
const plusButton = page.getByTestId(plusButtonId);
await expect(plusButton).toBeVisible({
diff --git a/tests/e2e-playwright/tests/conftest.py b/tests/e2e-playwright/tests/conftest.py
index 600a314c7168..be55e580ec93 100644
--- a/tests/e2e-playwright/tests/conftest.py
+++ b/tests/e2e-playwright/tests/conftest.py
@@ -552,7 +552,6 @@ def wait_for_done(response):
with log_context(logging.INFO, "Go back to dashboard"):
page.get_by_test_id("dashboardBtn").click()
page.get_by_test_id("confirmDashboardBtn").click()
- page.get_by_test_id("studiesTabBtn").click()
for project_uuid in created_project_uuids:
with log_context(
diff --git a/tests/e2e-playwright/tests/platform_CI_tests/test_platform.py b/tests/e2e-playwright/tests/platform_CI_tests/test_platform.py
index 15b3a86b730a..cd18aff6bb14 100644
--- a/tests/e2e-playwright/tests/platform_CI_tests/test_platform.py
+++ b/tests/e2e-playwright/tests/platform_CI_tests/test_platform.py
@@ -64,6 +64,7 @@ def test_simple_folder_workflow(
page.goto(f"{product_url}")
page.wait_for_timeout(1000)
+ page.get_by_test_id("newPlusBtn").click()
page.get_by_test_id("newFolderButton").click()
with page.expect_response(
diff --git a/tests/e2e-playwright/tests/tip/conftest.py b/tests/e2e-playwright/tests/tip/conftest.py
index dbe2d6813b81..b0d979921ed0 100644
--- a/tests/e2e-playwright/tests/tip/conftest.py
+++ b/tests/e2e-playwright/tests/tip/conftest.py
@@ -17,8 +17,7 @@ def _(
plan_name_test_id: str,
) -> None:
with log_context(logging.INFO, f"Finding {plan_name_test_id=} in dashboard"):
- page.get_by_test_id("studiesTabBtn").click()
- page.get_by_test_id("newStudyBtn").click()
+ page.get_by_test_id("newPlansBtn").click()
page.get_by_test_id(plan_name_test_id).click()
return _
diff --git a/tests/e2e/tests/tags.tes.js b/tests/e2e/tests/tags.tes.js
index 4b68209f4560..c7026220b888 100644
--- a/tests/e2e/tests/tags.tes.js
+++ b/tests/e2e/tests/tags.tes.js
@@ -48,7 +48,8 @@ describe('tags testing', () => {
await page.goto(url);
await auto.register(page, user, pass);
// Create new study
- await waitAndClick(page, '[osparc-test-id="newStudyBtn"]');
+ await waitAndClick(page, '[osparc-test-id="newPlusBtn"]');
+ await waitAndClick(page, '[osparc-test-id="emptyStudyBtn"]');
// Wait until project is created and Dashboard button is enabled
await utils.sleep(4000);
await auto.toDashboard(page);
diff --git a/tests/e2e/tutorials/tutorialBase.js b/tests/e2e/tutorials/tutorialBase.js
index 0d649cb384df..6899d3bcb269 100644
--- a/tests/e2e/tutorials/tutorialBase.js
+++ b/tests/e2e/tutorials/tutorialBase.js
@@ -577,7 +577,6 @@ class TutorialBase {
}
async removeStudy(studyId, waitFor = 5000) {
- await auto.dashboardStudiesBrowser(this.__page);
await this.waitFor(waitFor, 'Wait to be unlocked');
await this.takeScreenshot("deleteFirstStudy_before");
const intervalWait = 3000;
diff --git a/tests/e2e/utils/auto.js b/tests/e2e/utils/auto.js
index 3a745adaccd6..fb7b1367b6ac 100644
--- a/tests/e2e/utils/auto.js
+++ b/tests/e2e/utils/auto.js
@@ -94,11 +94,6 @@ async function dashboardPreferences(page) {
await utils.waitAndClick(page, '[osparc-test-id="preferencesWindowCloseBtn"]');
}
-async function dashboardStudiesBrowser(page) {
- console.log("Navigating through Studies");
- await utils.waitAndClick(page, '[osparc-test-id="studiesTabBtn"]')
-}
-
async function __dashboardTemplatesBrowser(page) {
console.log("Navigating through Templates");
await utils.waitAndClick(page, '[osparc-test-id="templatesTabBtn"]');
@@ -112,15 +107,13 @@ async function __dashboardServicesBrowser(page) {
async function dashboardNewTIPlan(page) {
console.log("Creating New Plan");
- await dashboardStudiesBrowser(page);
- await utils.waitAndClick(page, '[osparc-test-id="newStudyBtn"]');
+ await utils.waitAndClick(page, '[osparc-test-id="newPlansBtn"]');
await utils.waitAndClick(page, '[osparc-test-id="newTIPlanButton"]');
}
async function dashboardStartSim4LifeLite(page) {
console.log("Start Sim4Lite from + button");
- await dashboardStudiesBrowser(page);
await utils.waitAndClick(page, '[osparc-test-id="startS4LButton"]');
}
@@ -213,7 +206,6 @@ async function __openResource(page) {
}
async function __filterStudiesByText(page, studyName) {
- await dashboardStudiesBrowser(page);
await __typeInSearchBarFilter(page, "study", studyName);
}
@@ -296,8 +288,6 @@ async function runStudy(page) {
async function deleteFirstStudy(page, studyName) {
console.log("Deleting first study")
- await dashboardStudiesBrowser(page);
-
if (studyName) {
await __filterStudiesByText(page, studyName);
}
@@ -405,7 +395,6 @@ module.exports = {
logIn,
logOut,
dashboardAbout,
- dashboardStudiesBrowser,
dashboardPreferences,
dashboardNewTIPlan,
dashboardStartSim4LifeLite,