Canvas: Button API Editor support setting content-type (#74682)

This commit is contained in:
Adela Almasan 2023-09-14 10:17:21 -05:00 committed by GitHub
parent db2295bea2
commit a0e6e76ca6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 89 additions and 25 deletions

View File

@ -24,6 +24,7 @@ export const defaultApiConfig: APIEditorConfig = {
endpoint: '', endpoint: '',
method: HttpRequestMethod.POST, method: HttpRequestMethod.POST,
data: '{}', data: '{}',
contentType: 'application/json',
}; };
class ButtonDisplay extends PureComponent<CanvasElementProps<ButtonConfig, ButtonData>> { class ButtonDisplay extends PureComponent<CanvasElementProps<ButtonConfig, ButtonData>> {
@ -80,7 +81,11 @@ export const buttonItem: CanvasElementItem<ButtonConfig, ButtonData> = {
prepareData: (ctx: DimensionContext, cfg: ButtonConfig) => { prepareData: (ctx: DimensionContext, cfg: ButtonConfig) => {
const getCfgApi = () => { const getCfgApi = () => {
if (cfg?.api) { if (cfg?.api) {
cfg.api = { ...cfg.api, method: cfg.api.method ?? HttpRequestMethod.POST }; cfg.api = {
...cfg.api,
method: cfg.api.method ?? defaultApiConfig.method,
contentType: cfg.api.contentType ?? defaultApiConfig.contentType,
};
return cfg.api; return cfg.api;
} }

View File

@ -1,8 +1,14 @@
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
import { AppEvents, StandardEditorProps, StandardEditorsRegistryItem, StringFieldConfigSettings } from '@grafana/data'; import {
import { config, getBackendSrv } from '@grafana/runtime'; AppEvents,
import { Button, InlineField, InlineFieldRow, JSONFormatter, RadioButtonGroup } from '@grafana/ui'; SelectableValue,
StandardEditorProps,
StandardEditorsRegistryItem,
StringFieldConfigSettings,
} from '@grafana/data';
import { BackendSrvRequest, config, getBackendSrv } from '@grafana/runtime';
import { Button, Field, InlineField, InlineFieldRow, JSONFormatter, RadioButtonGroup, Select } from '@grafana/ui';
import { StringValueEditor } from 'app/core/components/OptionsUI/string'; import { StringValueEditor } from 'app/core/components/OptionsUI/string';
import { appEvents } from 'app/core/core'; import { appEvents } from 'app/core/core';
import { defaultApiConfig } from 'app/features/canvas/elements/button'; import { defaultApiConfig } from 'app/features/canvas/elements/button';
@ -13,20 +19,36 @@ export interface APIEditorConfig {
method: string; method: string;
endpoint: string; endpoint: string;
data?: string; data?: string;
contentType?: string;
} }
const dummyStringSettings = { const dummyStringSettings = {
settings: {}, settings: {},
} as StandardEditorsRegistryItem<string, StringFieldConfigSettings>; } as StandardEditorsRegistryItem<string, StringFieldConfigSettings>;
export const callApi = (api: APIEditorConfig, isTest = false) => { const getRequest = (api: APIEditorConfig) => {
if (api && api.endpoint) { const requestHeaders: HeadersInit = [];
getBackendSrv()
.fetch({ let request: BackendSrvRequest = {
url: api.endpoint, url: api.endpoint,
method: api.method, method: api.method,
data: getData(api), data: getData(api),
}) headers: requestHeaders,
};
if (api.method === HttpRequestMethod.POST) {
requestHeaders.push(['Content-Type', api.contentType!]);
}
request.headers = requestHeaders;
return request;
};
export const callApi = (api: APIEditorConfig, isTest = false) => {
if (api && api.endpoint) {
getBackendSrv()
.fetch(getRequest(api))
.subscribe({ .subscribe({
error: (error) => { error: (error) => {
if (isTest) { if (isTest) {
@ -59,6 +81,15 @@ const httpMethodOptions = [
{ label: HttpRequestMethod.POST, value: HttpRequestMethod.POST }, { label: HttpRequestMethod.POST, value: HttpRequestMethod.POST },
]; ];
const contentTypeOptions: SelectableValue[] = [
{ label: 'JSON', value: 'application/json' },
{ label: 'Text', value: 'text/plain' },
{ label: 'JavaScript', value: 'application/javascript' },
{ label: 'HTML', value: 'text/html' },
{ label: 'XML', value: 'application/XML' },
{ label: 'x-www-form-urlencoded', value: 'application/x-www-form-urlencoded' },
];
export function APIEditor({ value, context, onChange }: Props) { export function APIEditor({ value, context, onChange }: Props) {
const LABEL_WIDTH = 9; const LABEL_WIDTH = 9;
@ -96,6 +127,20 @@ export function APIEditor({ value, context, onChange }: Props) {
[onChange, value] [onChange, value]
); );
const onContentTypeChange = useCallback(
(contentType: SelectableValue<string>) => {
onChange({
...value,
contentType: contentType?.value,
});
},
[onChange, value]
);
const formatCreateLabel = (input: string) => {
return input;
};
const renderJSON = (data: string) => { const renderJSON = (data: string) => {
try { try {
const json = JSON.parse(data); const json = JSON.parse(data);
@ -124,12 +169,7 @@ export function APIEditor({ value, context, onChange }: Props) {
return config.disableSanitizeHtml ? ( return config.disableSanitizeHtml ? (
<> <>
<InlineFieldRow> <InlineFieldRow>
<InlineField label="Method" labelWidth={LABEL_WIDTH} grow={true}> <InlineField label="Endpoint" labelWidth={LABEL_WIDTH} grow={true}>
<RadioButtonGroup value={value?.method} options={httpMethodOptions} onChange={onMethodChange} fullWidth />
</InlineField>
</InlineFieldRow>
<InlineFieldRow>
<InlineField label={'Endpoint'} labelWidth={LABEL_WIDTH} grow={true}>
<StringValueEditor <StringValueEditor
context={context} context={context}
value={value?.endpoint} value={value?.endpoint}
@ -138,21 +178,40 @@ export function APIEditor({ value, context, onChange }: Props) {
/> />
</InlineField> </InlineField>
</InlineFieldRow> </InlineFieldRow>
{value?.method === HttpRequestMethod.POST && (
<InlineFieldRow> <InlineFieldRow>
<InlineField label={'Data'} labelWidth={LABEL_WIDTH} grow={true}> <InlineField label="Method" labelWidth={LABEL_WIDTH} grow={true}>
<RadioButtonGroup value={value?.method} options={httpMethodOptions} onChange={onMethodChange} fullWidth />
</InlineField>
</InlineFieldRow>
{value?.method === HttpRequestMethod.POST && (
<>
<Field label="Content-Type">
<Select
minMenuHeight={200}
options={contentTypeOptions}
allowCustomValue={true}
formatCreateLabel={formatCreateLabel}
value={value?.contentType}
onChange={onContentTypeChange}
/>
</Field>
{value?.contentType && (
<Field label="Payload">
<StringValueEditor <StringValueEditor
context={context} context={context}
value={value?.data ?? '{}'} value={value?.data ?? '{}'}
onChange={onDataChange} onChange={onDataChange}
item={dummyStringSettings} item={{ ...dummyStringSettings, settings: { useTextarea: true } }}
/> />
</InlineField> </Field>
</InlineFieldRow> )}
</>
)} )}
{renderTestAPIButton(value)} {renderTestAPIButton(value)}
<br /> <br />
{value?.method === HttpRequestMethod.POST && renderJSON(value?.data ?? '{}')} {value?.method === HttpRequestMethod.POST &&
value?.contentType === defaultApiConfig.contentType &&
renderJSON(value?.data ?? '{}')}
</> </>
) : ( ) : (
<>Must enable disableSanitizeHtml feature flag to access</> <>Must enable disableSanitizeHtml feature flag to access</>