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 d388bc43d fix(metrics): keep the current data source when cancelling
the auth dialog (#4643)
d388bc43d is described below
commit d388bc43dac1048a1f98f3097d4c777d07dfaeca
Author: Apulupie <[email protected]>
AuthorDate: Mon Sep 21 21:08:25 2026 +0800
fix(metrics): keep the current data source when cancelling the auth dialog
(#4643)
`restoreProtectedDataSource` in `MetricsExplorer.tsx` applied the
data-source switch before the credential dialog was even shown: it nulled
`dataSourceCredentialsRef.current` and pointed both `dataSourceKeyRef.current`
— the field queries actually read — and the `dataSourceKey` state at the
protected source. `handleAuthCancel` only clears the pending-auth refs and the
form, so cancelling left the explorer on a data source it has no credentials
for and every later query went to an unau [...]
Those three eager writes are gone; the function now only records
`pendingAuthReplayRef` and `setPendingDataSource`, and `handleAuthSubmit`
performs the switch through `activateDataSource`, which was already writing all
three. That matches how `handleDataSourceChange` behaves when a source needs
auth, and no effect depends on the range or profile ids, so nothing fires a
query in between.
Cancelling still leaves the range and profile the history record set, since
`handleRestoreHistory` writes those before the dialog. That predates this
change; rolling it back too would mean extending `PendingAuthReplay`.
Fixes #4644
---
web/src/components/MetricsExplorer.tsx | 6 +--
.../components/__tests__/MetricsExplorer.test.tsx | 43 ++++++++++++++++++++++
2 files changed, 46 insertions(+), 3 deletions(-)
diff --git a/web/src/components/MetricsExplorer.tsx
b/web/src/components/MetricsExplorer.tsx
index 0145316ec..4d9761987 100644
--- a/web/src/components/MetricsExplorer.tsx
+++ b/web/src/components/MetricsExplorer.tsx
@@ -1041,10 +1041,10 @@ const MetricsExplorer = ({ instanceId }:
MetricsExplorerProps) => {
range: RangeOption,
customPromqlToRun?: string,
) => {
- dataSourceCredentialsRef.current = null;
- dataSourceKeyRef.current = dataSource.key;
+ // The data source switch itself is deferred to handleAuthSubmit: the
current source stays
+ // active while credentials are being asked for, so cancelling the dialog
leaves the
+ // explorer exactly where it was instead of stranded on an unauthenticated
source.
pendingAuthReplayRef.current = { profile, range, customPromql:
customPromqlToRun };
- setDataSourceKey(dataSource.key);
setPendingDataSource(dataSource);
void message.info(copy.protectedHistory);
};
diff --git a/web/src/components/__tests__/MetricsExplorer.test.tsx
b/web/src/components/__tests__/MetricsExplorer.test.tsx
index 374024071..acf5704f9 100644
--- a/web/src/components/__tests__/MetricsExplorer.test.tsx
+++ b/web/src/components/__tests__/MetricsExplorer.test.tsx
@@ -921,6 +921,49 @@ describe('MetricsExplorer', () => {
expect(screen.getByText('Consumer Lag Messages')).toBeInTheDocument();
});
+ it('keeps the current data source when cancelling a protected history
restore', async () => {
+ const user = userEvent.setup();
+ vi.mocked(listDataSources).mockResolvedValue([
+ {
+ key: 'ds-basic',
+ name: 'Protected Prometheus',
+ type: 'Prometheus',
+ url: '',
+ auth: 'Basic Auth',
+ status: 'healthy',
+ },
+ ]);
+ localStorage.setItem(
+ METRICS_QUERY_HISTORY_STORAGE_KEY,
+ JSON.stringify([
+ createHistoryEntry({ dataSourceKey: 'ds-basic', dataSourceName:
'Protected Prometheus' }),
+ ]),
+ );
+
+ renderWithProviders(<MetricsExplorer />);
+
+ await screen.findByRole('img', { name: 'Message In TPS time series' });
+ const sourceSelect = await screen.findByRole('combobox', { name: '数据源' });
+ await user.click(screen.getByRole('button', { name: '查询历史' }));
+
+ const historyDialog = await screen.findByRole('dialog', { name: '指标查询历史'
});
+ const historyItem = within(historyDialog)
+ .getByText('Consumer Lag Messages')
+ .closest('.ant-list-item');
+ expect(historyItem).not.toBeNull();
+ await user.click(within(historyItem as HTMLElement).getByRole('button', {
name: '恢复' }));
+
+ // The auth dialog's generated title id collides with the still-closing
history dialog's
+ // title in jsdom, so the accessible name resolves to the wrong dialog.
Match on the
+ // unique body text instead.
+ await screen.findByText('凭据仅用于当前数据源,离开该数据源后会被清除。');
+ await user.click(screen.getByRole('button', { name: /取\s*消/ }));
+
+ const selectContainer = sourceSelect.closest('.ant-select') as HTMLElement;
+ expect(within(selectContainer).getByText('默认数据源')).toBeInTheDocument();
+ expect(within(selectContainer).queryByText('Protected
Prometheus')).not.toBeInTheDocument();
+ });
+
it('filters query history from other instances and shows the current
instance context', async () => {
const user = userEvent.setup();
localStorage.setItem(