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 fdf8a437 feat: support Grafana Mimir data sources (#746)
fdf8a437 is described below
commit fdf8a43749f696a04dcd879d707b7718fcda99fe
Author: yx9o <[email protected]>
AuthorDate: Mon Aug 3 11:17:58 2026 +0800
feat: support Grafana Mimir data sources (#746)
---
.../settings/__tests__/DataSourceTab.test.tsx | 55 +++++++++++++++++++++-
web/src/pages/settings/index.tsx | 12 ++++-
2 files changed, 64 insertions(+), 3 deletions(-)
diff --git a/web/src/pages/settings/__tests__/DataSourceTab.test.tsx
b/web/src/pages/settings/__tests__/DataSourceTab.test.tsx
index 2f177e02..c178bfd5 100644
--- a/web/src/pages/settings/__tests__/DataSourceTab.test.tsx
+++ b/web/src/pages/settings/__tests__/DataSourceTab.test.tsx
@@ -163,6 +163,55 @@ describe('DataSourceTab', () => {
});
});
+ it('creates and tests a Grafana Mimir data source', async () => {
+ vi.mocked(testDataSource).mockResolvedValue({ success: true, message: 'ok'
});
+ vi.mocked(createDataSource).mockResolvedValue({
+ key: 'mimir-prod',
+ name: 'Mimir prod',
+ type: 'Mimir',
+ url: 'http://mimir:9009',
+ auth: 'None',
+ status: 'healthy',
+ });
+
+ const user = userEvent.setup();
+ render(
+ <App>
+ <DataSourceTab />
+ </App>,
+ );
+
+ await screen.findByText('Prometheus prod');
+ await user.click(screen.getByRole('button', { name: /添加数据源/ }));
+ await user.type(screen.getByLabelText('名称'), 'Mimir prod');
+ await selectAntdOption(user, '类型', 'Grafana Mimir');
+ await user.type(screen.getByLabelText('URL'), 'http://mimir:9009');
+
+ const testButtons = screen.getAllByRole('button', { name: /测试连接/ });
+ await user.click(testButtons[testButtons.length - 1]);
+
+ await waitFor(() => {
+ expect(testDataSource).toHaveBeenCalledWith({
+ type: 'Mimir',
+ url: 'http://mimir:9009',
+ auth: 'None',
+ });
+ });
+
+ await user.click(screen.getByRole('button', { name: 'OK' }));
+
+ await waitFor(() => {
+ expect(createDataSource).toHaveBeenCalledWith({
+ name: 'Mimir prod',
+ type: 'Mimir',
+ url: 'http://mimir:9009',
+ auth: 'None',
+ });
+ });
+ expect(await screen.findByText('Mimir prod')).toBeInTheDocument();
+ expect(screen.getByText('Mimir')).toHaveClass('ant-tag-cyan');
+ });
+
it('does not persist modal-only credentials when creating a data source',
async () => {
vi.mocked(createDataSource).mockResolvedValue({
key: 'prom-secure',
@@ -202,7 +251,11 @@ describe('DataSourceTab', () => {
});
});
-async function selectAntdOption(user: ReturnType<typeof userEvent.setup>,
label: string, option: string) {
+async function selectAntdOption(
+ user: ReturnType<typeof userEvent.setup>,
+ label: string,
+ option: string,
+) {
await user.click(screen.getByLabelText(label));
const popupId = label === '类型' ? 'type_list' : 'auth_list';
const popup = await waitFor(() => {
diff --git a/web/src/pages/settings/index.tsx b/web/src/pages/settings/index.tsx
index 47080e4d..3f613fcc 100644
--- a/web/src/pages/settings/index.tsx
+++ b/web/src/pages/settings/index.tsx
@@ -68,6 +68,7 @@ const typeTagColor: Record<string, string> = {
Prometheus: 'orange',
VictoriaMetrics: 'blue',
Thanos: 'purple',
+ Mimir: 'cyan',
};
type DataSourceFormValues = Partial<DataSource>;
@@ -377,7 +378,9 @@ export const DataSourceTab = () => {
icon={<ApiOutlined />}
loading={testingKey === record.key}
disabled={authNeedsSecret(record.auth)}
- title={authNeedsSecret(record.auth) ? '认证数据源请编辑后输入凭据再测试连接' :
undefined}
+ title={
+ authNeedsSecret(record.auth) ? '认证数据源请编辑后输入凭据再测试连接' : undefined
+ }
onClick={() => void handleTestConnection(record, record.key)}
>
测试连接
@@ -454,6 +457,7 @@ export const DataSourceTab = () => {
{ value: 'Prometheus', label: 'Prometheus' },
{ value: 'VictoriaMetrics', label: 'VictoriaMetrics' },
{ value: 'Thanos', label: 'Thanos' },
+ { value: 'Mimir', label: 'Grafana Mimir' },
]}
/>
</Form.Item>
@@ -470,7 +474,11 @@ export const DataSourceTab = () => {
<Select
virtual={false}
onChange={() => {
- dsForm.setFieldsValue({ username: undefined, password:
undefined, bearerToken: undefined });
+ dsForm.setFieldsValue({
+ username: undefined,
+ password: undefined,
+ bearerToken: undefined,
+ });
}}
options={[
{ value: 'None', label: 'None' },