Explore: Allow Query Library drawer to delete queries (#89343)

* WIP

* WIP

* Add URL additions to query library API

* Add tag invalidation for refresh

* add styles

* Add verbiage from prototype

* Translations generation
This commit is contained in:
Kristina 2024-06-20 15:20:10 -05:00 committed by GitHub
parent 5e95c1bdf8
commit 3044319039
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 105 additions and 7 deletions

View File

@ -41,6 +41,7 @@ export function QueryTemplatesList() {
const datasourceType = getDatasourceSrv().getInstanceSettings(datasourceRef)?.meta.name || '';
return {
index: index.toString(),
uid: queryTemplate.uid,
datasourceRef,
datasourceType,
createdAtTimestamp: queryTemplate?.createdAtTimestamp || 0,

View File

@ -1,16 +1,67 @@
import React from 'react';
import { reportInteraction, getAppEvents } from '@grafana/runtime';
import { DataQuery } from '@grafana/schema';
import { IconButton } from '@grafana/ui';
import { notifyApp } from 'app/core/actions';
import { createSuccessNotification } from 'app/core/copy/appNotification';
import { t } from 'app/core/internationalization';
import { useDeleteQueryTemplateMutation } from 'app/features/query-library';
import { dispatch } from 'app/store/store';
import { ShowConfirmModalEvent } from 'app/types/events';
import ExploreRunQueryButton from '../../ExploreRunQueryButton';
import { useQueryLibraryListStyles } from './styles';
interface ActionsCellProps {
queryUid?: string;
query?: DataQuery;
rootDatasourceUid?: string;
}
function ActionsCell({ query, rootDatasourceUid }: ActionsCellProps) {
return <ExploreRunQueryButton queries={query ? [query] : []} rootDatasourceUid={rootDatasourceUid} />;
function ActionsCell({ query, rootDatasourceUid, queryUid }: ActionsCellProps) {
const [deleteQueryTemplate] = useDeleteQueryTemplateMutation();
const styles = useQueryLibraryListStyles();
const onDeleteQuery = (queryUid: string) => {
const performDelete = (queryUid: string) => {
deleteQueryTemplate({ uid: queryUid });
dispatch(notifyApp(createSuccessNotification(t('explore.query-library.query-deleted', 'Query deleted'))));
reportInteraction('grafana_explore_query_library_deleted');
};
getAppEvents().publish(
new ShowConfirmModalEvent({
title: t('explore.query-library.delete-query-title', 'Delete query'),
text: t(
'explore.query-library.delete-query-text',
"You're about to remove this query from the query library. This action cannot be undone. Do you want to continue?"
),
yesText: t('query-library.delete-query-button', 'Delete query'),
icon: 'trash-alt',
onConfirm: () => performDelete(queryUid),
})
);
};
return (
<div className={styles.cell}>
<IconButton
className={styles.actionButton}
size="lg"
name="trash-alt"
title={t('explore.query-library.delete-query', 'Delete query')}
tooltip={t('explore.query-library.delete-query', 'Delete query')}
onClick={() => {
if (queryUid) {
onDeleteQuery(queryUid);
}
}}
/>
<ExploreRunQueryButton queries={query ? [query] : []} rootDatasourceUid={rootDatasourceUid} />
</div>
);
}
export default ActionsCell;

View File

@ -26,7 +26,7 @@ const columns: Array<Column<QueryTemplateRow>> = [
id: 'actions',
header: '',
cell: ({ row: { original } }) => (
<ActionsCell query={original.query} rootDatasourceUid={original.datasourceRef?.uid} />
<ActionsCell query={original.query} rootDatasourceUid={original.datasourceRef?.uid} queryUid={original.uid} />
),
},
];

View File

@ -34,4 +34,14 @@ const getStyles = (theme: GrafanaTheme2) => ({
WebkitLineClamp: 1,
overflow: 'hidden',
}),
cell: css({
display: 'flex',
alignItems: 'center',
'&:last-child': {
justifyContent: 'end',
},
}),
actionButton: css({
padding: theme.spacing(1),
}),
});

View File

@ -7,4 +7,5 @@ export type QueryTemplateRow = {
datasourceRef?: DataSourceRef | null;
datasourceType?: string;
createdAtTimestamp?: number;
uid?: string;
};

View File

@ -1,6 +1,6 @@
import { createApi } from '@reduxjs/toolkit/query/react';
import { AddQueryTemplateCommand, QueryTemplate } from '../types';
import { AddQueryTemplateCommand, DeleteQueryTemplateCommand, QueryTemplate } from '../types';
import { convertAddQueryTemplateCommandToDataQuerySpec, convertDataQueryResponseToQueryTemplates } from './mappers';
import { baseQuery } from './query';
@ -21,6 +21,13 @@ export const queryLibraryApi = createApi({
}),
invalidatesTags: ['QueryTemplatesList'],
}),
deleteQueryTemplate: builder.mutation<void, DeleteQueryTemplateCommand>({
query: ({ uid }) => ({
url: `${uid}`,
method: 'DELETE',
}),
invalidatesTags: ['QueryTemplatesList'],
}),
}),
reducerPath: 'queryLibrary',
});

