insomnia/packages/insomnia-app/app/ui/components/modals/generate-config-modal.tsx
2021-05-19 08:32:18 +12:00

162 lines
4.3 KiB
TypeScript

import React, { PureComponent } from 'react';
import { autoBindMethodsForReact } from 'class-autobind-decorator';
import { AUTOBIND_CFG } from '../../../common/constants';
import Modal from '../base/modal';
import ModalBody from '../base/modal-body';
import ModalHeader from '../base/modal-header';
import type { ApiSpec } from '../../../models/api-spec';
import { Tab, TabList, TabPanel, Tabs } from 'react-tabs';
import CodeEditor from '../codemirror/code-editor';
import type { Settings } from '../../../models/settings';
import Notice from '../notice';
import CopyButton from '../base/copy-button';
import ModalFooter from '../base/modal-footer';
import type { ConfigGenerator } from '../../../plugins';
import * as plugins from '../../../plugins';
import { parseApiSpec } from '../../../common/api-specs';
import { showModal } from './index';
interface Props {
settings: Settings;
}
interface Config {
label: string;
content: string;
mimeType: string;
error: string | null;
}
interface State {
configs: Config[];
activeTab: number;
}
interface ShowOptions {
apiSpec: ApiSpec;
activeTabLabel: string;
}
@autoBindMethodsForReact(AUTOBIND_CFG)
class GenerateConfigModal extends PureComponent<Props, State> {
modal: Modal | null = null;
state: State = {
configs: [],
activeTab: 0,
}
_setModalRef(n: Modal) {
this.modal = n;
}
async _generate(generatePlugin: ConfigGenerator, apiSpec: ApiSpec) {
const config: Config = {
content: '',
mimeType: 'text/yaml',
label: generatePlugin.label,
error: null,
};
let result;
try {
// @ts-expect-error -- TSCONVERSION
result = await generatePlugin.generate(parseApiSpec(apiSpec.contents));
} catch (err) {
config.error = err.message;
return config;
}
config.content = result.document || null;
config.error = result.error || null;
return config;
}
async show({ activeTabLabel, apiSpec }: ShowOptions) {
const configs: Config[] = [];
for (const p of await plugins.getConfigGenerators()) {
configs.push(await this._generate(p, apiSpec));
}
const foundIndex = configs.findIndex(c => c.label === activeTabLabel);
this.setState({
configs,
activeTab: foundIndex < 0 ? 0 : foundIndex,
});
this.modal && this.modal.show();
}
renderConfigTabPanel(config: Config) {
const { settings } = this.props;
if (config.error) {
return (
<TabPanel key={config.label}>
<Notice color="error" className="margin-md">
{config.error}
</Notice>
</TabPanel>
);
}
return (
<TabPanel key={config.label}>
<CodeEditor
className="tall pad-top-sm"
defaultValue={config.content}
fontSize={settings.editorFontSize}
indentSize={settings.editorIndentSize}
keyMap={settings.editorKeyMap}
lineWrapping={settings.editorLineWrapping}
mode={config.mimeType}
nunjucksPowerUserMode={settings.nunjucksPowerUserMode}
// @ts-expect-error -- TSCONVERSION appears to be genuine
onChange={this._handleChange}
readOnly
/>
</TabPanel>
);
}
_handleTabSelect(index: number) {
this.setState({
activeTab: index,
});
}
renderConfigTab(config: Config) {
return (
<Tab key={config.label} tabIndex="-1">
<button>{config.label}</button>
</Tab>
);
}
render() {
const { configs, activeTab } = this.state;
const activeConfig = configs[activeTab];
return (
<Modal ref={this._setModalRef} freshState tall>
<ModalHeader>Generate Config</ModalHeader>
<ModalBody className="wide">
<Tabs forceRenderTabPanel defaultIndex={activeTab} onSelect={this._handleTabSelect}>
<TabList>{configs.map(this.renderConfigTab)}</TabList>
{configs.map(this.renderConfigTabPanel)}
</Tabs>
</ModalBody>
{activeConfig && (
<ModalFooter>
<CopyButton className="btn" content={activeConfig.content}>
Copy to Clipboard
</CopyButton>
</ModalFooter>
)}
</Modal>
);
}
}
export const showGenerateConfigModal = (opts: ShowOptions) => showModal(GenerateConfigModal, opts);
export default GenerateConfigModal;