Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ [Frontend] Read product_ui_config from backend #7220

Merged
merged 21 commits into from
Feb 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ Makefile @pcrespov @sanderegg
/services/payments/ @pcrespov @matusdrobuliak66
/services/resource-usage-tracker/ @matusdrobuliak66
/services/static-webserver/ @GitHK
/services/static-webserver/client/ @jsaq007 @odeimaiz @ignapas
/services/static-webserver/client/ @odeimaiz
/services/storage/ @sanderegg
/services/web/server/ @pcrespov @sanderegg @GitHK @matusdrobuliak66
/tests/e2e-frontend/ @odeimaiz
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,6 @@ qx.Class.define("osparc.dashboard.GridButtonBase", {
SPACING_IN: 5,
SPACING: 15,
ICON_SIZE: 32,
// TITLE_MAX_HEIGHT: 34, // two lines in Roboto
TITLE_MAX_HEIGHT: 40, // two lines in Manrope
THUMBNAIL_SIZE: 50,
POS: {
TITLE: {
Expand Down Expand Up @@ -119,7 +117,6 @@ qx.Class.define("osparc.dashboard.GridButtonBase", {
grid.setSpacing(this.self().SPACING_IN);
grid.setRowFlex(2, 1);
grid.setColumnFlex(0, 1);
grid.setRowMaxHeight(0, this.self().TITLE_MAX_HEIGHT);

control = new qx.ui.container.Composite().set({
maxWidth: this.self().ITEM_WIDTH,
Expand Down Expand Up @@ -205,7 +202,6 @@ qx.Class.define("osparc.dashboard.GridButtonBase", {
font: "text-14",
padding: this.self().TITLE_PADDING,
maxWidth: this.self().ITEM_WIDTH,
maxHeight: this.self().TITLE_MAX_HEIGHT,
});
layout = this.getChildControl("header");
layout.addAt(control, 0, {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ qx.Class.define("osparc.dashboard.GridButtonItem", {
break;
case "menu-button":
this.getChildControl("title").set({
maxWidth: osparc.dashboard.GridButtonBase.ITEM_WIDTH - osparc.dashboard.GridButtonBase.ICON_SIZE - this.self().MENU_BTN_DIMENSIONS,
maxWidth: osparc.dashboard.GridButtonBase.ITEM_WIDTH - osparc.dashboard.GridButtonBase.ICON_SIZE - this.self().MENU_BTN_DIMENSIONS - 2,
});
control = new qx.ui.form.MenuButton().set({
appearance: "form-button-outlined",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,45 @@

************************************************************************ */

/**
odeimaiz marked this conversation as resolved.
Show resolved Hide resolved
Supports:
"categories": [{
"id": "string", // required
"title": "string", // required
"description": "string" // optional
}],
"resources": [{
"resourceType": "study", // it will start an empty study
"title": "string", // required
"icon": "fontAwesome inner link | url", // optional
"newStudyLabel": "string", // optional
"idToWidget": "string" // optional
}, {
"resourceType": "template", // it will create a study from the template
"expectedTemplateLabel": "string", // required
"title": "string", // required
"icon": "fontAwesome inner link | url", // optional
"newStudyLabel": "string", // optional
"category": "categories.id", // optional
"idToWidget": "string" // optional
}, {
"resourceType": "service", // it will create a study from the service
"expectedKey": "service.key", // required
"title": "string", // required
"icon": "fontAwesome inner link | url", // optional
"newStudyLabel": "string", // optional
"category": "categories.id", // optional
"idToWidget": "string" // optional
}, {
"showDisabled": true, // it will show a disabled button on the defined item
"title": "string", // required
"icon": "fontAwesome inner link | url", // optional
"reason": "string", // optional
"newStudyLabel": "string", // optional
"category": "categories.id", // optional
"idToWidget": "string" // optional
}]
*/
qx.Class.define("osparc.dashboard.NewPlusMenu", {
extend: qx.ui.menu.Menu,

Expand Down Expand Up @@ -51,6 +90,7 @@ qx.Class.define("osparc.dashboard.NewPlusMenu", {
"replace_me_product_name",
osparc.store.StaticInfo.getInstance().getDisplayName()
);
title = title.replace(/<br>/g, " ");
const menuButton = new qx.ui.menu.Button().set({
icon: icon || null,
label: title,
Expand All @@ -66,7 +106,7 @@ qx.Class.define("osparc.dashboard.NewPlusMenu", {
});
if (infoText) {
infoText = osparc.utils.Utils.replaceTokens(
title,
infoText,
"replace_me_product_name",
osparc.store.StaticInfo.getInstance().getDisplayName()
);
Expand Down Expand Up @@ -116,27 +156,24 @@ qx.Class.define("osparc.dashboard.NewPlusMenu", {
},

__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);
await osparc.data.Resources.get("templates")
.then(templates => {
const plusButtonConfig = osparc.store.Products.getInstance().getPlusButtonUiConfig();
if (plusButtonConfig["categories"]) {
this.__addCategories(plusButtonConfig["categories"]);
}
plusButtonConfig["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) {
Expand Down Expand Up @@ -165,7 +202,7 @@ qx.Class.define("osparc.dashboard.NewPlusMenu", {
__addIcon: function(menuButton, resourceInfo, resourceMetadata) {
let source = null;
if (resourceInfo && "icon" in resourceInfo) {
// first the one set in the new_studies
// first the one set in the ui_config
source = resourceInfo["icon"];
} else if (resourceMetadata && "thumbnail" in resourceMetadata) {
// second the one from the resource
Expand Down Expand Up @@ -200,55 +237,55 @@ qx.Class.define("osparc.dashboard.NewPlusMenu", {
},

__addDisabledButton: function(newStudyData) {
const menuButton = this.self().createMenuButton(null, newStudyData.title, newStudyData.reason);
osparc.utils.Utils.setIdToWidget(menuButton, newStudyData.idToWidget);
const menuButton = this.self().createMenuButton(null, newStudyData["title"], newStudyData["reason"]);
odeimaiz marked this conversation as resolved.
Show resolved Hide resolved
osparc.utils.Utils.setIdToWidget(menuButton, newStudyData["idToWidget"]);
menuButton.setEnabled(false);

this.__addIcon(menuButton, newStudyData);
this.__addFromResourceButton(menuButton, newStudyData.category);
this.__addFromResourceButton(menuButton, newStudyData["category"]);
},

__addEmptyStudyButton: function(newStudyData) {
const menuButton = this.self().createMenuButton(null, newStudyData.title);
osparc.utils.Utils.setIdToWidget(menuButton, newStudyData.idToWidget);
const menuButton = this.self().createMenuButton(null, newStudyData["title"]);
osparc.utils.Utils.setIdToWidget(menuButton, newStudyData["idToWidget"]);

menuButton.addListener("tap", () => {
this.fireDataEvent("newEmptyStudyClicked", {
newStudyLabel: newStudyData.newStudyLabel,
newStudyLabel: newStudyData["newStudyLabel"],
});
});

this.__addIcon(menuButton, newStudyData);
this.__addFromResourceButton(menuButton, newStudyData.category);
this.__addFromResourceButton(menuButton, newStudyData["category"]);
},

__addFromTemplateButton: function(newStudyData, templates) {
const menuButton = this.self().createMenuButton(null, newStudyData.title);
osparc.utils.Utils.setIdToWidget(menuButton, newStudyData.idToWidget);
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);
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,
newStudyLabel: newStudyData["newStudyLabel"],
});
});
this.__addIcon(menuButton, newStudyData, templateMetadata);
this.__addFromResourceButton(menuButton, newStudyData.category);
this.__addFromResourceButton(menuButton, newStudyData["category"]);
}
},

__addFromServiceButton: function(newStudyData) {
const menuButton = this.self().createMenuButton(null, newStudyData.title);
osparc.utils.Utils.setIdToWidget(menuButton, newStudyData.idToWidget);
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;
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) {
Expand All @@ -265,7 +302,7 @@ qx.Class.define("osparc.dashboard.NewPlusMenu", {
menuButton.addListener("tap", () => {
this.fireDataEvent("newStudyFromServiceClicked", {
serviceMetadata: latestMetadata,
newStudyLabel: newStudyData.newStudyLabel,
newStudyLabel: newStudyData["newStudyLabel"],
});
});

Expand All @@ -283,7 +320,7 @@ qx.Class.define("osparc.dashboard.NewPlusMenu", {
menuButton._add(infoButton, {column: 2});

this.__addIcon(menuButton, newStudyData, latestMetadata);
this.__addFromResourceButton(menuButton, newStudyData.category);
this.__addFromResourceButton(menuButton, newStudyData["category"]);
})
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,10 @@ qx.Class.define("osparc.dashboard.NewStudies", {
const title = templateInfo.title;
const desc = templateInfo.description;
const newPlanButton = new osparc.dashboard.GridButtonNew(title, desc);
newPlanButton.setCardKey(templateInfo.idToWidget);
osparc.utils.Utils.setIdToWidget(newPlanButton, templateInfo.idToWidget);
if (templateInfo["idToWidget"]) {
newPlanButton.setCardKey(templateInfo["idToWidget"]);
osparc.utils.Utils.setIdToWidget(newPlanButton, templateInfo["idToWidget"]);
}
newPlanButton.addListener("tap", () => newStudyClicked());
return newPlanButton;
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,6 @@

************************************************************************ */

/**
* @asset(osparc/new_studies.json")
*/

/**
* Widget that shows lists user's studies.
*
Expand Down Expand Up @@ -979,39 +975,36 @@ qx.Class.define("osparc.dashboard.StudyBrowser", {
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) {
newPlansBtn.setEnabled(true);

newPlansBtn.addListener("tap", () => {
osparc.data.Resources.get("templates")
.then(templates => {
if (templates) {
const newStudies = new osparc.dashboard.NewStudies(newStudiesData[product]);
newStudies.addListener("templatesLoaded", () => {
newStudies.setGroupBy("category");
const winTitle = this.tr("New Plan");
const win = osparc.ui.window.Window.popUpInWindow(newStudies, winTitle, osparc.dashboard.NewStudies.WIDTH+40, 300).set({
clickAwayClose: false,
resizable: true
});
newStudies.addListener("newStudyClicked", e => {
win.close();
const templateInfo = e.getData();
const templateData = templates.find(t => t.name === templateInfo.expectedTemplateLabel);
if (templateData) {
this.__newPlanBtnClicked(templateData, templateInfo.newStudyLabel);
}
});
osparc.utils.Utils.setIdToWidget(win, "newStudiesWindow");
});
}
const newStudiesData = osparc.store.Products.getInstance().getNewStudiesUiConfig();
if (newStudiesData) {
newPlansBtn.setEnabled(true);

newPlansBtn.addListener("tap", () => {
osparc.data.Resources.get("templates")
.then(templates => {
if (templates) {
const newStudies = new osparc.dashboard.NewStudies(newStudiesData);
newStudies.addListener("templatesLoaded", () => {
newStudies.setGroupBy("category");
const winTitle = this.tr("New Plan");
const win = osparc.ui.window.Window.popUpInWindow(newStudies, winTitle, osparc.dashboard.NewStudies.WIDTH+40, 300).set({
clickAwayClose: false,
resizable: true
});
newStudies.addListener("newStudyClicked", e => {
win.close();
const templateInfo = e.getData();
const templateData = templates.find(t => t.name === templateInfo.expectedTemplateLabel);
if (templateData) {
this.__newPlanBtnClicked(templateData, templateInfo.newStudyLabel);
}
});
osparc.utils.Utils.setIdToWidget(win, "newStudiesWindow");
});
}
});
}
});
}
},

// Used in S4L products
Expand All @@ -1033,7 +1026,9 @@ qx.Class.define("osparc.dashboard.StudyBrowser", {
const mode = this._resourcesContainer.getMode();
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);
if (newButtonInfo["idToWidget"]) {
osparc.utils.Utils.setIdToWidget(newStudyFromServiceButton, newButtonInfo["idToWidget"]);
}
newStudyFromServiceButton.addListener("tap", () => this.__newStudyFromServiceBtnClicked(latestMetadata["key"], latestMetadata["version"], newButtonInfo.newStudyLabel));
this._resourcesContainer.addNonResourceCard(newStudyFromServiceButton);
})
Expand All @@ -1042,16 +1037,13 @@ qx.Class.define("osparc.dashboard.StudyBrowser", {

__addPlusButtonsFromServices: function() {
// add new plus buttons if key services exists
osparc.utils.Utils.fetchJSON("/resource/osparc/new_studies.json")
.then(newStudiesData => {
const product = osparc.product.Utils.getProductName()
if (product in newStudiesData) {
const newButtonsInfo = newStudiesData[product].resources;
newButtonsInfo.forEach(newButtonInfo => {
this.__addNewStudyFromServiceButtons(newButtonInfo.expectedKey, newButtonInfo);
});
}
const newStudiesData = osparc.store.Products.getInstance().getNewStudiesUiConfig();
if (newStudiesData) {
const newButtonsInfo = newStudiesData["resources"];
newButtonsInfo.forEach(newButtonInfo => {
this.__addNewStudyFromServiceButtons(newButtonInfo.expectedKey, newButtonInfo);
});
}
},

// LAYOUT //
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -981,7 +981,11 @@ qx.Class.define("osparc.data.Resources", {
updateEmailTemplate: {
method: "PUT",
url: statics.API + "/products/{productName}/templates/{templateId}"
}
},
getUiConfig: {
method: "GET",
url: statics.API + "/products/current/ui"
},
}
},
"invitations": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ qx.Class.define("osparc.desktop.MainPage", {
}
preloadPromises.push(store.getAllClassifiers(true));
preloadPromises.push(osparc.store.Tags.getInstance().fetchTags());
preloadPromises.push(osparc.store.Products.getInstance().fetchUiConfig());
Promise.all(preloadPromises)
.then(() => {
const mainStack = this.__createMainStack();
Expand Down
Loading
Loading