console: console support for actions response transform

PR-URL: https://github.com/hasura/graphql-engine-mono/pull/6455
Co-authored-by: Sooraj <8408875+soorajshankar@users.noreply.github.com>
GitOrigin-RevId: 82040e5a05c035f3319a94cfb6dd94acb5259505
This commit is contained in:
Varun Choudhary 2022-10-27 19:36:06 +05:30 committed by hasura-bot
parent 4589af44b4
commit bdf1aee641
10 changed files with 693 additions and 312 deletions

View File

@ -9,16 +9,20 @@ import {
KeyValuePair,
RequestTransformState,
RequestTransformStateBody,
ResponseTransformState,
ResponseTransformStateBody,
TransformationType,
} from './stateDefaults';
import RequestOptionsTransforms from './RequestOptionsTransforms';
import PayloadOptionsTransforms from './PayloadOptionsTransforms';
import SampleContextTransforms from './SampleContextTransforms';
import AddIcon from '../Icons/Add';
import ResponseTransforms from './ResponseTransform';
type ConfigureTransformationProps = {
transformationType: TransformationType;
state: RequestTransformState;
requestTransfromState: RequestTransformState;
responseTransformState?: ResponseTransformState;
resetSampleInput: () => void;
envVarsOnChange: (envVars: KeyValuePair[]) => void;
sessionVarsOnChange: (sessionVars: KeyValuePair[]) => void;
@ -33,187 +37,241 @@ type ConfigureTransformationProps = {
) => void;
requestUrlTransformOnChange: (data: boolean) => void;
requestPayloadTransformOnChange: (data: boolean) => void;
responsePayloadTransformOnChange?: (data: boolean) => void;
responseBodyOnChange?: (responseBody: ResponseTransformStateBody) => void;
};
const ConfigureTransformation: React.FC<ConfigureTransformationProps> = ({
transformationType,
state,
resetSampleInput,
envVarsOnChange,
sessionVarsOnChange,
requestMethodOnChange,
requestUrlOnChange,
requestQueryParamsOnChange,
requestAddHeadersOnChange,
requestBodyOnChange,
requestSampleInputOnChange,
requestUrlTransformOnChange,
requestPayloadTransformOnChange,
}) => {
const {
envVars,
sessionVars,
requestMethod,
requestUrl,
requestUrlError,
requestUrlPreview,
requestQueryParams,
requestAddHeaders,
requestBody,
requestBodyError,
requestSampleInput,
requestTransformedBody,
isRequestUrlTransform,
isRequestPayloadTransform,
} = state;
const ConfigureTransformation: React.FC<ConfigureTransformationProps> =
props => {
const {
transformationType,
requestTransfromState,
responseTransformState,
resetSampleInput,
envVarsOnChange,
sessionVarsOnChange,
requestMethodOnChange,
requestUrlOnChange,
requestQueryParamsOnChange,
requestAddHeadersOnChange,
requestBodyOnChange,
requestSampleInputOnChange,
requestUrlTransformOnChange,
requestPayloadTransformOnChange,
responsePayloadTransformOnChange,
responseBodyOnChange,
} = props;
const {
envVars,
sessionVars,
requestMethod,
requestUrl,
requestUrlError,
requestUrlPreview,
requestQueryParams,
requestAddHeaders,
requestBody,
requestBodyError,
requestSampleInput,
requestTransformedBody,
isRequestUrlTransform,
isRequestPayloadTransform,
} = requestTransfromState;
const [isContextAreaActive, toggleContextArea] = useState<boolean>(false);
const [isContextAreaActive, toggleContextArea] = useState<boolean>(false);
const contextAreaText = isContextAreaActive
? `Hide Sample Context`
: `Show Sample Context`;
const contextAreaText = isContextAreaActive
? `Hide Sample Context`
: `Show Sample Context`;
const requestUrlTransformText = isRequestUrlTransform
? `Remove Request Options Transform`
: `Add Request Options Transform`;
const requestUrlTransformText = isRequestUrlTransform
? `Remove Request Options Transform`
: `Add Request Options Transform`;
const requestPayloadTransformText = isRequestPayloadTransform
? `Remove Payload Transform`
: `Add Payload Transform`;
const requestPayloadTransformText = isRequestPayloadTransform
? `Remove Payload Transform`
: `Add Payload Transform`;
const responsePayloadTransformText =
responseTransformState?.isResponsePayloadTransform
? `Remove Response Transform`
: `Add Response Transform`;
return (
<>
<h2 className="text-lg font-semibold mb-sm flex items-center">
Configure REST Connectors
</h2>
return (
<>
<h2 className="text-lg font-semibold mb-sm flex items-center">
Configure REST Connectors
</h2>
<div className="mb-lg">
<label className="block text-gray-600 font-medium mb-xs">
Sample Context
</label>
<p className="text-sm text-gray-600 mb-sm">
Add sample env vars and session vars for testing the connector
</p>
<Analytics
name={
isContextAreaActive
? 'actions-tab-hide-sample-context-button'
: 'actions-tab-show-sample-context-button'
}
passHtmlAttributesToChildren
>
<Button
color="white"
size="sm"
data-test="toggle-context-area"
onClick={() => {
toggleContextArea(!isContextAreaActive);
}}
<div className="mb-lg">
<label className="block text-gray-600 font-medium mb-xs">
Sample Context
</label>
<p className="text-sm text-gray-600 mb-sm">
Add sample env vars and session vars for testing the connector
</p>
<Analytics
name={
isContextAreaActive
? 'actions-tab-hide-sample-context-button'
: 'actions-tab-show-sample-context-button'
}
passHtmlAttributesToChildren
>
{!isContextAreaActive ? <AddIcon /> : null}
{contextAreaText}
</Button>
</Analytics>
<Button
color="white"
size="sm"
data-test="toggle-context-area"
onClick={() => {
toggleContextArea(!isContextAreaActive);
}}
>
{!isContextAreaActive ? <AddIcon /> : null}
{contextAreaText}
</Button>
</Analytics>
{isContextAreaActive ? (
<SampleContextTransforms
transformationType={transformationType}
envVars={envVars}
sessionVars={sessionVars}
envVarsOnChange={envVarsOnChange}
sessionVarsOnChange={sessionVarsOnChange}
/>
) : null}
</div>
{isContextAreaActive ? (
<SampleContextTransforms
transformationType={transformationType}
envVars={envVars}
sessionVars={sessionVars}
envVarsOnChange={envVarsOnChange}
sessionVarsOnChange={sessionVarsOnChange}
/>
) : null}
</div>
<div className="mb-lg">
<label className="block text-gray-600 font-medium mb-xs">
Change Request Options
</label>
<p className="text-sm text-gray-600 mb-sm">
Change the method and URL to adapt to your API&apos;s expected format.
</p>
<Analytics
name={
isRequestUrlTransform
? 'actions-tab-hide-request-transform-button'
: 'actions-tab-show-request-transform-button'
}
passHtmlAttributesToChildren
>
<Button
size="sm"
icon={!isRequestUrlTransform ? <AddIcon /> : undefined}
iconPosition="start"
data-test="toggle-request-transform"
onClick={() => {
requestUrlTransformOnChange(!isRequestUrlTransform);
resetSampleInput();
}}
<div className="mb-lg">
<label className="block text-gray-600 font-medium mb-xs">
Change Request Options
</label>
<p className="text-sm text-gray-600 mb-sm">
Change the method and URL to adapt to your API&apos;s expected
format.
</p>
<Analytics
name={
isRequestUrlTransform
? 'actions-tab-hide-request-transform-button'
: 'actions-tab-show-request-transform-button'
}
passHtmlAttributesToChildren
>
{requestUrlTransformText}
</Button>
</Analytics>
<Button
size="sm"
icon={!isRequestUrlTransform ? <AddIcon /> : undefined}
iconPosition="start"
data-test="toggle-request-transform"
onClick={() => {
requestUrlTransformOnChange(!isRequestUrlTransform);
resetSampleInput();
}}
>
{requestUrlTransformText}
</Button>
</Analytics>
{isRequestUrlTransform ? (
<RequestOptionsTransforms
requestMethod={requestMethod}
requestUrl={requestUrl}
requestUrlError={requestUrlError}
requestUrlPreview={requestUrlPreview}
requestQueryParams={requestQueryParams}
requestAddHeaders={requestAddHeaders}
requestMethodOnChange={requestMethodOnChange}
requestUrlOnChange={requestUrlOnChange}
requestQueryParamsOnChange={requestQueryParamsOnChange}
requestAddHeadersOnChange={requestAddHeadersOnChange}
/>
) : null}
</div>
{isRequestUrlTransform ? (
<RequestOptionsTransforms
requestMethod={requestMethod}
requestUrl={requestUrl}
requestUrlError={requestUrlError}
requestUrlPreview={requestUrlPreview}
requestQueryParams={requestQueryParams}
requestAddHeaders={requestAddHeaders}
requestMethodOnChange={requestMethodOnChange}
requestUrlOnChange={requestUrlOnChange}
requestQueryParamsOnChange={requestQueryParamsOnChange}
requestAddHeadersOnChange={requestAddHeadersOnChange}
/>
) : null}
</div>
<div className="mb-lg">
<label className="block text-gray-600 font-medium mb-xs">
Change Payload
</label>
<p className="text-sm text-gray-600 mb-sm">
Change the payload to adapt to your API&apos;s expected format.
</p>
<Analytics
name={
isRequestPayloadTransform
? 'actions-tab-hide-payload-transform-button'
: 'actions-tab-show-payload-transform-button'
}
passHtmlAttributesToChildren
>
<Button
color="white"
size="sm"
data-test="toggle-payload-transform"
onClick={() => {
requestPayloadTransformOnChange(!isRequestPayloadTransform);
resetSampleInput();
}}
<div className="mb-lg">
<label className="block text-gray-600 font-medium mb-xs">
Change Payload
</label>
<p className="text-sm text-gray-600 mb-sm">
Change the payload to adapt to your API&apos;s expected format.
</p>
<Analytics
name={
isRequestPayloadTransform
? 'actions-tab-hide-payload-transform-button'
: 'actions-tab-show-payload-transform-button'
}
passHtmlAttributesToChildren
>
{!isRequestPayloadTransform ? <AddIcon /> : null}
{requestPayloadTransformText}
</Button>
</Analytics>
{isRequestPayloadTransform ? (
<PayloadOptionsTransforms
transformationType={transformationType}
requestBody={requestBody}
requestBodyError={requestBodyError}
requestSampleInput={requestSampleInput}
requestTransformedBody={requestTransformedBody}
resetSampleInput={resetSampleInput}
requestBodyOnChange={requestBodyOnChange}
requestSampleInputOnChange={requestSampleInputOnChange}
/>
) : null}
</div>
</>
);
};
<Button
color="white"
size="sm"
data-test="toggle-payload-transform"
onClick={() => {
requestPayloadTransformOnChange(!isRequestPayloadTransform);
resetSampleInput();
}}
>
{!isRequestPayloadTransform ? <AddIcon /> : null}
{requestPayloadTransformText}
</Button>
</Analytics>
{isRequestPayloadTransform ? (
<PayloadOptionsTransforms
transformationType={transformationType}
requestBody={requestBody}
requestBodyError={requestBodyError}
requestSampleInput={requestSampleInput}
requestTransformedBody={requestTransformedBody}
resetSampleInput={resetSampleInput}
requestBodyOnChange={requestBodyOnChange}
requestSampleInputOnChange={requestSampleInputOnChange}
/>
) : null}
</div>
{responseTransformState && responsePayloadTransformOnChange && (
<div className="mb-lg">
<label className="block text-gray-600 font-medium mb-xs">
Change Response
</label>
<p className="text-sm text-gray-600 mb-sm">
Change the incoming response to adapt to your declared types.
</p>
<Analytics
name={
isRequestPayloadTransform
? 'actions-tab-hide-response-transform-button'
: 'actions-tab-show-response-transform-button'
}
passHtmlAttributesToChildren
>
<Button
color="white"
size="sm"
data-test="toggle-response-transform"
onClick={() => {
responsePayloadTransformOnChange(
!responseTransformState.isResponsePayloadTransform
);
resetSampleInput();
}}
>
{!responseTransformState.isResponsePayloadTransform ? (
<AddIcon />
) : null}
{responsePayloadTransformText}
</Button>
</Analytics>
{responseTransformState.isResponsePayloadTransform &&
responseBodyOnChange ? (
<ResponseTransforms
requestSampleInput={responseTransformState.responseSampleInput}
requestBody={responseTransformState.responseBody}
requestBodyError={responseTransformState.responseBodyError}
requestBodyOnChange={responseBodyOnChange}
/>
) : null}
</div>
)}
</>
);
};
export default ConfigureTransformation;

