Skip to content
This repository was archived by the owner on Jul 19, 2024. It is now read-only.

Commit 989edf6

Browse files
author
archy
committed
re-enabled plugin & rename 'gen code' to 'show curl, etc'
1 parent 979cf04 commit 989edf6

File tree

5 files changed

+281
-3
lines changed

5 files changed

+281
-3
lines changed

packages/insomnia/src/main/install-plugin.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ async function _isInsomniaPlugin(lookupName: string) {
134134
}
135135

136136
const data = yarnOutput.data;
137+
console.log('plugin data', data);
137138

138139
if (!data.hasOwnProperty('insomnia')) {
139140
reject(new Error(`"${lookupName}" not a plugin! Package missing "insomnia" attribute`));

packages/insomnia/src/ui/components/modals/generate-code-modal.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ export const GenerateCodeModal = forwardRef<GenerateCodeModalHandle, Props>((pro
111111
}
112112
return (
113113
<Modal ref={modalRef} tall {...props}>
114-
<ModalHeader>Generate Client Code</ModalHeader>
114+
<ModalHeader>Show CURL code, etc</ModalHeader>
115115
<ModalBody
116116
noScroll
117117
style={{

packages/insomnia/src/ui/components/modals/settings-modal.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { ImportExport } from '../settings/import-export';
1313
import { Shortcuts } from '../settings/shortcuts';
1414
import { ThemePanel } from '../settings/theme-panel';
1515
import { showModal } from './index';
16+
import { Plugins } from '../settings/plugins';
1617

1718
export interface SettingsModalHandle {
1819
hide: () => void;
@@ -71,6 +72,11 @@ export const SettingsModal = forwardRef<SettingsModalHandle, ModalProps>((props,
7172
<Shortcuts />
7273
</PanelContainer>
7374
</TabItem>
75+
<TabItem key="plugins" title="Plugins">
76+
<PanelContainer className="pad">
77+
<Plugins />
78+
</PanelContainer>
79+
</TabItem>
7480

7581

7682
</Tabs>

packages/insomnia/src/ui/components/request-url-bar.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -261,10 +261,10 @@ export const RequestUrlBar = forwardRef<RequestUrlBarHandle, Props>(({
261261
<DropdownItem aria-label="send-now">
262262
<ItemContent icon="arrow-circle-o-right" label="Send Now" hint={hotKeyRegistry.request_send} onClick={sendOrConnect} />
263263
</DropdownItem>
264-
<DropdownItem aria-label='Generate Client Code'>
264+
<DropdownItem aria-label='Show CURL code, etc'>
265265
<ItemContent
266266
icon="code"
267-
label="Generate Client Code"
267+
label="Show CURL code, etc"
268268
onClick={() => showModal(GenerateCodeModal, { request: activeRequest })}
269269
/>
270270
</DropdownItem>
Lines changed: 271 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,271 @@
1+
import * as path from 'path';
2+
import React, { FC, useEffect, useState } from 'react';
3+
import { useRouteLoaderData } from 'react-router-dom';
4+
5+
import {
6+
NPM_PACKAGE_BASE,
7+
PLUGIN_HUB_BASE,
8+
} from '../../../common/constants';
9+
import { docsPlugins } from '../../../common/documentation';
10+
import { createPlugin } from '../../../plugins/create';
11+
import type { Plugin } from '../../../plugins/index';
12+
import { getPlugins } from '../../../plugins/index';
13+
import { reload } from '../../../templating/index';
14+
import { useSettingsPatcher } from '../../hooks/use-request';
15+
import { RootLoaderData } from '../../routes/root';
16+
import { CopyButton } from '../base/copy-button';
17+
import { Link } from '../base/link';
18+
import { HelpTooltip } from '../help-tooltip';
19+
import { showAlert, showPrompt } from '../modals';
20+
import { Button } from '../themed-button';
21+
interface State {
22+
plugins: Plugin[];
23+
npmPluginValue: string;
24+
error: Error | null;
25+
installPluginErrMsg: string;
26+
isInstallingFromNpm: boolean;
27+
isRefreshingPlugins: boolean;
28+
}
29+
export const Plugins: FC = () => {
30+
const [state, setState] = useState<State>({
31+
plugins: [],
32+
npmPluginValue: '',
33+
error: null,
34+
installPluginErrMsg: '',
35+
isInstallingFromNpm: false,
36+
isRefreshingPlugins: false,
37+
});
38+
const {
39+
plugins,
40+
error,
41+
installPluginErrMsg,
42+
isInstallingFromNpm,
43+
isRefreshingPlugins,
44+
npmPluginValue,
45+
} = state;
46+
const {
47+
settings,
48+
} = useRouteLoaderData('root') as RootLoaderData;
49+
50+
useEffect(() => {
51+
refreshPlugins();
52+
}, []);
53+
54+
async function refreshPlugins() {
55+
setState(state => ({ ...state, isRefreshingPlugins: true }));
56+
// Get and reload plugins
57+
const plugins = await getPlugins(true);
58+
reload();
59+
60+
setState(state => ({ ...state, plugins, isRefreshingPlugins: false }));
61+
}
62+
const patchSettings = useSettingsPatcher();
63+
64+
return (
65+
<div>
66+
<p className="notice info no-margin-top">
67+
Plugins is still an experimental feature. See{' '}
68+
<Link href={docsPlugins}>Documentation</Link> for more info.
69+
</p>
70+
{plugins.length === 0 ? (
71+
<div className="text-center faint italic pad">No Plugins Added</div>
72+
) : (
73+
<table className="table--fancy table--striped table--valign-middle margin-top margin-bottom">
74+
<thead>
75+
<tr>
76+
<th>Enable?</th>
77+
<th>Name</th>
78+
<th>Version</th>
79+
<th>Folder</th>
80+
</tr>
81+
</thead>
82+
<tbody>
83+
{plugins.map(plugin => {
84+
const link = path.join(/^insomnia-plugin-/.test(plugin.name) ? PLUGIN_HUB_BASE : NPM_PACKAGE_BASE, plugin.name);
85+
return !plugin.directory ? null : (
86+
<tr key={plugin.name}>
87+
<td style={{ width: '4rem' }}>
88+
<input
89+
type="checkbox"
90+
checked={!plugin.config.disabled}
91+
disabled={isRefreshingPlugins}
92+
onChange={async event => {
93+
const newConfig = { ...plugin.config, disabled: !event.target.checked };
94+
setState(state => ({ ...state, isRefreshingPlugins: true }));
95+
patchSettings({ pluginConfig: { ...settings.pluginConfig, [plugin.name]: newConfig } });
96+
refreshPlugins();
97+
}}
98+
/>
99+
</td>
100+
<td>
101+
{plugin.name}
102+
{plugin.description && (
103+
<HelpTooltip info className="space-left">
104+
{plugin.description}
105+
</HelpTooltip>
106+
)}
107+
</td>
108+
<td>
109+
{plugin.version}
110+
<a className="space-left" href={link} title={link}>
111+
<i className="fa fa-external-link-square" />
112+
</a>
113+
</td>
114+
<td
115+
className="no-wrap"
116+
style={{
117+
width: '10rem',
118+
}}
119+
>
120+
<CopyButton
121+
size="small"
122+
variant="contained"
123+
title={plugin.directory}
124+
content={plugin.directory}
125+
>
126+
Copy Path
127+
</CopyButton>{' '}
128+
<Button
129+
size="small"
130+
variant="contained"
131+
onClick={() => window.shell.showItemInFolder(plugin.directory)}
132+
>
133+
Reveal Folder
134+
</Button>
135+
</td>
136+
</tr>
137+
);
138+
}
139+
)}
140+
</tbody>
141+
</table>
142+
)}
143+
144+
{error && (
145+
<div className="notice error text-left margin-bottom">
146+
<button className="pull-right icon" onClick={() => setState(state => ({ ...state, error: null }))}>
147+
<i className="fa fa-times" />
148+
</button>
149+
<div className="selectable force-pre-wrap">
150+
<b>{installPluginErrMsg}</b>
151+
{'\n\nThere may be an issue with the plugin itself, as a note you can discover and install plugins from the '}
152+
<a href={PLUGIN_HUB_BASE}>Plugin Hub.</a>
153+
<details>
154+
<summary>Additional Information</summary>
155+
<pre className="pad-top-sm force-wrap selectable">
156+
<code>{error.stack || error.message}</code>
157+
</pre>
158+
</details>
159+
</div>
160+
</div>
161+
)}
162+
163+
<form
164+
onSubmit={async event => {
165+
event.preventDefault();
166+
setState(state => ({ ...state, isInstallingFromNpm: true }));
167+
const newState: Partial<State> = {
168+
isInstallingFromNpm: false,
169+
error: null,
170+
installPluginErrMsg: '',
171+
};
172+
try {
173+
await window.main.installPlugin(npmPluginValue.trim());
174+
await refreshPlugins();
175+
newState.npmPluginValue = ''; // Clear input if successful install
176+
} catch (err) {
177+
newState.installPluginErrMsg = `Failed to install ${npmPluginValue}`;
178+
newState.error = err;
179+
}
180+
setState(state => ({ ...state, ...newState }));
181+
}}
182+
>
183+
<div className="form-row">
184+
<div className="form-control form-control--outlined">
185+
<input
186+
onChange={event => {
187+
if (event.target instanceof HTMLInputElement) {
188+
setState(state => ({ ...state, npmPluginValue: event.target.value }));
189+
}
190+
}}
191+
disabled={isInstallingFromNpm}
192+
type="text"
193+
placeholder="npm-package-name"
194+
value={npmPluginValue}
195+
/>
196+
</div>
197+
<div className="form-control width-auto">
198+
<Button variant="contained" bg="surprise" disabled={isInstallingFromNpm}>
199+
{isInstallingFromNpm && <i className="fa fa-refresh fa-spin space-right" />}
200+
Install Plugin
201+
</Button>
202+
</div>
203+
</div>
204+
</form>
205+
<hr />
206+
<div className="text-right">
207+
<Button
208+
onClick={() => window.main.openInBrowser(PLUGIN_HUB_BASE)}
209+
>
210+
Browse Plugin Hub
211+
</Button>
212+
<Button
213+
style={{
214+
marginLeft: '0.3em',
215+
}}
216+
onClick={() => showPrompt({
217+
title: 'New Plugin',
218+
defaultValue: 'demo-example',
219+
placeholder: 'example-name',
220+
submitName: 'Generate',
221+
label: 'Plugin Name',
222+
selectText: true,
223+
validate: name =>
224+
name.match(/^[a-z][a-z-]*[a-z]$/) ? '' : 'Plugin name must be of format my-plugin-name',
225+
onComplete: async name => {
226+
// Remove insomnia-plugin- prefix if they accidentally typed it
227+
name = name.replace(/^insomnia-plugin-/, '');
228+
try {
229+
await createPlugin(
230+
`insomnia-plugin-${name}`,
231+
'0.0.1',
232+
[
233+
'// For help writing plugins, visit the documentation to get started:',
234+
`// ${docsPlugins}`,
235+
'',
236+
'// TODO: Add plugin code here...',
237+
].join('\n'),
238+
);
239+
} catch (err) {
240+
console.error(err);
241+
showAlert({
242+
title: 'Failed to Create Plugin',
243+
message: err.message,
244+
});
245+
}
246+
refreshPlugins();
247+
},
248+
})}
249+
>Generate New Plugin</Button>
250+
<Button
251+
style={{
252+
marginLeft: '0.3em',
253+
}}
254+
onClick={() => window.shell.showItemInFolder(path.join(process.env['INSOMNIA_DATA_PATH'] || window.app.getPath('userData'), 'plugins'))}
255+
>
256+
Reveal Plugins Folder
257+
</Button>
258+
<Button
259+
disabled={isRefreshingPlugins}
260+
style={{
261+
marginLeft: '0.3em',
262+
}}
263+
onClick={() => refreshPlugins()}
264+
>
265+
Reload Plugins
266+
{isRefreshingPlugins && <i className="fa fa-refresh fa-spin space-left" />}
267+
</Button>
268+
</div>
269+
</div>
270+
);
271+
};

0 commit comments

Comments
 (0)