@@ -131,14 +137,14 @@ export default class CloudConfigSettings extends DashboardView {
label={
}
input={
From 0d284a796831cf446ba58e96b83a722f21e3e903 Mon Sep 17 00:00:00 2001
From: Manuel Trezza <5673677+mtrezza@users.noreply.github.com>
Date: Wed, 4 Feb 2026 14:30:33 +0000
Subject: [PATCH 4/7] migrate
---
src/dashboard/Data/Config/Config.react.js | 110 +++++++++++++-----
.../Data/Config/ConfigDialog.react.js | 6 +-
.../Settings/CloudConfigSettings.react.js | 49 +++++---
.../DashboardSettings.react.js | 41 ++++++-
4 files changed, 152 insertions(+), 54 deletions(-)
diff --git a/src/dashboard/Data/Config/Config.react.js b/src/dashboard/Data/Config/Config.react.js
index 56d02c02ea..75b34a3fe8 100644
--- a/src/dashboard/Data/Config/Config.react.js
+++ b/src/dashboard/Data/Config/Config.react.js
@@ -28,6 +28,7 @@ import Modal from 'components/Modal/Modal.react';
import equal from 'fast-deep-equal';
import Notification from 'dashboard/Data/Browser/Notification.react';
import ServerConfigStorage from 'lib/ServerConfigStorage';
+import { prefersServerStorage } from 'lib/StoragePreferences';
@subscribeTo('Config', 'config')
class Config extends TableView {
@@ -55,8 +56,10 @@ class Config extends TableView {
removeEntryParam: '',
removeEntryArrayValue: [],
serverHistoryLimit: undefined,
+ currentParamHistory: null,
};
this.noteTimeout = null;
+ this.serverStorage = null;
}
componentWillMount() {
@@ -86,46 +89,80 @@ class Config extends TableView {
async loadCloudConfigSettings() {
try {
- const serverStorage = new ServerConfigStorage(this.context);
- if (!serverStorage.isServerConfigEnabled()) {
+ this.serverStorage = new ServerConfigStorage(this.context);
+ if (!this.serverStorage.isServerConfigEnabled()) {
return;
}
- const settings = await serverStorage.getConfig(
+ const settings = await this.serverStorage.getConfig(
'config.settings',
this.context.applicationId
);
- if (settings && settings.historyLimit !== undefined) {
- this.setState({ serverHistoryLimit: settings.historyLimit });
+ if (settings) {
+ if (settings.historyLimit !== undefined) {
+ this.setState({ serverHistoryLimit: settings.historyLimit });
+ }
}
} catch {
// Fall back to existing context value
}
}
- addToConfigHistory(name, value) {
+ async addToConfigHistory(name, value) {
const limit = this.context.cloudConfigHistoryLimit ?? this.state.serverHistoryLimit;
- const applicationId = this.context.applicationId;
- const configHistory = localStorage.getItem(`${applicationId}_configHistory`);
const newHistoryEntry = { time: new Date(), value };
+ const applicationId = this.context.applicationId;
- if (!configHistory) {
- localStorage.setItem(
- `${applicationId}_configHistory`,
- JSON.stringify({ [name]: [newHistoryEntry] })
- );
+ if (prefersServerStorage(applicationId) && this.serverStorage) {
+ try {
+ const key = `config.history.parameters.${name}`;
+ const existing = await this.serverStorage.getConfig(key, applicationId);
+ const values = existing?.values || [];
+ const history = [newHistoryEntry, ...values].slice(0, limit || 100);
+ await this.serverStorage.setConfig(key, { values: history }, applicationId);
+ } catch {
+ // Fall back silently
+ }
} else {
- const oldConfigHistory = JSON.parse(configHistory);
- const updatedHistory = !oldConfigHistory[name]
- ? [newHistoryEntry]
- : [newHistoryEntry, ...oldConfigHistory[name]].slice(0, limit || 100);
-
- localStorage.setItem(
- `${applicationId}_configHistory`,
- JSON.stringify({ ...oldConfigHistory, [name]: updatedHistory })
- );
+ const configHistory = localStorage.getItem(`${applicationId}_configHistory`);
+ if (!configHistory) {
+ localStorage.setItem(
+ `${applicationId}_configHistory`,
+ JSON.stringify({ [name]: [newHistoryEntry] })
+ );
+ } else {
+ const oldConfigHistory = JSON.parse(configHistory);
+ const updatedHistory = !oldConfigHistory[name]
+ ? [newHistoryEntry]
+ : [newHistoryEntry, ...oldConfigHistory[name]].slice(0, limit || 100);
+
+ localStorage.setItem(
+ `${applicationId}_configHistory`,
+ JSON.stringify({ ...oldConfigHistory, [name]: updatedHistory })
+ );
+ }
}
}
+ async loadConfigHistory(name) {
+ const applicationId = this.context.applicationId;
+
+ if (prefersServerStorage(applicationId) && this.serverStorage) {
+ try {
+ const key = `config.history.parameters.${name}`;
+ const result = await this.serverStorage.getConfig(key, applicationId);
+ return result?.values || [];
+ } catch {
+ return [];
+ }
+ }
+
+ const raw = localStorage.getItem(`${applicationId}_configHistory`);
+ if (!raw) {
+ return [];
+ }
+ return JSON.parse(raw)[name] || [];
+ }
+
renderToolbar() {
return (
@@ -155,6 +192,7 @@ class Config extends TableView {
masterKeyOnly={this.state.modalMasterKeyOnly}
parseServerVersion={this.context.serverInfo?.parseServerVersion}
loading={this.state.loading}
+ configHistory={this.state.currentParamHistory}
/>
);
} else if (this.state.showDeleteParameterDialog) {
@@ -296,10 +334,14 @@ class Config extends TableView {
modalType: type,
modalValue: modalValue,
modalMasterKeyOnly: data.masterKeyOnly,
+ currentParamHistory: null,
});
- // Fetch config data
- await this.loadData();
+ // Fetch config data and history in parallel
+ const [, history] = await Promise.all([
+ this.loadData(),
+ this.loadConfigHistory(data.param),
+ ]);
// Get latest param values
const fetchedParams = this.props.config.data.get('params');
@@ -314,6 +356,7 @@ class Config extends TableView {
this.setState({
modalValue: fetchedModalValue,
modalMasterKeyOnly: fetchedMasterKeyOnly,
+ currentParamHistory: history,
loading: false,
});
};
@@ -504,14 +547,26 @@ class Config extends TableView {
this.props.config.dispatch(ActionTypes.DELETE, { param: name }).then(() => {
this.setState({ showDeleteParameterDialog: false });
});
+
+ // Delete history from server
+ if (prefersServerStorage(this.context.applicationId) && this.serverStorage) {
+ this.serverStorage.deleteConfig(
+ `config.history.parameters.${name}`,
+ this.context.applicationId
+ ).catch(() => {});
+ }
+
+ // Delete history from localStorage
+ const applicationId = this.context.applicationId;
const configHistory =
- localStorage.getItem('configHistory') && JSON.parse(localStorage.getItem('configHistory'));
+ localStorage.getItem(`${applicationId}_configHistory`) &&
+ JSON.parse(localStorage.getItem(`${applicationId}_configHistory`));
if (configHistory) {
delete configHistory[name];
if (Object.keys(configHistory).length === 0) {
- localStorage.removeItem('configHistory');
+ localStorage.removeItem(`${applicationId}_configHistory`);
} else {
- localStorage.setItem('configHistory', JSON.stringify(configHistory));
+ localStorage.setItem(`${applicationId}_configHistory`, JSON.stringify(configHistory));
}
}
}
@@ -523,6 +578,7 @@ class Config extends TableView {
modalType: 'String',
modalValue: '',
modalMasterKeyOnly: false,
+ currentParamHistory: null,
});
}
diff --git a/src/dashboard/Data/Config/ConfigDialog.react.js b/src/dashboard/Data/Config/ConfigDialog.react.js
index 0eecb3dc22..92b7be729f 100644
--- a/src/dashboard/Data/Config/ConfigDialog.react.js
+++ b/src/dashboard/Data/Config/ConfigDialog.react.js
@@ -214,11 +214,7 @@ export default class ConfigDialog extends React.Component {
))}
);
- const configHistory =
- localStorage.getItem(`${this.context.applicationId}_configHistory`) &&
- JSON.parse(localStorage.getItem(`${this.context.applicationId}_configHistory`))[
- this.state.name
- ];
+ const configHistory = this.props.configHistory;
const handleIndexChange = index => {
if (this.state.type === 'Date') {
return;
diff --git a/src/dashboard/Settings/CloudConfigSettings.react.js b/src/dashboard/Settings/CloudConfigSettings.react.js
index 83d8dcb522..fd3b34f4f8 100644
--- a/src/dashboard/Settings/CloudConfigSettings.react.js
+++ b/src/dashboard/Settings/CloudConfigSettings.react.js
@@ -42,8 +42,10 @@ export default class CloudConfigSettings extends DashboardView {
CONFIG_KEY,
this.context.applicationId
);
- if (settings && settings.historyLimit !== undefined) {
- this.setState({ cloudConfigHistoryLimit: String(settings.historyLimit) });
+ if (settings) {
+ if (settings.historyLimit !== undefined) {
+ this.setState({ cloudConfigHistoryLimit: String(settings.historyLimit) });
+ }
}
} catch (error) {
this.showNote('Failed to load Cloud Config settings.', true);
@@ -52,6 +54,24 @@ export default class CloudConfigSettings extends DashboardView {
}
}
+ async saveSettings(updates) {
+ try {
+ const current = await this.serverStorage.getConfig(
+ CONFIG_KEY,
+ this.context.applicationId
+ );
+ const settings = { ...(current || {}), ...updates };
+ await this.serverStorage.setConfig(
+ CONFIG_KEY,
+ settings,
+ this.context.applicationId
+ );
+ return true;
+ } catch {
+ return false;
+ }
+ }
+
handleCloudConfigHistoryLimitChange(value) {
this.setState({ cloudConfigHistoryLimit: value });
}
@@ -60,13 +80,9 @@ export default class CloudConfigSettings extends DashboardView {
const value = this.state.cloudConfigHistoryLimit.trim();
if (value === '') {
- try {
- await this.serverStorage.deleteConfig(
- CONFIG_KEY,
- this.context.applicationId
- );
+ if (await this.saveSettings({ historyLimit: undefined })) {
this.showNote('Cloud Config history limit reset to default.');
- } catch {
+ } else {
this.showNote('Failed to reset setting.', true);
}
return;
@@ -78,15 +94,10 @@ export default class CloudConfigSettings extends DashboardView {
return;
}
- try {
- await this.serverStorage.setConfig(
- CONFIG_KEY,
- { historyLimit: parsed },
- this.context.applicationId
- );
+ if (await this.saveSettings({ historyLimit: parsed })) {
this.setState({ cloudConfigHistoryLimit: String(parsed) });
this.showNote(`Cloud Config history limit set to ${parsed}.`);
- } catch {
+ } else {
this.showNote('Failed to save setting.', true);
}
}
@@ -115,9 +126,9 @@ export default class CloudConfigSettings extends DashboardView {
const configFileLimit = this.context.cloudConfigHistoryLimit;
const isOverriddenByConfigFile = configFileLimit !== undefined && configFileLimit !== null;
- let description = 'Maximum number of history entries stored per Cloud Config parameter. Leave empty to use the default (100).';
+ let limitDescription = 'Maximum number of history entries stored per Cloud Config parameter. Leave empty to use the default (100).';
if (isOverriddenByConfigFile) {
- description = `This value is overridden by the dashboard config file (${configFileLimit}). Remove the "cloudConfigHistoryLimit" option from the config file to use this setting.`;
+ limitDescription = `This value is overridden by the dashboard config file (${configFileLimit}). Remove the "cloudConfigHistoryLimit" option from the config file to use this setting.`;
}
return (
@@ -130,14 +141,14 @@ export default class CloudConfigSettings extends DashboardView {