diff --git a/packages/insomnia-app/app/plugins/index.js b/packages/insomnia-app/app/plugins/index.js index 3ce8cb593b..6803c703b1 100644 --- a/packages/insomnia-app/app/plugins/index.js +++ b/packages/insomnia-app/app/plugins/index.js @@ -41,6 +41,19 @@ export type RequestGroupAction = { icon?: string, }; +export type RequestAction = { + plugin: Plugin, + action: ( + context: Object, + models: { + requestGroup: RequestGroup, + request: Array, + }, + ) => void | Promise, + label: string, + icon?: string, +}; + export type WorkspaceAction = { plugin: Plugin, action: ( @@ -218,6 +231,16 @@ export async function getRequestGroupActions(): Promise> { + let extensions = []; + for (const plugin of await getActivePlugins()) { + const actions = plugin.module.requestActions || []; + extensions = [...extensions, ...actions.map(p => ({ plugin, ...p }))]; + } + + return extensions; +} + export async function getWorkspaceActions(): Promise> { let extensions = []; for (const plugin of await getActivePlugins()) { diff --git a/packages/insomnia-app/app/ui/components/dropdowns/request-actions-dropdown.js b/packages/insomnia-app/app/ui/components/dropdowns/request-actions-dropdown.js index 89eea4da04..0935d5a142 100644 --- a/packages/insomnia-app/app/ui/components/dropdowns/request-actions-dropdown.js +++ b/packages/insomnia-app/app/ui/components/dropdowns/request-actions-dropdown.js @@ -1,4 +1,5 @@ -import React, { PureComponent } from 'react'; +// @flow +import React from 'react'; import PropTypes from 'prop-types'; import autobind from 'autobind-decorator'; import PromptButton from '../base/prompt-button'; @@ -15,8 +16,46 @@ import { isRequest } from '../../../models/helpers/is-model'; import * as requestOperations from '../../../models/helpers/request-operations'; import { incrementDeletedRequests } from '../../../models/stats'; +// Plugin action related imports +import type { RequestAction, RequestGroupAction } from '../../../plugins'; +import type { HotKeyRegistry } from '../../../common/hotkeys'; +import type { Request } from '../../../models/request'; +import type { RequestGroup } from '../../../models/request-group'; +import type { Environment } from '../../../models/environment'; +import { getRequestActions } from '../../../plugins'; +import * as pluginContexts from '../../../plugins/context/index'; +import { showError } from '../modals'; +import { RENDER_PURPOSE_NO_RENDER } from '../../../common/render'; +import classnames from 'classnames'; + +type Props = { + handleDuplicateRequest: Function, + handleGenerateCode: Function, + handleCopyAsCurl: Function, + handleShowSettings: Function, + isPinned: Boolean, + request: Request, + requestGroup: RequestGroup, + hotKeyRegistry: HotKeyRegistry, + handleSetRequestPinned: Function, + activeEnvironment: Environment | null, +}; + +// Setup state for plugin actions +type State = { + actionPlugins: Array, + loadingActions: { [string]: boolean }, +}; + @autobind -class RequestActionsDropdown extends PureComponent { +class RequestActionsDropdown extends React.PureComponent { + _dropdown: ?Dropdown; + + state = { + actionPlugins: [], + loadingActions: {}, + }; + _setDropdownRef(n) { this._dropdown = n; } @@ -49,8 +88,38 @@ class RequestActionsDropdown extends PureComponent { return requestOperations.remove(request); } - show() { - this._dropdown.show(); + async _onOpen() { + const plugins = await getRequestActions(); + this.setState({ actionPlugins: plugins }); + } + + async show() { + this._dropdown && this._dropdown.show(); + } + + async _handlePluginClick(p: RequestAction) { + this.setState(state => ({ loadingActions: { ...state.loadingActions, [p.label]: true } })); + + try { + const { activeEnvironment, request, requestGroup } = this.props; + const activeEnvironmentId = activeEnvironment ? activeEnvironment._id : null; + const context = { + ...(pluginContexts.app.init(RENDER_PURPOSE_NO_RENDER): Object), + ...(pluginContexts.data.init(): Object), + ...(pluginContexts.store.init(p.plugin): Object), + ...(pluginContexts.network.init(activeEnvironmentId): Object), + }; + + await p.action(context, { request, requestGroup }); + } catch (err) { + showError({ + title: 'Plugin Action Failed', + error: err, + }); + } + + this.setState(state => ({ loadingActions: { ...state.loadingActions, [p.label]: false } })); + this._dropdown && this._dropdown.hide(); } render() { @@ -61,11 +130,13 @@ class RequestActionsDropdown extends PureComponent { ...other } = this.props; + const { actionPlugins, loadingActions } = this.state; + // Can only generate code for regular requests, not gRPC requests const canGenerateCode = isRequest(request); return ( - + @@ -100,6 +171,22 @@ class RequestActionsDropdown extends PureComponent { + {actionPlugins.length > 0 && Plugins} + {actionPlugins.map((p: RequestAction) => ( + + {loadingActions[p.label] ? ( + + ) : ( + + )} + {p.label} + + ))} + diff --git a/packages/insomnia-app/app/ui/components/sidebar/sidebar-children.js b/packages/insomnia-app/app/ui/components/sidebar/sidebar-children.js index d87d54b80f..4fc10bd25c 100644 --- a/packages/insomnia-app/app/ui/components/sidebar/sidebar-children.js +++ b/packages/insomnia-app/app/ui/components/sidebar/sidebar-children.js @@ -122,6 +122,8 @@ class SidebarChildren extends React.PureComponent { request={child.doc} workspace={workspace} hotKeyRegistry={hotKeyRegistry} + // Necessary for plugin actions on requests + activeEnvironment={activeEnvironment} /> ); } diff --git a/packages/insomnia-app/app/ui/components/sidebar/sidebar-request-group-row.js b/packages/insomnia-app/app/ui/components/sidebar/sidebar-request-group-row.js index 51d4fe048c..7de06ff9c1 100644 --- a/packages/insomnia-app/app/ui/components/sidebar/sidebar-request-group-row.js +++ b/packages/insomnia-app/app/ui/components/sidebar/sidebar-request-group-row.js @@ -155,6 +155,8 @@ class SidebarRequestGroupRow extends PureComponent { filter={filter} hotKeyRegistry={hotKeyRegistry} isPinned={false} + // Necessary so that plugin actions work + activeEnvironment={activeEnvironment} /> )} diff --git a/packages/insomnia-app/app/ui/components/sidebar/sidebar-request-row.js b/packages/insomnia-app/app/ui/components/sidebar/sidebar-request-row.js index 9a5affb9f3..40da3c9f14 100644 --- a/packages/insomnia-app/app/ui/components/sidebar/sidebar-request-row.js +++ b/packages/insomnia-app/app/ui/components/sidebar/sidebar-request-row.js @@ -158,6 +158,7 @@ class SidebarRequestRow extends PureComponent { isPinned, disableDragAndDrop, hotKeyRegistry, + activeEnvironment, } = this.props; const { dragDirection } = this.state; @@ -232,6 +233,8 @@ class SidebarRequestRow extends PureComponent { isPinned={isPinned} requestGroup={requestGroup} hotKeyRegistry={hotKeyRegistry} + // Necessary for plugin actions to have network capabilities + activeEnvironment={activeEnvironment} /> {isPinned && (