diff --git a/services/static-webserver/client/source/class/osparc/Preferences.js b/services/static-webserver/client/source/class/osparc/Preferences.js index 8961120e2c2..6e12c18b23a 100644 --- a/services/static-webserver/client/source/class/osparc/Preferences.js +++ b/services/static-webserver/client/source/class/osparc/Preferences.js @@ -98,6 +98,22 @@ qx.Class.define("osparc.Preferences", { init: "always", event: "changeWalletIndicatorVisibility", apply: "__patchPreference" + }, + + userInactivityThreshold: { + check: "Number", + nullable: false, + init: 1800, + event: "changeUserInactivityThreshold", + apply: "__patchPreference" + }, + + jobConcurrencyLimit: { + check: "Number", + nullable: false, + init: 4, + event: "changeJobConcurrencyLimit", + apply: "__patchPreference" } }, diff --git a/services/static-webserver/client/source/class/osparc/desktop/preferences/pages/GeneralPage.js b/services/static-webserver/client/source/class/osparc/desktop/preferences/pages/GeneralPage.js index d4bc5361898..d04843fe1f0 100644 --- a/services/static-webserver/client/source/class/osparc/desktop/preferences/pages/GeneralPage.js +++ b/services/static-webserver/client/source/class/osparc/desktop/preferences/pages/GeneralPage.js @@ -26,6 +26,9 @@ qx.Class.define("osparc.desktop.preferences.pages.GeneralPage", { const walletIndicatorSettings = this.__createCreditsIndicatorSettings(); this.add(walletIndicatorSettings); + + this.add(this.__createInactivitySetting()); + this.add(this.__createJobConcurrencySetting()); }, statics: { @@ -100,6 +103,45 @@ qx.Class.define("osparc.desktop.preferences.pages.GeneralPage", { box.add(new qx.ui.form.renderer.Single(form)); + return box; + }, + __createInactivitySetting: function() { + const box = this._createSectionBox(this.tr("Inactivity shutdown")); + const label = this._createHelpLabel(this.tr("Choose after how long should inactive studies be closed. A value of zero disables this function.")); + box.add(label); + const form = new qx.ui.form.Form(); + const inactivitySpinner = new qx.ui.form.Spinner().set({ + minimum: 0, + maximum: Number.MAX_SAFE_INTEGER, + singleStep: 1, + allowGrowX: false + }); + const preferences = osparc.Preferences.getInstance(); + preferences.bind("userInactivityThreshold", inactivitySpinner, "value", { + converter: value => Math.round(value / 60) // Stored in seconds, displayed in minutes + }); + inactivitySpinner.addListener("changeValue", e => this.self().patchPreference("userInactivityThreshold", inactivitySpinner, e.getData() * 60)); + form.add(inactivitySpinner, this.tr("Idle time before closing (in minutes)")); + box.add(new qx.ui.form.renderer.Single(form)); + return box; + }, + __createJobConcurrencySetting: function() { + const box = this._createSectionBox(this.tr("Job concurrency")); + const label = this._createHelpLabel(this.tr("Choose how many jobs can run at the same time.")); + box.add(label); + const form = new qx.ui.form.Form(); + const jobConcurrencySpinner = new qx.ui.form.Spinner().set({ + minimum: 1, + maximum: 10, + singleStep: 1, + allowGrowX: false, + enabled: false + }); + const preferences = osparc.Preferences.getInstance(); + preferences.bind("jobConcurrencyLimit", jobConcurrencySpinner, "value"); + jobConcurrencySpinner.addListener("changeValue", e => this.self().patchPreference("jobConcurrencyLimit", jobConcurrencySpinner, e.getData())); + form.add(jobConcurrencySpinner, this.tr("Maximum concurrent jobs")); + box.add(new qx.ui.form.renderer.Single(form)); return box; } } diff --git a/services/web/server/src/simcore_service_webserver/users/_preferences_models.py b/services/web/server/src/simcore_service_webserver/users/_preferences_models.py index 13b1c3ed2c6..06bf7a9fa91 100644 --- a/services/web/server/src/simcore_service_webserver/users/_preferences_models.py +++ b/services/web/server/src/simcore_service_webserver/users/_preferences_models.py @@ -79,6 +79,10 @@ class UserInactivityThresholdFrontendUserPreference(FrontendUserPreference): preference_identifier = "userInactivityThreshold" value: int | None = 30 * _MINUTE # in seconds +class JobConcurrencyLimitFrontendUserPreference(FrontendUserPreference): + preference_identifier = "jobConcurrencyLimit" + value: int | None = 1 + ALL_FRONTEND_PREFERENCES: list[type[FrontendUserPreference]] = [ ConfirmationBackToDashboardFrontendUserPreference, @@ -95,6 +99,7 @@ class UserInactivityThresholdFrontendUserPreference(FrontendUserPreference): CreditsWarningThresholdFrontendUserPreference, WalletIndicatorVisibilityFrontendUserPreference, UserInactivityThresholdFrontendUserPreference, + JobConcurrencyLimitFrontendUserPreference, ]