View File

@ -0,0 +1,101 @@
import React, { useRef } from 'react';
import { useDebouncedEffect } from '@/hooks/useDebounceEffect';
import CrossIcon from '../Icons/Cross';
import TemplateEditor from './CustomEditors/TemplateEditor';
import { editorDebounceTime } from './utils';
import NumberedSidebar from './CustomEditors/NumberedSidebar';
import { KeyValuePair, RequestTransformStateBody } from './stateDefaults';
import KeyValueInput from './CustomEditors/KeyValueInput';
import { isEmpty } from '../utils/jsUtils';
import { requestBodyActionState } from './requestTransformState';
type PayloadOptionsTransformsProps = {
requestBody: RequestTransformStateBody;
requestBodyError: string;
requestSampleInput: string;
requestBodyOnChange: (requestBody: RequestTransformStateBody) => void;
};
const ResponseTransforms: React.FC<PayloadOptionsTransformsProps> = ({
requestSampleInput,
requestBody,
requestBodyError,
requestBodyOnChange,
}) => {
const editorRef = useRef<any>();
const [localFormElements, setLocalFormElements] = React.useState<
KeyValuePair[]
>(requestBody.form_template ?? [{ name: '', value: '' }]);
React.useEffect(() => {
setLocalFormElements(
requestBody.form_template ?? [{ name: '', value: '' }]
);
}, [requestBody]);
useDebouncedEffect(
() => {
requestBodyOnChange({ ...requestBody, form_template: localFormElements });
},
editorDebounceTime,
[localFormElements]
);
if (editorRef?.current?.editor?.renderer?.$cursorLayer?.element?.style) {
editorRef.current.editor.renderer.$cursorLayer.element.style.display =
'none';
}
return (
<div
className="m-md pl-lg pr-sm border-l border-l-gray-400"
data-cy="Change Payload"
>
<div className="mb-md">
<NumberedSidebar
title="Configure Response Body"
description={
<span>
The template which will transform your response body into the
required specification. You can use{' '}
<code className="text-xs">&#123;&#123;$body&#125;&#125;</code> to
access the original response body
</span>
}
number="1"
/>
{requestBody.action ===
requestBodyActionState.transformApplicationJson ? (
<TemplateEditor
requestBody={requestBody}
requestBodyError={requestBodyError}
requestSampleInput={requestSampleInput}
requestBodyOnChange={requestBodyOnChange}
/>
) : null}
{requestBody.action ===
requestBodyActionState.transformFormUrlEncoded ? (
<>
{!isEmpty(requestBodyError) && (
<div className="mb-sm" data-test="transform-requestBody-error">
<CrossIcon />
<span className="text-red-500 ml-sm">{requestBodyError}</span>
</div>
)}
<div className="grid gap-3 grid-cols-3 mb-sm">
<KeyValueInput
pairs={localFormElements}
setPairs={setLocalFormElements}
testId="add-url-encoded-body"
/>
</div>
</>
) : null}
</div>
</div>
);
};
export default ResponseTransforms;

