From 78ea58a1401f21fb83b9b313c49eb021ef096e48 Mon Sep 17 00:00:00 2001 From: Steve-Mcl Date: Mon, 16 Dec 2024 12:27:55 +0000 Subject: [PATCH 01/10] add KEY_DISABLE_AUTO_SAFE_MODE to project settings --- forge/db/models/Project.js | 5 +++-- forge/db/models/ProjectSettings.js | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/forge/db/models/Project.js b/forge/db/models/Project.js index c972312f41..d9b8b1013a 100644 --- a/forge/db/models/Project.js +++ b/forge/db/models/Project.js @@ -17,7 +17,7 @@ const { col, fn, DataTypes, Op, where } = require('sequelize') const Controllers = require('../controllers') -const { KEY_HOSTNAME, KEY_SETTINGS, KEY_HA, KEY_PROTECTED, KEY_HEALTH_CHECK_INTERVAL, KEY_CUSTOM_HOSTNAME } = require('./ProjectSettings') +const { KEY_HOSTNAME, KEY_SETTINGS, KEY_HA, KEY_PROTECTED, KEY_HEALTH_CHECK_INTERVAL, KEY_CUSTOM_HOSTNAME, KEY_DISABLE_AUTO_SAFE_MODE } = require('./ProjectSettings') const BANNED_NAME_LIST = [ 'app', @@ -408,7 +408,8 @@ module.exports = { { key: KEY_HA }, { key: KEY_PROTECTED }, { key: KEY_CUSTOM_HOSTNAME }, - { key: KEY_HEALTH_CHECK_INTERVAL } + { key: KEY_HEALTH_CHECK_INTERVAL }, + { key: KEY_DISABLE_AUTO_SAFE_MODE } ] }, required: false diff --git a/forge/db/models/ProjectSettings.js b/forge/db/models/ProjectSettings.js index 628574e766..4f6b50e2de 100644 --- a/forge/db/models/ProjectSettings.js +++ b/forge/db/models/ProjectSettings.js @@ -16,6 +16,7 @@ const KEY_PROTECTED = 'protected' const KEY_HEALTH_CHECK_INTERVAL = 'healthCheckInterval' const KEY_CUSTOM_HOSTNAME = 'customHostname' const KEY_SHARED_ASSETS = 'sharedAssets' +const KEY_DISABLE_AUTO_SAFE_MODE = 'disableAutoSafeMode' module.exports = { KEY_SETTINGS, @@ -25,6 +26,7 @@ module.exports = { KEY_HEALTH_CHECK_INTERVAL, KEY_CUSTOM_HOSTNAME, KEY_SHARED_ASSETS, + KEY_DISABLE_AUTO_SAFE_MODE, name: 'ProjectSettings', schema: { ProjectId: { type: DataTypes.UUID, unique: 'pk_settings' }, From 95c56b2c627482786b739cc30f0c7b14b86ca157 Mon Sep 17 00:00:00 2001 From: Steve-Mcl Date: Mon, 16 Dec 2024 12:28:30 +0000 Subject: [PATCH 02/10] Update view to permit disableAutoSafeMode to be sent to launcher --- forge/db/views/Project.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/forge/db/views/Project.js b/forge/db/views/Project.js index 3d9033c4d8..2f4c4d28d1 100644 --- a/forge/db/views/Project.js +++ b/forge/db/views/Project.js @@ -1,4 +1,4 @@ -const { KEY_HOSTNAME, KEY_SETTINGS, KEY_HA, KEY_PROTECTED, KEY_HEALTH_CHECK_INTERVAL, KEY_CUSTOM_HOSTNAME } = require('../models/ProjectSettings') +const { KEY_HOSTNAME, KEY_SETTINGS, KEY_HA, KEY_PROTECTED, KEY_HEALTH_CHECK_INTERVAL, KEY_CUSTOM_HOSTNAME, KEY_DISABLE_AUTO_SAFE_MODE } = require('../models/ProjectSettings') module.exports = function (app) { app.addSchema({ @@ -37,7 +37,8 @@ module.exports = function (app) { launcherSettings: { type: 'object', properties: { - healthCheckInterval: { type: 'number' } + healthCheckInterval: { type: 'number' }, + disableAutoSafeMode: { type: 'boolean' } }, additionalProperties: false } @@ -75,6 +76,11 @@ module.exports = function (app) { result.launcherSettings = {} result.launcherSettings.healthCheckInterval = heathCheckIntervalRow?.value } + const disableAutoSafeMode = proj.ProjectSettings?.find((projectSettingsRow) => projectSettingsRow.key === KEY_DISABLE_AUTO_SAFE_MODE) + if (typeof disableAutoSafeMode?.value === 'boolean') { + result.launcherSettings = result.launcherSettings || {} + result.launcherSettings.disableAutoSafeMode = disableAutoSafeMode.value + } // Environment result.settings.env = app.db.controllers.Project.insertPlatformSpecificEnvVars(proj, result.settings.env) if (!result.settings.palette?.modules) { From bf885d85af51a1c625ec1da84662faee5454af2b Mon Sep 17 00:00:00 2001 From: Steve-Mcl Date: Mon, 16 Dec 2024 12:28:53 +0000 Subject: [PATCH 03/10] update API to persist disableAutoSafeMode setting --- forge/routes/api/project.js | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/forge/routes/api/project.js b/forge/routes/api/project.js index 1c635e258c..46bdc75f94 100644 --- a/forge/routes/api/project.js +++ b/forge/routes/api/project.js @@ -1,4 +1,4 @@ -const { KEY_SETTINGS, KEY_HEALTH_CHECK_INTERVAL, KEY_SHARED_ASSETS } = require('../../db/models/ProjectSettings') +const { KEY_SETTINGS, KEY_HEALTH_CHECK_INTERVAL, KEY_DISABLE_AUTO_SAFE_MODE, KEY_SHARED_ASSETS } = require('../../db/models/ProjectSettings') const { Roles } = require('../../lib/roles') const ProjectActions = require('./projectActions') @@ -456,15 +456,24 @@ module.exports = async function (app) { } // Launcher settings - if (request.body?.launcherSettings?.healthCheckInterval) { - const oldInterval = await request.project.getSetting(KEY_HEALTH_CHECK_INTERVAL) - const newInterval = parseInt(request.body.launcherSettings.healthCheckInterval, 10) - if (isNaN(newInterval) || newInterval < 5000) { - reply.code(400).send({ code: 'invalid_heathCheckInterval', error: 'Invalid heath check interval' }) - return + if (request.body?.launcherSettings) { + if (request.body.launcherSettings.healthCheckInterval) { + const oldInterval = await request.project.getSetting(KEY_HEALTH_CHECK_INTERVAL) + const newInterval = parseInt(request.body.launcherSettings.healthCheckInterval, 10) + if (isNaN(newInterval) || newInterval < 5000) { + reply.code(400).send({ code: 'invalid_heathCheckInterval', error: 'Invalid heath check interval' }) + return + } + if (oldInterval !== newInterval) { + changesToPersist.healthCheckInterval = { from: oldInterval, to: newInterval } + } } - if (oldInterval !== newInterval) { - changesToPersist.healthCheckInterval = { from: oldInterval, to: newInterval } + if (typeof request.body.launcherSettings.disableAutoSafeMode === 'boolean') { + const oldInterval = await request.project.getSetting(KEY_DISABLE_AUTO_SAFE_MODE) + const newInterval = request.body.launcherSettings.disableAutoSafeMode + if (oldInterval !== newInterval) { + changesToPersist.disableAutoSafeMode = { from: oldInterval, to: newInterval } + } } } @@ -529,6 +538,10 @@ module.exports = async function (app) { await request.project.updateSetting(KEY_HEALTH_CHECK_INTERVAL, changesToPersist.healthCheckInterval.to, { transaction }) updates.pushDifferences({ healthCheckInterval: changesToPersist.healthCheckInterval.from }, { healthCheckInterval: changesToPersist.healthCheckInterval.to }) } + if (changesToPersist.disableAutoSafeMode) { + await request.project.updateSetting(KEY_DISABLE_AUTO_SAFE_MODE, changesToPersist.disableAutoSafeMode.to, { transaction }) + updates.pushDifferences({ disableAutoSafeMode: changesToPersist.disableAutoSafeMode.from }, { disableAutoSafeMode: changesToPersist.disableAutoSafeMode.to }) + } await transaction.commit() // all good, commit the transaction @@ -802,6 +815,7 @@ module.exports = async function (app) { settings.state = request.project.state settings.stack = request.project.ProjectStack?.properties || {} settings.healthCheckInterval = await request.project.getSetting(KEY_HEALTH_CHECK_INTERVAL) + settings.disableAutoSafeMode = await request.project.getSetting(KEY_DISABLE_AUTO_SAFE_MODE) settings.settings = await app.db.controllers.Project.getRuntimeSettings(request.project) if (settings.settings.env) { settings.env = Object.assign({}, settings.settings.env, settings.env) From a2ea361e986fb1af865e3835b3ef09ffab969309 Mon Sep 17 00:00:00 2001 From: Steve-Mcl Date: Mon, 16 Dec 2024 12:29:17 +0000 Subject: [PATCH 04/10] Add UI to display disableAutoSafeMode option under launcher settings --- .../instance/Settings/LauncherSettings.vue | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/frontend/src/pages/instance/Settings/LauncherSettings.vue b/frontend/src/pages/instance/Settings/LauncherSettings.vue index ba3de78328..76d5654657 100644 --- a/frontend/src/pages/instance/Settings/LauncherSettings.vue +++ b/frontend/src/pages/instance/Settings/LauncherSettings.vue @@ -8,6 +8,13 @@ Flows that perform CPU intensive work may need to increase this from the default of 7500ms. + + Disable Auto Safe Mode + +
Save settings @@ -60,7 +67,8 @@ export default { computed: { ...mapState('account', ['team', 'teamMembership']), unsavedChanges: function () { - return this.original.healthCheckInterval !== this.input.healthCheckInterval + return this.original.healthCheckInterval !== this.input.healthCheckInterval || + this.original.disableAutoSafeMode !== this.input.disableAutoSafeMode } }, watch: { @@ -69,6 +77,11 @@ export default { if (this.mounted) { this.validateFormInputs() } + }, + 'input.disableAutoSafeMode': function (value) { + if (this.mounted) { + this.validateFormInputs() + } } }, mounted () { @@ -98,10 +111,13 @@ export default { getSettings: function () { this.original.healthCheckInterval = this.project?.launcherSettings?.healthCheckInterval this.input.healthCheckInterval = this.project?.launcherSettings.healthCheckInterval + this.original.disableAutoSafeMode = this.project?.launcherSettings?.disableAutoSafeMode ?? false + this.input.disableAutoSafeMode = this.project?.launcherSettings.disableAutoSafeMode ?? false }, async saveSettings () { const launcherSettings = { - healthCheckInterval: this.input.healthCheckInterval + healthCheckInterval: this.input.healthCheckInterval, + disableAutoSafeMode: this.input.disableAutoSafeMode ?? false } if (!this.validateFormInputs()) { alerts.emit('Please correct the errors before saving.', 'error') From e049af055f0c5eb6a46bba74d0d1979b582ce496 Mon Sep 17 00:00:00 2001 From: Steve-Mcl Date: Mon, 16 Dec 2024 12:30:11 +0000 Subject: [PATCH 05/10] update unit tests to ensure disableAutoSafeMode setting is persisted --- test/unit/forge/routes/api/project_spec.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/test/unit/forge/routes/api/project_spec.js b/test/unit/forge/routes/api/project_spec.js index 3d9623c841..23bd4b1c54 100644 --- a/test/unit/forge/routes/api/project_spec.js +++ b/test/unit/forge/routes/api/project_spec.js @@ -10,7 +10,7 @@ const setup = require('../setup') const FF_UTIL = require('flowforge-test-utils') const { Roles } = FF_UTIL.require('forge/lib/roles') -const { KEY_HEALTH_CHECK_INTERVAL } = FF_UTIL.require('forge/db/models/ProjectSettings') +const { KEY_HEALTH_CHECK_INTERVAL, KEY_DISABLE_AUTO_SAFE_MODE } = FF_UTIL.require('forge/db/models/ProjectSettings') const { START_DELAY, STOP_DELAY } = FF_UTIL.require('forge/containers/stub/index.js') describe('Project API', function () { @@ -1691,7 +1691,7 @@ describe('Project API', function () { { name: 'two', value: '2' } ]) // should be unchanged }) - it('Change launcher health check interval - owner', async function () { + it('Change launcher settings - owner', async function () { // Setup some flows/credentials await addFlowsToProject(app, TestObjects.project1.id, @@ -1708,15 +1708,18 @@ describe('Project API', function () { url: `/api/v1/projects/${TestObjects.project1.id}`, payload: { launcherSettings: { - healthCheckInterval: 9876 + healthCheckInterval: 9876, + disableAutoSafeMode: true } }, cookies: { sid: TestObjects.tokens.alice } }) response.statusCode.should.equal(200) - const newValue = await TestObjects.project1.getSetting(KEY_HEALTH_CHECK_INTERVAL) - should(newValue).equal(9876) + const healthValue = await TestObjects.project1.getSetting(KEY_HEALTH_CHECK_INTERVAL) + should(healthValue).equal(9876) + const safeModeValue = await TestObjects.project1.getSetting(KEY_DISABLE_AUTO_SAFE_MODE) + should(safeModeValue).equal(true) }) it('Change launcher health check interval bad value - owner', async function () { // Setup some flows/credentials From dc5cec1372888d01efedeba59510799ea9f747ed Mon Sep 17 00:00:00 2001 From: Steve-Mcl Date: Mon, 16 Dec 2024 14:39:49 +0000 Subject: [PATCH 06/10] Add conditional rendering for disableAutoSafeMode based on launcher version support --- .../instance/Settings/LauncherSettings.vue | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/frontend/src/pages/instance/Settings/LauncherSettings.vue b/frontend/src/pages/instance/Settings/LauncherSettings.vue index 76d5654657..5fce2d4bb0 100644 --- a/frontend/src/pages/instance/Settings/LauncherSettings.vue +++ b/frontend/src/pages/instance/Settings/LauncherSettings.vue @@ -8,7 +8,7 @@ Flows that perform CPU intensive work may need to increase this from the default of 7500ms. - + Disable Auto Safe Mode