Extract foundational components from request and response panes (#2799)

This commit is contained in:
Opender Singh
2020-11-03 11:09:45 +13:00
committed by GitHub
parent dd86bd3369
commit e6bdbf27ea
9 changed files with 334 additions and 206 deletions

View File

@@ -0,0 +1,16 @@
// @flow
import React from 'react';
import { Pane, PaneBody, PaneHeader } from './pane';
type Props = {
type: 'request' | 'response',
};
const BlankPane = ({ type }: Props) => (
<Pane type={type}>
<PaneHeader />
<PaneBody placeholder />
</Pane>
);
export default BlankPane;

View File

@@ -0,0 +1,7 @@
// @flow
import React from 'react';
import BlankPane from './blank-pane';
const GrpcRequestPane = () => <BlankPane type="request" />;
export default GrpcRequestPane;

View File

@@ -0,0 +1,7 @@
// @flow
import React from 'react';
import BlankPane from './blank-pane';
const GrpcResponsePane = () => <BlankPane type="response" />;
export default GrpcResponsePane;

View File

@@ -0,0 +1,45 @@
// @flow
import classnames from 'classnames';
import React from 'react';
type PaneProps = {
className?: string,
type: 'request' | 'response',
};
type PaneHeaderProps = {
className?: string,
};
type PaneBodyProps = {
className?: string,
placeholder?: boolean,
};
export const Pane = ({ className, type, children }: PaneProps) => (
<section className={classnames(`${type}-pane`, 'theme--pane', 'pane', className)}>
{children}
</section>
);
export const PaneHeader = ({ className, children }: PaneHeaderProps) => (
<header className={classnames('pane__header', 'theme--pane__header', className)}>
{children}
</header>
);
export const paneBodyClasses = 'pane__body theme--pane__body';
export const PaneBody = ({ placeholder, children }: PaneBodyProps) => (
<div className={classnames(paneBodyClasses, placeholder && 'pane__body--placeholder')}>
{children}
</div>
);
// This class component is needed in order to apply a ref to it for resizing
// The component can be removed, once PR #2712 is merged
export class ResizablePaneWrapper extends React.PureComponent {
render() {
return <>{this.props.children}</>;
}
}

View File

@@ -0,0 +1,76 @@
// @flow
import React from 'react';
import Hotkey from '../hotkey';
import { hotKeyRefs } from '../../../common/hotkeys';
import * as hotkeys from '../../../common/hotkeys';
import type { Request } from '../../../models/request';
import type { ForceToWorkspace } from '../../redux/modules/helpers';
import { Pane, PaneBody, PaneHeader } from './pane';
type Props = {
hotKeyRegistry: hotkeys.HotKeyRegistry,
handleImportFile: (forceToWorkspace?: ForceToWorkspace) => void,
handleCreateRequest: () => Promise<Request>,
};
const PlaceholderRequestPane = ({
hotKeyRegistry,
handleImportFile,
handleCreateRequest,
}: Props) => (
<Pane type="request">
<PaneHeader />
<PaneBody placeholder>
<div>
<table className="table--fancy">
<tbody>
<tr>
<td>New Request</td>
<td className="text-right">
<code>
<Hotkey
keyBindings={hotKeyRegistry[hotKeyRefs.REQUEST_SHOW_CREATE.id]}
useFallbackMessage
/>
</code>
</td>
</tr>
<tr>
<td>Switch Requests</td>
<td className="text-right">
<code>
<Hotkey
keyBindings={hotKeyRegistry[hotKeyRefs.REQUEST_QUICK_SWITCH.id]}
useFallbackMessage
/>
</code>
</td>
</tr>
<tr>
<td>Edit Environments</td>
<td className="text-right">
<code>
<Hotkey
keyBindings={hotKeyRegistry[hotKeyRefs.ENVIRONMENT_SHOW_EDITOR.id]}
useFallbackMessage
/>
</code>
</td>
</tr>
</tbody>
</table>
<div className="text-center pane__body--placeholder__cta">
<button className="btn inline-block btn--clicky" onClick={handleImportFile}>
Import from File
</button>
<button className="btn inline-block btn--clicky" onClick={handleCreateRequest}>
New Request
</button>
</div>
</div>
</PaneBody>
</Pane>
);
export default PlaceholderRequestPane;

View File

@@ -0,0 +1,71 @@
// @flow
import React from 'react';
import Hotkey from '../hotkey';
import { hotKeyRefs } from '../../../common/hotkeys';
import * as hotkeys from '../../../common/hotkeys';
import { Pane, PaneBody, PaneHeader } from './pane';
type Props = {
hotKeyRegistry: hotkeys.HotKeyRegistry,
};
const PlaceholderResponsePane = ({ hotKeyRegistry, children }: Props) => (
<Pane type="response">
<PaneHeader />
<PaneBody placeholder>
<div>
<table className="table--fancy">
<tbody>
<tr>
<td>Send Request</td>
<td className="text-right">
<code>
<Hotkey
keyBindings={hotKeyRegistry[hotKeyRefs.REQUEST_SEND.id]}
useFallbackMessage
/>
</code>
</td>
</tr>
<tr>
<td>Focus Url Bar</td>
<td className="text-right">
<code>
<Hotkey
keyBindings={hotKeyRegistry[hotKeyRefs.REQUEST_FOCUS_URL.id]}
useFallbackMessage
/>
</code>
</td>
</tr>
<tr>
<td>Manage Cookies</td>
<td className="text-right">
<code>
<Hotkey
keyBindings={hotKeyRegistry[hotKeyRefs.SHOW_COOKIES_EDITOR.id]}
useFallbackMessage
/>
</code>
</td>
</tr>
<tr>
<td>Edit Environments</td>
<td className="text-right">
<code>
<Hotkey
keyBindings={hotKeyRegistry[hotKeyRefs.ENVIRONMENT_SHOW_EDITOR.id]}
useFallbackMessage
/>
</code>
</td>
</tr>
</tbody>
</table>
</div>
</PaneBody>
{children}
</Pane>
);
export default PlaceholderResponsePane;

View File

@@ -5,31 +5,33 @@ import type {
RequestBody,
RequestHeader,
RequestParameter,
} from '../../models/request';
import type { Workspace } from '../../models/workspace';
import type { OAuth2Token } from '../../models/o-auth-2-token';
} from '../../../models/request';
import type { Workspace } from '../../../models/workspace';
import type { OAuth2Token } from '../../../models/o-auth-2-token';
import autobind from 'autobind-decorator';
import { deconstructQueryStringToParams, extractQueryStringFromUrl } from 'insomnia-url';
import * as React from 'react';
import { Tab, TabList, TabPanel, Tabs } from 'react-tabs';
import { getAuthTypeName, getContentTypeName } from '../../common/constants';
import * as db from '../../common/database';
import { hotKeyRefs } from '../../common/hotkeys';
import * as models from '../../models';
import AuthDropdown from './dropdowns/auth-dropdown';
import ContentTypeDropdown from './dropdowns/content-type-dropdown';
import AuthWrapper from './editors/auth/auth-wrapper';
import BodyEditor from './editors/body/body-editor';
import RequestHeadersEditor from './editors/request-headers-editor';
import ErrorBoundary from './error-boundary';
import Hotkey from './hotkey';
import MarkdownPreview from './markdown-preview';
import { showModal } from './modals/index';
import RequestSettingsModal from './modals/request-settings-modal';
import RenderedQueryString from './rendered-query-string';
import RequestUrlBar from './request-url-bar.js';
import type { Settings } from '../../models/settings';
import RequestParametersEditor from './editors/request-parameters-editor';
import { getAuthTypeName, getContentTypeName } from '../../../common/constants';
import * as db from '../../../common/database';
import * as models from '../../../models';
import AuthDropdown from '../dropdowns/auth-dropdown';
import ContentTypeDropdown from '../dropdowns/content-type-dropdown';
import AuthWrapper from '../editors/auth/auth-wrapper';
import BodyEditor from '../editors/body/body-editor';
import RequestHeadersEditor from '../editors/request-headers-editor';
import ErrorBoundary from '../error-boundary';
import MarkdownPreview from '../markdown-preview';
import { showModal } from '../modals';
import RequestSettingsModal from '../modals/request-settings-modal';
import RenderedQueryString from '../rendered-query-string';
import RequestUrlBar from '../request-url-bar.js';
import type { Settings } from '../../../models/settings';
import RequestParametersEditor from '../editors/request-parameters-editor';
import type { ForceToWorkspace } from '../../redux/modules/helpers';
import PlaceholderRequestPane from './placeholder-request-pane';
import { Pane, paneBodyClasses, PaneHeader } from './pane';
import classnames from 'classnames';
type Props = {
// Functions
@@ -53,7 +55,7 @@ type Props = {
updateSettingsUseBulkHeaderEditor: Function,
updateSettingsUseBulkParametersEditor: Function,
handleImport: Function,
handleImportFile: Function,
handleImportFile: (forceToWorkspace?: ForceToWorkspace) => void,
// Other
workspace: Workspace,
@@ -109,14 +111,6 @@ class RequestPane extends React.PureComponent<Props> {
updateSettingsUseBulkParametersEditor(!settings.useBulkParametersEditor);
}
_handleImportFile() {
this.props.handleImportFile();
}
_handleCreateRequest() {
this.props.handleCreateRequest();
}
_handleImportQueryFromUrl() {
const { request, forceUpdateRequest } = this.props;
@@ -150,6 +144,8 @@ class RequestPane extends React.PureComponent<Props> {
handleGenerateCode,
handleGetRenderContext,
handleImport,
handleImportFile,
handleCreateRequest,
handleRender,
handleSend,
handleSendAndDownload,
@@ -172,69 +168,15 @@ class RequestPane extends React.PureComponent<Props> {
downloadPath,
} = this.props;
const paneClasses = 'request-pane theme--pane pane';
const paneHeaderClasses = 'pane__header theme--pane__header';
const paneBodyClasses = 'pane__body theme--pane__body';
const hotKeyRegistry = settings.hotKeyRegistry;
if (!request) {
return (
<section className={paneClasses}>
<header className={paneHeaderClasses} />
<div className={paneBodyClasses + ' pane__body--placeholder'}>
<div>
<table className="table--fancy">
<tbody>
<tr>
<td>New Request</td>
<td className="text-right">
<code>
<Hotkey
keyBindings={hotKeyRegistry[hotKeyRefs.REQUEST_SHOW_CREATE.id]}
useFallbackMessage
/>
</code>
</td>
</tr>
<tr>
<td>Switch Requests</td>
<td className="text-right">
<code>
<Hotkey
keyBindings={hotKeyRegistry[hotKeyRefs.REQUEST_QUICK_SWITCH.id]}
useFallbackMessage
/>
</code>
</td>
</tr>
<tr>
<td>Edit Environments</td>
<td className="text-right">
<code>
<Hotkey
keyBindings={hotKeyRegistry[hotKeyRefs.ENVIRONMENT_SHOW_EDITOR.id]}
useFallbackMessage
/>
</code>
</td>
</tr>
</tbody>
</table>
<div className="text-center pane__body--placeholder__cta">
<button className="btn inline-block btn--clicky" onClick={this._handleImportFile}>
Import from File
</button>
<button
className="btn inline-block btn--clicky"
onClick={this._handleCreateRequest}>
New Request
</button>
</div>
</div>
</div>
</section>
<PlaceholderRequestPane
hotKeyRegistry={hotKeyRegistry}
handleImportFile={handleImportFile}
handleCreateRequest={handleCreateRequest}
/>
);
}
@@ -250,8 +192,8 @@ class RequestPane extends React.PureComponent<Props> {
const uniqueKey = `${forceRefreshCounter}::${request._id}`;
return (
<section className={paneClasses}>
<header className={paneHeaderClasses}>
<Pane type="request">
<PaneHeader>
<ErrorBoundary errorClassName="font-error pad text-center">
<RequestUrlBar
uniquenessKey={uniqueKey}
@@ -272,8 +214,8 @@ class RequestPane extends React.PureComponent<Props> {
downloadPath={downloadPath}
/>
</ErrorBoundary>
</header>
<Tabs className={paneBodyClasses + ' react-tabs'} forceRenderTabPanel>
</PaneHeader>
<Tabs className={classnames(paneBodyClasses, 'react-tabs')} forceRenderTabPanel>
<TabList>
<Tab tabIndex="-1">
<ContentTypeDropdown
@@ -459,7 +401,7 @@ class RequestPane extends React.PureComponent<Props> {
)}
</TabPanel>
</Tabs>
</section>
</Pane>
);
}
}

View File

@@ -1,6 +1,6 @@
// @flow
import type { Request } from '../../models/request';
import type { Response } from '../../models/response';
import type { Request } from '../../../models/request';
import type { Response } from '../../../models/response';
import * as React from 'react';
import autobind from 'autobind-decorator';
@@ -8,30 +8,32 @@ import fs from 'fs';
import mime from 'mime-types';
import { remote } from 'electron';
import { Tab, TabList, TabPanel, Tabs } from 'react-tabs';
import SizeTag from './tags/size-tag';
import StatusTag from './tags/status-tag';
import TimeTag from './tags/time-tag';
import Button from './base/button';
import PreviewModeDropdown from './dropdowns/preview-mode-dropdown';
import ResponseViewer from './viewers/response-viewer';
import ResponseHistoryDropdown from './dropdowns/response-history-dropdown';
import ResponseTimer from './response-timer';
import ResponseTimelineViewer from './viewers/response-timeline-viewer';
import ResponseHeadersViewer from './viewers/response-headers-viewer';
import ResponseCookiesViewer from './viewers/response-cookies-viewer';
import * as models from '../../models';
import { PREVIEW_MODE_SOURCE } from '../../common/constants';
import { getSetCookieHeaders } from '../../common/misc';
import { cancelRequestById } from '../../network/network';
import Hotkey from './hotkey';
import ErrorBoundary from './error-boundary';
import type { HotKeyRegistry } from '../../common/hotkeys';
import { hotKeyRefs } from '../../common/hotkeys';
import type { RequestVersion } from '../../models/request-version';
import { showError } from '../components/modals/index';
import SizeTag from '../tags/size-tag';
import StatusTag from '../tags/status-tag';
import TimeTag from '../tags/time-tag';
import Button from '../base/button';
import PreviewModeDropdown from '../dropdowns/preview-mode-dropdown';
import ResponseViewer from '../viewers/response-viewer';
import ResponseHistoryDropdown from '../dropdowns/response-history-dropdown';
import ResponseTimer from '../response-timer';
import ResponseTimelineViewer from '../viewers/response-timeline-viewer';
import ResponseHeadersViewer from '../viewers/response-headers-viewer';
import ResponseCookiesViewer from '../viewers/response-cookies-viewer';
import * as models from '../../../models';
import { PREVIEW_MODE_SOURCE } from '../../../common/constants';
import { getSetCookieHeaders } from '../../../common/misc';
import { cancelRequestById } from '../../../network/network';
import ErrorBoundary from '../error-boundary';
import type { HotKeyRegistry } from '../../../common/hotkeys';
import type { RequestVersion } from '../../../models/request-version';
import { showError } from '../modals';
import { json as jsonPrettify } from 'insomnia-prettify';
import type { Environment } from '../../models/environment';
import type { UnitTestResult } from '../../models/unit-test-result';
import type { Environment } from '../../../models/environment';
import type { UnitTestResult } from '../../../models/unit-test-result';
import BlankPane from './blank-pane';
import PlaceholderResponsePane from './placeholder-response-pane';
import { Pane, paneBodyClasses, PaneHeader } from './pane';
import classnames from 'classnames';
type Props = {
// Functions
@@ -204,90 +206,28 @@ class ResponsePane extends React.PureComponent<Props> {
responses,
showCookiesModal,
} = this.props;
const paneClasses = 'response-pane theme--pane pane';
const paneHeaderClasses = 'pane__header theme--pane__header';
const paneBodyClasses = 'pane__body theme--pane__body';
if (!request) {
return (
<section className={paneClasses}>
<header className={paneHeaderClasses} />
<div className={paneBodyClasses + ' pane__body--placeholder'} />
</section>
);
return <BlankPane type="response" />;
}
if (!response) {
return (
<section className={paneClasses}>
<header className={paneHeaderClasses} />
<div className={paneBodyClasses + ' pane__body--placeholder'}>
<div>
<table className="table--fancy">
<tbody>
<tr>
<td>Send Request</td>
<td className="text-right">
<code>
<Hotkey
keyBindings={hotKeyRegistry[hotKeyRefs.REQUEST_SEND.id]}
useFallbackMessage
/>
</code>
</td>
</tr>
<tr>
<td>Focus Url Bar</td>
<td className="text-right">
<code>
<Hotkey
keyBindings={hotKeyRegistry[hotKeyRefs.REQUEST_FOCUS_URL.id]}
useFallbackMessage
/>
</code>
</td>
</tr>
<tr>
<td>Manage Cookies</td>
<td className="text-right">
<code>
<Hotkey
keyBindings={hotKeyRegistry[hotKeyRefs.SHOW_COOKIES_EDITOR.id]}
useFallbackMessage
/>
</code>
</td>
</tr>
<tr>
<td>Edit Environments</td>
<td className="text-right">
<code>
<Hotkey
keyBindings={hotKeyRegistry[hotKeyRefs.ENVIRONMENT_SHOW_EDITOR.id]}
useFallbackMessage
/>
</code>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<PlaceholderResponsePane hotKeyRegistry={hotKeyRegistry}>
<ResponseTimer
handleCancel={() => cancelRequestById(request._id)}
loadStartTime={loadStartTime}
/>
</section>
</PlaceholderResponsePane>
);
}
const cookieHeaders = getSetCookieHeaders(response.headers);
return (
<section className={paneClasses}>
<Pane type="response">
{!response ? null : (
<header className={paneHeaderClasses + ' row-spaced'}>
<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} />
@@ -305,10 +245,10 @@ class ResponsePane extends React.PureComponent<Props> {
className="tall pane__header__right"
right
/>
</header>
</PaneHeader>
)}
<Tabs
className={paneBodyClasses + ' react-tabs'}
className={classnames(paneBodyClasses, 'react-tabs')}
onSelect={this._handleTabSelect}
forceRenderTabPanel>
<TabList>
@@ -400,7 +340,7 @@ class ResponsePane extends React.PureComponent<Props> {
loadStartTime={loadStartTime}
/>
</ErrorBoundary>
</section>
</Pane>
);
}
}

View File

@@ -4,9 +4,9 @@ import autobind from 'autobind-decorator';
import { Breadcrumb, Header } from 'insomnia-components';
import PageLayout from './page-layout';
import type { WrapperProps } from './wrapper';
import RequestPane from './request-pane';
import RequestPane from './panes/request-pane';
import ErrorBoundary from './error-boundary';
import ResponsePane from './response-pane';
import ResponsePane from './panes/response-pane';
import SidebarChildren from './sidebar/sidebar-children';
import SidebarFilter from './sidebar/sidebar-filter';
import EnvironmentsDropdown from './dropdowns/environments-dropdown';
@@ -15,6 +15,10 @@ import WorkspaceDropdown from './dropdowns/workspace-dropdown';
import { ACTIVITY_HOME, isInsomnia } from '../../common/constants';
import ActivityToggle from './activity-toggle';
import { isGrpcRequest } from '../../models/helpers/is-model';
import type { ForceToWorkspace } from '../redux/modules/helpers';
import GrpcRequestPane from './panes/grpc-request-pane';
import GrpcResponsePane from './panes/grpc-response-pane';
import { ResizablePaneWrapper } from './panes/pane';
type Props = {
forceRefreshKey: string,
@@ -26,7 +30,7 @@ type Props = {
handleForceUpdateRequest: Function,
handleForceUpdateRequestHeaders: Function,
handleImport: Function,
handleImportFile: Function,
handleImportFile: (forceToWorkspace?: ForceToWorkspace) => void,
handleRequestCreate: Function,
handleRequestGroupCreate: Function,
handleSendAndDownloadRequestWithActiveEnvironment: Function,
@@ -252,10 +256,42 @@ class WrapperDebug extends React.PureComponent<Props> {
settings,
} = this.props.wrapperProps;
const dragPanes = (
<>
<div className="drag drag--pane-horizontal">
<div
onMouseDown={handleStartDragPaneHorizontal}
onDoubleClick={handleResetDragPaneHorizontal}
/>
</div>
<div className="drag drag--pane-vertical">
<div
onMouseDown={handleStartDragPaneVertical}
onDoubleClick={handleResetDragPaneVertical}
/>
</div>
</>
);
// activeRequest being truthy only needs to be checked for isGrpcRequest (for now)
// The RequestPane and ResponsePane components already handle the case where activeRequest is null
if (activeRequest && isGrpcRequest(activeRequest)) {
return null;
return (
<React.Fragment>
<ErrorBoundary showAlert>
<ResizablePaneWrapper ref={handleSetRequestPaneRef}>
<GrpcRequestPane />
</ResizablePaneWrapper>
</ErrorBoundary>
{dragPanes}
<ErrorBoundary showAlert>
<ResizablePaneWrapper ref={handleSetResponsePaneRef}>
<GrpcResponsePane />
</ResizablePaneWrapper>
</ErrorBoundary>
</React.Fragment>
);
}
return (
@@ -298,19 +334,7 @@ class WrapperDebug extends React.PureComponent<Props> {
/>
</ErrorBoundary>
<div className="drag drag--pane-horizontal">
<div
onMouseDown={handleStartDragPaneHorizontal}
onDoubleClick={handleResetDragPaneHorizontal}
/>
</div>
<div className="drag drag--pane-vertical">
<div
onMouseDown={handleStartDragPaneVertical}
onDoubleClick={handleResetDragPaneVertical}
/>
</div>
{dragPanes}
<ErrorBoundary showAlert>
<ResponsePane