Skip to content

Commit 58c2741

Browse files
Merge branch 'master' into is7516/web-api-tasks
2 parents 31b34e5 + c5fe5bc commit 58c2741

File tree

11 files changed

+482
-17
lines changed

11 files changed

+482
-17
lines changed
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/* ************************************************************************
2+
3+
osparc - the simcore frontend
4+
5+
https://osparc.io
6+
7+
Copyright:
8+
2025 IT'IS Foundation, https://itis.swiss
9+
10+
License:
11+
MIT: https://opensource.org/licenses/MIT
12+
13+
Authors:
14+
* Odei Maiz (odeimaiz)
15+
16+
************************************************************************ */
17+
18+
qx.Class.define("osparc.data.Cluster", {
19+
extend: qx.core.Object,
20+
21+
construct: function(clusterData) {
22+
this.base(arguments);
23+
24+
this.set({
25+
clusterId: clusterData["cluster_id"],
26+
name: clusterData["name"],
27+
status: clusterData["status"],
28+
nWorkers: clusterData["n_workers"],
29+
});
30+
},
31+
32+
properties: {
33+
clusterId: {
34+
check: "String",
35+
nullable: false,
36+
init: null,
37+
},
38+
39+
name: {
40+
check: "String",
41+
nullable: false,
42+
init: null,
43+
},
44+
45+
status: {
46+
check: "String",
47+
nullable: false,
48+
init: null,
49+
},
50+
51+
nWorkers: {
52+
check: "Number",
53+
init: 0,
54+
nullable: true,
55+
},
56+
},
57+
});
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/* ************************************************************************
2+
3+
osparc - the simcore frontend
4+
5+
https://osparc.io
6+
7+
Copyright:
8+
2025 IT'IS Foundation, https://itis.swiss
9+
10+
License:
11+
MIT: https://opensource.org/licenses/MIT
12+
13+
Authors:
14+
* Odei Maiz (odeimaiz)
15+
16+
************************************************************************ */
17+
18+
19+
qx.Class.define("osparc.jobs.ClustersBrowser", {
20+
extend: qx.ui.core.Widget,
21+
22+
construct() {
23+
this.base(arguments);
24+
25+
this._setLayout(new qx.ui.layout.VBox(10));
26+
27+
this.getChildControl("clusters-table");
28+
},
29+
30+
members: {
31+
_createChildControlImpl: function(id) {
32+
let control;
33+
switch (id) {
34+
case "clusters-table":
35+
control = new osparc.jobs.ClustersTable();
36+
this._add(control);
37+
break;
38+
}
39+
40+
return control || this.base(arguments, id);
41+
},
42+
}
43+
})
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/* ************************************************************************
2+
3+
osparc - the simcore frontend
4+
5+
https://osparc.io
6+
7+
Copyright:
8+
2025 IT'IS Foundation, https://itis.swiss
9+
10+
License:
11+
MIT: https://opensource.org/licenses/MIT
12+
13+
Authors:
14+
* Odei Maiz (odeimaiz)
15+
16+
************************************************************************ */
17+
18+
19+
qx.Class.define("osparc.jobs.ClustersTable", {
20+
extend: qx.ui.table.Table,
21+
22+
construct: function(filters) {
23+
this.base(arguments);
24+
25+
const model = new osparc.jobs.ClustersTableModel(filters);
26+
this.setTableModel(model);
27+
28+
this.set({
29+
statusBarVisible: false,
30+
headerCellHeight: 26,
31+
rowHeight: 26,
32+
});
33+
34+
const columnModel = this.getTableColumnModel();
35+
columnModel.setColumnVisible(this.self().COLS.CLUSTER_ID.column, true);
36+
37+
Object.values(this.self().COLS).forEach(col => columnModel.setColumnWidth(col.column, col.width));
38+
},
39+
40+
statics: {
41+
COLS: {
42+
CLUSTER_ID: {
43+
id: "clusterId",
44+
column: 0,
45+
label: qx.locale.Manager.tr("Cluster Id"),
46+
width: 280
47+
},
48+
NAME: {
49+
id: "name",
50+
column: 1,
51+
label: qx.locale.Manager.tr("Name"),
52+
width: 100
53+
},
54+
STATUS: {
55+
id: "status",
56+
column: 2,
57+
label: qx.locale.Manager.tr("Status"),
58+
width: 170
59+
},
60+
N_WORKERS: {
61+
id: "nWorkers",
62+
column: 3,
63+
label: qx.locale.Manager.tr("# Workers"),
64+
width: 80
65+
},
66+
}
67+
},
68+
});
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
/* ************************************************************************
2+
3+
osparc - the simcore frontend
4+
5+
https://osparc.io
6+
7+
Copyright:
8+
2025 IT'IS Foundation, https://itis.swiss
9+
10+
License:
11+
MIT: https://opensource.org/licenses/MIT
12+
13+
Authors:
14+
* Odei Maiz (odeimaiz)
15+
16+
************************************************************************ */
17+
18+
19+
qx.Class.define("osparc.jobs.ClustersTableModel", {
20+
extend: qx.ui.table.model.Remote,
21+
22+
construct(filters) {
23+
this.base(arguments);
24+
25+
const clustersCols = osparc.jobs.ClustersTable.COLS;
26+
const colLabels = Object.values(clustersCols).map(col => col.label);
27+
const colIDs = Object.values(clustersCols).map(col => col.id);
28+
this.setColumns(colLabels, colIDs);
29+
30+
if (filters) {
31+
this.setFilters(filters);
32+
}
33+
34+
this.setSortAscendingWithoutSortingData(false);
35+
this.setColumnSortable(clustersCols.CLUSTER_ID.column, false);
36+
this.setColumnSortable(clustersCols.N_WORKERS.column, false);
37+
},
38+
39+
properties: {
40+
isFetching: {
41+
check: "Boolean",
42+
init: false,
43+
event: "changeFetching"
44+
},
45+
46+
filters: {
47+
check: "Object",
48+
init: null,
49+
apply: "reloadData", // force reload
50+
},
51+
52+
orderBy: {
53+
check: "Object",
54+
init: {
55+
field: "name",
56+
direction: "asc"
57+
}
58+
},
59+
},
60+
61+
statics: {
62+
SERVER_MAX_LIMIT: 49,
63+
},
64+
65+
members: {
66+
// overridden
67+
_loadRowCount() {
68+
const urlParams = {
69+
offset: 0,
70+
limit: 1,
71+
filters: this.getFilters() ?
72+
JSON.stringify({
73+
"started_at": this.getFilters()
74+
}) :
75+
null,
76+
orderBy: JSON.stringify(this.getOrderBy()),
77+
};
78+
const options = {
79+
resolveWResponse: true
80+
};
81+
osparc.store.Clusters.getInstance().fetchClusters(urlParams, options)
82+
.then(clusters => {
83+
this._onRowCountLoaded(clusters.length);
84+
})
85+
.catch(() => this._onRowCountLoaded(null));
86+
},
87+
88+
// overridden
89+
_loadRowData(firstRow, qxLastRow) {
90+
this.setIsFetching(true);
91+
92+
const lastRow = Math.min(qxLastRow, this._rowCount - 1);
93+
// Returns a request promise with given offset and limit
94+
const getFetchPromise = (offset, limit=this.self().SERVER_MAX_LIMIT) => {
95+
const urlParams = {
96+
limit,
97+
offset,
98+
filters: this.getFilters() ?
99+
JSON.stringify({
100+
"started_at": this.getFilters()
101+
}) :
102+
null,
103+
orderBy: JSON.stringify(this.getOrderBy())
104+
};
105+
return osparc.store.Clusters.getInstance().fetchClusters(urlParams)
106+
.then(clusters => {
107+
const data = [];
108+
const clustersCols = osparc.jobs.ClustersTable.COLS;
109+
clusters.forEach(cluster => {
110+
data.push({
111+
[clustersCols.CLUSTER_ID.id]: cluster.getClusterId(),
112+
[clustersCols.NAME.id]: cluster.getName(),
113+
[clustersCols.STATUS.id]: cluster.getStatus(),
114+
[clustersCols.N_WORKERS.id]: cluster.getNWorkers() ? cluster.getNWorkers() : 0,
115+
});
116+
});
117+
return data;
118+
});
119+
};
120+
121+
// Divides the model row request into several server requests to comply with the number of rows server limit
122+
const reqLimit = lastRow - firstRow + 1; // Number of requested rows
123+
const nRequests = Math.ceil(reqLimit / this.self().SERVER_MAX_LIMIT);
124+
if (nRequests > 1) {
125+
const requests = [];
126+
for (let i=firstRow; i <= lastRow; i += this.self().SERVER_MAX_LIMIT) {
127+
requests.push(getFetchPromise(i, i > lastRow - this.self().SERVER_MAX_LIMIT + 1 ? reqLimit % this.self().SERVER_MAX_LIMIT : this.self().SERVER_MAX_LIMIT))
128+
}
129+
Promise.all(requests)
130+
.then(responses => this._onRowDataLoaded(responses.flat()))
131+
.catch(err => {
132+
console.error(err);
133+
this._onRowDataLoaded(null);
134+
})
135+
.finally(() => this.setIsFetching(false));
136+
} else {
137+
getFetchPromise(firstRow, reqLimit)
138+
.then(data => {
139+
this._onRowDataLoaded(data);
140+
})
141+
.catch(err => {
142+
console.error(err)
143+
this._onRowDataLoaded(null);
144+
})
145+
.finally(() => this.setIsFetching(false));
146+
}
147+
}
148+
}
149+
})
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/* ************************************************************************
2+
3+
osparc - the simcore frontend
4+
5+
https://osparc.io
6+
7+
Copyright:
8+
2025 IT'IS Foundation, https://itis.swiss
9+
10+
License:
11+
MIT: https://opensource.org/licenses/MIT
12+
13+
Authors:
14+
* Odei Maiz (odeimaiz)
15+
16+
************************************************************************ */
17+
18+
19+
qx.Class.define("osparc.jobs.JobsAndClusters", {
20+
extend: qx.ui.tabview.TabView,
21+
22+
construct() {
23+
this.base(arguments);
24+
25+
this.set({
26+
contentPadding: 5,
27+
barPosition: "top",
28+
});
29+
30+
const jobsPage = new qx.ui.tabview.Page(this.tr("Jobs")).set({
31+
layout: new qx.ui.layout.VBox(10)
32+
});
33+
const jobsBrowser = new osparc.jobs.JobsBrowser();
34+
const scroller1 = new qx.ui.container.Scroll();
35+
scroller1.add(jobsBrowser);
36+
jobsPage.add(scroller1);
37+
this.add(jobsPage);
38+
39+
const clustersPage = new qx.ui.tabview.Page(this.tr("Clusters")).set({
40+
layout: new qx.ui.layout.VBox(10)
41+
});
42+
const clustersBrowser = new osparc.jobs.ClustersBrowser();
43+
const scroller2 = new qx.ui.container.Scroll();
44+
scroller2.add(clustersBrowser);
45+
clustersPage.add(scroller2);
46+
this.add(clustersPage);
47+
},
48+
49+
statics: {
50+
popUpInWindow: function(jobsAndClusters) {
51+
if (!jobsAndClusters) {
52+
jobsAndClusters = new osparc.jobs.JobsAndClusters();
53+
}
54+
const title = qx.locale.Manager.tr("Jobs and Clusters");
55+
const win = osparc.ui.window.Window.popUpInWindow(jobsAndClusters, title, 1100, 500);
56+
win.open();
57+
return win;
58+
}
59+
},
60+
});

0 commit comments

Comments
 (0)