diff --git a/public/app/features/explore/hooks/useStateSync/index.test.tsx b/public/app/features/explore/hooks/useStateSync/index.test.tsx
index 841a220d03e..01aa4046af5 100644
--- a/public/app/features/explore/hooks/useStateSync/index.test.tsx
+++ b/public/app/features/explore/hooks/useStateSync/index.test.tsx
@@ -12,6 +12,7 @@ import { MIXED_DATASOURCE_NAME } from 'app/plugins/datasource/mixed/MixedDataSou
import { configureStore } from 'app/store/configureStore';
import { makeDatasourceSetup } from '../../spec/helper/setup';
+import { updateQueryRefAction } from '../../state/explorePane';
import { splitClose, splitOpen } from '../../state/main';
import { useStateSync } from './';
@@ -584,4 +585,80 @@ describe('useStateSync', () => {
expect(store.getState().explore.panes['one']?.queries[0]).toMatchObject({ expr: 'b', refId: 'B' });
});
});
+
+ it('should sync queryRef from URL to state', async () => {
+ const { store } = setup({
+ queryParams: {
+ panes: JSON.stringify({
+ one: {
+ datasource: 'loki-uid',
+ queries: [{ expr: 'test', refId: 'A' }],
+ queryRef: 'library-query-123',
+ },
+ }),
+ schemaVersion: 1,
+ },
+ });
+
+ await waitFor(() => {
+ expect(store.getState().explore.panes['one']?.queryRef).toBe('library-query-123');
+ });
+ });
+
+ it('should sync queryRef from state to URL', async () => {
+ const { store, location } = setup({
+ queryParams: {
+ panes: JSON.stringify({
+ one: {
+ datasource: 'loki-uid',
+ queries: [{ expr: 'test', refId: 'A' }],
+ },
+ }),
+ schemaVersion: 1,
+ },
+ });
+
+ await waitFor(() => {
+ expect(store.getState().explore.panes['one']).toBeDefined();
+ });
+
+ act(() => {
+ store.dispatch(updateQueryRefAction({ exploreId: 'one', queryRef: 'library-query-456' }));
+ });
+
+ await waitFor(() => {
+ const search = location.getSearchObject();
+ const panes = search.panes && typeof search.panes === 'string' ? JSON.parse(search.panes) : {};
+ expect(panes.one?.queryRef).toBe('library-query-456');
+ });
+ });
+
+ it('should handle queryRef cleanup in URL when queryRef is undefined', async () => {
+ const { store, location } = setup({
+ queryParams: {
+ panes: JSON.stringify({
+ one: {
+ datasource: 'loki-uid',
+ queries: [{ expr: 'test', refId: 'A' }],
+ queryRef: 'library-query-123',
+ },
+ }),
+ schemaVersion: 1,
+ },
+ });
+
+ await waitFor(() => {
+ expect(store.getState().explore.panes['one']?.queryRef).toBe('library-query-123');
+ });
+
+ act(() => {
+ store.dispatch(updateQueryRefAction({ exploreId: 'one', queryRef: undefined }));
+ });
+
+ await waitFor(() => {
+ const search = location.getSearchObject();
+ const panes = search.panes && typeof search.panes === 'string' ? JSON.parse(search.panes) : {};
+ expect(panes.one?.queryRef).toBeUndefined();
+ });
+ });
});
diff --git a/public/app/features/query/components/QueryEditorRow.test.tsx b/public/app/features/query/components/QueryEditorRow.test.tsx
index 3a9d33542f1..98b1f0cc031 100644
--- a/public/app/features/query/components/QueryEditorRow.test.tsx
+++ b/public/app/features/query/components/QueryEditorRow.test.tsx
@@ -5,15 +5,28 @@ import { DataQueryRequest, dateTime, LoadingState, PanelData, toDataFrame } from
import { DataQuery } from '@grafana/schema';
import { mockDataSource } from 'app/features/alerting/unified/mocks';
-import { DataSourceType } from '../../alerting/unified/utils/datasource';
-
-import { filterPanelDataToQuery, Props, QueryEditorRow } from './QueryEditorRow';
+import { filterPanelDataToQuery, Props, QueryEditorRow, QueryLibraryBadgeWrapper } from './QueryEditorRow';
const mockDS = mockDataSource({
name: 'test',
- type: DataSourceType.Alertmanager,
+ type: 'testdata',
});
+// Mock the QueryLibraryContext
+const mockQueryLibraryContext = {
+ queryLibraryEnabled: true,
+};
+
+jest.mock('app/features/explore/QueryLibrary/QueryLibraryContext', () => ({
+ useQueryLibraryContext: () => mockQueryLibraryContext,
+}));
+
+// Mock the internationalization function
+jest.mock('@grafana/i18n', () => ({
+ ...jest.requireActual('@grafana/i18n'),
+ t: (key: string, defaultValue: string) => defaultValue,
+}));
+
jest.mock('@grafana/runtime', () => ({
...jest.requireActual('@grafana/runtime'),
getDataSourceSrv: () => ({
@@ -392,3 +405,30 @@ describe('QueryEditorRow', () => {
});
});
});
+
+describe('QueryLibraryBadge', () => {
+ beforeEach(() => {
+ mockQueryLibraryContext.queryLibraryEnabled = true;
+ });
+
+ it('should display badge when queryLibraryEnabled is true and queryRef is provided', () => {
+ render();
+ expect(screen.getByText('Editing From Query Library')).toBeInTheDocument();
+ });
+
+ it('should not display badge when queryLibraryEnabled is false', () => {
+ mockQueryLibraryContext.queryLibraryEnabled = false;
+ render();
+ expect(screen.queryByText('Editing From Query Library')).not.toBeInTheDocument();
+ });
+
+ it('should not display badge when queryRef is not provided', () => {
+ render();
+ expect(screen.queryByText('Editing From Query Library')).not.toBeInTheDocument();
+ });
+
+ it('should not display badge when queryRef is empty string', () => {
+ render();
+ expect(screen.queryByText('Editing From Query Library')).not.toBeInTheDocument();
+ });
+});
diff --git a/public/app/features/query/components/QueryEditorRow.tsx b/public/app/features/query/components/QueryEditorRow.tsx
index 8ba101449f9..41330d74228 100644
--- a/public/app/features/query/components/QueryEditorRow.tsx
+++ b/public/app/features/query/components/QueryEditorRow.tsx
@@ -489,7 +489,7 @@ export class QueryEditorRow extends PureComponent