insomnia/packages/insomnia-app/app/ui/components/modals/code-prompt-modal.tsx
2021-08-07 08:03:56 +00:00

236 lines
6.8 KiB
TypeScript

import { autoBindMethodsForReact } from 'class-autobind-decorator';
import React, { PureComponent } from 'react';
import { AUTOBIND_CFG } from '../../../common/constants';
import { HandleGetRenderContext, HandleRender } from '../../../common/render';
import CopyButton from '../base/copy-button';
import Dropdown from '../base/dropdown/dropdown';
import DropdownButton from '../base/dropdown/dropdown-button';
import DropdownDivider from '../base/dropdown/dropdown-divider';
import DropdownItem from '../base/dropdown/dropdown-item';
import Modal from '../base/modal';
import ModalBody from '../base/modal-body';
import ModalFooter from '../base/modal-footer';
import ModalHeader from '../base/modal-header';
import CodeEditor from '../codemirror/code-editor';
import MarkdownEditor from '../markdown-editor';
const MODES = {
'text/plain': 'Plain Text',
'application/json': 'JSON',
'application/xml': 'XML',
'application/edn': 'EDN',
'text/x-markdown': 'Markdown',
'text/html': 'HTML',
};
interface Props {
editorFontSize: number;
editorIndentSize: number;
editorKeyMap: string;
editorLineWrapping: boolean;
nunjucksPowerUserMode: boolean;
isVariableUncovered: boolean;
handleGetRenderContext?: HandleGetRenderContext;
handleRender?: HandleRender;
}
interface State {
title: string;
defaultValue: string;
submitName: string;
placeholder: string;
hint: string;
mode: string;
hideMode: boolean,
enableRender: boolean,
showCopyButton: boolean,
}
@autoBindMethodsForReact(AUTOBIND_CFG)
class CodePromptModal extends PureComponent<Props, State> {
state: State = {
title: 'Not Set',
defaultValue: '',
submitName: 'Not Set',
placeholder: '',
hint: '',
mode: 'text/plain',
hideMode: false,
enableRender: false,
showCopyButton: false,
}
modal: Modal | null = null;
_onModeChange: Function = () => {};
_onChange: Function = () => {};
_setModalRef(n: Modal) {
this.modal = n;
}
_handleChange(value) {
this._onChange(value);
}
_handleChangeMode(mode) {
this.setState({ mode });
this._onModeChange?.(mode);
}
hide() {
this.modal?.hide();
}
show(options) {
const {
title,
defaultValue,
submitName,
placeholder,
hint,
mode,
hideMode,
enableRender,
onChange,
onModeChange,
showCopyButton,
} = options;
this._onChange = onChange;
this._onModeChange = onModeChange;
const realMode = typeof mode === 'string' ? mode : 'text/plain';
this.setState({
title,
defaultValue,
submitName,
placeholder,
hint,
enableRender,
hideMode,
showCopyButton,
mode: realMode || this.state.mode || 'text/plain',
});
this.modal?.show();
}
render() {
const {
handleGetRenderContext,
nunjucksPowerUserMode,
isVariableUncovered,
handleRender,
editorKeyMap,
editorIndentSize,
editorFontSize,
editorLineWrapping,
} = this.props;
const {
submitName,
title,
placeholder,
defaultValue,
hint,
mode,
hideMode,
enableRender,
showCopyButton,
} = this.state;
return (
<Modal ref={this._setModalRef} freshState tall>
<ModalHeader>{title}</ModalHeader>
<ModalBody
noScroll
className="wide tall"
style={
showCopyButton
? {
display: 'grid',
gridTemplateColumns: 'minmax(0, 1fr)',
gridTemplateRows: 'auto minmax(0, 1fr)',
}
: {
minHeight: '10rem',
}
}
>
{showCopyButton ? (
<div className="pad-top-sm pad-right-sm">
<CopyButton content={defaultValue} className="pull-right" />
</div>
) : null}
{mode === 'text/x-markdown' ? (
<div className="pad-sm tall">
<MarkdownEditor
tall
defaultValue={defaultValue}
placeholder={placeholder}
onChange={this._handleChange}
// @ts-expect-error -- TSCONVERSION appears to be a genuine error
handleGetRenderContext={enableRender ? handleGetRenderContext : null}
// @ts-expect-error -- TSCONVERSION appears to be a genuine error
handleRender={enableRender ? handleRender : null}
mode={mode}
keyMap={editorKeyMap}
indentSize={editorIndentSize}
fontSize={editorFontSize}
lineWrapping={editorLineWrapping}
nunjucksPowerUserMode={nunjucksPowerUserMode}
isVariableUncovered={isVariableUncovered}
/>
</div>
) : (
<div className="pad-sm pad-bottom tall">
<div className="form-control form-control--outlined form-control--tall tall">
<CodeEditor
hideLineNumbers
manualPrettify
className="tall"
defaultValue={defaultValue}
placeholder={placeholder}
onChange={this._handleChange}
nunjucksPowerUserMode={nunjucksPowerUserMode}
isVariableUncovered={isVariableUncovered}
// @ts-expect-error -- TSCONVERSION appears to be a genuine error
getRenderContext={enableRender ? handleGetRenderContext : null}
// @ts-expect-error -- TSCONVERSION appears to be a genuine error
render={enableRender ? handleRender : null}
mode={mode}
keyMap={editorKeyMap}
indentSize={editorIndentSize}
fontSize={editorFontSize}
lineWrapping={editorLineWrapping}
/>
</div>
</div>
)}
</ModalBody>
<ModalFooter>
{!hideMode ? (
<Dropdown>
<DropdownButton className="btn btn--clicky margin-left-sm">
{MODES[mode]}
<i className="fa fa-caret-down space-left" />
</DropdownButton>
<DropdownDivider>Editor Syntax</DropdownDivider>
{Object.keys(MODES).map(mode => (
<DropdownItem key={mode} value={mode} onClick={this._handleChangeMode}>
<i className="fa fa-code" />
{MODES[mode]}
</DropdownItem>
))}
</Dropdown>
) : null}
<div className="margin-left faint italic txt-sm tall">{hint ? `* ${hint}` : ''}</div>
<button className="btn" onClick={this.hide}>
{submitName || 'Submit'}
</button>
</ModalFooter>
</Modal>
);
}
}
export default CodePromptModal;