Skip to content
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/* ************************************************************************

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.data.Cluster", {
extend: qx.core.Object,

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

this.set({
clusterId: clusterData["cluster_id"],
name: clusterData["name"],
status: clusterData["status"],
nWorkers: clusterData["n_workers"],
});
},

properties: {
clusterId: {
check: "String",
nullable: false,
init: null,
},

name: {
check: "String",
nullable: false,
init: null,
},

status: {
check: "String",
nullable: false,
init: null,
},

nWorkers: {
check: "Number",
init: 0,
nullable: true,
},
},
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/* ************************************************************************

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.jobs.ClustersBrowser", {
extend: qx.ui.core.Widget,

construct() {
this.base(arguments);

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

this.getChildControl("clusters-table");
},

members: {
_createChildControlImpl: function(id) {
let control;
switch (id) {
case "clusters-table":
control = new osparc.jobs.ClustersTable();
this._add(control);
break;
}

return control || this.base(arguments, id);
},
}
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/* ************************************************************************

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.jobs.ClustersTable", {
extend: qx.ui.table.Table,

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

const model = new osparc.jobs.ClustersTableModel(filters);
this.setTableModel(model);

this.set({
statusBarVisible: false,
headerCellHeight: 26,
rowHeight: 26,
});

const columnModel = this.getTableColumnModel();
columnModel.setColumnVisible(this.self().COLS.CLUSTER_ID.column, true);

Object.values(this.self().COLS).forEach(col => columnModel.setColumnWidth(col.column, col.width));
},

statics: {
COLS: {
CLUSTER_ID: {
id: "clusterId",
column: 0,
label: qx.locale.Manager.tr("Cluster Id"),
width: 280
},
NAME: {
id: "name",
column: 1,
label: qx.locale.Manager.tr("Name"),
width: 100
},
STATUS: {
id: "status",
column: 2,
label: qx.locale.Manager.tr("Status"),
width: 170
},
N_WORKERS: {
id: "nWorkers",
column: 3,
label: qx.locale.Manager.tr("# Workers"),
width: 80
},
}
},
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
/* ************************************************************************

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.jobs.ClustersTableModel", {
extend: qx.ui.table.model.Remote,

construct(filters) {
this.base(arguments);

const clustersCols = osparc.jobs.ClustersTable.COLS;
const colLabels = Object.values(clustersCols).map(col => col.label);
const colIDs = Object.values(clustersCols).map(col => col.id);
this.setColumns(colLabels, colIDs);

if (filters) {
this.setFilters(filters);
}

this.setSortAscendingWithoutSortingData(false);
this.setColumnSortable(clustersCols.CLUSTER_ID.column, false);
this.setColumnSortable(clustersCols.N_WORKERS.column, false);
},

properties: {
isFetching: {
check: "Boolean",
init: false,
event: "changeFetching"
},

filters: {
check: "Object",
init: null,
apply: "reloadData", // force reload
},

orderBy: {
check: "Object",
init: {
field: "name",
direction: "asc"
}
},
},

statics: {
SERVER_MAX_LIMIT: 49,
},

members: {
// overridden
_loadRowCount() {
const urlParams = {
offset: 0,
limit: 1,
filters: this.getFilters() ?
JSON.stringify({
"started_at": this.getFilters()
}) :
null,
orderBy: JSON.stringify(this.getOrderBy()),
};
const options = {
resolveWResponse: true
};
osparc.store.Clusters.getInstance().fetchClusters(urlParams, options)
.then(clusters => {
this._onRowCountLoaded(clusters.length);
})
.catch(() => this._onRowCountLoaded(null));
},

// overridden
_loadRowData(firstRow, qxLastRow) {
this.setIsFetching(true);

const lastRow = Math.min(qxLastRow, this._rowCount - 1);
// Returns a request promise with given offset and limit
const getFetchPromise = (offset, limit=this.self().SERVER_MAX_LIMIT) => {
const urlParams = {
limit,
offset,
filters: this.getFilters() ?
JSON.stringify({
"started_at": this.getFilters()
}) :
null,
orderBy: JSON.stringify(this.getOrderBy())
};
return osparc.store.Clusters.getInstance().fetchClusters(urlParams)
.then(clusters => {
const data = [];
const clustersCols = osparc.jobs.ClustersTable.COLS;
clusters.forEach(cluster => {
data.push({
[clustersCols.CLUSTER_ID.id]: cluster.getClusterId(),
[clustersCols.NAME.id]: cluster.getName(),
[clustersCols.STATUS.id]: cluster.getStatus(),
[clustersCols.N_WORKERS.id]: cluster.getNWorkers() ? cluster.getNWorkers() : 0,
});
});
return data;
});
};

// Divides the model row request into several server requests to comply with the number of rows server limit
const reqLimit = lastRow - firstRow + 1; // Number of requested rows
const nRequests = Math.ceil(reqLimit / this.self().SERVER_MAX_LIMIT);
if (nRequests > 1) {
const requests = [];
for (let i=firstRow; i <= lastRow; i += this.self().SERVER_MAX_LIMIT) {
requests.push(getFetchPromise(i, i > lastRow - this.self().SERVER_MAX_LIMIT + 1 ? reqLimit % this.self().SERVER_MAX_LIMIT : this.self().SERVER_MAX_LIMIT))
}
Promise.all(requests)
.then(responses => this._onRowDataLoaded(responses.flat()))
.catch(err => {
console.error(err);
this._onRowDataLoaded(null);
})
.finally(() => this.setIsFetching(false));
} else {
getFetchPromise(firstRow, reqLimit)
.then(data => {
this._onRowDataLoaded(data);
})
.catch(err => {
console.error(err)
this._onRowDataLoaded(null);
})
.finally(() => this.setIsFetching(false));
}
}
}
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/* ************************************************************************

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.jobs.JobsAndClusters", {
extend: qx.ui.tabview.TabView,

construct() {
this.base(arguments);

this.set({
contentPadding: 5,
barPosition: "top",
});

const jobsPage = new qx.ui.tabview.Page(this.tr("Jobs")).set({
layout: new qx.ui.layout.VBox(10)
});
const jobsBrowser = new osparc.jobs.JobsBrowser();
const scroller1 = new qx.ui.container.Scroll();
scroller1.add(jobsBrowser);
jobsPage.add(scroller1);
this.add(jobsPage);

const clustersPage = new qx.ui.tabview.Page(this.tr("Clusters")).set({
layout: new qx.ui.layout.VBox(10)
});
const clustersBrowser = new osparc.jobs.ClustersBrowser();
const scroller2 = new qx.ui.container.Scroll();
scroller2.add(clustersBrowser);
clustersPage.add(scroller2);
this.add(clustersPage);
},

statics: {
popUpInWindow: function(jobsAndClusters) {
if (!jobsAndClusters) {
jobsAndClusters = new osparc.jobs.JobsAndClusters();
}
const title = qx.locale.Manager.tr("Jobs and Clusters");
const win = osparc.ui.window.Window.popUpInWindow(jobsAndClusters, title, 1100, 500);
win.open();
return win;
}
},
});
Loading
Loading