This is an automated email from the ASF dual-hosted git repository.
lizhimins pushed a commit to branch rocketmq-studio
in repository https://gitbox.apache.org/repos/asf/rocketmq-dashboard.git
The following commit(s) were added to refs/heads/rocketmq-studio by this push:
new 77f5c126e fix(settings): save data sources without query credentials
(#2657)
77f5c126e is described below
commit 77f5c126e65e8c66e7be8f66d41df0adaba71f10
Author: btlqql <[email protected]>
AuthorDate: Wed Sep 2 17:07:54 2026 +0800
fix(settings): save data sources without query credentials (#2657)
---
web/src/pages/settings/DataSourceTab.tsx | 12 ++++++++-
.../settings/__tests__/DataSourceTab.test.tsx | 31 ++++++++++++++++++++++
2 files changed, 42 insertions(+), 1 deletion(-)
diff --git a/web/src/pages/settings/DataSourceTab.tsx
b/web/src/pages/settings/DataSourceTab.tsx
index df7140bca..81fa9087d 100644
--- a/web/src/pages/settings/DataSourceTab.tsx
+++ b/web/src/pages/settings/DataSourceTab.tsx
@@ -99,6 +99,14 @@ const testFieldNames = (auth?: string) => {
return ['type', 'url', 'auth'];
};
+const saveFieldNames: (keyof DataSourceFormValues)[] = [
+ 'name',
+ 'type',
+ 'url',
+ 'auth',
+ 'instanceIds',
+];
+
const withoutSecrets = (values: DataSourceFormValues): Partial<DataSource> => {
const sanitized = { ...values };
secretFieldNames.forEach((field) => {
@@ -233,7 +241,9 @@ export const DataSourceTab = () => {
const handleSubmit = async () => {
try {
- const values = await dsForm.validateFields();
+ // Credentials are supplied per metrics query and are only used here by
the
+ // connection test. Saving metadata must not require re-entering them.
+ const values = await dsForm.validateFields(saveFieldNames);
const dataSourceValues = withoutSecrets(values);
setSubmitting(true);
const saved = editingDataSource
diff --git a/web/src/pages/settings/__tests__/DataSourceTab.test.tsx
b/web/src/pages/settings/__tests__/DataSourceTab.test.tsx
index ca3f1a5a8..68ba44bd0 100644
--- a/web/src/pages/settings/__tests__/DataSourceTab.test.tsx
+++ b/web/src/pages/settings/__tests__/DataSourceTab.test.tsx
@@ -25,6 +25,7 @@ import {
listAllDataSources,
listDataSourcesPage,
testDataSource,
+ updateDataSource,
} from '../../../api/settings';
import { LangProvider } from '../../../i18n/LangContext';
import { LANGUAGE_STORAGE_KEY } from '../../../i18n/languagePreference';
@@ -346,6 +347,36 @@ describe('DataSourceTab', () => {
});
});
+ it('updates authenticated data source metadata without requiring query
credentials', async () => {
+ localStorage.setItem(LANGUAGE_STORAGE_KEY, 'en');
+ vi.mocked(updateDataSource).mockResolvedValue({
+ ...sources[1],
+ name: 'Thanos primary',
+ });
+ const user = userEvent.setup({ pointerEventsCheck: 0 });
+ render(
+ <App>
+ <DataSourceTab />
+ </App>,
+ );
+ await screen.findByText('Thanos DR');
+
+ const editButtons = screen.getAllByRole('button', { name: /edit/i });
+ await user.click(editButtons[1]);
+ const dialog = await screen.findByRole('dialog');
+ const nameInput = within(dialog).getByDisplayValue('Thanos DR');
+ await user.clear(nameInput);
+ await user.type(nameInput, 'Thanos primary');
+ await user.click(within(dialog).getByRole('button', { name: 'OK' }));
+
+ await waitFor(() =>
+ expect(updateDataSource).toHaveBeenCalledWith({
+ ...sources[1],
+ name: 'Thanos primary',
+ }),
+ );
+ });
+
it('creates and tests a Grafana Mimir data source', async () => {
vi.mocked(testDataSource).mockResolvedValue({ success: true, message: 'ok'
});
vi.mocked(createDataSource).mockResolvedValue({