[Feature] Save request body when switching to 'No Body' (#752) (#762)

* Save body when switching to No Body, restore on returning

* Hide body clearing warning when switching to no body

* Remove unused import

* Add tests
This commit is contained in:
Alan Seymour
2018-02-17 00:24:54 +08:00
committed by Gregory Schier
parent b3e4730718
commit c5b946c07c
6 changed files with 76 additions and 31 deletions

View File

@@ -120,6 +120,34 @@ describe('updateMimeType()', async () => {
expect(newRequest.body).toEqual({});
expect(newRequest.headers).toEqual([{name: 'content-tYPE', value: 'application/json'}]);
});
it('uses saved body when provided', async () => {
const request = await models.request.create({
name: 'My Request',
parentId: 'fld_1',
body: {
text: 'My Data'
}
});
expect(request).not.toBeNull();
const newRequest = await models.request.updateMimeType(request, 'application/json', false, {text: 'Saved Data'});
expect(newRequest.body.text).toEqual('Saved Data');
});
it('uses existing body when saved body not provided', async () => {
const request = await models.request.create({
name: 'My Request',
parentId: 'fld_1',
body: {
text: 'My Data'
}
});
expect(request).not.toBeNull();
const newRequest = await models.request.updateMimeType(request, 'application/json', false, {});
expect(newRequest.body.text).toEqual('My Data');
});
});
describe('migrate()', () => {

View File

@@ -12,7 +12,8 @@ export function init () {
previewMode: PREVIEW_MODE_FRIENDLY,
responseFilter: '',
responseFilterHistory: [],
activeResponseId: null
activeResponseId: null,
savedRequestBody: {}
};
}

View File

@@ -243,7 +243,8 @@ export function update (request: Request, patch: Object): Promise<Request> {
export function updateMimeType (
request: Request,
mimeType: string,
doCreate: boolean = false
doCreate: boolean = false,
savedBody: RequestBody = {}
): Promise<Request> {
let headers = request.headers ? [...request.headers] : [];
const contentTypeHeader = getContentTypeHeader(headers);
@@ -288,16 +289,20 @@ export function updateMimeType (
let body;
const oldBody = Object.keys(savedBody).length === 0
? request.body
: savedBody;
if (mimeType === CONTENT_TYPE_FORM_URLENCODED) {
// Urlencoded
body = request.body.params
? newBodyFormUrlEncoded(request.body.params)
: newBodyFormUrlEncoded(deconstructQueryStringToParams(request.body.text));
body = oldBody.params
? newBodyFormUrlEncoded(oldBody.params)
: newBodyFormUrlEncoded(deconstructQueryStringToParams(oldBody.text));
} else if (mimeType === CONTENT_TYPE_FORM_DATA) {
// Form Data
body = request.body.params
? newBodyForm(request.body.params)
: newBodyForm(deconstructQueryStringToParams(request.body.text));
body = oldBody.params
? newBodyForm(oldBody.params)
: newBodyForm(deconstructQueryStringToParams(oldBody.text));
} else if (mimeType === CONTENT_TYPE_FILE) {
// File
body = newBodyFile('');
@@ -305,15 +310,15 @@ export function updateMimeType (
if (contentTypeHeader) {
contentTypeHeader.value = CONTENT_TYPE_JSON;
}
body = newBodyRaw(request.body.text || '', CONTENT_TYPE_GRAPHQL);
body = newBodyRaw(oldBody.text || '', CONTENT_TYPE_GRAPHQL);
} else if (typeof mimeType !== 'string') {
// No body
body = newBodyNone();
} else {
// Raw Content-Type (ex: application/json)
body = request.body.params
? newBodyRaw(buildQueryStringFromParams(request.body.params, false), mimeType)
: newBodyRaw(request.body.text || '', mimeType);
body = oldBody.params
? newBodyRaw(buildQueryStringFromParams(oldBody.params, false), mimeType)
: newBodyRaw(oldBody.text || '', mimeType);
}
// ~~~~~~~~~~~~~~~~~~~~~~~~ //

View File

@@ -40,10 +40,9 @@ class ContentTypeDropdown extends React.PureComponent<Props> {
const willBeFile = mimeType === CONTENT_TYPE_FILE;
const willBeMultipart = mimeType === CONTENT_TYPE_FORM_DATA;
const willBeEmpty = typeof mimeType !== 'string';
const willBeGraphQL = mimeType === CONTENT_TYPE_GRAPHQL;
const willConvertToText = !willBeGraphQL && !willBeFile && !willBeMultipart && !willBeEmpty;
const willConvertToText = !willBeGraphQL && !willBeFile && !willBeMultipart;
const willPreserveText = willConvertToText && isText;
const willPreserveForm = isFormUrlEncoded && willBeMultipart;

View File

@@ -4,7 +4,6 @@ import type {Response} from '../../models/response';
import type {OAuth2Token} from '../../models/o-auth-2-token';
import type {Workspace} from '../../models/workspace';
import type {Request, RequestAuthentication, RequestBody, RequestHeader, RequestParameter} from '../../models/request';
import {updateMimeType} from '../../models/request';
import * as React from 'react';
import autobind from 'autobind-decorator';
@@ -82,6 +81,7 @@ type Props = {
handleSetRequestGroupCollapsed: Function,
handleSendRequestWithEnvironment: Function,
handleSendAndDownloadRequestWithEnvironment: Function,
handleUpdateRequestMimeType: Function,
// Properties
loadStartTime: number,
@@ -175,21 +175,6 @@ class Wrapper extends React.PureComponent<Props, State> {
}
// Special request updaters
async _handleUpdateRequestMimeType (mimeType: string): Promise<Request | null> {
if (!this.props.activeRequest) {
console.warn('Tried to update request mime-type when no active request');
return null;
}
const newRequest = await updateMimeType(this.props.activeRequest, mimeType);
// Force it to update, because other editor components (header editor)
// needs to change. Need to wait a delay so the next render can finish
setTimeout(this._forceRequestPaneRefresh, 300);
return newRequest;
}
_handleStartDragSidebar (e: Event): void {
e.preventDefault();
this.props.handleStartDragSidebar();
@@ -375,6 +360,7 @@ class Wrapper extends React.PureComponent<Props, State> {
handleGenerateCodeForActiveRequest,
handleGenerateCode,
handleCopyAsCurl,
handleUpdateRequestMimeType,
isLoading,
loadStartTime,
paneWidth,
@@ -599,7 +585,7 @@ class Wrapper extends React.PureComponent<Props, State> {
updateRequestParameters={this._handleUpdateRequestParameters}
updateRequestAuthentication={this._handleUpdateRequestAuthentication}
updateRequestHeaders={this._handleUpdateRequestHeaders}
updateRequestMimeType={this._handleUpdateRequestMimeType}
updateRequestMimeType={handleUpdateRequestMimeType}
updateSettingsShowPasswords={this._handleUpdateSettingsShowPasswords}
updateSettingsUseBulkHeaderEditor={this._handleUpdateSettingsUseBulkHeaderEditor}
forceRefreshCounter={this.state.forceRefreshKey}

View File

@@ -39,6 +39,7 @@ import ErrorBoundary from '../components/error-boundary';
import * as plugins from '../../plugins';
import * as templating from '../../templating/index';
import AskModal from '../components/modals/ask-modal';
import {updateMimeType} from '../../models/request';
@autobind
class App extends PureComponent {
@@ -356,6 +357,30 @@ class App extends PureComponent {
}, 2000);
}
async _handleUpdateRequestMimeType (mimeType) {
if (!this.props.activeRequest) {
console.warn('Tried to update request mime-type when no active request');
return null;
}
const requestMeta = await models.requestMeta.getByParentId(this.props.activeRequest._id);
const savedBody = requestMeta.savedRequestBody;
const saveValue = (typeof mimeType !== 'string') // Switched to No body
? this.props.activeRequest.body
: {}; // Clear saved value in requestMeta
await models.requestMeta.update(requestMeta, {savedRequestBody: saveValue});
const newRequest = await updateMimeType(this.props.activeRequest, mimeType, false, savedBody);
// Force it to update, because other editor components (header editor)
// needs to change. Need to wait a delay so the next render can finish
setTimeout(this._forceRequestPaneRefresh, 300);
return newRequest;
}
async _handleSendAndDownloadRequestWithEnvironment (requestId, environmentId, dir) {
const request = await models.request.getById(requestId);
if (!request) {
@@ -856,6 +881,7 @@ class App extends PureComponent {
handleSetActiveEnvironment={this._handleSetActiveEnvironment}
handleSetSidebarFilter={this._handleSetSidebarFilter}
handleToggleMenuBar={this._handleToggleMenuBar}
handleUpdateRequestMimeType={this._handleUpdateRequestMimeType}
/>
</ErrorBoundary>