diff --git a/services/static-webserver/client/source/class/osparc/jobs/ActivityCenterWindow.js b/services/static-webserver/client/source/class/osparc/jobs/ActivityCenterWindow.js
index 69293492585..d374a28f99b 100644
--- a/services/static-webserver/client/source/class/osparc/jobs/ActivityCenterWindow.js
+++ b/services/static-webserver/client/source/class/osparc/jobs/ActivityCenterWindow.js
@@ -72,7 +72,6 @@ qx.Class.define("osparc.jobs.ActivityCenterWindow", {
});
this.addListener("close", () => {
- runsBrowser.stopInterval();
subRunsBrowser.stopInterval();
});
},
diff --git a/services/static-webserver/client/source/class/osparc/jobs/RunsBrowser.js b/services/static-webserver/client/source/class/osparc/jobs/RunsBrowser.js
index c5ab4355df9..2636961004d 100644
--- a/services/static-webserver/client/source/class/osparc/jobs/RunsBrowser.js
+++ b/services/static-webserver/client/source/class/osparc/jobs/RunsBrowser.js
@@ -24,6 +24,8 @@ qx.Class.define("osparc.jobs.RunsBrowser", {
this._setLayout(new qx.ui.layout.VBox(10));
+ const reloadButton = this.getChildControl("reload-button");
+ reloadButton.addListener("execute", () => this.reloadRuns());
this.getChildControl("intro-label");
const jobsFilter = this.getChildControl("jobs-filter");
const runningCB = this.getChildControl("running-only-cb");
@@ -35,8 +37,6 @@ qx.Class.define("osparc.jobs.RunsBrowser", {
});
runningCB.bind("value", runsTable, "runningOnly");
-
- this.__reloadInterval = setInterval(() => this.reloadRuns(), 10*1000);
},
events: {
@@ -49,13 +49,19 @@ qx.Class.define("osparc.jobs.RunsBrowser", {
_createChildControlImpl: function(id) {
let control;
switch (id) {
- case "header-filter":
+ case "header-toolbar":
control = new qx.ui.container.Composite(new qx.ui.layout.HBox(5));
this._add(control);
break;
+ case "reload-button":
+ control = new qx.ui.form.Button(this.tr("Reload"), "@FontAwesome5Solid/sync-alt/14");
+ this.getChildControl("header-toolbar").add(control);
+ break;
case "intro-label":
- control = new qx.ui.basic.Label(this.tr("Select a Run to check the details"));
- this.getChildControl("header-filter").add(control);
+ control = new qx.ui.basic.Label(this.tr("Select a Run to check the details")).set({
+ alignY: "middle",
+ });
+ this.getChildControl("header-toolbar").add(control);
break;
case "jobs-filter":
control = new osparc.filter.TextFilter("text", "jobsList").set({
@@ -66,7 +72,7 @@ qx.Class.define("osparc.jobs.RunsBrowser", {
placeholder: qx.locale.Manager.tr("Filter by name or ID"),
});
control.hide(); // @matusdrobuliak66: remove this when the backend is ready
- this.getChildControl("header-filter").add(control, {
+ this.getChildControl("header-toolbar").add(control, {
flex: 1
});
break;
@@ -75,7 +81,7 @@ qx.Class.define("osparc.jobs.RunsBrowser", {
value: true,
label: qx.locale.Manager.tr("Active only"),
});
- this.getChildControl("header-filter").add(control);
+ this.getChildControl("header-toolbar").add(control);
break;
case "runs-table": {
const projectUuid = null;
@@ -95,11 +101,5 @@ qx.Class.define("osparc.jobs.RunsBrowser", {
const runsTable = this.getChildControl("runs-table");
runsTable.reloadRuns();
},
-
- stopInterval: function() {
- if (this.__reloadInterval) {
- clearInterval(this.__reloadInterval);
- }
- },
}
})
diff --git a/services/static-webserver/client/source/class/osparc/jobs/RunsTableModel.js b/services/static-webserver/client/source/class/osparc/jobs/RunsTableModel.js
index f11bb85e402..1e620708b1b 100644
--- a/services/static-webserver/client/source/class/osparc/jobs/RunsTableModel.js
+++ b/services/static-webserver/client/source/class/osparc/jobs/RunsTableModel.js
@@ -79,12 +79,8 @@ qx.Class.define("osparc.jobs.RunsTableModel", {
},
},
- statics: {
- SERVER_MAX_LIMIT: 49,
- },
-
members: {
- __includeChildren: false,
+ __includeChildren: null,
// overridden
sortByColumn(columnIndex, ascending) {
@@ -126,7 +122,7 @@ qx.Class.define("osparc.jobs.RunsTableModel", {
const lastRow = Math.min(qxLastRow, this._rowCount - 1);
// Returns a request promise with given offset and limit
const getFetchPromise = (offset, limit) => {
- const orderBy = this.getOrderBy();
+ const orderBy = this.getOrderBy();
let promise;
if (this.getProjectUuid()) {
promise = osparc.store.Jobs.getInstance().fetchJobsHistory(this.getProjectUuid(), this.__includeChildren, offset, limit, orderBy);
@@ -153,15 +149,13 @@ qx.Class.define("osparc.jobs.RunsTableModel", {
};
// Divides the model row request into several server requests to comply with the number of rows server limit
+ const serverMaxLimit = osparc.store.Jobs.SERVER_MAX_LIMIT;
const reqLimit = lastRow - firstRow + 1; // Number of requested rows
- let nRequests = Math.ceil(reqLimit / this.self().SERVER_MAX_LIMIT);
+ let nRequests = Math.ceil(reqLimit / serverMaxLimit);
if (nRequests > 1) {
const requests = [];
- for (let i=firstRow; i <= lastRow; i += this.self().SERVER_MAX_LIMIT) {
- // fetch the first page only
- if (i < 1) {
- requests.push(getFetchPromise(i, i > lastRow - this.self().SERVER_MAX_LIMIT + 1 ? reqLimit % this.self().SERVER_MAX_LIMIT : this.self().SERVER_MAX_LIMIT))
- }
+ for (let i=firstRow; i <= lastRow; i += serverMaxLimit) {
+ requests.push(getFetchPromise(i, i > lastRow - serverMaxLimit + 1 ? reqLimit % serverMaxLimit : serverMaxLimit));
}
Promise.all(requests)
.then(responses => this._onRowDataLoaded(responses.flat()))
diff --git a/services/static-webserver/client/source/class/osparc/jobs/SubRunsTableModel.js b/services/static-webserver/client/source/class/osparc/jobs/SubRunsTableModel.js
index 2c43fa59ed9..58ad6040cfb 100644
--- a/services/static-webserver/client/source/class/osparc/jobs/SubRunsTableModel.js
+++ b/services/static-webserver/client/source/class/osparc/jobs/SubRunsTableModel.js
@@ -57,10 +57,6 @@ qx.Class.define("osparc.jobs.SubRunsTableModel", {
},
},
- statics: {
- SERVER_MAX_LIMIT: 49,
- },
-
members: {
// overridden
sortByColumn(columnIndex, ascending) {
@@ -132,12 +128,13 @@ qx.Class.define("osparc.jobs.SubRunsTableModel", {
};
// Divides the model row request into several server requests to comply with the number of rows server limit
+ const serverMaxLimit = osparc.store.Jobs.SERVER_MAX_LIMIT;
const reqLimit = lastRow - firstRow + 1; // Number of requested rows
- const nRequests = Math.ceil(reqLimit / this.self().SERVER_MAX_LIMIT);
+ const nRequests = Math.ceil(reqLimit / serverMaxLimit);
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))
+ for (let i=firstRow; i <= lastRow; i += serverMaxLimit) {
+ requests.push(getFetchPromise(i, i > lastRow - serverMaxLimit + 1 ? reqLimit % serverMaxLimit : serverMaxLimit))
}
Promise.all(requests)
.then(responses => this._onRowDataLoaded(responses.flat()))
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 c0a1a3da81c..2dcb2db7d46 100644
--- a/services/static-webserver/client/source/class/osparc/theme/Appearance.js
+++ b/services/static-webserver/client/source/class/osparc/theme/Appearance.js
@@ -1192,8 +1192,8 @@ qx.Theme.define("osparc.theme.Appearance", {
padding: [5, 10],
// showTimeout is themeable so it can be tuned
// it was defaulted to 700 which was too short
- showTimeout: 2000,
- hideTimeout: 6000,
+ showTimeout: 1400,
+ hideTimeout: 5000,
})
},
diff --git a/services/static-webserver/client/source/class/osparc/ui/table/cellrenderer/ImageButtonRenderer.js b/services/static-webserver/client/source/class/osparc/ui/table/cellrenderer/ImageButtonRenderer.js
index 8b9fd7896bd..43cfd6b8b05 100644
--- a/services/static-webserver/client/source/class/osparc/ui/table/cellrenderer/ImageButtonRenderer.js
+++ b/services/static-webserver/client/source/class/osparc/ui/table/cellrenderer/ImageButtonRenderer.js
@@ -21,6 +21,8 @@ qx.Class.define("osparc.ui.table.cellrenderer.ImageButtonRenderer", {
construct: function(clickAction, iconPath) {
this.base(arguments, clickAction);
+ this.__imageCache = {};
+
this.setIconPath(iconPath);
},
@@ -34,11 +36,43 @@ qx.Class.define("osparc.ui.table.cellrenderer.ImageButtonRenderer", {
},
members: {
+ __imageCache: null,
+
__applyIconPath: function(iconPath) {
const resMgr = qx.util.ResourceManager.getInstance();
- const iconUrl = resMgr.toUri(iconPath); // Resolves to the correct URL of the asset
+ const iconUrl = resMgr.toUri(iconPath);
+
+ // Create a data URI or use a more cache-friendly approach
+ // Use base64 encoding for small icons (best for caching)
+ this.__loadImageAsDataUri(iconUrl, iconPath);
+ },
+
+ __loadImageAsDataUri: function(iconUrl, iconPath) {
+ if (this.__imageCache[iconPath]) {
+ this.setButtonContent(this.__imageCache[iconPath]);
+ return;
+ }
+
+ // Fetch and convert to data URI for permanent caching
+ fetch(iconUrl)
+ .then(response => response.blob())
+ .then(blob => {
+ const reader = new FileReader();
+ reader.onload = () => {
+ const dataUri = reader.result;
+ const content = `
`;
- this.setButtonContent(`
`);
+ // Cache the data URI
+ this.__imageCache[iconPath] = content;
+ this.setButtonContent(content);
+ };
+ reader.readAsDataURL(blob);
+ })
+ .catch(err => {
+ console.warn("Failed to cache icon as data URI:", iconPath, err);
+ // Fallback to original method
+ this.setButtonContent(`
`);
+ });
},
}
});