mirror of
https://github.com/Kong/insomnia
synced 2024-11-12 17:26:32 +00:00
ad278ea01a
* Added request-specific follow redirect setting * Added hint text to follow redirects setting
401 lines
12 KiB
JavaScript
401 lines
12 KiB
JavaScript
// @flow
|
|
import * as React from 'react';
|
|
import autobind from 'autobind-decorator';
|
|
import Modal from '../base/modal';
|
|
import ModalBody from '../base/modal-body';
|
|
import ModalHeader from '../base/modal-header';
|
|
import HelpTooltip from '../help-tooltip';
|
|
import * as models from '../../../models';
|
|
import DebouncedInput from '../base/debounced-input';
|
|
import MarkdownEditor from '../markdown-editor';
|
|
import * as db from '../../../common/database';
|
|
import type { Workspace } from '../../../models/workspace';
|
|
import type { Request } from '../../../models/request';
|
|
|
|
type Props = {
|
|
editorFontSize: number,
|
|
editorIndentSize: number,
|
|
editorKeyMap: string,
|
|
editorLineWrapping: boolean,
|
|
nunjucksPowerUserMode: boolean,
|
|
isVariableUncovered: boolean,
|
|
handleRender: Function,
|
|
handleGetRenderContext: Function,
|
|
workspaces: Array<Workspace>,
|
|
};
|
|
|
|
type State = {
|
|
request: Request | null,
|
|
showDescription: boolean,
|
|
defaultPreviewMode: boolean,
|
|
activeWorkspaceIdToCopyTo: string | null,
|
|
workspace: Workspace | null,
|
|
justCopied: boolean,
|
|
justMoved: boolean,
|
|
};
|
|
|
|
@autobind
|
|
class RequestSettingsModal extends React.PureComponent<Props, State> {
|
|
modal: ?Modal;
|
|
_editor: ?MarkdownEditor;
|
|
|
|
constructor(props: Props) {
|
|
super(props);
|
|
this.state = {
|
|
request: null,
|
|
showDescription: false,
|
|
defaultPreviewMode: false,
|
|
activeWorkspaceIdToCopyTo: null,
|
|
workspace: null,
|
|
workspaces: [],
|
|
justCopied: false,
|
|
justMoved: false,
|
|
};
|
|
}
|
|
|
|
_setModalRef(n: ?Modal) {
|
|
this.modal = n;
|
|
}
|
|
|
|
_setEditorRef(n: ?MarkdownEditor) {
|
|
this._editor = n;
|
|
}
|
|
|
|
async _updateRequestSettingBoolean(e: SyntheticEvent<HTMLInputElement>) {
|
|
if (!this.state.request) {
|
|
// Should never happen
|
|
return;
|
|
}
|
|
|
|
const value = e.currentTarget.checked;
|
|
const setting = e.currentTarget.name;
|
|
const request = await models.request.update(this.state.request, {
|
|
[setting]: value,
|
|
});
|
|
this.setState({ request });
|
|
}
|
|
|
|
async _updateRequestSettingString(e: SyntheticEvent<HTMLInputElement>) {
|
|
if (!this.state.request) {
|
|
// Should never happen
|
|
return;
|
|
}
|
|
|
|
const value = e.currentTarget.value;
|
|
const setting = e.currentTarget.name;
|
|
const request = await models.request.update(this.state.request, {
|
|
[setting]: value,
|
|
});
|
|
this.setState({ request });
|
|
}
|
|
|
|
async _handleNameChange(name: string) {
|
|
if (!this.state.request) {
|
|
return;
|
|
}
|
|
const request = await models.request.update(this.state.request, { name });
|
|
this.setState({ request });
|
|
}
|
|
|
|
async _handleDescriptionChange(description: string) {
|
|
if (!this.state.request) {
|
|
return;
|
|
}
|
|
const request = await models.request.update(this.state.request, {
|
|
description,
|
|
});
|
|
this.setState({ request, defaultPreviewMode: false });
|
|
}
|
|
|
|
_handleAddDescription() {
|
|
this.setState({ showDescription: true });
|
|
}
|
|
|
|
_handleUpdateMoveCopyWorkspace(e: SyntheticEvent<HTMLSelectElement>) {
|
|
const { value } = e.currentTarget;
|
|
const workspaceId = value === '__NULL__' ? null : value;
|
|
this.setState({ activeWorkspaceIdToCopyTo: workspaceId });
|
|
}
|
|
|
|
async _handleMoveToWorkspace() {
|
|
const { activeWorkspaceIdToCopyTo, request } = this.state;
|
|
if (!request) {
|
|
return;
|
|
}
|
|
|
|
const workspace = await models.workspace.getById(activeWorkspaceIdToCopyTo || 'n/a');
|
|
if (!workspace) {
|
|
return;
|
|
}
|
|
|
|
await models.request.update(request, {
|
|
sortKey: -1e9, // Move to top of sort order
|
|
parentId: activeWorkspaceIdToCopyTo,
|
|
});
|
|
|
|
this.setState({ justMoved: true });
|
|
setTimeout(() => {
|
|
this.setState({ justMoved: false });
|
|
}, 2000);
|
|
}
|
|
|
|
async _handleCopyToWorkspace() {
|
|
const { activeWorkspaceIdToCopyTo, request } = this.state;
|
|
if (!request) {
|
|
return;
|
|
}
|
|
|
|
const workspace = await models.workspace.getById(activeWorkspaceIdToCopyTo || 'n/a');
|
|
if (!workspace) {
|
|
return;
|
|
}
|
|
|
|
const newRequest = await models.request.duplicate(request);
|
|
await models.request.update(newRequest, {
|
|
sortKey: -1e9, // Move to top of sort order
|
|
name: request.name, // Because duplicate will add (Copy) suffix
|
|
parentId: activeWorkspaceIdToCopyTo,
|
|
});
|
|
|
|
this.setState({ justCopied: true });
|
|
setTimeout(() => {
|
|
this.setState({ justCopied: false });
|
|
}, 2000);
|
|
}
|
|
|
|
async show({ request, forceEditMode }: { request: Request, forceEditMode: boolean }) {
|
|
const { workspaces } = this.props;
|
|
|
|
const hasDescription = !!request.description;
|
|
|
|
// Find workspaces for use with moving workspace
|
|
const ancestors = await db.withAncestors(request);
|
|
const doc = ancestors.find(doc => doc.type === models.workspace.type);
|
|
const workspaceId = doc ? doc._id : 'should-never-happen';
|
|
const workspace = workspaces.find(w => w._id === workspaceId);
|
|
|
|
this.setState(
|
|
{
|
|
request,
|
|
workspace: workspace,
|
|
activeWorkspaceIdToCopyTo: null,
|
|
showDescription: forceEditMode || hasDescription,
|
|
defaultPreviewMode: hasDescription && !forceEditMode,
|
|
},
|
|
() => {
|
|
this.modal && this.modal.show();
|
|
|
|
if (forceEditMode) {
|
|
setTimeout(() => {
|
|
this._editor && this._editor.focus();
|
|
}, 400);
|
|
}
|
|
},
|
|
);
|
|
}
|
|
|
|
hide() {
|
|
this.modal && this.modal.hide();
|
|
}
|
|
|
|
renderCheckboxInput(setting: string) {
|
|
const { request } = this.state;
|
|
if (!request) {
|
|
return;
|
|
}
|
|
|
|
return (
|
|
<input
|
|
type="checkbox"
|
|
name={setting}
|
|
checked={request[setting]}
|
|
onChange={this._updateRequestSettingBoolean}
|
|
/>
|
|
);
|
|
}
|
|
|
|
renderModalBody(request: Request) {
|
|
const {
|
|
editorLineWrapping,
|
|
editorFontSize,
|
|
editorIndentSize,
|
|
editorKeyMap,
|
|
handleRender,
|
|
handleGetRenderContext,
|
|
nunjucksPowerUserMode,
|
|
isVariableUncovered,
|
|
workspaces,
|
|
} = this.props;
|
|
|
|
const {
|
|
showDescription,
|
|
defaultPreviewMode,
|
|
activeWorkspaceIdToCopyTo,
|
|
justMoved,
|
|
justCopied,
|
|
workspace,
|
|
} = this.state;
|
|
|
|
return (
|
|
<div>
|
|
<div className="form-control form-control--outlined">
|
|
<label>
|
|
Name{' '}
|
|
<span className="txt-sm faint italic">(also rename by double-clicking in sidebar)</span>
|
|
<DebouncedInput
|
|
delay={500}
|
|
type="text"
|
|
placeholder="My Request"
|
|
defaultValue={request.name}
|
|
onChange={this._handleNameChange}
|
|
/>
|
|
</label>
|
|
</div>
|
|
{showDescription ? (
|
|
<MarkdownEditor
|
|
ref={this._setEditorRef}
|
|
className="margin-top"
|
|
defaultPreviewMode={defaultPreviewMode}
|
|
fontSize={editorFontSize}
|
|
indentSize={editorIndentSize}
|
|
keyMap={editorKeyMap}
|
|
placeholder="Write a description"
|
|
lineWrapping={editorLineWrapping}
|
|
handleRender={handleRender}
|
|
handleGetRenderContext={handleGetRenderContext}
|
|
nunjucksPowerUserMode={nunjucksPowerUserMode}
|
|
isVariableUncovered={isVariableUncovered}
|
|
defaultValue={request.description}
|
|
onChange={this._handleDescriptionChange}
|
|
/>
|
|
) : (
|
|
<button
|
|
onClick={this._handleAddDescription}
|
|
className="btn btn--outlined btn--super-duper-compact">
|
|
Add Description
|
|
</button>
|
|
)}
|
|
<div className="pad-top">
|
|
<div className="form-control form-control--thin">
|
|
<label>
|
|
Send cookies automatically
|
|
{this.renderCheckboxInput('settingSendCookies')}
|
|
</label>
|
|
</div>
|
|
<div className="form-control form-control--thin">
|
|
<label>
|
|
Store cookies automatically
|
|
{this.renderCheckboxInput('settingStoreCookies')}
|
|
</label>
|
|
</div>
|
|
<div className="form-control form-control--thin">
|
|
<label>
|
|
Automatically encode special characters in URL
|
|
{this.renderCheckboxInput('settingEncodeUrl')}
|
|
<HelpTooltip position="top" className="space-left">
|
|
Automatically encode special characters at send time (does not apply to query
|
|
parameters editor)
|
|
</HelpTooltip>
|
|
</label>
|
|
</div>
|
|
<div className="form-control form-control--thin">
|
|
<label>
|
|
Skip rendering of request body
|
|
{this.renderCheckboxInput('settingDisableRenderRequestBody')}
|
|
<HelpTooltip position="top" className="space-left">
|
|
Disable rendering of environment variables and tags for the request body
|
|
</HelpTooltip>
|
|
</label>
|
|
</div>
|
|
<div className="form-control form-control--thin">
|
|
<label>
|
|
Rebuild path dot sequences
|
|
<HelpTooltip position="top" className="space-left">
|
|
This instructs libcurl to squash sequences of "/../" or "/./" that may exist in the
|
|
URL's path part and that is supposed to be removed according to RFC 3986 section
|
|
5.2.4
|
|
</HelpTooltip>
|
|
{this.renderCheckboxInput('settingRebuildPath')}
|
|
</label>
|
|
</div>
|
|
</div>
|
|
<div className="pad-top">
|
|
<div className="form-control form-control--outlined">
|
|
<label>
|
|
Follow redirects{' '}
|
|
<span className="txt-sm faint italic">(overrides global setting)</span>
|
|
<select
|
|
defaultValue={this.state.request && this.state.request.settingFollowRedirects}
|
|
name="settingFollowRedirects"
|
|
onChange={this._updateRequestSettingString}>
|
|
<option value={'global'}>Use global setting</option>
|
|
<option value={'off'}>Don't follow redirects</option>
|
|
<option value={'on'}>Follow redirects</option>
|
|
</select>
|
|
</label>
|
|
</div>
|
|
<hr />
|
|
<div className="form-row">
|
|
<div className="form-control form-control--outlined">
|
|
<label>
|
|
Move/Copy to Workspace
|
|
<HelpTooltip position="top" className="space-left">
|
|
Copy or move the current request to a new workspace. It will be placed at the root
|
|
of the new workspace's folder structure.
|
|
</HelpTooltip>
|
|
<select
|
|
value={activeWorkspaceIdToCopyTo || '__NULL__'}
|
|
onChange={this._handleUpdateMoveCopyWorkspace}>
|
|
<option value="__NULL__">-- Select Workspace --</option>
|
|
{workspaces.map(w => {
|
|
if (workspace && workspace._id === w._id) {
|
|
return null;
|
|
}
|
|
|
|
return (
|
|
<option key={w._id} value={w._id}>
|
|
{w.name}
|
|
</option>
|
|
);
|
|
})}
|
|
</select>
|
|
</label>
|
|
</div>
|
|
<div className="form-control form-control--no-label width-auto">
|
|
<button
|
|
disabled={justCopied || !activeWorkspaceIdToCopyTo}
|
|
className="btn btn--clicky"
|
|
onClick={this._handleCopyToWorkspace}>
|
|
{justCopied ? 'Copied!' : 'Copy'}
|
|
</button>
|
|
</div>
|
|
<div className="form-control form-control--no-label width-auto">
|
|
<button
|
|
disabled={justMoved || !activeWorkspaceIdToCopyTo}
|
|
className="btn btn--clicky"
|
|
onClick={this._handleMoveToWorkspace}>
|
|
{justMoved ? 'Moved!' : 'Move'}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
render() {
|
|
const { request } = this.state;
|
|
return (
|
|
<Modal ref={this._setModalRef} freshState>
|
|
<ModalHeader>
|
|
Request Settings{' '}
|
|
<span className="txt-sm selectable faint monospace">{request ? request._id : ''}</span>
|
|
</ModalHeader>
|
|
<ModalBody className="pad">{request ? this.renderModalBody(request) : null}</ModalBody>
|
|
</Modal>
|
|
);
|
|
}
|
|
}
|
|
|
|
export default RequestSettingsModal;
|