mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Explore: Show a modal to edit query template before saving it (#88211)
* Create a mock modal * Add basic form handling * Update tests * Extract translations * Disable auto-star switch * Keep disabled input uncontrolled
This commit is contained in:
parent
287e3868ed
commit
ce23a455c3
@ -1,18 +1,21 @@
|
||||
import { t } from 'i18next';
|
||||
import React from 'react';
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import { AppEvents, dateTime } from '@grafana/data';
|
||||
import { getAppEvents } from '@grafana/runtime';
|
||||
import { DataQuery } from '@grafana/schema';
|
||||
import { Button } from '@grafana/ui';
|
||||
import { Button, Modal } from '@grafana/ui';
|
||||
import { isQueryLibraryEnabled, useAddQueryTemplateMutation } from 'app/features/query-library';
|
||||
import { AddQueryTemplateCommand } from 'app/features/query-library/types';
|
||||
|
||||
import { QueryDetails, RichHistoryAddToLibraryForm } from './RichHistoryAddToLibraryForm';
|
||||
|
||||
type Props = {
|
||||
query: DataQuery;
|
||||
};
|
||||
|
||||
export const RichHistoryAddToLibrary = ({ query }: Props) => {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [addQueryTemplate, { isSuccess }] = useAddQueryTemplateMutation();
|
||||
|
||||
const handleAddQueryTemplate = async (addQueryTemplateCommand: AddQueryTemplateCommand) => {
|
||||
@ -29,17 +32,31 @@ export const RichHistoryAddToLibrary = ({ query }: Props) => {
|
||||
|
||||
const buttonLabel = t('explore.rich-history-card.add-to-library', 'Add to library');
|
||||
|
||||
const submit = (data: QueryDetails) => {
|
||||
const timestamp = dateTime().toISOString();
|
||||
const temporaryDefaultTitle = data.description || `Imported from Explore - ${timestamp}`;
|
||||
handleAddQueryTemplate({ title: temporaryDefaultTitle, targets: [query] });
|
||||
};
|
||||
|
||||
return isQueryLibraryEnabled() && !isSuccess ? (
|
||||
<Button
|
||||
variant="secondary"
|
||||
aria-label={buttonLabel}
|
||||
onClick={() => {
|
||||
const timestamp = dateTime().toISOString();
|
||||
const temporaryDefaultTitle = `Imported from Explore - ${timestamp}`;
|
||||
handleAddQueryTemplate({ title: temporaryDefaultTitle, targets: [query] });
|
||||
}}
|
||||
>
|
||||
{buttonLabel}
|
||||
</Button>
|
||||
<>
|
||||
<Button variant="secondary" aria-label={buttonLabel} onClick={() => setIsOpen(true)}>
|
||||
{buttonLabel}
|
||||
</Button>
|
||||
<Modal
|
||||
title={t('explore.add-to-library-modal.title', 'Add query to Query Library')}
|
||||
isOpen={isOpen}
|
||||
onDismiss={() => setIsOpen(false)}
|
||||
>
|
||||
<RichHistoryAddToLibraryForm
|
||||
onCancel={() => setIsOpen(() => false)}
|
||||
query={query}
|
||||
onSave={(data) => {
|
||||
submit(data);
|
||||
setIsOpen(false);
|
||||
}}
|
||||
/>
|
||||
</Modal>
|
||||
</>
|
||||
) : undefined;
|
||||
};
|
||||
|
@ -0,0 +1,83 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
|
||||
import { DataSourcePicker } from '@grafana/runtime';
|
||||
import { DataQuery } from '@grafana/schema';
|
||||
import { Button, InlineSwitch, Modal, RadioButtonGroup, TextArea } from '@grafana/ui';
|
||||
import { Field } from '@grafana/ui/';
|
||||
import { Input } from '@grafana/ui/src/components/Input/Input';
|
||||
import { t } from 'app/core/internationalization';
|
||||
|
||||
import { getQueryDisplayText } from '../../../core/utils/richHistory';
|
||||
import { useDatasource } from '../QueryLibrary/utils/useDatasource';
|
||||
|
||||
type Props = {
|
||||
onCancel: () => void;
|
||||
onSave: (details: QueryDetails) => void;
|
||||
query: DataQuery;
|
||||
};
|
||||
|
||||
export type QueryDetails = {
|
||||
description: string;
|
||||
};
|
||||
|
||||
const VisibilityOptions = [
|
||||
{ value: 'Public', label: 'Public' },
|
||||
{ value: 'Private', label: 'Private' },
|
||||
];
|
||||
|
||||
const info = t(
|
||||
'explore.add-to-library-modal.info',
|
||||
`You're about to save this query. Once saved, you can easily access it in the Query Library tab for future use and reference.`
|
||||
);
|
||||
|
||||
export const RichHistoryAddToLibraryForm = ({ onCancel, onSave, query }: Props) => {
|
||||
const { register, handleSubmit } = useForm<QueryDetails>();
|
||||
|
||||
const datasource = useDatasource(query.datasource);
|
||||
|
||||
const displayText = useMemo(() => {
|
||||
return datasource?.getQueryDisplayText?.(query) || getQueryDisplayText(query);
|
||||
}, [datasource, query]);
|
||||
|
||||
const onSubmit = (data: QueryDetails) => {
|
||||
onSave(data);
|
||||
};
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
<p>{info}</p>
|
||||
<Field label={t('explore.add-to-library-modal.query', 'Query')}>
|
||||
<TextArea readOnly={true} value={displayText}></TextArea>
|
||||
</Field>
|
||||
<Field label={t('explore.add-to-library-modal.data-source-name', 'Data source name')}>
|
||||
<DataSourcePicker current={datasource?.uid} disabled={true} />
|
||||
</Field>
|
||||
<Field label={t('explore.add-to-library-modal.data-source-type', 'Data source type')}>
|
||||
<Input disabled={true} defaultValue={datasource?.meta.name}></Input>
|
||||
</Field>
|
||||
<Field label={t('explore.add-to-library-modal.description', 'Description')}>
|
||||
<Input id="query-template-description" autoFocus={true} {...register('description')}></Input>
|
||||
</Field>
|
||||
<Field label={t('explore.add-to-library-modal.visibility', 'Visibility')}>
|
||||
<RadioButtonGroup options={VisibilityOptions} value={'Public'} disabled={true} />
|
||||
</Field>
|
||||
<InlineSwitch
|
||||
showLabel={true}
|
||||
disabled={true}
|
||||
label={t(
|
||||
'explore.add-to-library-modal.auto-star',
|
||||
'Auto-star this query to add it to your starred list in the Query Library.'
|
||||
)}
|
||||
/>
|
||||
<Modal.ButtonRow>
|
||||
<Button variant="secondary" onClick={() => onCancel()} fill="outline">
|
||||
Cancel
|
||||
</Button>
|
||||
<Button variant="primary" type="submit">
|
||||
Save
|
||||
</Button>
|
||||
</Modal.ButtonRow>
|
||||
</form>
|
||||
);
|
||||
};
|
@ -55,6 +55,15 @@ export const addQueryHistoryToQueryLibrary = async () => {
|
||||
await userEvent.click(button);
|
||||
};
|
||||
|
||||
export const submitAddToQueryLibrary = async ({ description }: { description: string }) => {
|
||||
const input = within(screen.getByRole('dialog')).getByLabelText('Description');
|
||||
await userEvent.type(input, description);
|
||||
const saveButton = screen.getByRole('button', {
|
||||
name: /save/i,
|
||||
});
|
||||
await userEvent.click(saveButton);
|
||||
};
|
||||
|
||||
export const closeQueryHistory = async () => {
|
||||
const selector = withinQueryHistory();
|
||||
const closeButton = selector.getByRole('button', { name: 'Close query history' });
|
||||
|
@ -16,6 +16,7 @@ import {
|
||||
addQueryHistoryToQueryLibrary,
|
||||
openQueryHistory,
|
||||
openQueryLibrary,
|
||||
submitAddToQueryLibrary,
|
||||
switchToQueryHistory,
|
||||
} from './helper/interactions';
|
||||
import { setupExplore, waitForExplore } from './helper/setup';
|
||||
@ -134,6 +135,7 @@ describe('QueryLibrary', () => {
|
||||
await switchToQueryHistory();
|
||||
await assertQueryHistory(['{"expr":"TEST"}']);
|
||||
await addQueryHistoryToQueryLibrary();
|
||||
await submitAddToQueryLibrary({ description: 'Test' });
|
||||
expect(testEventBus.publish).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
type: 'alert-success',
|
||||
|
@ -465,6 +465,16 @@
|
||||
},
|
||||
"explore": {
|
||||
"add-to-dashboard": "Add to dashboard",
|
||||
"add-to-library-modal": {
|
||||
"auto-star": "Auto-star this query to add it to your starred list in the Query Library.",
|
||||
"data-source-name": "Data source name",
|
||||
"data-source-type": "Data source type",
|
||||
"description": "Description",
|
||||
"info": "You're about to save this query. Once saved, you can easily access it in the Query Library tab for future use and reference.",
|
||||
"query": "Query",
|
||||
"title": "Add query to Query Library",
|
||||
"visibility": "Visibility"
|
||||
},
|
||||
"rich-history": {
|
||||
"close-tooltip": "Close query history",
|
||||
"datasource-a-z": "Data source A-Z",
|
||||
|
@ -465,6 +465,16 @@
|
||||
},
|
||||
"explore": {
|
||||
"add-to-dashboard": "Åđđ ŧő đäşĥþőäřđ",
|
||||
"add-to-library-modal": {
|
||||
"auto-star": "Åūŧő-şŧäř ŧĥįş qūęřy ŧő äđđ įŧ ŧő yőūř şŧäřřęđ ľįşŧ įʼn ŧĥę Qūęřy Ŀįþřäřy.",
|
||||
"data-source-name": "Đäŧä şőūřčę ʼnämę",
|
||||
"data-source-type": "Đäŧä şőūřčę ŧypę",
|
||||
"description": "Đęşčřįpŧįőʼn",
|
||||
"info": "Ÿőū'řę äþőūŧ ŧő şävę ŧĥįş qūęřy. Øʼnčę şävęđ, yőū čäʼn ęäşįľy äččęşş įŧ įʼn ŧĥę Qūęřy Ŀįþřäřy ŧäþ ƒőř ƒūŧūřę ūşę äʼnđ řęƒęřęʼnčę.",
|
||||
"query": "Qūęřy",
|
||||
"title": "Åđđ qūęřy ŧő Qūęřy Ŀįþřäřy",
|
||||
"visibility": "Vįşįþįľįŧy"
|
||||
},
|
||||
"rich-history": {
|
||||
"close-tooltip": "Cľőşę qūęřy ĥįşŧőřy",
|
||||
"datasource-a-z": "Đäŧä şőūřčę Å-Ż",
|
||||
|
Loading…
Reference in New Issue
Block a user