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

Commit

Permalink
re-enabled plugin & rename 'gen code' to 'show curl, etc'
Browse files Browse the repository at this point in the history
  • Loading branch information
archywillhe committed Sep 30, 2023
1 parent 979cf04 commit 989edf6
Show file tree
Hide file tree
Showing 5 changed files with 281 additions and 3 deletions.
1 change: 1 addition & 0 deletions packages/insomnia/src/main/install-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ async function _isInsomniaPlugin(lookupName: string) {
}

const data = yarnOutput.data;
console.log('plugin data', data);

if (!data.hasOwnProperty('insomnia')) {
reject(new Error(`"${lookupName}" not a plugin! Package missing "insomnia" attribute`));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ export const GenerateCodeModal = forwardRef<GenerateCodeModalHandle, Props>((pro
}
return (
<Modal ref={modalRef} tall {...props}>
<ModalHeader>Generate Client Code</ModalHeader>
<ModalHeader>Show CURL code, etc</ModalHeader>
<ModalBody
noScroll
style={{
Expand Down
6 changes: 6 additions & 0 deletions packages/insomnia/src/ui/components/modals/settings-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { ImportExport } from '../settings/import-export';
import { Shortcuts } from '../settings/shortcuts';
import { ThemePanel } from '../settings/theme-panel';
import { showModal } from './index';
import { Plugins } from '../settings/plugins';

export interface SettingsModalHandle {
hide: () => void;
Expand Down Expand Up @@ -71,6 +72,11 @@ export const SettingsModal = forwardRef<SettingsModalHandle, ModalProps>((props,
<Shortcuts />
</PanelContainer>
</TabItem>
<TabItem key="plugins" title="Plugins">
<PanelContainer className="pad">
<Plugins />
</PanelContainer>
</TabItem>


</Tabs>
Expand Down
4 changes: 2 additions & 2 deletions packages/insomnia/src/ui/components/request-url-bar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -261,10 +261,10 @@ export const RequestUrlBar = forwardRef<RequestUrlBarHandle, Props>(({
<DropdownItem aria-label="send-now">
<ItemContent icon="arrow-circle-o-right" label="Send Now" hint={hotKeyRegistry.request_send} onClick={sendOrConnect} />
</DropdownItem>
<DropdownItem aria-label='Generate Client Code'>
<DropdownItem aria-label='Show CURL code, etc'>
<ItemContent
icon="code"
label="Generate Client Code"
label="Show CURL code, etc"
onClick={() => showModal(GenerateCodeModal, { request: activeRequest })}
/>
</DropdownItem>
Expand Down
271 changes: 271 additions & 0 deletions packages/insomnia/src/ui/components/settings/plugins.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,271 @@
import * as path from 'path';
import React, { FC, useEffect, useState } from 'react';
import { useRouteLoaderData } from 'react-router-dom';

import {
NPM_PACKAGE_BASE,
PLUGIN_HUB_BASE,
} from '../../../common/constants';
import { docsPlugins } from '../../../common/documentation';
import { createPlugin } from '../../../plugins/create';
import type { Plugin } from '../../../plugins/index';
import { getPlugins } from '../../../plugins/index';
import { reload } from '../../../templating/index';
import { useSettingsPatcher } from '../../hooks/use-request';
import { RootLoaderData } from '../../routes/root';
import { CopyButton } from '../base/copy-button';
import { Link } from '../base/link';
import { HelpTooltip } from '../help-tooltip';
import { showAlert, showPrompt } from '../modals';
import { Button } from '../themed-button';
interface State {
plugins: Plugin[];
npmPluginValue: string;
error: Error | null;
installPluginErrMsg: string;
isInstallingFromNpm: boolean;
isRefreshingPlugins: boolean;
}
export const Plugins: FC = () => {
const [state, setState] = useState<State>({
plugins: [],
npmPluginValue: '',
error: null,
installPluginErrMsg: '',
isInstallingFromNpm: false,
isRefreshingPlugins: false,
});
const {
plugins,
error,
installPluginErrMsg,
isInstallingFromNpm,
isRefreshingPlugins,
npmPluginValue,
} = state;
const {
settings,
} = useRouteLoaderData('root') as RootLoaderData;

useEffect(() => {
refreshPlugins();
}, []);

async function refreshPlugins() {
setState(state => ({ ...state, isRefreshingPlugins: true }));
// Get and reload plugins
const plugins = await getPlugins(true);
reload();

setState(state => ({ ...state, plugins, isRefreshingPlugins: false }));
}
const patchSettings = useSettingsPatcher();

return (
<div>
<p className="notice info no-margin-top">
Plugins is still an experimental feature. See{' '}
<Link href={docsPlugins}>Documentation</Link> for more info.
</p>
{plugins.length === 0 ? (
<div className="text-center faint italic pad">No Plugins Added</div>
) : (
<table className="table--fancy table--striped table--valign-middle margin-top margin-bottom">
<thead>
<tr>
<th>Enable?</th>
<th>Name</th>
<th>Version</th>
<th>Folder</th>
</tr>
</thead>
<tbody>
{plugins.map(plugin => {
const link = path.join(/^insomnia-plugin-/.test(plugin.name) ? PLUGIN_HUB_BASE : NPM_PACKAGE_BASE, plugin.name);
return !plugin.directory ? null : (
<tr key={plugin.name}>
<td style={{ width: '4rem' }}>
<input
type="checkbox"
checked={!plugin.config.disabled}
disabled={isRefreshingPlugins}
onChange={async event => {
const newConfig = { ...plugin.config, disabled: !event.target.checked };
setState(state => ({ ...state, isRefreshingPlugins: true }));
patchSettings({ pluginConfig: { ...settings.pluginConfig, [plugin.name]: newConfig } });
refreshPlugins();
}}
/>
</td>
<td>
{plugin.name}
{plugin.description && (
<HelpTooltip info className="space-left">
{plugin.description}
</HelpTooltip>
)}
</td>
<td>
{plugin.version}
<a className="space-left" href={link} title={link}>
<i className="fa fa-external-link-square" />
</a>
</td>
<td
className="no-wrap"
style={{
width: '10rem',
}}
>
<CopyButton
size="small"
variant="contained"
title={plugin.directory}
content={plugin.directory}
>
Copy Path
</CopyButton>{' '}
<Button
size="small"
variant="contained"
onClick={() => window.shell.showItemInFolder(plugin.directory)}
>
Reveal Folder
</Button>
</td>
</tr>
);
}
)}
</tbody>
</table>
)}

{error && (
<div className="notice error text-left margin-bottom">
<button className="pull-right icon" onClick={() => setState(state => ({ ...state, error: null }))}>
<i className="fa fa-times" />
</button>
<div className="selectable force-pre-wrap">
<b>{installPluginErrMsg}</b>
{'\n\nThere may be an issue with the plugin itself, as a note you can discover and install plugins from the '}
<a href={PLUGIN_HUB_BASE}>Plugin Hub.</a>
<details>
<summary>Additional Information</summary>
<pre className="pad-top-sm force-wrap selectable">
<code>{error.stack || error.message}</code>
</pre>
</details>
</div>
</div>
)}

<form
onSubmit={async event => {
event.preventDefault();
setState(state => ({ ...state, isInstallingFromNpm: true }));
const newState: Partial<State> = {
isInstallingFromNpm: false,
error: null,
installPluginErrMsg: '',
};
try {
await window.main.installPlugin(npmPluginValue.trim());
await refreshPlugins();
newState.npmPluginValue = ''; // Clear input if successful install
} catch (err) {
newState.installPluginErrMsg = `Failed to install ${npmPluginValue}`;
newState.error = err;
}
setState(state => ({ ...state, ...newState }));
}}
>
<div className="form-row">
<div className="form-control form-control--outlined">
<input
onChange={event => {
if (event.target instanceof HTMLInputElement) {
setState(state => ({ ...state, npmPluginValue: event.target.value }));
}
}}
disabled={isInstallingFromNpm}
type="text"
placeholder="npm-package-name"
value={npmPluginValue}
/>
</div>
<div className="form-control width-auto">
<Button variant="contained" bg="surprise" disabled={isInstallingFromNpm}>
{isInstallingFromNpm && <i className="fa fa-refresh fa-spin space-right" />}
Install Plugin
</Button>
</div>
</div>
</form>
<hr />
<div className="text-right">
<Button
onClick={() => window.main.openInBrowser(PLUGIN_HUB_BASE)}
>
Browse Plugin Hub
</Button>
<Button
style={{
marginLeft: '0.3em',
}}
onClick={() => showPrompt({
title: 'New Plugin',
defaultValue: 'demo-example',
placeholder: 'example-name',
submitName: 'Generate',
label: 'Plugin Name',
selectText: true,
validate: name =>
name.match(/^[a-z][a-z-]*[a-z]$/) ? '' : 'Plugin name must be of format my-plugin-name',
onComplete: async name => {
// Remove insomnia-plugin- prefix if they accidentally typed it
name = name.replace(/^insomnia-plugin-/, '');
try {
await createPlugin(
`insomnia-plugin-${name}`,
'0.0.1',
[
'// For help writing plugins, visit the documentation to get started:',
`// ${docsPlugins}`,
'',
'// TODO: Add plugin code here...',
].join('\n'),
);
} catch (err) {
console.error(err);
showAlert({
title: 'Failed to Create Plugin',
message: err.message,
});
}
refreshPlugins();
},
})}
>Generate New Plugin</Button>
<Button
style={{
marginLeft: '0.3em',
}}
onClick={() => window.shell.showItemInFolder(path.join(process.env['INSOMNIA_DATA_PATH'] || window.app.getPath('userData'), 'plugins'))}
>
Reveal Plugins Folder
</Button>
<Button
disabled={isRefreshingPlugins}
style={{
marginLeft: '0.3em',
}}
onClick={() => refreshPlugins()}
>
Reload Plugins
{isRefreshingPlugins && <i className="fa fa-refresh fa-spin space-left" />}
</Button>
</div>
</div>
);
};

0 comments on commit 989edf6

Please sign in to comment.