From fbca1eb7a69b5437d89ee5b79098c1476ddfa51a Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Thu, 15 May 2025 13:39:05 +0200 Subject: [PATCH 01/10] getPage -> create --- .../client/source/class/osparc/data/Resources.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/static-webserver/client/source/class/osparc/data/Resources.js b/services/static-webserver/client/source/class/osparc/data/Resources.js index eeba96b1c001..85ec289047f3 100644 --- a/services/static-webserver/client/source/class/osparc/data/Resources.js +++ b/services/static-webserver/client/source/class/osparc/data/Resources.js @@ -608,7 +608,7 @@ qx.Class.define("osparc.data.Resources", { "functions": { useCache: false, endpoints: { - getPage: { + create: { method: "POST", url: statics.API + "/functions" } From 209b266ad4034e9431a3dae8ea1b4f90f8a76628 Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Thu, 15 May 2025 13:50:07 +0200 Subject: [PATCH 02/10] getPageLatest --- .../client/source/class/osparc/data/Resources.js | 4 ++-- .../static-webserver/client/source/class/osparc/store/Jobs.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/services/static-webserver/client/source/class/osparc/data/Resources.js b/services/static-webserver/client/source/class/osparc/data/Resources.js index 85ec289047f3..554e825c65fb 100644 --- a/services/static-webserver/client/source/class/osparc/data/Resources.js +++ b/services/static-webserver/client/source/class/osparc/data/Resources.js @@ -350,7 +350,7 @@ qx.Class.define("osparc.data.Resources", { "jobsActive": { useCache: false, // handled in osparc.store.Jobs endpoints: { - getPage: { + getPageLatest: { method: "GET", url: statics.API + "/computations/-/iterations/latest?offset={offset}&limit={limit}&order_by=%7B%22field%22:%22submitted_at%22,%22direction%22:%22desc%22%7D&filter_only_running=true" }, @@ -359,7 +359,7 @@ qx.Class.define("osparc.data.Resources", { "subJobs": { useCache: false, // handled in osparc.store.Jobs endpoints: { - getPage: { + getPageLatest: { method: "GET", url: statics.API + "/computations/{studyId}/iterations/latest/tasks?offset={offset}&limit={limit}" }, diff --git a/services/static-webserver/client/source/class/osparc/store/Jobs.js b/services/static-webserver/client/source/class/osparc/store/Jobs.js index 87ea782e18a6..7d668bb378ab 100644 --- a/services/static-webserver/client/source/class/osparc/store/Jobs.js +++ b/services/static-webserver/client/source/class/osparc/store/Jobs.js @@ -56,7 +56,7 @@ qx.Class.define("osparc.store.Jobs", { const options = { resolveWResponse: true }; - return osparc.data.Resources.fetch("jobsActive", "getPage", params, options) + return osparc.data.Resources.fetch("jobsActive", "getPageLatest", params, options) .then(jobsResp => { this.fireDataEvent("changeJobsActive", jobsResp["_meta"]["total"]); const jobsActive = []; @@ -79,7 +79,7 @@ qx.Class.define("osparc.store.Jobs", { studyId: projectUuid, } }; - return osparc.data.Resources.getInstance().getAllPages("subJobs", params) + return osparc.data.Resources.getInstance().getAllPages("subJobs", params, "getPageLatest") .then(subJobsData => { const subJobs = []; subJobsData.forEach(subJobData => { From b8070fab695ad68ba725e09f5c0fdcc354376143 Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Thu, 15 May 2025 13:51:34 +0200 Subject: [PATCH 03/10] add resource --- .../client/source/class/osparc/data/Resources.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/services/static-webserver/client/source/class/osparc/data/Resources.js b/services/static-webserver/client/source/class/osparc/data/Resources.js index 554e825c65fb..c10d8001cacb 100644 --- a/services/static-webserver/client/source/class/osparc/data/Resources.js +++ b/services/static-webserver/client/source/class/osparc/data/Resources.js @@ -363,6 +363,10 @@ qx.Class.define("osparc.data.Resources", { method: "GET", url: statics.API + "/computations/{studyId}/iterations/latest/tasks?offset={offset}&limit={limit}" }, + getPageHistory: { + method: "GET", + url: statics.API + "/computations/{studyId}/iterations?offset={offset}&limit={limit}" + }, } }, "folders": { From ac05199cbc299932c587d11d5269d25790cce503 Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Thu, 15 May 2025 14:03:01 +0200 Subject: [PATCH 04/10] renaming --- .../client/source/class/osparc/data/Resources.js | 12 ++++++------ .../client/source/class/osparc/store/Jobs.js | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/services/static-webserver/client/source/class/osparc/data/Resources.js b/services/static-webserver/client/source/class/osparc/data/Resources.js index c10d8001cacb..bd8310447245 100644 --- a/services/static-webserver/client/source/class/osparc/data/Resources.js +++ b/services/static-webserver/client/source/class/osparc/data/Resources.js @@ -347,13 +347,17 @@ qx.Class.define("osparc.data.Resources", { }, } }, - "jobsActive": { + "jobs": { useCache: false, // handled in osparc.store.Jobs endpoints: { - getPageLatest: { + getPageLatestActive: { method: "GET", url: statics.API + "/computations/-/iterations/latest?offset={offset}&limit={limit}&order_by=%7B%22field%22:%22submitted_at%22,%22direction%22:%22desc%22%7D&filter_only_running=true" }, + getPageHistory: { + method: "GET", + url: statics.API + "/computations/{studyId}/iterations?offset={offset}&limit={limit}" + }, } }, "subJobs": { @@ -363,10 +367,6 @@ qx.Class.define("osparc.data.Resources", { method: "GET", url: statics.API + "/computations/{studyId}/iterations/latest/tasks?offset={offset}&limit={limit}" }, - getPageHistory: { - method: "GET", - url: statics.API + "/computations/{studyId}/iterations?offset={offset}&limit={limit}" - }, } }, "folders": { diff --git a/services/static-webserver/client/source/class/osparc/store/Jobs.js b/services/static-webserver/client/source/class/osparc/store/Jobs.js index 7d668bb378ab..13c4b96a5945 100644 --- a/services/static-webserver/client/source/class/osparc/store/Jobs.js +++ b/services/static-webserver/client/source/class/osparc/store/Jobs.js @@ -56,7 +56,7 @@ qx.Class.define("osparc.store.Jobs", { const options = { resolveWResponse: true }; - return osparc.data.Resources.fetch("jobsActive", "getPageLatest", params, options) + return osparc.data.Resources.fetch("jobs", "getPageLatestActive", params, options) .then(jobsResp => { this.fireDataEvent("changeJobsActive", jobsResp["_meta"]["total"]); const jobsActive = []; From 90c7268b76debad032b609bbf6b048431dcaa12e Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Thu, 15 May 2025 14:06:45 +0200 Subject: [PATCH 05/10] RunTable with two arguments --- .../client/source/class/osparc/jobs/ActivityOverview.js | 5 +++++ .../client/source/class/osparc/jobs/RunsBrowser.js | 7 +++++-- .../client/source/class/osparc/jobs/RunsTable.js | 4 ++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/services/static-webserver/client/source/class/osparc/jobs/ActivityOverview.js b/services/static-webserver/client/source/class/osparc/jobs/ActivityOverview.js index 0f985f4e03da..8f5ed3c9246d 100644 --- a/services/static-webserver/client/source/class/osparc/jobs/ActivityOverview.js +++ b/services/static-webserver/client/source/class/osparc/jobs/ActivityOverview.js @@ -36,6 +36,11 @@ qx.Class.define("osparc.jobs.ActivityOverview", { members: { __buildLayout: function(projectData) { + const latestOnly = false; + const projectUuid = projectData["uuid"]; + const runsTable = new osparc.jobs.RunsTable(latestOnly, projectUuid); + this._add(runsTable); + const subRunsTable = new osparc.jobs.SubRunsTable(projectData["uuid"]); this._add(subRunsTable); }, 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 ff9e5414b840..4ce0a15ae602 100644 --- a/services/static-webserver/client/source/class/osparc/jobs/RunsBrowser.js +++ b/services/static-webserver/client/source/class/osparc/jobs/RunsBrowser.js @@ -60,11 +60,14 @@ qx.Class.define("osparc.jobs.RunsBrowser", { flex: 1 }); break; - case "runs-table": - control = new osparc.jobs.RunsTable(); + case "runs-table": { + const latestOnly = true; + const projectUuid = null; + control = new osparc.jobs.RunsTable(latestOnly, projectUuid); control.addListener("runSelected", e => this.fireDataEvent("runSelected", e.getData())); this._add(control); break; + } } return control || this.base(arguments, id); diff --git a/services/static-webserver/client/source/class/osparc/jobs/RunsTable.js b/services/static-webserver/client/source/class/osparc/jobs/RunsTable.js index 81244349a299..f5a116e7b74f 100644 --- a/services/static-webserver/client/source/class/osparc/jobs/RunsTable.js +++ b/services/static-webserver/client/source/class/osparc/jobs/RunsTable.js @@ -19,10 +19,10 @@ qx.Class.define("osparc.jobs.RunsTable", { extend: qx.ui.table.Table, - construct: function(filters) { + construct: function(latestOnly = true, projectUuid = null) { this.base(arguments); - const model = new osparc.jobs.RunsTableModel(filters); + const model = new osparc.jobs.RunsTableModel(); this.setTableModel(model); this.set({ From 2d15bb8be44e3c4d8c8c9659267863f18a066926 Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Thu, 15 May 2025 14:23:05 +0200 Subject: [PATCH 06/10] Activity Overview with two tables --- .../source/class/osparc/data/Resources.js | 2 +- .../class/osparc/jobs/ActivityOverview.js | 27 ++++++++++++- .../source/class/osparc/jobs/RunsTable.js | 2 +- .../class/osparc/jobs/RunsTableModel.js | 21 ++++++++-- .../client/source/class/osparc/store/Jobs.js | 38 +++++++++++++++++++ 5 files changed, 83 insertions(+), 7 deletions(-) diff --git a/services/static-webserver/client/source/class/osparc/data/Resources.js b/services/static-webserver/client/source/class/osparc/data/Resources.js index bd8310447245..b1acdedc8b7e 100644 --- a/services/static-webserver/client/source/class/osparc/data/Resources.js +++ b/services/static-webserver/client/source/class/osparc/data/Resources.js @@ -356,7 +356,7 @@ qx.Class.define("osparc.data.Resources", { }, getPageHistory: { method: "GET", - url: statics.API + "/computations/{studyId}/iterations?offset={offset}&limit={limit}" + url: statics.API + "/computations/{studyId}/iterations?offset={offset}&limit={limit}&order_by=%7B%22field%22:%22submitted_at%22,%22direction%22:%22desc%22%7D" }, } }, diff --git a/services/static-webserver/client/source/class/osparc/jobs/ActivityOverview.js b/services/static-webserver/client/source/class/osparc/jobs/ActivityOverview.js index 8f5ed3c9246d..951845c29c8c 100644 --- a/services/static-webserver/client/source/class/osparc/jobs/ActivityOverview.js +++ b/services/static-webserver/client/source/class/osparc/jobs/ActivityOverview.js @@ -21,7 +21,7 @@ qx.Class.define("osparc.jobs.ActivityOverview", { construct: function(projectData) { this.base(arguments); - this._setLayout(new qx.ui.layout.VBox(15)); + this._setLayout(new qx.ui.layout.VBox(10)); this.__buildLayout(projectData); }, @@ -30,18 +30,41 @@ qx.Class.define("osparc.jobs.ActivityOverview", { popUpInWindow: function(projectData) { const activityOverview = new osparc.jobs.ActivityOverview(projectData); const title = qx.locale.Manager.tr("Activity Overview"); - return osparc.ui.window.Window.popUpInWindow(activityOverview, title, osparc.jobs.ActivityCenterWindow.WIDTH, osparc.jobs.ActivityCenterWindow.HEIGHT); + const win = osparc.ui.window.Window.popUpInWindow(activityOverview, title, osparc.jobs.ActivityCenterWindow.WIDTH, osparc.jobs.ActivityCenterWindow.HEIGHT); + win.set({ + maxHeight: 700, + }); + return win; }, }, members: { __buildLayout: function(projectData) { + this._add(new qx.ui.basic.Label(this.tr("Runs History")).set({ + font: "text-14" + })); + const latestOnly = false; const projectUuid = projectData["uuid"]; const runsTable = new osparc.jobs.RunsTable(latestOnly, projectUuid); + const columnModel = runsTable.getTableColumnModel(); + // Hide project name column + columnModel.setColumnVisible(osparc.jobs.RunsTable.COLS.PROJECT_NAME.column, false); + // Hide cancel column + columnModel.setColumnVisible(osparc.jobs.RunsTable.COLS.ACTION_CANCEL.column, false); + runsTable.set({ + maxHeight: 250, + }) this._add(runsTable); + this._add(new qx.ui.basic.Label(this.tr("Latest Tasks")).set({ + font: "text-14" + })); + const subRunsTable = new osparc.jobs.SubRunsTable(projectData["uuid"]); + subRunsTable.set({ + maxHeight: 250, + }) this._add(subRunsTable); }, } diff --git a/services/static-webserver/client/source/class/osparc/jobs/RunsTable.js b/services/static-webserver/client/source/class/osparc/jobs/RunsTable.js index f5a116e7b74f..393be95f1099 100644 --- a/services/static-webserver/client/source/class/osparc/jobs/RunsTable.js +++ b/services/static-webserver/client/source/class/osparc/jobs/RunsTable.js @@ -22,7 +22,7 @@ qx.Class.define("osparc.jobs.RunsTable", { construct: function(latestOnly = true, projectUuid = null) { this.base(arguments); - const model = new osparc.jobs.RunsTableModel(); + const model = new osparc.jobs.RunsTableModel(latestOnly, projectUuid); this.setTableModel(model); this.set({ 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 da829b670989..e1235fe7481f 100644 --- a/services/static-webserver/client/source/class/osparc/jobs/RunsTableModel.js +++ b/services/static-webserver/client/source/class/osparc/jobs/RunsTableModel.js @@ -19,9 +19,12 @@ qx.Class.define("osparc.jobs.RunsTableModel", { extend: qx.ui.table.model.Remote, - construct: function() { + construct: function(latestOnly = true, projectUuid = null) { this.base(arguments); + this.__latestOnly = latestOnly; + this.__projectUuid = projectUuid; + const jobsCols = osparc.jobs.RunsTable.COLS; const colLabels = Object.values(jobsCols).map(col => col.label); const colIDs = Object.values(jobsCols).map(col => col.id); @@ -60,7 +63,13 @@ qx.Class.define("osparc.jobs.RunsTableModel", { const offset = 0; const limit = 1; const resolveWResponse = true; - osparc.store.Jobs.getInstance().fetchJobsActive(offset, limit, JSON.stringify(this.getOrderBy()), resolveWResponse) + let promise; + if (this.__latestOnly && this.__projectUuid === null) { + promise = osparc.store.Jobs.getInstance().fetchJobsActive(offset, limit, JSON.stringify(this.getOrderBy()), resolveWResponse); + } else { + promise = osparc.store.Jobs.getInstance().fetchJobsHistory(this.__projectUuid, offset, limit, JSON.stringify(this.getOrderBy()), resolveWResponse); + } + promise .then(resp => { this._onRowCountLoaded(resp["_meta"].total) }) @@ -76,7 +85,13 @@ 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) => { - return osparc.store.Jobs.getInstance().fetchJobsActive(offset, limit, JSON.stringify(this.getOrderBy())) + let promise; + if (this.__latestOnly && this.__projectUuid === null) { + promise = osparc.store.Jobs.getInstance().fetchJobsActive(offset, limit, JSON.stringify(this.getOrderBy())); + } else { + promise = osparc.store.Jobs.getInstance().fetchJobsHistory(this.__projectUuid, offset, limit, JSON.stringify(this.getOrderBy())); + } + promise .then(jobs => { const data = []; const jobsCols = osparc.jobs.RunsTable.COLS; diff --git a/services/static-webserver/client/source/class/osparc/store/Jobs.js b/services/static-webserver/client/source/class/osparc/store/Jobs.js index 13c4b96a5945..197b1ff0637c 100644 --- a/services/static-webserver/client/source/class/osparc/store/Jobs.js +++ b/services/static-webserver/client/source/class/osparc/store/Jobs.js @@ -73,6 +73,44 @@ qx.Class.define("osparc.store.Jobs", { .catch(err => console.error(err)); }, + fetchJobsHistory: function( + studyId, + offset = 0, + limit = this.self().SERVER_MAX_LIMIT, + orderBy = { + field: "submitted_at", + direction: "desc" + }, + resolveWResponse = false + ) { + const params = { + url: { + studyId, + offset, + limit, + orderBy: JSON.stringify(orderBy), + } + }; + const options = { + resolveWResponse: true + }; + return osparc.data.Resources.fetch("jobs", "getPageHistory", params, options) + .then(jobsResp => { + if (resolveWResponse) { + return jobsResp; + } + const jobs = []; + if ("data" in jobsResp) { + jobsResp["data"].forEach(jobData => { + const job = new osparc.data.Job(jobData); + jobs.push(job); + }); + } + return jobs; + }) + .catch(err => console.error(err)); + }, + fetchSubJobs: function(projectUuid) { const params = { url: { From de1b7ffbe022b50b3b6039176c8619fe05c9e013 Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Thu, 15 May 2025 14:30:55 +0200 Subject: [PATCH 07/10] working --- .../client/source/class/osparc/jobs/RunsTableModel.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 e1235fe7481f..4dd2e241d707 100644 --- a/services/static-webserver/client/source/class/osparc/jobs/RunsTableModel.js +++ b/services/static-webserver/client/source/class/osparc/jobs/RunsTableModel.js @@ -91,7 +91,7 @@ qx.Class.define("osparc.jobs.RunsTableModel", { } else { promise = osparc.store.Jobs.getInstance().fetchJobsHistory(this.__projectUuid, offset, limit, JSON.stringify(this.getOrderBy())); } - promise + return promise .then(jobs => { const data = []; const jobsCols = osparc.jobs.RunsTable.COLS; From d16b1f0bbcbf81e9955ea9633d0f7aa4ee45703a Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Thu, 15 May 2025 14:42:58 +0200 Subject: [PATCH 08/10] minor --- .../source/class/osparc/dashboard/ResourceDetails.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/services/static-webserver/client/source/class/osparc/dashboard/ResourceDetails.js b/services/static-webserver/client/source/class/osparc/dashboard/ResourceDetails.js index 8fbf22b7c31f..bd6580564902 100644 --- a/services/static-webserver/client/source/class/osparc/dashboard/ResourceDetails.js +++ b/services/static-webserver/client/source/class/osparc/dashboard/ResourceDetails.js @@ -44,7 +44,12 @@ qx.Class.define("osparc.dashboard.ResourceDetails", { latestPromise .then(latestResourceData => { - this.__resourceData = latestResourceData; + if (!latestResourceData) { + const msg = this.tr("Data not found, please try again"); + osparc.FlashMessenger.logAs(msg, "WARNING"); + return; + } + this.__resourceData = osparc.utils.Utils.deepCloneObject(latestResourceData); this.__resourceData["resourceType"] = resourceData["resourceType"]; switch (resourceData["resourceType"]) { case "study": From 5ebd776626d313e42fec358f992368a33dedec3c Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Thu, 15 May 2025 15:21:59 +0200 Subject: [PATCH 09/10] minor --- .../client/source/class/osparc/store/Services.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/services/static-webserver/client/source/class/osparc/store/Services.js b/services/static-webserver/client/source/class/osparc/store/Services.js index 47983eba6e4f..55023106af82 100644 --- a/services/static-webserver/client/source/class/osparc/store/Services.js +++ b/services/static-webserver/client/source/class/osparc/store/Services.js @@ -133,15 +133,16 @@ qx.Class.define("osparc.store.Services", { this.__addServiceToCache(service); // Resolve the promise locally before deleting it resolve(service); - // Remove the promise from the cache - delete this.__servicesPromisesCached[key][version]; }) .catch(err => { - // store it in cache to avoid asking again + // Store null in cache to avoid repeated failed requests this.__addToCache(key, version, null); - delete this.__servicesPromisesCached[key][version]; console.error(err); reject(err); + }) + .finally(() => { + // Remove the promise from the cache + delete this.__servicesPromisesCached[key][version]; }); }); }, From 7c48b1a7aa3bf3b86e3d48678f719a2f9333f603 Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Thu, 15 May 2025 15:28:31 +0200 Subject: [PATCH 10/10] better practice --- .../client/source/class/osparc/store/Services.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/services/static-webserver/client/source/class/osparc/store/Services.js b/services/static-webserver/client/source/class/osparc/store/Services.js index 55023106af82..eac4a2ba3384 100644 --- a/services/static-webserver/client/source/class/osparc/store/Services.js +++ b/services/static-webserver/client/source/class/osparc/store/Services.js @@ -106,7 +106,8 @@ qx.Class.define("osparc.store.Services", { return this.__servicesPromisesCached[key][version]; } - return new Promise((resolve, reject) => { + // Create a new promise + const promise = new Promise((resolve, reject) => { if ( useCache && this.__isInCache(key, version) && @@ -145,6 +146,14 @@ qx.Class.define("osparc.store.Services", { delete this.__servicesPromisesCached[key][version]; }); }); + + // Store the promise in the cache + // The point of keeping this assignment outside of the main Promise block is to + // ensure that the promise is immediately stored in the cache before any asynchronous + // operations (like fetch) are executed. This prevents duplicate requests for the + // same key and version when multiple consumers call getService concurrently. + this.__servicesPromisesCached[key][version] = promise; + return promise; }, getStudyServices: function(studyId) {