Add support for request action plugins (#2678)

Co-authored-by: Opender Singh <opender.singh@konghq.com>
This commit is contained in:
Nijiko YonskaiandOpender Singh authored and GitHub committed 2021-01-15 11:11:10 +13:00
1 parent 45a8aa45b8
commit fba78881db
5 files changed
+122 -5

No files matched your search

@@ -41,6 +41,19 @@ export type RequestGroupAction = {
icon?: string,
};
export type RequestAction = {
plugin: Plugin,
action: (
context: Object,
models: {
requestGroup: RequestGroup,
request: Array<Request>,
},
) => void | Promise<void>,
label: string,
icon?: string,
};
export type WorkspaceAction = {
plugin: Plugin,
action: (
@@ -218,6 +231,16 @@ export async function getRequestGroupActions(): Promise<Array<RequestGroupAction
return extensions;
}
export async function getRequestActions(): Promise<Array<RequestAction>> {
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<Array<WorkspaceAction>> {
let extensions = [];
for (const plugin of await getActivePlugins()) {
@@ -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<RequestGroupAction>,
loadingActions: { [string]: boolean },
};
@autobind
class RequestActionsDropdown extends PureComponent {
class RequestActionsDropdown extends React.PureComponent<Props, State> {
_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 (
<Dropdown ref={this._setDropdownRef} {...other}>
<Dropdown ref={this._setDropdownRef} onOpen={this._onOpen} {...other}>
<DropdownButton>
<i className="fa fa-caret-down" />
</DropdownButton>
@@ -100,6 +171,22 @@ class RequestActionsDropdown extends PureComponent {
<DropdownHint keyBindings={hotKeyRegistry[hotKeyRefs.REQUEST_SHOW_DELETE.id]} />
</DropdownItem>
{actionPlugins.length > 0 && <DropdownDivider>Plugins</DropdownDivider>}
{actionPlugins.map((p: RequestAction) => (
<DropdownItem
key={`${p.plugin.name}::${p.label}`}
value={p}
onClick={this._handlePluginClick}
stayOpenAfterClick>
{loadingActions[p.label] ? (
<i className="fa fa-refresh fa-spin" />
) : (
<i className={classnames('fa', p.icon || 'fa-code')} />
)}
{p.label}
</DropdownItem>
))}
<DropdownDivider />
<DropdownItem onClick={handleShowSettings}>
@@ -122,6 +122,8 @@ class SidebarChildren extends React.PureComponent<Props> {
request={child.doc}
workspace={workspace}
hotKeyRegistry={hotKeyRegistry}
// Necessary for plugin actions on requests
activeEnvironment={activeEnvironment}
/>
);
}
@@ -155,6 +155,8 @@ class SidebarRequestGroupRow extends PureComponent {
filter={filter}
hotKeyRegistry={hotKeyRegistry}
isPinned={false}
// Necessary so that plugin actions work
activeEnvironment={activeEnvironment}
/>
)}
</ul>
@@ -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}
/>
</div>
{isPinned && (