mirror of
https://github.com/Kong/insomnia
synced 2024-11-08 06:39:48 +00:00
response pane class->fc (#4982)
* first pass * remove old * remove delete drill prop * remove two more drills * two more drills * remove one drill * constify * two more drills * remove preview mode get/set drills * undrill exportAsHAR * undrill debug response download * undrill prettify option * save ipc for next pass * fix delete response * make delete function uniform * address feedback comments
This commit is contained in:
parent
4d82d4ddb7
commit
ac166158c8
@ -1,6 +1,12 @@
|
||||
import fs from 'fs';
|
||||
import React, { FC, useCallback } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
|
||||
import { getPreviewModeName, PREVIEW_MODES, PreviewMode } from '../../../common/constants';
|
||||
import { exportHarCurrentRequest } from '../../../common/har';
|
||||
import * as models from '../../../models';
|
||||
import { isRequest } from '../../../models/request';
|
||||
import { selectActiveRequest, selectActiveResponse, selectResponsePreviewMode } from '../../redux/selectors';
|
||||
import { Dropdown } from '../base/dropdown/dropdown';
|
||||
import { DropdownButton } from '../base/dropdown/dropdown-button';
|
||||
import { DropdownDivider } from '../base/dropdown/dropdown-divider';
|
||||
@ -8,39 +14,85 @@ import { DropdownItem } from '../base/dropdown/dropdown-item';
|
||||
|
||||
interface Props {
|
||||
download: (pretty: boolean) => any;
|
||||
fullDownload: (pretty: boolean) => any;
|
||||
exportAsHAR: () => void;
|
||||
copyToClipboard: () => any;
|
||||
updatePreviewMode: Function;
|
||||
previewMode: PreviewMode;
|
||||
showPrettifyOption?: boolean;
|
||||
}
|
||||
|
||||
export const PreviewModeDropdown: FC<Props> = ({
|
||||
fullDownload,
|
||||
previewMode,
|
||||
showPrettifyOption,
|
||||
download,
|
||||
copyToClipboard,
|
||||
exportAsHAR,
|
||||
updatePreviewMode,
|
||||
}) => {
|
||||
const request = useSelector(selectActiveRequest);
|
||||
const previewMode = useSelector(selectResponsePreviewMode);
|
||||
const response = useSelector(selectActiveResponse);
|
||||
|
||||
const handleClick = async (previewMode: string) => {
|
||||
await updatePreviewMode(previewMode);
|
||||
const handleClick = async (previewMode: PreviewMode) => {
|
||||
if (!request || !isRequest(request)) {
|
||||
return;
|
||||
}
|
||||
return models.requestMeta.updateOrCreateByParentId(request._id, { previewMode });
|
||||
};
|
||||
const handleDownloadPrettify = useCallback(() => {
|
||||
download(true);
|
||||
}, [download]);
|
||||
const handleDownloadPrettify = useCallback(() => download(true), [download]);
|
||||
|
||||
const handleDownloadNormal = useCallback(() => {
|
||||
download(false);
|
||||
}, [download]);
|
||||
const handleDownloadNormal = useCallback(() => download(false), [download]);
|
||||
|
||||
const handleCopyRawResponse = useCallback(() => {
|
||||
copyToClipboard();
|
||||
}, [copyToClipboard]);
|
||||
const exportAsHAR = useCallback(async () => {
|
||||
if (!response || !request || !isRequest(request)) {
|
||||
console.warn('Nothing to download');
|
||||
return;
|
||||
}
|
||||
|
||||
const data = await exportHarCurrentRequest(request, response);
|
||||
const har = JSON.stringify(data, null, '\t');
|
||||
|
||||
const { filePath } = await window.dialog.showSaveDialog({
|
||||
title: 'Export As HAR',
|
||||
buttonLabel: 'Save',
|
||||
defaultPath: `${request.name.replace(/ +/g, '_')}-${Date.now()}.har`,
|
||||
});
|
||||
|
||||
if (!filePath) {
|
||||
return;
|
||||
}
|
||||
const to = fs.createWriteStream(filePath);
|
||||
to.on('error', err => {
|
||||
console.warn('Failed to export har', err);
|
||||
});
|
||||
to.end(har);
|
||||
}, [request, response]);
|
||||
|
||||
const exportDebugFile = useCallback(async () => {
|
||||
if (!response || !request) {
|
||||
console.warn('Nothing to download');
|
||||
return;
|
||||
}
|
||||
|
||||
const timeline = models.response.getTimeline(response);
|
||||
const headers = timeline
|
||||
.filter(v => v.name === 'HeaderIn')
|
||||
.map(v => v.value)
|
||||
.join('');
|
||||
|
||||
const { canceled, filePath } = await window.dialog.showSaveDialog({
|
||||
title: 'Save Full Response',
|
||||
buttonLabel: 'Save',
|
||||
defaultPath: `${request.name.replace(/ +/g, '_')}-${Date.now()}.txt`,
|
||||
});
|
||||
|
||||
if (canceled) {
|
||||
return;
|
||||
}
|
||||
const readStream = models.response.getBodyStream(response);
|
||||
|
||||
if (readStream && filePath) {
|
||||
const to = fs.createWriteStream(filePath);
|
||||
to.write(headers);
|
||||
readStream.pipe(to);
|
||||
to.on('error', err => {
|
||||
console.warn('Failed to save full response', err);
|
||||
});
|
||||
}
|
||||
}, [request, response]);
|
||||
const shouldPrettifyOption = response.contentType.includes('json');
|
||||
return <Dropdown beside>
|
||||
<DropdownButton className="tall">
|
||||
{getPreviewModeName(previewMode)}
|
||||
@ -52,7 +104,7 @@ export const PreviewModeDropdown: FC<Props> = ({
|
||||
{getPreviewModeName(mode, true)}
|
||||
</DropdownItem>)}
|
||||
<DropdownDivider>Actions</DropdownDivider>
|
||||
<DropdownItem onClick={handleCopyRawResponse}>
|
||||
<DropdownItem onClick={copyToClipboard}>
|
||||
<i className="fa fa-copy" />
|
||||
Copy raw response
|
||||
</DropdownItem>
|
||||
@ -60,11 +112,11 @@ export const PreviewModeDropdown: FC<Props> = ({
|
||||
<i className="fa fa-save" />
|
||||
Export raw response
|
||||
</DropdownItem>
|
||||
{showPrettifyOption && <DropdownItem onClick={handleDownloadPrettify}>
|
||||
{shouldPrettifyOption && <DropdownItem onClick={handleDownloadPrettify}>
|
||||
<i className="fa fa-save" />
|
||||
Export prettified response
|
||||
</DropdownItem>}
|
||||
<DropdownItem onClick={fullDownload}>
|
||||
<DropdownItem onClick={exportDebugFile}>
|
||||
<i className="fa fa-bug" />
|
||||
Export HTTP debug
|
||||
</DropdownItem>
|
||||
|
@ -1,12 +1,13 @@
|
||||
import { differenceInHours, differenceInMinutes, isThisWeek, isToday } from 'date-fns';
|
||||
import React, { FC, Fragment, useCallback, useRef } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
|
||||
import { hotKeyRefs } from '../../../common/hotkeys';
|
||||
import { executeHotKey } from '../../../common/hotkeys-listener';
|
||||
import { decompressObject } from '../../../common/misc';
|
||||
import type { Environment } from '../../../models/environment';
|
||||
import type { RequestVersion } from '../../../models/request-version';
|
||||
import * as models from '../../../models/index';
|
||||
import type { Response } from '../../../models/response';
|
||||
import { selectActiveEnvironment, selectActiveRequest, selectActiveRequestResponses, selectRequestVersions } from '../../redux/selectors';
|
||||
import { type DropdownHandle, Dropdown } from '../base/dropdown/dropdown';
|
||||
import { DropdownButton } from '../base/dropdown/dropdown-button';
|
||||
import { DropdownDivider } from '../base/dropdown/dropdown-divider';
|
||||
@ -20,30 +21,23 @@ import { URLTag } from '../tags/url-tag';
|
||||
import { TimeFromNow } from '../time-from-now';
|
||||
|
||||
interface Props {
|
||||
activeEnvironment?: Environment | null;
|
||||
activeResponse: Response;
|
||||
className?: string;
|
||||
handleDeleteResponse: Function;
|
||||
handleDeleteResponses: Function;
|
||||
handleSetActiveResponse: Function;
|
||||
requestId: string;
|
||||
requestVersions: RequestVersion[];
|
||||
responses: Response[];
|
||||
}
|
||||
|
||||
export const ResponseHistoryDropdown: FC<Props> = ({
|
||||
activeEnvironment,
|
||||
activeResponse,
|
||||
className,
|
||||
handleDeleteResponse,
|
||||
handleDeleteResponses,
|
||||
handleSetActiveResponse,
|
||||
requestId,
|
||||
requestVersions,
|
||||
responses,
|
||||
}) => {
|
||||
const dropdownRef = useRef<DropdownHandle>(null);
|
||||
|
||||
const activeEnvironment = useSelector(selectActiveEnvironment);
|
||||
const responses = useSelector(selectActiveRequestResponses);
|
||||
const activeRequest = useSelector(selectActiveRequest);
|
||||
const requestVersions = useSelector(selectRequestVersions);
|
||||
const now = new Date();
|
||||
const categories: Record<string, Response[]> = {
|
||||
minutes: [],
|
||||
@ -53,6 +47,22 @@ export const ResponseHistoryDropdown: FC<Props> = ({
|
||||
other: [],
|
||||
};
|
||||
|
||||
const handleDeleteResponses = useCallback(async () => {
|
||||
const environmentId = activeEnvironment ? activeEnvironment._id : null;
|
||||
await models.response.removeForRequest(requestId, environmentId);
|
||||
|
||||
if (activeRequest && activeRequest._id === requestId) {
|
||||
await handleSetActiveResponse(requestId, null);
|
||||
}
|
||||
}, [activeEnvironment, activeRequest, handleSetActiveResponse, requestId]);
|
||||
|
||||
const handleDeleteResponse = useCallback(async () => {
|
||||
if (activeResponse) {
|
||||
await models.response.remove(activeResponse);
|
||||
}
|
||||
handleSetActiveResponse(null);
|
||||
}, [activeResponse, handleSetActiveResponse]);
|
||||
|
||||
responses.forEach(response => {
|
||||
const responseTime = new Date(response.created);
|
||||
|
||||
@ -148,7 +158,7 @@ export const ResponseHistoryDropdown: FC<Props> = ({
|
||||
<i className="fa fa-trash-o" />
|
||||
Delete Current Response
|
||||
</DropdownItem>
|
||||
<DropdownItem buttonClass={PromptButton} addIcon onClick={() => handleDeleteResponses(requestId, activeEnvironment ? activeEnvironment._id : null)}>
|
||||
<DropdownItem buttonClass={PromptButton} addIcon onClick={handleDeleteResponses}>
|
||||
<i className="fa fa-trash-o" />
|
||||
Clear History
|
||||
</DropdownItem>
|
||||
|
@ -1,25 +1,18 @@
|
||||
import { autoBindMethodsForReact } from 'class-autobind-decorator';
|
||||
import classnames from 'classnames';
|
||||
import { clipboard } from 'electron';
|
||||
import fs from 'fs';
|
||||
import { json as jsonPrettify } from 'insomnia-prettify';
|
||||
import { extension as mimeExtension } from 'mime-types';
|
||||
import React, { PureComponent } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import React, { FC, useCallback, useRef } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { Tab, TabList, TabPanel, Tabs } from 'react-tabs';
|
||||
|
||||
import { AUTOBIND_CFG, PREVIEW_MODE_SOURCE, PreviewMode } from '../../../common/constants';
|
||||
import { exportHarCurrentRequest } from '../../../common/har';
|
||||
import { PREVIEW_MODE_SOURCE } from '../../../common/constants';
|
||||
import { getSetCookieHeaders } from '../../../common/misc';
|
||||
import * as models from '../../../models';
|
||||
import type { Environment } from '../../../models/environment';
|
||||
import type { Request } from '../../../models/request';
|
||||
import type { RequestVersion } from '../../../models/request-version';
|
||||
import type { Response } from '../../../models/response';
|
||||
import type { UnitTestResult } from '../../../models/unit-test-result';
|
||||
import { cancelRequestById } from '../../../network/network';
|
||||
import { RootState } from '../../redux/modules';
|
||||
import { selectHotKeyRegistry } from '../../redux/selectors';
|
||||
import { selectActiveResponse, selectLoadStartTime, selectResponseFilter, selectResponseFilterHistory, selectResponsePreviewMode, selectSettings } from '../../redux/selectors';
|
||||
import { Button } from '../base/button';
|
||||
import { PreviewModeDropdown } from '../dropdowns/preview-mode-dropdown';
|
||||
import { ResponseHistoryDropdown } from '../dropdowns/response-history-dropdown';
|
||||
@ -32,63 +25,47 @@ import { TimeTag } from '../tags/time-tag';
|
||||
import { ResponseCookiesViewer } from '../viewers/response-cookies-viewer';
|
||||
import { ResponseHeadersViewer } from '../viewers/response-headers-viewer';
|
||||
import { ResponseTimelineViewer } from '../viewers/response-timeline-viewer';
|
||||
import { ResponseViewer } from '../viewers/response-viewer';
|
||||
import { ResponseViewer } from '../viewers/response-viewer';
|
||||
import { BlankPane } from './blank-pane';
|
||||
import { Pane, paneBodyClasses, PaneHeader } from './pane';
|
||||
import { PlaceholderResponsePane } from './placeholder-response-pane';
|
||||
|
||||
interface OwnProps {
|
||||
handleSetFilter: (filter: string) => void;
|
||||
handleSetPreviewMode: Function;
|
||||
interface Props {
|
||||
handleSetActiveResponse: Function;
|
||||
handleDeleteResponses: Function;
|
||||
handleDeleteResponse: Function;
|
||||
handleSetFilter: (filter: string) => void;
|
||||
handleShowRequestSettings: Function;
|
||||
previewMode: PreviewMode;
|
||||
filter: string;
|
||||
filterHistory: string[];
|
||||
disableHtmlPreviewJs: boolean;
|
||||
editorFontSize: number;
|
||||
loadStartTime: number;
|
||||
responses: Response[];
|
||||
disableResponsePreviewLinks: boolean;
|
||||
requestVersions: RequestVersion[];
|
||||
request?: Request | null;
|
||||
response?: Response | null;
|
||||
environment?: Environment | null;
|
||||
unitTestResult?: UnitTestResult | null;
|
||||
}
|
||||
export const ResponsePane: FC<Props> = ({
|
||||
handleSetActiveResponse,
|
||||
handleSetFilter,
|
||||
handleShowRequestSettings,
|
||||
request,
|
||||
}) => {
|
||||
const response = useSelector(selectActiveResponse);
|
||||
const filterHistory = useSelector(selectResponseFilterHistory);
|
||||
const filter = useSelector(selectResponseFilter);
|
||||
const settings = useSelector(selectSettings);
|
||||
const loadStartTime = useSelector(selectLoadStartTime);
|
||||
const previewMode = useSelector(selectResponsePreviewMode);
|
||||
|
||||
const mapStateToProps = (state: RootState) => ({
|
||||
hotKeyRegistry: selectHotKeyRegistry(state),
|
||||
});
|
||||
|
||||
type ReduxProps = ReturnType<typeof mapStateToProps>;
|
||||
|
||||
type Props = OwnProps & ReduxProps;
|
||||
|
||||
@autoBindMethodsForReact(AUTOBIND_CFG)
|
||||
class UnconnectedResponsePane extends PureComponent<Props> {
|
||||
_responseViewer: ResponseViewer | null = null;
|
||||
|
||||
_setResponseViewerRef(responseViewer: ResponseViewer) {
|
||||
this._responseViewer = responseViewer;
|
||||
}
|
||||
|
||||
_handleGetResponseBody(): Buffer | null {
|
||||
if (!this.props.response) {
|
||||
const responseViewerRef = useRef<ResponseViewer>(null);
|
||||
const handleGetResponseBody = useCallback(() => {
|
||||
if (!response) {
|
||||
return null;
|
||||
}
|
||||
return models.response.getBodyBuffer(response);
|
||||
}, [response]);
|
||||
const handleCopyResponseToClipboard = useCallback(async () => {
|
||||
const bodyBuffer = handleGetResponseBody();
|
||||
if (bodyBuffer) {
|
||||
clipboard.writeText(bodyBuffer.toString('utf8'));
|
||||
}
|
||||
}, [handleGetResponseBody]);
|
||||
|
||||
return models.response.getBodyBuffer(this.props.response);
|
||||
}
|
||||
|
||||
async _handleDownloadResponseBody(prettify: boolean) {
|
||||
const { response, request } = this.props;
|
||||
|
||||
const handleDownloadResponseBody = useCallback(async (prettify: boolean) => {
|
||||
if (!response || !request) {
|
||||
// Should never happen
|
||||
console.warn('No response to download');
|
||||
console.warn('Nothing to download');
|
||||
return;
|
||||
}
|
||||
|
||||
@ -107,12 +84,11 @@ class UnconnectedResponsePane extends PureComponent<Props> {
|
||||
const readStream = models.response.getBodyStream(response);
|
||||
const dataBuffers: any[] = [];
|
||||
|
||||
if (readStream) {
|
||||
if (readStream && outputPath) {
|
||||
readStream.on('data', data => {
|
||||
dataBuffers.push(data);
|
||||
});
|
||||
readStream.on('end', () => {
|
||||
// @ts-expect-error -- TSCONVERSION
|
||||
const to = fs.createWriteStream(outputPath);
|
||||
const finalBuffer = Buffer.concat(dataBuffers);
|
||||
to.on('error', err => {
|
||||
@ -132,256 +108,136 @@ class UnconnectedResponsePane extends PureComponent<Props> {
|
||||
to.end();
|
||||
});
|
||||
}
|
||||
}
|
||||
}, [request, response]);
|
||||
|
||||
async _handleDownloadFullResponseBody() {
|
||||
const { response, request } = this.props;
|
||||
|
||||
if (!response || !request) {
|
||||
// Should never happen
|
||||
console.warn('No response to download');
|
||||
return;
|
||||
}
|
||||
|
||||
const timeline = models.response.getTimeline(response);
|
||||
const headers = timeline
|
||||
.filter(v => v.name === 'HeaderIn')
|
||||
.map(v => v.value)
|
||||
.join('');
|
||||
|
||||
const { canceled, filePath } = await window.dialog.showSaveDialog({
|
||||
title: 'Save Full Response',
|
||||
buttonLabel: 'Save',
|
||||
defaultPath: `${request.name.replace(/ +/g, '_')}-${Date.now()}.txt`,
|
||||
});
|
||||
|
||||
if (canceled) {
|
||||
return;
|
||||
}
|
||||
|
||||
const readStream = models.response.getBodyStream(response);
|
||||
|
||||
if (readStream) {
|
||||
// @ts-expect-error -- TSCONVERSION
|
||||
const to = fs.createWriteStream(filePath);
|
||||
to.write(headers);
|
||||
readStream.pipe(to);
|
||||
to.on('error', err => {
|
||||
console.warn('Failed to save full response', err);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async _handleCopyResponseToClipboard() {
|
||||
if (!this.props.response) {
|
||||
return;
|
||||
}
|
||||
|
||||
const bodyBuffer = models.response.getBodyBuffer(this.props.response);
|
||||
if (bodyBuffer) {
|
||||
clipboard.writeText(bodyBuffer.toString('utf8'));
|
||||
}
|
||||
}
|
||||
|
||||
async _handleExportAsHAR() {
|
||||
const { response, request } = this.props;
|
||||
|
||||
if (!response) {
|
||||
// Should never happen
|
||||
console.warn('No response to download');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!request) {
|
||||
// Should never happen
|
||||
console.warn('No request to download');
|
||||
return;
|
||||
}
|
||||
|
||||
const data = await exportHarCurrentRequest(request, response);
|
||||
const har = JSON.stringify(data, null, '\t');
|
||||
|
||||
const { filePath } = await window.dialog.showSaveDialog({
|
||||
title: 'Export As HAR',
|
||||
buttonLabel: 'Save',
|
||||
defaultPath: `${request.name.replace(/ +/g, '_')}-${Date.now()}.har`,
|
||||
});
|
||||
|
||||
if (!filePath) {
|
||||
return;
|
||||
}
|
||||
|
||||
const to = fs.createWriteStream(filePath);
|
||||
to.on('error', err => {
|
||||
console.warn('Failed to export har', err);
|
||||
});
|
||||
to.end(har);
|
||||
}
|
||||
|
||||
_handleTabSelect(index: number, lastIndex: number) {
|
||||
if (this._responseViewer != null && index === 0 && index !== lastIndex) {
|
||||
const handleTabSelect = (index: number, lastIndex: number) => {
|
||||
if (responseViewerRef.current != null && index === 0 && index !== lastIndex) {
|
||||
// Fix for CodeMirror editor not updating its content.
|
||||
// Refresh must be called when the editor is visible,
|
||||
// so use nextTick to give time for it to be visible.
|
||||
process.nextTick(() => {
|
||||
// @ts-expect-error -- TSCONVERSION
|
||||
this._responseViewer.refresh();
|
||||
responseViewerRef.current?.refresh();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
if (!request) {
|
||||
return <BlankPane type="response" />;
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
disableHtmlPreviewJs,
|
||||
editorFontSize,
|
||||
environment,
|
||||
filter,
|
||||
disableResponsePreviewLinks,
|
||||
filterHistory,
|
||||
handleDeleteResponse,
|
||||
handleDeleteResponses,
|
||||
handleSetActiveResponse,
|
||||
handleSetFilter,
|
||||
handleSetPreviewMode,
|
||||
handleShowRequestSettings,
|
||||
loadStartTime,
|
||||
previewMode,
|
||||
request,
|
||||
requestVersions,
|
||||
response,
|
||||
responses,
|
||||
} = this.props;
|
||||
|
||||
if (!request) {
|
||||
return <BlankPane type="response" />;
|
||||
}
|
||||
|
||||
if (!response) {
|
||||
return (
|
||||
<PlaceholderResponsePane>
|
||||
<ResponseTimer
|
||||
handleCancel={() => cancelRequestById(request._id)}
|
||||
loadStartTime={loadStartTime}
|
||||
/>
|
||||
</PlaceholderResponsePane>
|
||||
);
|
||||
}
|
||||
|
||||
const cookieHeaders = getSetCookieHeaders(response.headers);
|
||||
if (!response) {
|
||||
return (
|
||||
<Pane type="response">
|
||||
{!response ? null : (
|
||||
<PaneHeader className="row-spaced">
|
||||
<div className="no-wrap scrollable scrollable--no-bars pad-left">
|
||||
<StatusTag statusCode={response.statusCode} statusMessage={response.statusMessage} />
|
||||
<TimeTag milliseconds={response.elapsedTime} />
|
||||
<SizeTag bytesRead={response.bytesRead} bytesContent={response.bytesContent} />
|
||||
</div>
|
||||
<ResponseHistoryDropdown
|
||||
activeResponse={response}
|
||||
activeEnvironment={environment}
|
||||
responses={responses}
|
||||
requestVersions={requestVersions}
|
||||
requestId={request._id}
|
||||
handleSetActiveResponse={handleSetActiveResponse}
|
||||
handleDeleteResponses={handleDeleteResponses}
|
||||
handleDeleteResponse={handleDeleteResponse}
|
||||
className="tall pane__header__right"
|
||||
/>
|
||||
</PaneHeader>
|
||||
)}
|
||||
<Tabs
|
||||
className={classnames(paneBodyClasses, 'react-tabs')}
|
||||
onSelect={this._handleTabSelect}
|
||||
forceRenderTabPanel
|
||||
>
|
||||
<TabList>
|
||||
<Tab tabIndex="-1">
|
||||
<PreviewModeDropdown
|
||||
download={this._handleDownloadResponseBody}
|
||||
fullDownload={this._handleDownloadFullResponseBody}
|
||||
exportAsHAR={this._handleExportAsHAR}
|
||||
previewMode={previewMode}
|
||||
updatePreviewMode={handleSetPreviewMode}
|
||||
showPrettifyOption={response.contentType.includes('json')}
|
||||
copyToClipboard={this._handleCopyResponseToClipboard}
|
||||
/>
|
||||
</Tab>
|
||||
<Tab tabIndex="-1">
|
||||
<Button>
|
||||
Header{' '}
|
||||
{response.headers.length > 0 && (
|
||||
<span className="bubble">{response.headers.length}</span>
|
||||
)}
|
||||
</Button>
|
||||
</Tab>
|
||||
<Tab tabIndex="-1">
|
||||
<Button>
|
||||
Cookie{' '}
|
||||
{cookieHeaders.length ? (
|
||||
<span className="bubble">{cookieHeaders.length}</span>
|
||||
) : null}
|
||||
</Button>
|
||||
</Tab>
|
||||
<Tab tabIndex="-1">
|
||||
<Button>Timeline</Button>
|
||||
</Tab>
|
||||
</TabList>
|
||||
<TabPanel className="react-tabs__tab-panel">
|
||||
<ResponseViewer
|
||||
ref={this._setResponseViewerRef}
|
||||
bytes={Math.max(response.bytesContent, response.bytesRead)}
|
||||
contentType={response.contentType || ''}
|
||||
disableHtmlPreviewJs={disableHtmlPreviewJs}
|
||||
disablePreviewLinks={disableResponsePreviewLinks}
|
||||
download={this._handleDownloadResponseBody}
|
||||
editorFontSize={editorFontSize}
|
||||
error={response.error}
|
||||
filter={filter}
|
||||
filterHistory={filterHistory}
|
||||
getBody={this._handleGetResponseBody}
|
||||
previewMode={response.error ? PREVIEW_MODE_SOURCE : previewMode}
|
||||
responseId={response._id}
|
||||
updateFilter={response.error ? undefined : handleSetFilter}
|
||||
url={response.url}
|
||||
/>
|
||||
</TabPanel>
|
||||
<TabPanel className="react-tabs__tab-panel scrollable-container">
|
||||
<div className="scrollable pad">
|
||||
<ErrorBoundary key={response._id} errorClassName="font-error pad text-center">
|
||||
<ResponseHeadersViewer headers={response.headers} />
|
||||
</ErrorBoundary>
|
||||
</div>
|
||||
</TabPanel>
|
||||
<TabPanel className="react-tabs__tab-panel scrollable-container">
|
||||
<div className="scrollable pad">
|
||||
<ErrorBoundary key={response._id} errorClassName="font-error pad text-center">
|
||||
<ResponseCookiesViewer
|
||||
handleShowRequestSettings={handleShowRequestSettings}
|
||||
cookiesSent={response.settingSendCookies}
|
||||
cookiesStored={response.settingStoreCookies}
|
||||
headers={cookieHeaders}
|
||||
/>
|
||||
</ErrorBoundary>
|
||||
</div>
|
||||
</TabPanel>
|
||||
<TabPanel className="react-tabs__tab-panel">
|
||||
<ErrorBoundary key={response._id} errorClassName="font-error pad text-center">
|
||||
<ResponseTimelineViewer
|
||||
response={response}
|
||||
/>
|
||||
</ErrorBoundary>
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
<ErrorBoundary errorClassName="font-error pad text-center">
|
||||
<ResponseTimer
|
||||
handleCancel={() => cancelRequestById(request._id)}
|
||||
loadStartTime={loadStartTime}
|
||||
/>
|
||||
</ErrorBoundary>
|
||||
</Pane>
|
||||
<PlaceholderResponsePane>
|
||||
<ResponseTimer
|
||||
handleCancel={() => cancelRequestById(request._id)}
|
||||
loadStartTime={loadStartTime}
|
||||
/>
|
||||
</PlaceholderResponsePane>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export const ResponsePane = connect(mapStateToProps)(UnconnectedResponsePane);
|
||||
const cookieHeaders = getSetCookieHeaders(response.headers);
|
||||
return (
|
||||
<Pane type="response">
|
||||
{!response ? null : (
|
||||
<PaneHeader className="row-spaced">
|
||||
<div className="no-wrap scrollable scrollable--no-bars pad-left">
|
||||
<StatusTag statusCode={response.statusCode} statusMessage={response.statusMessage} />
|
||||
<TimeTag milliseconds={response.elapsedTime} />
|
||||
<SizeTag bytesRead={response.bytesRead} bytesContent={response.bytesContent} />
|
||||
</div>
|
||||
<ResponseHistoryDropdown
|
||||
activeResponse={response}
|
||||
requestId={request._id}
|
||||
handleSetActiveResponse={handleSetActiveResponse}
|
||||
className="tall pane__header__right"
|
||||
/>
|
||||
</PaneHeader>
|
||||
)}
|
||||
<Tabs
|
||||
className={classnames(paneBodyClasses, 'react-tabs')}
|
||||
onSelect={handleTabSelect}
|
||||
forceRenderTabPanel
|
||||
>
|
||||
<TabList>
|
||||
<Tab tabIndex="-1">
|
||||
<PreviewModeDropdown
|
||||
download={handleDownloadResponseBody}
|
||||
copyToClipboard={handleCopyResponseToClipboard}
|
||||
/>
|
||||
</Tab>
|
||||
<Tab tabIndex="-1">
|
||||
<Button>
|
||||
Header{' '}
|
||||
{response.headers.length > 0 && (
|
||||
<span className="bubble">{response.headers.length}</span>
|
||||
)}
|
||||
</Button>
|
||||
</Tab>
|
||||
<Tab tabIndex="-1">
|
||||
<Button>
|
||||
Cookie{' '}
|
||||
{cookieHeaders.length ? (
|
||||
<span className="bubble">{cookieHeaders.length}</span>
|
||||
) : null}
|
||||
</Button>
|
||||
</Tab>
|
||||
<Tab tabIndex="-1">
|
||||
<Button>Timeline</Button>
|
||||
</Tab>
|
||||
</TabList>
|
||||
<TabPanel className="react-tabs__tab-panel">
|
||||
<ResponseViewer
|
||||
ref={responseViewerRef}
|
||||
bytes={Math.max(response.bytesContent, response.bytesRead)}
|
||||
contentType={response.contentType || ''}
|
||||
disableHtmlPreviewJs={settings.disableHtmlPreviewJs}
|
||||
disablePreviewLinks={settings.disableResponsePreviewLinks}
|
||||
download={handleDownloadResponseBody}
|
||||
editorFontSize={settings.editorFontSize}
|
||||
error={response.error}
|
||||
filter={filter}
|
||||
filterHistory={filterHistory}
|
||||
getBody={handleGetResponseBody}
|
||||
previewMode={response.error ? PREVIEW_MODE_SOURCE : previewMode}
|
||||
responseId={response._id}
|
||||
updateFilter={response.error ? undefined : handleSetFilter}
|
||||
url={response.url}
|
||||
/>
|
||||
</TabPanel>
|
||||
<TabPanel className="react-tabs__tab-panel scrollable-container">
|
||||
<div className="scrollable pad">
|
||||
<ErrorBoundary key={response._id} errorClassName="font-error pad text-center">
|
||||
<ResponseHeadersViewer headers={response.headers} />
|
||||
</ErrorBoundary>
|
||||
</div>
|
||||
</TabPanel>
|
||||
<TabPanel className="react-tabs__tab-panel scrollable-container">
|
||||
<div className="scrollable pad">
|
||||
<ErrorBoundary key={response._id} errorClassName="font-error pad text-center">
|
||||
<ResponseCookiesViewer
|
||||
handleShowRequestSettings={handleShowRequestSettings}
|
||||
cookiesSent={response.settingSendCookies}
|
||||
cookiesStored={response.settingStoreCookies}
|
||||
headers={cookieHeaders}
|
||||
/>
|
||||
</ErrorBoundary>
|
||||
</div>
|
||||
</TabPanel>
|
||||
<TabPanel className="react-tabs__tab-panel">
|
||||
<ErrorBoundary key={response._id} errorClassName="font-error pad text-center">
|
||||
<ResponseTimelineViewer
|
||||
response={response}
|
||||
/>
|
||||
</ErrorBoundary>
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
<ErrorBoundary errorClassName="font-error pad text-center">
|
||||
<ResponseTimer
|
||||
handleCancel={() => cancelRequestById(request._id)}
|
||||
loadStartTime={loadStartTime}
|
||||
/>
|
||||
</ErrorBoundary>
|
||||
</Pane>
|
||||
);
|
||||
};
|
||||
|
@ -7,7 +7,14 @@ import { isRemoteProject } from '../../models/project';
|
||||
import { Request, RequestAuthentication, RequestBody, RequestHeader, RequestParameter } from '../../models/request';
|
||||
import { Settings } from '../../models/settings';
|
||||
import { isCollection, isDesign } from '../../models/workspace';
|
||||
import { selectActiveEnvironment, selectActiveRequest, selectActiveRequestResponses, selectActiveResponse, selectActiveUnitTestResult, selectActiveWorkspace, selectEnvironments, selectLoadStartTime, selectRequestVersions, selectResponseDownloadPath, selectResponseFilter, selectResponseFilterHistory, selectResponsePreviewMode, selectSettings } from '../redux/selectors';
|
||||
import {
|
||||
selectActiveEnvironment,
|
||||
selectActiveRequest,
|
||||
selectActiveWorkspace,
|
||||
selectEnvironments,
|
||||
selectResponseDownloadPath,
|
||||
selectSettings,
|
||||
} from '../redux/selectors';
|
||||
import { selectSidebarChildren, selectSidebarFilter } from '../redux/sidebar-selectors';
|
||||
import { EnvironmentsDropdown } from './dropdowns/environments-dropdown';
|
||||
import { SyncDropdown } from './dropdowns/sync-dropdown';
|
||||
@ -28,15 +35,12 @@ interface Props {
|
||||
gitSyncDropdown: ReactNode;
|
||||
handleActivityChange: HandleActivityChange;
|
||||
handleChangeEnvironment: Function;
|
||||
handleDeleteResponse: Function;
|
||||
handleDeleteResponses: Function;
|
||||
handleForceUpdateRequest: (r: Request, patch: Partial<Request>) => Promise<Request>;
|
||||
handleForceUpdateRequestHeaders: (r: Request, headers: RequestHeader[]) => Promise<Request>;
|
||||
handleImport: Function;
|
||||
handleSendAndDownloadRequestWithActiveEnvironment: (filepath?: string) => Promise<void>;
|
||||
handleSendRequestWithActiveEnvironment: () => void;
|
||||
handleSetActiveResponse: Function;
|
||||
handleSetPreviewMode: Function;
|
||||
handleSetResponseFilter: (filter: string) => void;
|
||||
handleShowRequestSettingsModal: Function;
|
||||
handleSidebarSort: (sortOrder: SortOrder) => void;
|
||||
@ -55,15 +59,12 @@ export const WrapperDebug: FC<Props> = ({
|
||||
gitSyncDropdown,
|
||||
handleActivityChange,
|
||||
handleChangeEnvironment,
|
||||
handleDeleteResponse,
|
||||
handleDeleteResponses,
|
||||
handleForceUpdateRequest,
|
||||
handleForceUpdateRequestHeaders,
|
||||
handleImport,
|
||||
handleSendAndDownloadRequestWithActiveEnvironment,
|
||||
handleSendRequestWithActiveEnvironment,
|
||||
handleSetActiveResponse,
|
||||
handleSetPreviewMode,
|
||||
handleSetResponseFilter,
|
||||
handleShowRequestSettingsModal,
|
||||
handleSidebarSort,
|
||||
@ -100,17 +101,11 @@ export const WrapperDebug: FC<Props> = ({
|
||||
|
||||
const activeEnvironment = useSelector(selectActiveEnvironment);
|
||||
const activeRequest = useSelector(selectActiveRequest);
|
||||
const activeRequestResponses = useSelector(selectActiveRequestResponses);
|
||||
const activeResponse = useSelector(selectActiveResponse);
|
||||
const activeUnitTestResult = useSelector(selectActiveUnitTestResult);
|
||||
|
||||
const activeWorkspace = useSelector(selectActiveWorkspace);
|
||||
const environments = useSelector(selectEnvironments);
|
||||
const loadStartTime = useSelector(selectLoadStartTime);
|
||||
const requestVersions = useSelector(selectRequestVersions);
|
||||
|
||||
const responseDownloadPath = useSelector(selectResponseDownloadPath);
|
||||
const responseFilter = useSelector(selectResponseFilter);
|
||||
const responseFilterHistory = useSelector(selectResponseFilterHistory);
|
||||
const responsePreviewMode = useSelector(selectResponsePreviewMode);
|
||||
const settings = useSelector(selectSettings);
|
||||
const sidebarChildren = useSelector(selectSidebarChildren);
|
||||
const sidebarFilter = useSelector(selectSidebarFilter);
|
||||
@ -215,25 +210,10 @@ export const WrapperDebug: FC<Props> = ({
|
||||
/>
|
||||
:
|
||||
<ResponsePane
|
||||
disableHtmlPreviewJs={settings.disableHtmlPreviewJs}
|
||||
disableResponsePreviewLinks={settings.disableResponsePreviewLinks}
|
||||
editorFontSize={settings.editorFontSize}
|
||||
environment={activeEnvironment}
|
||||
filter={responseFilter}
|
||||
filterHistory={responseFilterHistory}
|
||||
handleDeleteResponse={handleDeleteResponse}
|
||||
handleDeleteResponses={handleDeleteResponses}
|
||||
handleSetActiveResponse={handleSetActiveResponse}
|
||||
handleSetFilter={handleSetResponseFilter}
|
||||
handleSetPreviewMode={handleSetPreviewMode}
|
||||
handleShowRequestSettings={handleShowRequestSettingsModal}
|
||||
loadStartTime={loadStartTime}
|
||||
previewMode={responsePreviewMode}
|
||||
request={activeRequest}
|
||||
requestVersions={requestVersions}
|
||||
response={activeResponse}
|
||||
responses={activeRequestResponses}
|
||||
unitTestResult={activeUnitTestResult}
|
||||
/>}
|
||||
</ErrorBoundary>}
|
||||
/>
|
||||
|
@ -27,7 +27,6 @@ import {
|
||||
RequestParameter,
|
||||
} from '../../models/request';
|
||||
import { RequestGroup } from '../../models/request-group';
|
||||
import type { Response } from '../../models/response';
|
||||
import { GitVCS } from '../../sync/git/git-vcs';
|
||||
import { VCS } from '../../sync/vcs/vcs';
|
||||
import { CookieModifyModal } from '../components/modals/cookie-modify-modal';
|
||||
@ -350,26 +349,6 @@ export class Wrapper extends PureComponent<WrapperProps, State> {
|
||||
showModal(RequestSettingsModal, { request: this.props.activeRequest });
|
||||
}
|
||||
|
||||
async _handleDeleteResponses(requestId: string, environmentId: string | null) {
|
||||
const { handleSetActiveResponse, activeRequest } = this.props;
|
||||
await models.response.removeForRequest(requestId, environmentId);
|
||||
|
||||
if (activeRequest && activeRequest._id === requestId) {
|
||||
await handleSetActiveResponse(requestId, null);
|
||||
}
|
||||
}
|
||||
|
||||
async _handleDeleteResponse(response: Response) {
|
||||
if (response) {
|
||||
await models.response.remove(response);
|
||||
}
|
||||
|
||||
// Also unset active response it's the one we're deleting
|
||||
if (this.props.activeResponse?._id === response._id) {
|
||||
this._handleSetActiveResponse(null);
|
||||
}
|
||||
}
|
||||
|
||||
async _handleRemoveActiveWorkspace() {
|
||||
const { activeWorkspace, handleSetActiveActivity } = this.props;
|
||||
|
||||
@ -654,8 +633,6 @@ export class Wrapper extends PureComponent<WrapperProps, State> {
|
||||
gitSyncDropdown={gitSyncDropdown}
|
||||
handleActivityChange={this._handleWorkspaceActivityChange}
|
||||
handleChangeEnvironment={this._handleChangeEnvironment}
|
||||
handleDeleteResponse={this._handleDeleteResponse}
|
||||
handleDeleteResponses={this._handleDeleteResponses}
|
||||
handleForceUpdateRequest={this._handleForceUpdateRequest}
|
||||
handleForceUpdateRequestHeaders={this._handleForceUpdateRequestHeaders}
|
||||
handleImport={this._handleImport}
|
||||
|
Loading…
Reference in New Issue
Block a user