View File

@ -46,6 +46,18 @@ import {
defaultEventRequestBody,
defaultEventRequestSampleInput,
RequestTransformStateBody,
SET_RESPONSE_PAYLOAD_TRANSFORM,
SetResponsePayloadTransform,
ResponseTransformStateBody,
SET_RESPONSE_BODY,
SetResponseBody,
SET_RESPONSE_BODY_ERROR,
SetResponseBodyError,
ResponseTransformState,
ResponseTransformEvents,
SET_RESPONSE_TRANSFORM_STATE,
defaultActionResponseBody,
SetResponseTransformState,
} from './stateDefaults';
import { getSessionVarsFromLS, getEnvVarsFromLS } from './utils';
@ -108,6 +120,13 @@ export const setRequestBody = (
requestBody,
});
export const setResponseBody = (
responseBody: ResponseTransformStateBody
): SetResponseBody => ({
type: SET_RESPONSE_BODY,
responseBody,
});
export const setRequestBodyError = (
requestBodyError: string
): SetRequestBodyError => ({
@ -115,6 +134,13 @@ export const setRequestBodyError = (
requestBodyError,
});
export const setResponseBodyError = (
responseBodyError: string
): SetResponseBodyError => ({
type: SET_RESPONSE_BODY_ERROR,
responseBodyError,
});
export const setRequestSampleInput = (
requestSampleInput: string
): SetRequestSampleInput => ({
@ -150,6 +176,13 @@ export const setRequestPayloadTransform = (
isRequestPayloadTransform,
});
export const setResponsePayloadTransform = (
isResponsePayloadTransform: boolean
): SetResponsePayloadTransform => ({
type: SET_RESPONSE_PAYLOAD_TRANSFORM,
isResponsePayloadTransform,
});
export const setRequestTransformState = (
newState: RequestTransformState
): SetRequestTransformState => ({
@ -157,6 +190,13 @@ export const setRequestTransformState = (
newState,
});
export const setResponseTransformState = (
newState: ResponseTransformState
): SetResponseTransformState => ({
type: SET_RESPONSE_TRANSFORM_STATE,
newState,
});
const currentVersion = 2;
export const requestBodyActionState = {
@ -166,6 +206,10 @@ export const requestBodyActionState = {
'x_www_form_urlencoded' as RequestTransformBodyActions,
};
export const responseBodyActionState = {
transformApplicationJson: 'transform' as RequestTransformBodyActions,
};
export const requestTransformState: RequestTransformState = {
version: currentVersion,
envVars: [],
@ -186,6 +230,15 @@ export const requestTransformState: RequestTransformState = {
templatingEngine: 'Kriti',
};
export const responseTransformState: ResponseTransformState = {
version: currentVersion,
isResponsePayloadTransform: false,
responseSampleInput: '',
responseBody: { action: responseBodyActionState.transformApplicationJson },
responseBodyError: '',
templatingEngine: 'Kriti',
};
export const getActionRequestTransformDefaultState =
(): RequestTransformState => {
return {
@ -203,6 +256,19 @@ export const getActionRequestTransformDefaultState =
};
};
export const getActionResponseTransformDefaultState =
(): ResponseTransformState => {
return {
...responseTransformState,
responseBody: {
action: responseBodyActionState.transformApplicationJson,
template: defaultActionResponseBody,
form_template: [{ name: 'name', value: '{{$body.action.name}}' }],
},
responseSampleInput: defaultActionRequestSampleInput,
};
};
export const getEventRequestTransformDefaultState =
(): RequestTransformState => {
return {
@ -311,3 +377,32 @@ export const requestTransformReducer = (
return state;
}
};
export const responseTransformReducer = (
state = responseTransformState,
action: ResponseTransformEvents
): ResponseTransformState => {
switch (action.type) {
case SET_RESPONSE_BODY:
return {
...state,
responseBody: action.responseBody,
};
case SET_RESPONSE_BODY_ERROR:
return {
...state,
responseBodyError: action.responseBodyError,
};
case SET_RESPONSE_PAYLOAD_TRANSFORM:
return {
...state,
isResponsePayloadTransform: action.isResponsePayloadTransform,
};
case SET_RESPONSE_TRANSFORM_STATE:
return {
...action.newState,
};
default:
return state;
}
};

View File

@ -10,6 +10,7 @@ import {
RequestTransformContentType,
RequestTransformTemplateEngine,
RequestTransformBody,
ResponseTransformBody,
} from '../../../metadata/types';
import { Nullable } from '../utils/tsUtils';
@ -40,6 +41,13 @@ export const SET_REQUEST_PAYLOAD_TRANSFORM =
'RequestTransform/SET_REQUEST_PAYLOAD_TRANSFORM';
export const SET_REQUEST_TRANSFORM_STATE =
'RequestTransform/SET_REQUEST_TRANSFORM_STATE';
export const SET_RESPONSE_BODY = 'ResponseTransform/SET_RESPONSE_BODY';
export const SET_RESPONSE_BODY_ERROR =
'ResponseTransform/SET_RESPONSE_BODY_ERROR';
export const SET_RESPONSE_PAYLOAD_TRANSFORM =
'ResponseTransform/SET_RESPONSE_PAYLOAD_TRANSFORM';
export const SET_RESPONSE_TRANSFORM_STATE =
'RequestTransform/SET_REQUEST_TRANSFORM_STATE';
export interface SetEnvVars extends ReduxAction {
type: typeof SET_ENV_VARS;
@ -86,11 +94,21 @@ export interface SetRequestBody extends ReduxAction {
requestBody: RequestTransformStateBody;
}
export interface SetResponseBody extends ReduxAction {
type: typeof SET_RESPONSE_BODY;
responseBody: ResponseTransformStateBody;
}
export interface SetRequestBodyError extends ReduxAction {
type: typeof SET_REQUEST_BODY_ERROR;
requestBodyError: string;
}
export interface SetResponseBodyError extends ReduxAction {
type: typeof SET_RESPONSE_BODY_ERROR;
responseBodyError: string;
}
export interface SetRequestSampleInput extends ReduxAction {
type: typeof SET_REQUEST_SAMPLE_INPUT;
requestSampleInput: string;
@ -116,11 +134,21 @@ export interface SetRequestPayloadTransform extends ReduxAction {
isRequestPayloadTransform: boolean;
}
export interface SetResponsePayloadTransform extends ReduxAction {
type: typeof SET_RESPONSE_PAYLOAD_TRANSFORM;
isResponsePayloadTransform: boolean;
}
export interface SetRequestTransformState extends ReduxAction {
type: typeof SET_REQUEST_TRANSFORM_STATE;
newState: RequestTransformState;
}
export interface SetResponseTransformState extends ReduxAction {
type: typeof SET_RESPONSE_TRANSFORM_STATE;
newState: ResponseTransformState;
}
export type RequestTransformEvents =
| SetEnvVars
| SetSessionVars
@ -139,6 +167,12 @@ export type RequestTransformEvents =
| SetRequestPayloadTransform
| SetRequestTransformState;
export type ResponseTransformEvents =
| SetResponseBody
| SetResponseBodyError
| SetResponsePayloadTransform
| SetResponseTransformState;
export type RequestTransformState = {
version: 1 | 2;
envVars: KeyValuePair[];
@ -161,8 +195,11 @@ export type RequestTransformState = {
export type ResponseTransformState = {
version: 1 | 2;
requestBody: RequestTransformStateBody;
templatingEngine: RequestTransformTemplateEngine;
isResponsePayloadTransform: boolean;
responseSampleInput: string;
responseBody: ResponseTransformStateBody;
responseBodyError: string;
};
export type RequestTransformStateBody = Omit<
@ -170,6 +207,11 @@ export type RequestTransformStateBody = Omit<
'form_template'
> & { form_template?: KeyValuePair[] };
export type ResponseTransformStateBody = Omit<
ResponseTransformBody,
'form_template'
> & { form_template?: KeyValuePair[] };
export type KeyValuePair = {
name: string;
value: string;
@ -199,6 +241,10 @@ export const defaultActionRequestBody = `{
}
}`;
export const defaultActionResponseBody = `{
"response": {{$body}},
}`;
export const defaultEventRequestBody = `{
"table": {
"name": {{$body.table.name}},

View File

@ -12,10 +12,14 @@ import {
RequestTransformState,
RequestTransformStateBody,
ResponseTransformState,
ResponseTransformStateBody,
} from './stateDefaults';
import { isEmpty, isJsonString } from '../utils/jsUtils';
import { Nullable } from '../utils/tsUtils';
import { requestBodyActionState } from './requestTransformState';
import {
requestBodyActionState,
responseBodyActionState,
} from './requestTransformState';
export const getPairsObjFromArray = (
pairs: KeyValuePair[]
@ -177,12 +181,21 @@ export const getRequestTransformObject = (
};
export const getResponseTransformObject = (
transformState: ResponseTransformState
): ResponseTranform => ({
version: 2,
body: getTransformBodyServer(transformState.requestBody),
template_engine: transformState.templatingEngine,
});
responseTransformState: ResponseTransformState
) => {
const isResponsePayloadTransform =
responseTransformState.isResponsePayloadTransform;
if (!isResponsePayloadTransform) return null;
const obj: ResponseTranform = {
version: 2,
body: getTransformBodyServer(responseTransformState.responseBody),
template_engine: responseTransformState.templatingEngine,
};
return obj;
};
const getErrorFromCode = (data: Record<string, any>) => {
const errorCode = data.code ? data.code : '';
@ -439,6 +452,15 @@ const getRequestTransformBody = (
};
};
const getResponseTransformBody = (
responseTransform: ResponseTranform
): ResponseTransformStateBody => {
return {
action: responseBodyActionState.transformApplicationJson,
template: responseTransform.body?.template ?? '',
};
};
export const getTransformState = (
transform: RequestTransform,
sampleInput: string
@ -469,6 +491,17 @@ export const getTransformState = (
templatingEngine: transform?.template_engine ?? 'Kriti',
});
export const getResponseTransformState = (
responseTransform: ResponseTranform
): ResponseTransformState => ({
version: responseTransform?.version,
templatingEngine: responseTransform?.template_engine ?? 'Kriti',
isResponsePayloadTransform: !!responseTransform?.body,
responseBody: getResponseTransformBody(responseTransform),
responseSampleInput: '',
responseBodyError: '',
});
export const capitaliseFirstLetter = (val: string) =>
`${val[0].toUpperCase()}${val.slice(1)}`;

View File

@ -29,6 +29,10 @@ import {
setRequestContentType,
setRequestUrlTransform,
setRequestPayloadTransform,
setResponsePayloadTransform,
setResponseBody,
responseTransformReducer,
getActionResponseTransformDefaultState,
} from '@/components/Common/ConfigureTransformation/requestTransformState';
import {
RequestTransformContentType,
@ -37,6 +41,7 @@ import {
import {
KeyValuePair,
RequestTransformStateBody,
ResponseTransformStateBody,
} from '@/components/Common/ConfigureTransformation/stateDefaults';
import ConfigureTransformation from '@/components/Common/ConfigureTransformation/ConfigureTransformation';
import ActionEditor from '../Common/components/ActionEditor';
@ -82,6 +87,11 @@ const AddAction: React.FC<AddActionProps> = ({
getActionRequestTransformDefaultState()
);
const [responseTransformState, responseTransformDispatch] = useReducer(
responseTransformReducer,
getActionResponseTransformDefaultState()
);
useEffect(() => {
if (readOnlyMode)
dispatch(
@ -120,7 +130,7 @@ const AddAction: React.FC<AddActionProps> = ({
} = actionDefinition;
const onSubmit = () => {
dispatch(createAction(transformState));
dispatch(createAction(transformState, responseTransformState));
};
const setHeaders = (hs: Header[]) => {
@ -222,6 +232,14 @@ const AddAction: React.FC<AddActionProps> = ({
transformDispatch(setRequestPayloadTransform(data));
};
const responsePayloadTransformOnChange = (data: boolean) => {
responseTransformDispatch(setResponsePayloadTransform(data));
};
const responseBodyOnChange = (responseBody: ResponseTransformStateBody) => {
responseTransformDispatch(setResponseBody(responseBody));
};
// we send separate requests for the `url` preview and `body` preview, as in case of error,
// we will not be able to resolve if the error is with url or body transform, with the current state of `test_webhook_transform` api
useEffect(() => {
@ -357,7 +375,8 @@ const AddAction: React.FC<AddActionProps> = ({
<ConfigureTransformation
transformationType="action"
state={transformState}
requestTransfromState={transformState}
responseTransformState={responseTransformState}
resetSampleInput={resetSampleInput}
envVarsOnChange={envVarsOnChange}
sessionVarsOnChange={sessionVarsOnChange}
@ -370,6 +389,8 @@ const AddAction: React.FC<AddActionProps> = ({
requestContentTypeOnChange={requestContentTypeOnChange}
requestUrlTransformOnChange={requestUrlTransformOnChange}
requestPayloadTransformOnChange={requestPayloadTransformOnChange}
responsePayloadTransformOnChange={responsePayloadTransformOnChange}
responseBodyOnChange={responseBodyOnChange}
/>
<div>

View File

@ -12,6 +12,7 @@ import {
parseValidateApiData,
getValidateTransformOptions,
getTransformState,
getResponseTransformState,
} from '@/components/Common/ConfigureTransformation/utils';
import { Button } from '@/new-components/Button';
import requestAction from '@/utils/requestAction';
@ -34,10 +35,16 @@ import {
setRequestUrlTransform,
setRequestPayloadTransform,
setRequestTransformState,
responseTransformReducer,
getActionResponseTransformDefaultState,
setResponsePayloadTransform,
setResponseBody,
setResponseTransformState,
} from '@/components/Common/ConfigureTransformation/requestTransformState';
import {
KeyValuePair,
RequestTransformStateBody,
ResponseTransformStateBody,
} from '@/components/Common/ConfigureTransformation/stateDefaults';
import {
RequestTransformContentType,
@ -106,6 +113,11 @@ const ModifyAction: React.FC<ModifyProps> = ({
getActionRequestTransformDefaultState()
);
const [responseTransformState, responseTransformDispatch] = useReducer(
responseTransformReducer,
getActionResponseTransformDefaultState()
);
// initialize action state
const init = () => {
const modifyState = getModifyState(currentAction, allTypes);
@ -128,6 +140,16 @@ const ModifyAction: React.FC<ModifyProps> = ({
setRequestTransformState(getActionRequestTransformDefaultState())
);
}
if (currentAction?.definition?.response_transform) {
const responseState = getResponseTransformState(
currentAction?.definition?.response_transform
);
responseTransformDispatch(setResponseTransformState(responseState));
} else {
responseTransformDispatch(
setResponseTransformState(getActionResponseTransformDefaultState())
);
}
};
useEffect(init, [currentAction, allTypes, dispatch]);
@ -155,9 +177,8 @@ const ModifyAction: React.FC<ModifyProps> = ({
) => {
dispatch(setTypeDefinition(value, error as any, timer, ast));
};
const onSave = () => {
dispatch(saveAction(currentAction, transformState));
dispatch(saveAction(currentAction, transformState, responseTransformState));
};
const onDelete = () => {
@ -245,6 +266,14 @@ const ModifyAction: React.FC<ModifyProps> = ({
transformDispatch(setRequestPayloadTransform(data));
};
const responsePayloadTransformOnChange = (data: boolean) => {
responseTransformDispatch(setResponsePayloadTransform(data));
};
const responseBodyOnChange = (responseBody: ResponseTransformStateBody) => {
responseTransformDispatch(setResponseBody(responseBody));
};
useEffect(() => {
requestUrlErrorOnChange('');
requestUrlPreviewOnChange('');
@ -405,7 +434,8 @@ const ModifyAction: React.FC<ModifyProps> = ({
<ConfigureTransformation
transformationType="action"
state={transformState}
requestTransfromState={transformState}
responseTransformState={responseTransformState}
resetSampleInput={resetSampleInput}
envVarsOnChange={envVarsOnChange}
sessionVarsOnChange={sessionVarsOnChange}
@ -418,6 +448,10 @@ const ModifyAction: React.FC<ModifyProps> = ({
requestContentTypeOnChange={requestContentTypeOnChange}
requestUrlTransformOnChange={requestUrlTransformOnChange}
requestPayloadTransformOnChange={requestPayloadTransformOnChange}
responsePayloadTransformOnChange={
responsePayloadTransformOnChange
}
responseBodyOnChange={responseBodyOnChange}
/>
<div className="flex items-start mb-lg">

View File

@ -64,141 +64,139 @@ import {
getResponseTransformObject,
} from '../../Common/ConfigureTransformation/utils';
export const createAction = transformState => (dispatch, getState) => {
const { add: rawState } = getState().actions;
const existingTypesList = customTypesSelector(getState());
const allActions = actionsSelector(getState());
export const createAction =
(transformState, responseTransformState) => (dispatch, getState) => {
const { add: rawState } = getState().actions;
const existingTypesList = customTypesSelector(getState());
const allActions = actionsSelector(getState());
const actionComment = rawState.comment ? rawState.comment.trim() : null;
const actionComment = rawState.comment ? rawState.comment.trim() : null;
const {
name: actionName,
arguments: args,
outputType,
error: actionDefError,
type: actionType,
} = getActionDefinitionFromSdl(rawState.actionDefinition.sdl);
if (actionDefError) {
return dispatch(
showErrorNotification('Invalid Action Definition', actionDefError)
const {
name: actionName,
arguments: args,
outputType,
error: actionDefError,
type: actionType,
} = getActionDefinitionFromSdl(rawState.actionDefinition.sdl);
if (actionDefError) {
return dispatch(
showErrorNotification('Invalid Action Definition', actionDefError)
);
}
const { types, error: typeDefError } = getTypesFromSdl(
rawState.typeDefinition.sdl
);
}
const { types, error: typeDefError } = getTypesFromSdl(
rawState.typeDefinition.sdl
);
if (typeDefError) {
return dispatch(
showErrorNotification('Invalid Types Definition', typeDefError)
);
}
if (typeDefError) {
return dispatch(
showErrorNotification('Invalid Types Definition', typeDefError)
const state = {
handler: rawState.handler.trim(),
kind: rawState.kind,
types,
actionType,
name: actionName,
arguments: args,
outputType,
headers: rawState.headers,
comment: actionComment,
timeout: parseInt(rawState.timeout, 10),
};
const requestTransform = getRequestTransformObject(transformState);
const responseTransform = getResponseTransformObject(
responseTransformState
);
}
const validationError = getStateValidationError(state, existingTypesList);
if (validationError) {
return dispatch(showErrorNotification(validationError));
}
const state = {
handler: rawState.handler.trim(),
kind: rawState.kind,
types,
actionType,
name: actionName,
arguments: args,
outputType,
headers: rawState.headers,
comment: actionComment,
timeout: parseInt(rawState.timeout, 10),
};
const typesWithRelationships = hydrateTypeRelationships(
state.types,
existingTypesList
);
const requestTransform = getRequestTransformObject(transformState);
const { types: mergedTypes, overlappingTypenames } = mergeCustomTypes(
typesWithRelationships,
existingTypesList
);
const validationError = getStateValidationError(state, existingTypesList);
if (validationError) {
return dispatch(showErrorNotification(validationError));
}
if (overlappingTypenames) {
const isOk = getOverlappingTypeConfirmation(
state.name,
allActions,
existingTypesList,
overlappingTypenames
);
if (!isOk) {
return;
}
}
// Migration queries start
const migration = new Migration();
const typesWithRelationships = hydrateTypeRelationships(
state.types,
existingTypesList
);
const customFieldsQueryUp = generateSetCustomTypesQuery(
reformCustomTypes(mergedTypes)
);
const { types: mergedTypes, overlappingTypenames } = mergeCustomTypes(
typesWithRelationships,
existingTypesList
);
const customFieldsQueryDown = generateSetCustomTypesQuery(
reformCustomTypes(existingTypesList)
);
migration.add(customFieldsQueryUp, customFieldsQueryDown);
if (overlappingTypenames) {
const isOk = getOverlappingTypeConfirmation(
const actionQueryUp = generateCreateActionQuery(
state.name,
allActions,
existingTypesList,
overlappingTypenames
generateActionDefinition(state, requestTransform, responseTransform),
actionComment
);
if (!isOk) {
return;
}
}
// Migration queries start
const migration = new Migration();
const customFieldsQueryUp = generateSetCustomTypesQuery(
reformCustomTypes(mergedTypes)
);
const actionQueryDown = generateDropActionQuery(state.name);
const customFieldsQueryDown = generateSetCustomTypesQuery(
reformCustomTypes(existingTypesList)
);
migration.add(customFieldsQueryUp, customFieldsQueryDown);
migration.add(actionQueryUp, actionQueryDown);
// Migration queries end
const actionQueryUp = requestTransform
? generateCreateActionQuery(
state.name,
generateActionDefinition(state, requestTransform),
actionComment
)
: generateCreateActionQuery(
state.name,
generateActionDefinition(state),
actionComment
);
const actionQueryDown = generateDropActionQuery(state.name);
migration.add(actionQueryUp, actionQueryDown);
// Migration queries end
const migrationName = `create_action_${state.name}`;
const requestMsg = 'Creating action...';
const successMsg = 'Created action successfully';
const errorMsg = 'Creating action failed';
const customOnSuccess = () => {
if (rawState.derive.operation) {
persistDerivedAction(state.name, rawState.derive.operation);
}
dispatch(exportMetadata()).then(() => {
const migrationName = `create_action_${state.name}`;
const requestMsg = 'Creating action...';
const successMsg = 'Created action successfully';
const errorMsg = 'Creating action failed';
const customOnSuccess = () => {
if (rawState.derive.operation) {
persistDerivedAction(state.name, rawState.derive.operation);
}
dispatch(exportMetadata()).then(() => {
dispatch(createActionRequestComplete());
dispatch(
push(`${globals.urlPrefix}${appPrefix}/manage/${state.name}/modify`)
);
});
};
const customOnError = () => {
dispatch(createActionRequestComplete());
dispatch(
push(`${globals.urlPrefix}${appPrefix}/manage/${state.name}/modify`)
);
});
};
dispatch(createActionRequestInProgress());
makeMigrationCall(
dispatch,
getState,
migration.upMigration,
migration.downMigration,
migrationName,
customOnSuccess,
customOnError,
requestMsg,
successMsg,
errorMsg
);
};
const customOnError = () => {
dispatch(createActionRequestComplete());
};
dispatch(createActionRequestInProgress());
makeMigrationCall(
dispatch,
getState,
migration.upMigration,
migration.downMigration,
migrationName,
customOnSuccess,
customOnError,
requestMsg,
successMsg,
errorMsg
);
};
export const saveAction =
(currentAction, transformState) => (dispatch, getState) => {
(currentAction, transformState, responseTransformState) =>
(dispatch, getState) => {
const { modify: rawState } = getState().actions;
const existingTypesList = customTypesSelector(getState());
const {
@ -241,7 +239,9 @@ export const saveAction =
};
const requestTransform = getRequestTransformObject(transformState);
const responseTransform = getResponseTransformObject(transformState);
const responseTransform = getResponseTransformObject(
responseTransformState
);
const validationError = getStateValidationError(state);
if (validationError) {
@ -269,7 +269,6 @@ export const saveAction =
);
const dropCurrentActionQuery = generateDropActionQuery(currentAction.name);
const updateCurrentActionQuery = getUpdateActionQuery(
generateActionDefinition(state, requestTransform, responseTransform),
currentAction.name,
@ -281,17 +280,11 @@ export const saveAction =
currentAction.comment
);
const createNewActionQuery = requestTransform
? generateCreateActionQuery(
state.name,
generateActionDefinition(state, requestTransform),
actionComment
)
: generateCreateActionQuery(
state.name,
generateActionDefinition(state),
actionComment
);
const createNewActionQuery = generateCreateActionQuery(
state.name,
generateActionDefinition(state, requestTransform, responseTransform),
actionComment
);
const actionQueryDown = generateDropActionQuery(state.name);
const oldActionQueryUp = generateCreateActionQuery(

View File

@ -374,7 +374,7 @@ const Add: React.FC<Props> = props => {
/>
<ConfigureTransformation
transformationType="event"
state={transformState}
requestTransfromState={transformState}
resetSampleInput={resetSampleInput}
envVarsOnChange={envVarsOnChange}
sessionVarsOnChange={sessionVarsOnChange}

View File

@ -388,7 +388,7 @@ const Modify: React.FC<Props> = props => {
/>
<ConfigureTransformation
transformationType="event"
state={transformState}
requestTransfromState={transformState}
resetSampleInput={resetSampleInput}
envVarsOnChange={envVarsOnChange}
sessionVarsOnChange={sessionVarsOnChange}