-
+
+
{dsName}
-
- {queryDisplayText}
+
+
+ {queryDisplayText}
+
- {description}
+ {description}
);
}
+
+const getStyles = (theme: GrafanaTheme2) => ({
+ container: css({
+ maxWidth: theme.spacing(60),
+ }),
+ queryDisplayText: css({
+ backgroundColor: theme.colors.background.canvas,
+ }),
+});
diff --git a/public/app/features/explore/QueryLibrary/QueryTemplatesTable/index.tsx b/public/app/features/explore/QueryLibrary/QueryTemplatesTable/index.tsx
index c95398b0956..b7809baf026 100644
--- a/public/app/features/explore/QueryLibrary/QueryTemplatesTable/index.tsx
+++ b/public/app/features/explore/QueryLibrary/QueryTemplatesTable/index.tsx
@@ -1,4 +1,3 @@
-import { css } from '@emotion/css';
import { SortByFn } from 'react-table';
import { Column, InteractiveTable } from '@grafana/ui';
@@ -30,14 +29,6 @@ const columns: Array
> = [
},
];
-const styles = {
- tableWithSpacing: css({
- 'th:first-child': {
- width: '50%',
- },
- }),
-};
-
type Props = {
queryTemplateRows: QueryTemplateRow[];
};
@@ -45,10 +36,10 @@ type Props = {
export default function QueryTemplatesTable({ queryTemplateRows }: Props) {
return (
row.index}
+ pageSize={20}
/>
);
}
diff --git a/public/app/features/explore/QueryLibrary/QueryTemplatesTable/types.ts b/public/app/features/explore/QueryLibrary/QueryTemplatesTable/types.ts
index b9ca932e980..eae57422d0c 100644
--- a/public/app/features/explore/QueryLibrary/QueryTemplatesTable/types.ts
+++ b/public/app/features/explore/QueryLibrary/QueryTemplatesTable/types.ts
@@ -2,8 +2,10 @@ import { DataQuery, DataSourceRef } from '@grafana/schema';
export type QueryTemplateRow = {
index: string;
+ datasourceName?: string;
description?: string;
query?: DataQuery;
+ queryText?: string;
datasourceRef?: DataSourceRef | null;
datasourceType?: string;
createdAtTimestamp?: number;
diff --git a/public/app/features/explore/QueryLibrary/utils/search.ts b/public/app/features/explore/QueryLibrary/utils/search.ts
new file mode 100644
index 00000000000..6ad6e277322
--- /dev/null
+++ b/public/app/features/explore/QueryLibrary/utils/search.ts
@@ -0,0 +1,16 @@
+import { QueryTemplateRow } from '../QueryTemplatesTable/types';
+
+export const searchQueryLibrary = (queryLibrary: QueryTemplateRow[], query: string, filter: string[]) => {
+ const result = queryLibrary.filter((item) => {
+ const matchesFilter =
+ filter.length === 0 || filter.some((f) => item.datasourceName?.toLowerCase().includes(f.toLowerCase()));
+ return (
+ (item.datasourceName?.toLowerCase().includes(query.toLowerCase()) ||
+ item.datasourceType?.toLowerCase().includes(query.toLowerCase()) ||
+ item.description?.toLowerCase().includes(query.toLowerCase()) ||
+ item.queryText?.toLowerCase().includes(query.toLowerCase())) &&
+ matchesFilter
+ );
+ });
+ return result;
+};
diff --git a/public/app/features/explore/RichHistory/RichHistory.tsx b/public/app/features/explore/RichHistory/RichHistory.tsx
index 063029baaea..cb00212d199 100644
--- a/public/app/features/explore/RichHistory/RichHistory.tsx
+++ b/public/app/features/explore/RichHistory/RichHistory.tsx
@@ -5,13 +5,20 @@ import { SelectableValue } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { TabbedContainer, TabConfig } from '@grafana/ui';
import { t } from 'app/core/internationalization';
-import { SortOrder, RichHistorySearchFilters, RichHistorySettings } from 'app/core/utils/richHistory';
+import {
+ SortOrder,
+ RichHistorySearchFilters,
+ RichHistorySettings,
+ createDatasourcesList,
+} from 'app/core/utils/richHistory';
+import { useSelector } from 'app/types';
import { RichHistoryQuery } from 'app/types/explore';
import { supportedFeatures } from '../../../core/history/richHistoryStorageProvider';
import { Tabs, useQueriesDrawerContext } from '../QueriesDrawer/QueriesDrawerContext';
import { i18n } from '../QueriesDrawer/utils';
import { QueryLibrary } from '../QueryLibrary/QueryLibrary';
+import { selectExploreDSMaps } from '../state/selectors';
import { RichHistoryQueriesTab } from './RichHistoryQueriesTab';
import { RichHistorySettingsTab } from './RichHistorySettingsTab';
@@ -83,10 +90,16 @@ export function RichHistory(props: RichHistoryProps) {
setLoading(false);
}, [richHistory]);
+ const exploreActiveDS = useSelector(selectExploreDSMaps);
+ const listOfDatasources = createDatasourcesList();
+ const activeDatasources = exploreActiveDS.dsToExplore
+ .map((eDs) => listOfDatasources.find((ds) => ds.uid === eDs.datasource?.uid)?.name)
+ .filter((name): name is string => !!name);
+
const QueryLibraryTab: TabConfig = {
label: i18n.queryLibrary,
value: Tabs.QueryLibrary,
- content: ,
+ content: ,
icon: 'book',
};
@@ -104,6 +117,8 @@ export function RichHistory(props: RichHistoryProps) {
richHistorySettings={props.richHistorySettings}
richHistorySearchFilters={props.richHistorySearchFilters}
height={height}
+ activeDatasources={activeDatasources}
+ listOfDatasources={listOfDatasources}
/>
),
icon: 'history',
diff --git a/public/app/features/explore/RichHistory/RichHistoryQueriesTab.test.tsx b/public/app/features/explore/RichHistory/RichHistoryQueriesTab.test.tsx
index a996a5b5b89..7b32ea7bf26 100644
--- a/public/app/features/explore/RichHistory/RichHistoryQueriesTab.test.tsx
+++ b/public/app/features/explore/RichHistory/RichHistoryQueriesTab.test.tsx
@@ -20,6 +20,8 @@ const setup = (propOverrides?: Partial) => {
updateFilters: jest.fn(),
clearRichHistoryResults: jest.fn(),
loadMoreRichHistory: jest.fn(),
+ activeDatasources: ['test-ds'],
+ listOfDatasources: [{ name: 'test-ds', uid: 'test-123' }],
richHistorySearchFilters: {
search: '',
sortOrder: SortOrder.Descending,
diff --git a/public/app/features/explore/RichHistory/RichHistoryQueriesTab.tsx b/public/app/features/explore/RichHistory/RichHistoryQueriesTab.tsx
index 5b644563fe0..5c8a3636e9b 100644
--- a/public/app/features/explore/RichHistory/RichHistoryQueriesTab.tsx
+++ b/public/app/features/explore/RichHistory/RichHistoryQueriesTab.tsx
@@ -7,18 +7,14 @@ import { config, getDataSourceSrv } from '@grafana/runtime';
import { Button, FilterInput, MultiSelect, RangeSlider, Select, useStyles2 } from '@grafana/ui';
import { Trans, t } from 'app/core/internationalization';
import {
- createDatasourcesList,
mapNumbertoTimeInSlider,
mapQueriesToHeadings,
SortOrder,
RichHistorySearchFilters,
RichHistorySettings,
} from 'app/core/utils/richHistory';
-import { useSelector } from 'app/types';
import { RichHistoryQuery } from 'app/types/explore';
-import { selectExploreDSMaps } from '../state/selectors';
-
import { getSortOrderOptions } from './RichHistory';
import RichHistoryCard from './RichHistoryCard';
@@ -31,6 +27,8 @@ export interface RichHistoryQueriesTabProps {
loadMoreRichHistory: () => void;
richHistorySettings: RichHistorySettings;
richHistorySearchFilters?: RichHistorySearchFilters;
+ activeDatasources: string[];
+ listOfDatasources: Array<{ name: string; uid: string }>;
height: number;
}
@@ -125,21 +123,18 @@ export function RichHistoryQueriesTab(props: RichHistoryQueriesTabProps) {
loadMoreRichHistory,
richHistorySettings,
height,
+ listOfDatasources,
+ activeDatasources,
} = props;
- const exploreActiveDS = useSelector(selectExploreDSMaps);
const styles = useStyles2(getStyles, height);
- const listOfDatasources = createDatasourcesList();
-
// on mount, set filter to either active datasource or all datasources
useEffect(() => {
const datasourceFilters =
!richHistorySettings.activeDatasourcesOnly && richHistorySettings.lastUsedDatasourceFilters
? richHistorySettings.lastUsedDatasourceFilters
- : exploreActiveDS.dsToExplore
- .map((eDs) => listOfDatasources.find((ds) => ds.uid === eDs.datasource?.uid)?.name)
- .filter((name): name is string => !!name);
+ : activeDatasources;
const filters: RichHistorySearchFilters = {
search: '',
sortOrder: SortOrder.Descending,
diff --git a/public/app/features/explore/spec/queryLibrary.test.tsx b/public/app/features/explore/spec/queryLibrary.test.tsx
index 7b00a22ee21..d69cc001f16 100644
--- a/public/app/features/explore/spec/queryLibrary.test.tsx
+++ b/public/app/features/explore/spec/queryLibrary.test.tsx
@@ -105,7 +105,6 @@ describe('QueryLibrary', () => {
await waitForExplore();
await openQueryLibrary();
await assertQueryLibraryTemplateExists('loki', 'Loki Query Template');
- await assertQueryLibraryTemplateExists('elastic', 'Elastic Query Template');
});
it('Shows add to query library button only when the toggle is enabled', async () => {
diff --git a/public/app/features/query-library/api/factory.ts b/public/app/features/query-library/api/factory.ts
index d67b8666aac..5ee9b021c59 100644
--- a/public/app/features/query-library/api/factory.ts
+++ b/public/app/features/query-library/api/factory.ts
@@ -5,12 +5,18 @@ import { AddQueryTemplateCommand, DeleteQueryTemplateCommand, EditQueryTemplateC
import { convertAddQueryTemplateCommandToDataQuerySpec, convertDataQueryResponseToQueryTemplates } from './mappers';
import { baseQuery } from './query';
+// Currently, we are loading all query templates
+// Organizations can have maximum of 1000 query templates
+const GET_LIMIT = 1000;
+
export const queryLibraryApi = createApi({
baseQuery,
tagTypes: ['QueryTemplatesList'],
endpoints: (builder) => ({
allQueryTemplates: builder.query({
- query: () => ({}),
+ query: () => ({
+ url: `?limit=${GET_LIMIT}`,
+ }),
transformResponse: convertDataQueryResponseToQueryTemplates,
providesTags: ['QueryTemplatesList'],
}),
@@ -23,14 +29,14 @@ export const queryLibraryApi = createApi({
}),
deleteQueryTemplate: builder.mutation({
query: ({ uid }) => ({
- url: `${uid}`,
+ url: `/${uid}`,
method: 'DELETE',
}),
invalidatesTags: ['QueryTemplatesList'],
}),
editQueryTemplate: builder.mutation({
query: (editQueryTemplateCommand) => ({
- url: `${editQueryTemplateCommand.uid}`,
+ url: `/${editQueryTemplateCommand.uid}`,
method: 'PATCH',
headers: {
'Content-Type': 'application/merge-patch+json',
diff --git a/public/app/features/query-library/api/query.ts b/public/app/features/query-library/api/query.ts
index eb730daf594..89b72fb3210 100644
--- a/public/app/features/query-library/api/query.ts
+++ b/public/app/features/query-library/api/query.ts
@@ -23,7 +23,7 @@ export enum QueryTemplateKinds {
*
* @alpha
*/
-export const BASE_URL = `/apis/${API_VERSION}/namespaces/${config.namespace}/querytemplates/`;
+export const BASE_URL = `/apis/${API_VERSION}/namespaces/${config.namespace}/querytemplates`;
// URL is optional for these requests
interface QueryLibraryBackendRequest extends Pick {
diff --git a/public/locales/en-US/grafana.json b/public/locales/en-US/grafana.json
index 2d48513aa12..38c42b79850 100644
--- a/public/locales/en-US/grafana.json
+++ b/public/locales/en-US/grafana.json
@@ -2198,7 +2198,10 @@
}
},
"query-library": {
- "delete-query-button": "Delete query"
+ "datasource-names": "Datasource name(s):",
+ "delete-query-button": "Delete query",
+ "query-template-get-error": "Error attempting to get query template from the library: {{error}}",
+ "search": "Search by data source, query content or description"
},
"query-operation": {
"header": {
diff --git a/public/locales/pseudo-LOCALE/grafana.json b/public/locales/pseudo-LOCALE/grafana.json
index b9816e154bf..77dcd640032 100644
--- a/public/locales/pseudo-LOCALE/grafana.json
+++ b/public/locales/pseudo-LOCALE/grafana.json
@@ -2198,7 +2198,10 @@
}
},
"query-library": {
- "delete-query-button": "Đęľęŧę qūęřy"
+ "datasource-names": "Đäŧäşőūřčę ʼnämę(ş):",
+ "delete-query-button": "Đęľęŧę qūęřy",
+ "query-template-get-error": "Ēřřőř äŧŧęmpŧįʼnģ ŧő ģęŧ qūęřy ŧęmpľäŧę ƒřőm ŧĥę ľįþřäřy: {{error}}",
+ "search": "Ŝęäřčĥ þy đäŧä şőūřčę, qūęřy čőʼnŧęʼnŧ őř đęşčřįpŧįőʼn"
},
"query-operation": {
"header": {