View File

@ -24,15 +24,20 @@ export enum QueryTemplateKinds {
*/
export const BASE_URL = `/apis/${API_VERSION}/namespaces/default/querytemplates/`;
// URL is optional for these requests
interface QueryLibraryBackendRequest extends Pick<BackendSrvRequest, 'data' | 'method'> {
url?: string;
}
/**
* TODO: similar code is duplicated in many places. To be unified in #86960
*/
export const baseQuery: BaseQueryFn<Pick<BackendSrvRequest, 'data' | 'method'>, DataQuerySpecResponse, Error> = async (
export const baseQuery: BaseQueryFn<QueryLibraryBackendRequest, DataQuerySpecResponse, Error> = async (
requestOptions
) => {
try {
const responseObservable = getBackendSrv().fetch<DataQuerySpecResponse>({
url: BASE_URL,
url: `${BASE_URL}${requestOptions.url ?? ''}`,
showErrorAlert: true,
method: requestOptions.method || 'GET',
data: requestOptions.data,

View File

@ -12,7 +12,8 @@ import { config } from '@grafana/runtime';
import { queryLibraryApi } from './api/factory';
import { mockData } from './api/mocks';
export const { useAllQueryTemplatesQuery, useAddQueryTemplateMutation } = queryLibraryApi;
export const { useAllQueryTemplatesQuery, useAddQueryTemplateMutation, useDeleteQueryTemplateMutation } =
queryLibraryApi;
export function isQueryLibraryEnabled() {
return config.featureToggles.queryLibrary;

View File

@ -11,3 +11,7 @@ export type AddQueryTemplateCommand = {
title: string;
targets: DataQuery[];
};
export type DeleteQueryTemplateCommand = {
uid: string;
};

View File

@ -532,6 +532,12 @@
"scan-for-older-logs": "Scan for older logs",
"stop-scan": "Stop scan"
},
"query-library": {
"delete-query": "Delete query",
"delete-query-text": "You're about to remove this query from the query library. This action cannot be undone. Do you want to continue?",
"delete-query-title": "Delete query",
"query-deleted": "Query deleted"
},
"rich-history": {
"close-tooltip": "Close query history",
"datasource-a-z": "Data source A-Z",
@ -1559,6 +1565,9 @@
"role-label": "Role"
}
},
"query-library": {
"delete-query-button": "Delete query"
},
"query-operation": {
"header": {
"collapse-row": "Collapse query row",

View File

@ -532,6 +532,12 @@
"scan-for-older-logs": "Ŝčäʼn ƒőř őľđęř ľőģş",
"stop-scan": "Ŝŧőp şčäʼn"
},
"query-library": {
"delete-query": "Đęľęŧę qūęřy",
"delete-query-text": "Ÿőū'řę äþőūŧ ŧő řęmővę ŧĥįş qūęřy ƒřőm ŧĥę qūęřy ľįþřäřy. Ŧĥįş äčŧįőʼn čäʼnʼnőŧ þę ūʼnđőʼnę. Đő yőū ŵäʼnŧ ŧő čőʼnŧįʼnūę?",
"delete-query-title": "Đęľęŧę qūęřy",
"query-deleted": "Qūęřy đęľęŧęđ"
},
"rich-history": {
"close-tooltip": "Cľőşę qūęřy ĥįşŧőřy",
"datasource-a-z": "Đäŧä şőūřčę Å-Ż",
@ -1559,6 +1565,9 @@
"role-label": "Ŗőľę"
}
},
"query-library": {
"delete-query-button": "Đęľęŧę qūęřy"
},
"query-operation": {
"header": {
"collapse-row": "Cőľľäpşę qūęřy řőŵ",