mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Explore: List query templates (#86897)
* Create basic feature toggle * Rename context to reflect it contains query history and query library * Update icons and variants * Rename hooks * Update tests * Fix mock * Add tracking * Turn button into a toggle * Make dropdown active as well This is required to have better UI and an indication of selected state in split view * Update Query Library icon This is to make it consistent with the toolbar button * Hide query history button when query library is available This is to avoid confusing UX with 2 button triggering the drawer but with slightly different behavior * Make the drawer bigger for query library To avoid confusion for current users and test it internally a bit more it's behind a feature toggle. Bigger drawer may obstruct the view and add more friction in the UX. * Fix tests The test was failing because queryLibraryAvailable was set to true for tests. This change makes it more explicit what use case is being tested * Remove active state underline from the dropdown * Add basic types and api methods This is just moved from the app. To be cleaned up and refactored later. * Move API utils from Query Library app to Grafana packages * Move API utils from Query Library app to Grafana packages * Move API utils from Query Library app to Grafana packages * Add basic table for query templates * Add sorting * Style cells * Style table cells * Allow closing Query Library drawer from the toolbar * Remove Private Query toggle It will be moved to the kebab * Add empty state * Remove variables detection for now Just to simplify the PR, it's not needed for Explore yet. * Simplify getting useDatasource.tsx * Rename cell * Move QueryTemplatesTable to a separate folder * Use RTK Query to get list of query templates * Clean up query templates table * Simplify useDatasource hook * Add a test * Retrigger the build * Remove unused code * Small clean up * Update import * Add reduxjs/toolkit as a peer dependecy * Revert "Add reduxjs/toolkit as a peer dependecy" This reverts commitaa9da6e442. * Update import * Add reduxjs/toolkit as a peer dependecy * Revert "Add reduxjs/toolkit as a peer dependecy" This reverts commit2e68a62ab6. * Add @reduxjs/toolkit as peer dependency * Add @reduxjs/toolkit as peer dependecy * Move reactjs/toolkit to dev dependecies * Minor clean up and use react-redux as a peer dependency * Move query library code to core features * Update code owners * Update export * Update exports * Use Redux store instead of APIProvider * Await for query templates to show during the test * Add more explicit docs that the feature is experimental --------- Co-authored-by: Kristina Durivage <kristina.durivage@grafana.com>
This commit is contained in:
17
public/app/features/query-library/api/factory.ts
Normal file
17
public/app/features/query-library/api/factory.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { createApi } from '@reduxjs/toolkit/query/react';
|
||||
|
||||
import { QueryTemplate } from '../types';
|
||||
|
||||
import { convertDataQueryResponseToQueryTemplates } from './mappers';
|
||||
import { baseQuery } from './query';
|
||||
|
||||
export const queryLibraryApi = createApi({
|
||||
baseQuery,
|
||||
endpoints: (builder) => ({
|
||||
allQueryTemplates: builder.query<QueryTemplate[], void>({
|
||||
query: () => undefined,
|
||||
transformResponse: convertDataQueryResponseToQueryTemplates,
|
||||
}),
|
||||
}),
|
||||
reducerPath: 'queryLibrary',
|
||||
});
|
||||
17
public/app/features/query-library/api/mappers.ts
Normal file
17
public/app/features/query-library/api/mappers.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { QueryTemplate } from '../types';
|
||||
|
||||
import { DataQuerySpecResponse, DataQueryTarget } from './types';
|
||||
|
||||
export const convertDataQueryResponseToQueryTemplates = (result: DataQuerySpecResponse): QueryTemplate[] => {
|
||||
if (!result.items) {
|
||||
return [];
|
||||
}
|
||||
return result.items.map((spec) => {
|
||||
return {
|
||||
uid: spec.metadata.name || '',
|
||||
title: spec.spec.title,
|
||||
targets: spec.spec.targets.map((target: DataQueryTarget) => target.properties),
|
||||
createdAtTimestamp: new Date(spec.metadata.creationTimestamp || '').getTime(),
|
||||
};
|
||||
});
|
||||
};
|
||||
9
public/app/features/query-library/api/mocks.ts
Normal file
9
public/app/features/query-library/api/mocks.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { BASE_URL } from './query';
|
||||
import { getTestQueryList } from './testdata/testQueryList';
|
||||
|
||||
export const mockData = {
|
||||
all: {
|
||||
url: BASE_URL,
|
||||
response: getTestQueryList(),
|
||||
},
|
||||
};
|
||||
34
public/app/features/query-library/api/query.ts
Normal file
34
public/app/features/query-library/api/query.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { BaseQueryFn } from '@reduxjs/toolkit/query/react';
|
||||
import { lastValueFrom } from 'rxjs';
|
||||
|
||||
import { getBackendSrv, isFetchError } from '@grafana/runtime/src/services/backendSrv';
|
||||
|
||||
import { DataQuerySpecResponse } from './types';
|
||||
|
||||
/**
|
||||
* Query Library is an experimental feature. API (including the URL path) will likely change.
|
||||
*
|
||||
* @alpha
|
||||
*/
|
||||
export const BASE_URL = '/apis/peakq.grafana.app/v0alpha1/namespaces/default/querytemplates/';
|
||||
|
||||
/**
|
||||
* TODO: similar code is duplicated in many places. To be unified in #86960
|
||||
*/
|
||||
export const baseQuery: BaseQueryFn<void, DataQuerySpecResponse, Error> = async () => {
|
||||
try {
|
||||
const responseObservable = getBackendSrv().fetch<DataQuerySpecResponse>({
|
||||
url: BASE_URL,
|
||||
showErrorAlert: true,
|
||||
});
|
||||
return await lastValueFrom(responseObservable);
|
||||
} catch (error) {
|
||||
if (isFetchError(error)) {
|
||||
return { error: new Error(error.data.message) };
|
||||
} else if (error instanceof Error) {
|
||||
return { error };
|
||||
} else {
|
||||
return { error: new Error('Unknown error') };
|
||||
}
|
||||
}
|
||||
};
|
||||
122
public/app/features/query-library/api/testdata/testQueryList.ts
vendored
Normal file
122
public/app/features/query-library/api/testdata/testQueryList.ts
vendored
Normal file
@@ -0,0 +1,122 @@
|
||||
export const getTestQueryList = () => ({
|
||||
kind: 'QueryTemplateList',
|
||||
apiVersion: 'peakq.grafana.app/v0alpha1',
|
||||
metadata: {
|
||||
resourceVersion: '1783293408052252672',
|
||||
remainingItemCount: 0,
|
||||
},
|
||||
items: [
|
||||
{
|
||||
kind: 'QueryTemplate',
|
||||
apiVersion: 'peakq.grafana.app/v0alpha1',
|
||||
metadata: {
|
||||
name: 'AElastic2nkf9',
|
||||
generateName: 'AElastic',
|
||||
namespace: 'default',
|
||||
uid: '65327fce-c545-489d-ada5-16f909453d12',
|
||||
resourceVersion: '1783293341664808960',
|
||||
creationTimestamp: '2024-04-25T20:32:58Z',
|
||||
},
|
||||
spec: {
|
||||
title: 'Elastic Query Template',
|
||||
targets: [
|
||||
{
|
||||
variables: {},
|
||||
properties: {
|
||||
refId: 'A',
|
||||
datasource: {
|
||||
type: 'elasticsearch',
|
||||
uid: 'elastic-uid',
|
||||
},
|
||||
alias: '',
|
||||
metrics: [
|
||||
{
|
||||
id: '1',
|
||||
type: 'count',
|
||||
},
|
||||
],
|
||||
bucketAggs: [
|
||||
{
|
||||
field: '@timestamp',
|
||||
id: '2',
|
||||
settings: {
|
||||
interval: 'auto',
|
||||
},
|
||||
type: 'date_histogram',
|
||||
},
|
||||
],
|
||||
timeField: '@timestamp',
|
||||
query: 'test:test ',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
kind: 'QueryTemplate',
|
||||
apiVersion: 'peakq.grafana.app/v0alpha1',
|
||||
metadata: {
|
||||
name: 'ALoki296tj',
|
||||
generateName: 'ALoki',
|
||||
namespace: 'default',
|
||||
uid: '3e71de65-efa7-40e3-8f23-124212cca455',
|
||||
resourceVersion: '1783214217151647744',
|
||||
creationTimestamp: '2024-04-25T11:05:55Z',
|
||||
},
|
||||
spec: {
|
||||
title: 'Loki Query Template',
|
||||
vars: [
|
||||
{
|
||||
key: '__value',
|
||||
defaultValues: [''],
|
||||
valueListDefinition: {
|
||||
customValues: '',
|
||||
},
|
||||
},
|
||||
],
|
||||
targets: [
|
||||
{
|
||||
variables: {
|
||||
__value: [
|
||||
{
|
||||
path: '$.datasource.jsonData.derivedFields.0.url',
|
||||
position: {
|
||||
start: 0,
|
||||
end: 14,
|
||||
},
|
||||
format: 'raw',
|
||||
},
|
||||
{
|
||||
path: '$.datasource.jsonData.derivedFields.1.url',
|
||||
position: {
|
||||
start: 0,
|
||||
end: 14,
|
||||
},
|
||||
format: 'raw',
|
||||
},
|
||||
{
|
||||
path: '$.datasource.jsonData.derivedFields.2.url',
|
||||
position: {
|
||||
start: 0,
|
||||
end: 14,
|
||||
},
|
||||
format: 'raw',
|
||||
},
|
||||
],
|
||||
},
|
||||
properties: {
|
||||
refId: 'A',
|
||||
datasource: {
|
||||
type: 'loki',
|
||||
uid: 'loki-uid',
|
||||
},
|
||||
queryType: 'range',
|
||||
editorMode: 'code',
|
||||
expr: '{test="test"}',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
26
public/app/features/query-library/api/types.ts
Normal file
26
public/app/features/query-library/api/types.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { DataQuery } from '@grafana/schema/dist/esm/index';
|
||||
|
||||
export type DataQueryTarget = {
|
||||
variables: object; // TODO: Detect variables in #86838
|
||||
properties: DataQuery;
|
||||
};
|
||||
|
||||
export type DataQuerySpec = {
|
||||
apiVersion: string;
|
||||
kind: string;
|
||||
metadata: {
|
||||
generateName: string;
|
||||
name?: string;
|
||||
creationTimestamp?: string;
|
||||
};
|
||||
spec: {
|
||||
title: string;
|
||||
vars: object[]; // TODO: Detect variables in #86838
|
||||
targets: DataQueryTarget[];
|
||||
};
|
||||
};
|
||||
|
||||
export type DataQuerySpecResponse = {
|
||||
apiVersion: string;
|
||||
items: DataQuerySpec[];
|
||||
};
|
||||
17
public/app/features/query-library/index.ts
Normal file
17
public/app/features/query-library/index.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* This is a temporary place for Query Library API and data types.
|
||||
* To be exposed via grafana-runtime/data in the future.
|
||||
*
|
||||
* Query Library is an experimental feature, the API and components are subject to change
|
||||
*
|
||||
* @alpha
|
||||
*/
|
||||
|
||||
import { queryLibraryApi } from './api/factory';
|
||||
import { mockData } from './api/mocks';
|
||||
|
||||
export const { useAllQueryTemplatesQuery } = queryLibraryApi;
|
||||
|
||||
export const QueryLibraryMocks = {
|
||||
data: mockData,
|
||||
};
|
||||
8
public/app/features/query-library/types.ts
Normal file
8
public/app/features/query-library/types.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { DataQuery } from '@grafana/schema';
|
||||
|
||||
export type QueryTemplate = {
|
||||
uid: string;
|
||||
title: string;
|
||||
targets: DataQuery[];
|
||||
createdAtTimestamp: number;
|
||||
};
|
||||
Reference in New Issue
Block a user