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: Usage overview #4455

Merged
merged 14 commits into from
Jul 6, 2023
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
/* ************************************************************************

osparc - the simcore frontend

https://osparc.io

Copyright:
2023 IT'IS Foundation, https://itis.swiss

License:
MIT: https://opensource.org/licenses/MIT

Authors:
* Odei Maiz (odeimaiz)

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

qx.Class.define("osparc.component.resourceUsage.Overview", {
extend: qx.ui.core.Widget,

construct: function() {
this.base(arguments);

this._setLayout(new qx.ui.layout.VBox(15));

const loadingImage = this.getChildControl("loading-image");
loadingImage.show();
const table = this.getChildControl("usage-table");
table.exclude();

this.__fetchData();
},

statics: {
ITEMS_PER_PAGE: 15,

popUpInWindow: function() {
const title = qx.locale.Manager.tr("Usage Overview");
const noteEditor = new osparc.component.resourceUsage.Overview();
const viewWidth = 900;
const viewHeight = 450;
const win = osparc.ui.window.Window.popUpInWindow(noteEditor, title, viewWidth, viewHeight);
win.center();
win.open();
return win;
}
},

members: {
__prevRequestParams: null,
__nextRequestParams: null,

_createChildControlImpl: function(id) {
let control;
switch (id) {
case "loading-image":
control = new qx.ui.basic.Image().set({
source: "@FontAwesome5Solid/circle-notch/64",
alignX: "center",
alignY: "middle"
});
control.getContentElement().addClass("rotate");
this._add(control);
break;
case "usage-table":
control = new osparc.component.resourceUsage.OverviewTable().set({
height: (this.self().ITEMS_PER_PAGE*20 + 40)
});
this._add(control);
break;
case "page-buttons":
control = new qx.ui.container.Composite(new qx.ui.layout.HBox(5)).set({
allowGrowX: true,
alignX: "center",
alignY: "middle"
});
this._add(control);
break;
case "prev-page-button": {
control = new qx.ui.form.Button().set({
icon: "@FontAwesome5Solid/chevron-left/12",
allowGrowX: false
});
control.addListener("execute", () => this.__fetchData(this.__getPrevRequest()));
const pageButtons = this.getChildControl("page-buttons");
pageButtons.add(control);
break;
}
case "current-page-label": {
control = new qx.ui.basic.Label().set({
font: "text-14",
textAlign: "center",
alignY: "middle"
});
const pageButtons = this.getChildControl("page-buttons");
pageButtons.add(control);
break;
}
case "next-page-button": {
control = new qx.ui.form.Button().set({
icon: "@FontAwesome5Solid/chevron-right/12",
allowGrowX: false
});
control.addListener("execute", () => this.__fetchData(this.__getNextRequest()));
const pageButtons = this.getChildControl("page-buttons");
pageButtons.add(control);
break;
}
}
return control || this.base(arguments, id);
},

__fetchData: function(request) {
const loadingImage = this.getChildControl("loading-image");
loadingImage.show();
const table = this.getChildControl("usage-table");
table.exclude();

if (request === undefined) {
request = this.__getNextRequest();
}
request
.then(resp => {
const data = resp["data"];
this.__setData(data);
this.__prevRequestParams = resp["_links"]["prev"];
this.__nextRequestParams = resp["_links"]["next"];
this.__evaluatePageButtons(resp);
})
.finally(() => {
loadingImage.exclude();
table.show();
});
},

__getPrevRequest: function() {
const params = {
url: {
offset: osparc.component.resourceUsage.Overview.ITEMS_PER_PAGE,
limit: osparc.component.resourceUsage.Overview.ITEMS_PER_PAGE
}
};
if (this.__prevRequestParams) {
params.url.offset = osparc.utils.Utils.getParamFromURL(this.__prevRequestParams, "offset");
params.url.limit = osparc.utils.Utils.getParamFromURL(this.__prevRequestParams, "limit");
}
const options = {
resolveWResponse: true
};
return osparc.data.Resources.fetch("resourceUsage", "getPage", params, undefined, options);
},

__getNextRequest: function() {
const params = {
url: {
offset: 0,
limit: osparc.component.resourceUsage.Overview.ITEMS_PER_PAGE
}
};
if (this.__nextRequestParams) {
params.url.offset = osparc.utils.Utils.getParamFromURL(this.__nextRequestParams, "offset");
params.url.limit = osparc.utils.Utils.getParamFromURL(this.__nextRequestParams, "limit");
}
const options = {
resolveWResponse: true
};
return osparc.data.Resources.fetch("resourceUsage", "getPage", params, undefined, options);
},

__setData: function(data) {
const table = this.getChildControl("usage-table");
table.addData(data);
},

__evaluatePageButtons:function(resp) {
this.getChildControl("prev-page-button").setEnabled(Boolean(this.__prevRequestParams));
this.getChildControl("current-page-label").setValue(((resp["_meta"]["offset"]/this.self().ITEMS_PER_PAGE)+1).toString());
this.getChildControl("next-page-button").setEnabled(Boolean(this.__nextRequestParams));
}
}
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/* ************************************************************************

osparc - the simcore frontend

https://osparc.io

Copyright:
2023 IT'IS Foundation, https://itis.swiss

License:
MIT: https://opensource.org/licenses/MIT

Authors:
* Odei Maiz (odeimaiz)

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

qx.Class.define("osparc.component.resourceUsage.OverviewTable", {
extend: osparc.ui.table.Table,

construct: function() {
const cols = this.self().COLUMNS;
const model = this.__model = new qx.ui.table.model.Simple();
const colNames = Object.values(cols).map(col => col.title);
model.setColumns(colNames);

this.base(arguments, model, {
tableColumnModel: obj => new qx.ui.table.columnmodel.Resize(obj),
statusBarVisible: false
});
const columnModel = this.getTableColumnModel();
columnModel.getBehavior().setWidth(this.self().COLUMNS.duration.pos, 60);
columnModel.getBehavior().setWidth(this.self().COLUMNS.processors.pos, 80);
columnModel.getBehavior().setWidth(this.self().COLUMNS.coreHours.pos, 80);
columnModel.getBehavior().setWidth(this.self().COLUMNS.status.pos, 70);
columnModel.setDataCellRenderer(this.self().COLUMNS.duration.pos, new qx.ui.table.cellrenderer.Number());
columnModel.setDataCellRenderer(this.self().COLUMNS.processors.pos, new qx.ui.table.cellrenderer.Number());
columnModel.setDataCellRenderer(this.self().COLUMNS.coreHours.pos, new qx.ui.table.cellrenderer.Number());
},

statics: {
COLUMNS: {
project: {
pos: 0,
title: "Project"
},
node: {
pos: 1,
title: "Node"
},
service: {
pos: 2,
title: "Service"
},
start: {
pos: 3,
title: "Start"
},
duration: {
pos: 4,
title: "Duration"
},
processors: {
pos: 5,
title: "Processors"
},
coreHours: {
pos: 6,
title: "Core Hours"
},
status: {
pos: 7,
title: "Status"
}
}
},

members: {
__model: null,

addData: function(datas) {
const newDatas = [];
if (datas) {
const cols = this.self().COLUMNS;
datas.forEach(data => {
const newData = [];
newData[cols["project"].pos] = data["project_name"] ? data["project_name"] : data["project_uuid"];
newData[cols["node"].pos] = data["node_label"] ? data["node_label"] : data["node_uuid"];
if (data["service_key"]) {
const parts = data["service_key"].split("/");
const serviceName = parts.pop();
newData[cols["service"].pos] = serviceName + ":" + data["service_version"];
}
newData[cols["start"].pos] = osparc.utils.Utils.formatDateAndTime(new Date(data["start_time"]));
newData[cols["duration"].pos] = data["duration"];
newData[cols["processors"].pos] = data["processors"];
newData[cols["coreHours"].pos] = data["core_hours"];
newData[cols["status"].pos] = qx.lang.String.firstUp(data["status"]);
newDatas.push(newData);
});
}
this.setData(newDatas);
}
}
});
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ qx.Class.define("osparc.dashboard.ResourceMoreOptions", {

statics: {
WIDTH: 715,
HEIGHT: 715,
HEIGHT: 720,

popUpInWindow: function(moreOpts) {
const title = qx.locale.Manager.tr("Details");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,8 @@ qx.Class.define("osparc.data.Permissions", {
"study.nodestree.uuid.read",
"study.filestree.uuid.read",
"study.logger.debug.read",
"statics.read"
"statics.read",
"usage.all.read"
],
"admin": []
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,15 @@ qx.Class.define("osparc.data.Resources", {
}
}
},
"resourceUsage": {
useCache: true,
endpoints: {
getPage: {
method: "GET",
url: statics.API + "/resource-usage/containers?offset={offset}&limit={limit}"
}
}
},
/*
* NODES
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,11 @@ qx.Class.define("osparc.navigation.UserMenuButton", {
control.addListener("execute", () => osparc.desktop.organizations.OrganizationsWindow.openWindow(), this);
this.getMenu().add(control);
break;
case "usage-overview":
control = new qx.ui.menu.Button(this.tr("Usage Overview"));
control.addListener("execute", () => osparc.component.resourceUsage.Overview.popUpInWindow(), this);
this.getMenu().add(control);
break;
case "clusters":
control = new qx.ui.menu.Button(this.tr("Clusters"));
control.exclude();
Expand Down Expand Up @@ -156,6 +161,9 @@ qx.Class.define("osparc.navigation.UserMenuButton", {
} else {
this.getChildControl("preferences");
this.getChildControl("organizations");
if (osparc.data.Permissions.getInstance().canDo("usage.all.read")) {
this.getChildControl("usage-overview");
}
this.getChildControl("clusters");
}
if (osparc.product.tutorial.Utils.getTutorial()) {
Expand Down Expand Up @@ -189,6 +197,9 @@ qx.Class.define("osparc.navigation.UserMenuButton", {
} else {
this.getChildControl("preferences");
this.getChildControl("organizations");
if (osparc.data.Permissions.getInstance().canDo("usage.all.read")) {
this.getChildControl("usage-overview");
}
this.getChildControl("clusters");
}
this.getMenu().addSeparator();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ qx.Class.define("osparc.store.Store", {
check: "Array",
init: []
},
resourceUsage: {
check: "Array",
init: []
},
nodesInStudyResources: {
check: "Array",
init: []
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -712,9 +712,10 @@ qx.Class.define("osparc.utils.Utils", {
return parsedFragment;
},

getParamFromURL: (url, param) => {
const urlParams = new URLSearchParams(url);
return urlParams.get(param);
getParamFromURL: (urlStr, param) => {
const url = new URL(urlStr);
const args = new URLSearchParams(url.search);
return args.get(param);
},

hasParamFromURL: (url, param) => {
Expand Down