mirror of
https://github.com/Kong/insomnia
synced 2024-11-08 06:39:48 +00:00
Add ability for plugins to add folder actions (#774)
This commit is contained in:
parent
ec1310000d
commit
d8066bc558
@ -192,7 +192,7 @@ export async function render<T>(
|
||||
|
||||
export async function getRenderContext(
|
||||
request: Request,
|
||||
environmentId: string,
|
||||
environmentId: string | null,
|
||||
ancestors: Array<BaseModel> | null = null,
|
||||
purpose: RenderPurpose | null = null,
|
||||
): Promise<Object> {
|
||||
@ -212,7 +212,7 @@ export async function getRenderContext(
|
||||
const rootEnvironment = await models.environment.getOrCreateForWorkspaceId(
|
||||
workspace ? workspace._id : 'n/a',
|
||||
);
|
||||
const subEnvironment = await models.environment.getById(environmentId);
|
||||
const subEnvironment = await models.environment.getById(environmentId || 'n/a');
|
||||
|
||||
let keySource = {};
|
||||
for (let key in (rootEnvironment || {}).data) {
|
||||
@ -261,7 +261,7 @@ export async function getRenderContext(
|
||||
|
||||
export async function getRenderedRequestAndContext(
|
||||
request: Request,
|
||||
environmentId: string,
|
||||
environmentId: string | null,
|
||||
purpose?: RenderPurpose,
|
||||
): Promise<{ request: RenderedRequest, context: Object }> {
|
||||
const ancestors = await db.withAncestors(request, [
|
||||
|
@ -805,7 +805,10 @@ export async function sendWithSettings(
|
||||
return _actuallySend(renderResult.request, renderResult.context, workspace, settings);
|
||||
}
|
||||
|
||||
export async function send(requestId: string, environmentId: string): Promise<ResponsePatch> {
|
||||
export async function send(
|
||||
requestId: string,
|
||||
environmentId: string | null,
|
||||
): Promise<ResponsePatch> {
|
||||
// HACK: wait for all debounces to finish
|
||||
/*
|
||||
* TODO: Do this in a more robust way
|
||||
|
@ -12,6 +12,7 @@ describe('init()', () => {
|
||||
'alert',
|
||||
'getPath',
|
||||
'prompt',
|
||||
'showGenericModalDialog',
|
||||
'showSaveDialog',
|
||||
]);
|
||||
});
|
||||
|
@ -1,12 +1,13 @@
|
||||
// @flow
|
||||
import * as electron from 'electron';
|
||||
import { showAlert, showPrompt } from '../../ui/components/modals/index';
|
||||
import { showAlert, showModal, showPrompt } from '../../ui/components/modals';
|
||||
import type { RenderPurpose } from '../../common/render';
|
||||
import {
|
||||
RENDER_PURPOSE_GENERAL,
|
||||
RENDER_PURPOSE_NO_RENDER,
|
||||
RENDER_PURPOSE_SEND,
|
||||
} from '../../common/render';
|
||||
import WrapperModal from '../../ui/components/modals/wrapper-modal';
|
||||
|
||||
export function init(renderPurpose: RenderPurpose = RENDER_PURPOSE_GENERAL): { app: Object } {
|
||||
return {
|
||||
@ -18,6 +19,9 @@ export function init(renderPurpose: RenderPurpose = RENDER_PURPOSE_GENERAL): { a
|
||||
|
||||
return showAlert({ title, message });
|
||||
},
|
||||
showGenericModalDialog(title: string, options?: { html: string } = {}): Promise<void> {
|
||||
return showModal(WrapperModal, { title, bodyHTML: options.html });
|
||||
},
|
||||
prompt(
|
||||
title: string,
|
||||
options?: {
|
||||
|
@ -4,7 +4,7 @@ import { send } from '../../network/network';
|
||||
import type { Request } from '../../models/request';
|
||||
import * as models from '../../models';
|
||||
|
||||
export function init(activeEnvironmentId: string): { network: Object } {
|
||||
export function init(activeEnvironmentId: string | null): { network: Object } {
|
||||
const network = {
|
||||
async sendRequest(request: Request): Promise<Response> {
|
||||
const responsePatch = await send(request._id, activeEnvironmentId);
|
||||
|
@ -8,6 +8,8 @@ import { resolveHomePath } from '../common/misc';
|
||||
import { showError } from '../ui/components/modals/index';
|
||||
import type { PluginTemplateTag } from '../templating/extensions/index';
|
||||
import type { PluginTheme } from './misc';
|
||||
import type { RequestGroup } from '../models/request-group';
|
||||
import type { Request } from '../models/request';
|
||||
|
||||
export type Plugin = {
|
||||
name: string,
|
||||
@ -22,6 +24,19 @@ export type TemplateTag = {
|
||||
templateTag: PluginTemplateTag,
|
||||
};
|
||||
|
||||
export type RequestGroupAction = {
|
||||
plugin: Plugin,
|
||||
action: (
|
||||
context: Object,
|
||||
models: {
|
||||
requestGroup: RequestGroup,
|
||||
requests: Array<Request>,
|
||||
},
|
||||
) => void | Promise<void>,
|
||||
label: string,
|
||||
icon?: string,
|
||||
};
|
||||
|
||||
export type RequestHook = {
|
||||
plugin: Plugin,
|
||||
hook: Function,
|
||||
@ -156,6 +171,16 @@ export async function getPlugins(force: boolean = false): Promise<Array<Plugin>>
|
||||
return plugins;
|
||||
}
|
||||
|
||||
export async function getRequestGroupActions(): Promise<Array<RequestGroupAction>> {
|
||||
let extensions = [];
|
||||
for (const plugin of await getPlugins()) {
|
||||
const actions = plugin.module.requestGroupActions || [];
|
||||
extensions = [...extensions, ...actions.map(p => ({ plugin, ...p }))];
|
||||
}
|
||||
|
||||
return extensions;
|
||||
}
|
||||
|
||||
export async function getTemplateTags(): Promise<Array<TemplateTag>> {
|
||||
let extensions = [];
|
||||
for (const plugin of await getPlugins()) {
|
||||
|
@ -1,6 +1,7 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
// @flow
|
||||
import * as React from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import classnames from 'classnames';
|
||||
import PromptButton from '../base/prompt-button';
|
||||
import {
|
||||
Dropdown,
|
||||
@ -11,12 +12,43 @@ import {
|
||||
} from '../base/dropdown';
|
||||
import EnvironmentEditModal from '../modals/environment-edit-modal';
|
||||
import * as models from '../../../models';
|
||||
import { showPrompt, showModal } from '../modals/index';
|
||||
import { showError, showModal, showPrompt } from '../modals';
|
||||
import type { HotKeyRegistry } from '../../../common/hotkeys';
|
||||
import { hotKeyRefs } from '../../../common/hotkeys';
|
||||
import type { RequestGroupAction } from '../../../plugins';
|
||||
import { getRequestGroupActions } from '../../../plugins';
|
||||
import type { RequestGroup } from '../../../models/request-group';
|
||||
import type { Workspace } from '../../../models/workspace';
|
||||
import * as pluginContexts from '../../../plugins/context/index';
|
||||
import { RENDER_PURPOSE_NO_RENDER } from '../../../common/render';
|
||||
import type { Environment } from '../../../models/environment';
|
||||
|
||||
type Props = {
|
||||
workspace: Workspace,
|
||||
requestGroup: RequestGroup,
|
||||
hotKeyRegistry: HotKeyRegistry,
|
||||
activeEnvironment: Environment | null,
|
||||
handleCreateRequest: (id: string) => any,
|
||||
handleDuplicateRequestGroup: (rg: RequestGroup) => any,
|
||||
handleMoveRequestGroup: (rg: RequestGroup) => any,
|
||||
handleCreateRequestGroup: (id: string) => any,
|
||||
};
|
||||
|
||||
type State = {
|
||||
actionPlugins: Array<RequestGroupAction>,
|
||||
loadingActions: { [string]: boolean },
|
||||
};
|
||||
|
||||
@autobind
|
||||
class RequestGroupActionsDropdown extends PureComponent {
|
||||
_setDropdownRef(n) {
|
||||
class RequestGroupActionsDropdown extends React.PureComponent<Props, State> {
|
||||
_dropdown: ?Dropdown;
|
||||
|
||||
state = {
|
||||
actionPlugins: [],
|
||||
loadingActions: {},
|
||||
};
|
||||
|
||||
_setDropdownRef(n: ?Dropdown) {
|
||||
this._dropdown = n;
|
||||
}
|
||||
|
||||
@ -56,19 +88,54 @@ class RequestGroupActionsDropdown extends PureComponent {
|
||||
showModal(EnvironmentEditModal, this.props.requestGroup);
|
||||
}
|
||||
|
||||
show() {
|
||||
this._dropdown.show();
|
||||
async onOpen() {
|
||||
const plugins = await getRequestGroupActions();
|
||||
this.setState({ actionPlugins: plugins });
|
||||
}
|
||||
|
||||
async show() {
|
||||
this._dropdown && this._dropdown.show();
|
||||
}
|
||||
|
||||
async _handlePluginClick(p: RequestGroupAction) {
|
||||
this.setState(state => ({ loadingActions: { ...state.loadingActions, [p.label]: true } }));
|
||||
|
||||
try {
|
||||
const { activeEnvironment, requestGroup } = this.props;
|
||||
const activeEnvironmentId = activeEnvironment ? activeEnvironment._id : null;
|
||||
|
||||
const context = {
|
||||
...pluginContexts.app.init(RENDER_PURPOSE_NO_RENDER),
|
||||
...pluginContexts.store.init(p.plugin),
|
||||
...pluginContexts.network.init(activeEnvironmentId),
|
||||
};
|
||||
|
||||
const requests = await models.request.findByParentId(requestGroup._id);
|
||||
requests.sort((a, b) => a.metaSortKey - b.metaSortKey);
|
||||
await p.action(context, { requestGroup, requests });
|
||||
} catch (err) {
|
||||
showError({
|
||||
title: 'Plugin Action Failed',
|
||||
error: err,
|
||||
});
|
||||
}
|
||||
|
||||
this.setState(state => ({ loadingActions: { ...state.loadingActions, [p.label]: false } }));
|
||||
this._dropdown && this._dropdown.hide();
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
workspace, // eslint-disable-line no-unused-vars
|
||||
requestGroup, // eslint-disable-line no-unused-vars
|
||||
hotKeyRegistry,
|
||||
...other
|
||||
} = this.props;
|
||||
|
||||
const { actionPlugins, loadingActions } = this.state;
|
||||
|
||||
return (
|
||||
<Dropdown ref={this._setDropdownRef} {...other}>
|
||||
<Dropdown ref={this._setDropdownRef} onOpen={this.onOpen} {...other}>
|
||||
<DropdownButton>
|
||||
<i className="fa fa-caret-down" />
|
||||
</DropdownButton>
|
||||
@ -96,21 +163,20 @@ class RequestGroupActionsDropdown extends PureComponent {
|
||||
<DropdownItem buttonClass={PromptButton} addIcon onClick={this._handleDeleteFolder}>
|
||||
<i className="fa fa-trash-o" /> Delete
|
||||
</DropdownItem>
|
||||
{actionPlugins.length > 0 && <DropdownDivider>Plugins</DropdownDivider>}
|
||||
{actionPlugins.map((p: RequestGroupAction) => (
|
||||
<DropdownItem key={p.label} onClick={() => this._handlePluginClick(p)} stayOpenAfterClick>
|
||||
{loadingActions[p.label] ? (
|
||||
<i className="fa fa-refresh fa-spin" />
|
||||
) : (
|
||||
<i className={classnames('fa', p.icon || 'fa-code')} />
|
||||
)}
|
||||
{p.label}
|
||||
</DropdownItem>
|
||||
))}
|
||||
</Dropdown>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
RequestGroupActionsDropdown.propTypes = {
|
||||
workspace: PropTypes.object.isRequired,
|
||||
hotKeyRegistry: PropTypes.object.isRequired,
|
||||
handleCreateRequest: PropTypes.func.isRequired,
|
||||
handleCreateRequestGroup: PropTypes.func.isRequired,
|
||||
handleDuplicateRequestGroup: PropTypes.func.isRequired,
|
||||
handleMoveRequestGroup: PropTypes.func.isRequired,
|
||||
|
||||
// Optional
|
||||
requestGroup: PropTypes.object,
|
||||
};
|
||||
|
||||
export default RequestGroupActionsDropdown;
|
||||
|
@ -9,6 +9,7 @@ type Props = {};
|
||||
type State = {
|
||||
title: string,
|
||||
body: React.Node,
|
||||
bodyHTML: ?string,
|
||||
tall: boolean,
|
||||
};
|
||||
|
||||
@ -22,6 +23,7 @@ class WrapperModal extends React.PureComponent<Props, State> {
|
||||
this.state = {
|
||||
title: '',
|
||||
body: null,
|
||||
bodyHTML: null,
|
||||
tall: false,
|
||||
};
|
||||
}
|
||||
@ -31,10 +33,11 @@ class WrapperModal extends React.PureComponent<Props, State> {
|
||||
}
|
||||
|
||||
show(options: Object = {}) {
|
||||
const { title, body, tall } = options;
|
||||
const { title, body, bodyHTML, tall } = options;
|
||||
this.setState({
|
||||
title,
|
||||
body,
|
||||
bodyHTML,
|
||||
tall: !!tall,
|
||||
});
|
||||
|
||||
@ -42,12 +45,17 @@ class WrapperModal extends React.PureComponent<Props, State> {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { title, body, tall } = this.state;
|
||||
const { title, body, bodyHTML, tall } = this.state;
|
||||
|
||||
let finalBody = body;
|
||||
if (bodyHTML) {
|
||||
finalBody = <div dangerouslySetInnerHTML={{ __html: bodyHTML }} className="tall wide pad" />;
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal ref={this._setModalRef} tall={tall}>
|
||||
<ModalHeader>{title || 'Uh Oh!'}</ModalHeader>
|
||||
<ModalBody>{body}</ModalBody>
|
||||
<ModalBody>{finalBody}</ModalBody>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import type { RequestGroup } from '../../../models/request-group';
|
||||
import type { Workspace } from '../../../models/workspace';
|
||||
import type { Request } from '../../../models/request';
|
||||
import type { HotKeyRegistry } from '../../../common/hotkeys';
|
||||
import type { Environment } from '../../../models/environment';
|
||||
|
||||
type Child = {
|
||||
doc: Request | RequestGroup,
|
||||
@ -31,6 +32,7 @@ type Props = {
|
||||
workspace: Workspace,
|
||||
filter: string,
|
||||
hotKeyRegistry: HotKeyRegistry,
|
||||
activeEnvironment: Environment | null,
|
||||
|
||||
// Optional
|
||||
activeRequest?: Request,
|
||||
@ -53,6 +55,7 @@ class SidebarChildren extends React.PureComponent<Props> {
|
||||
activeRequest,
|
||||
workspace,
|
||||
hotKeyRegistry,
|
||||
activeEnvironment,
|
||||
} = this.props;
|
||||
|
||||
const activeRequestId = activeRequest ? activeRequest._id : 'n/a';
|
||||
@ -119,6 +122,7 @@ class SidebarChildren extends React.PureComponent<Props> {
|
||||
requestGroup={requestGroup}
|
||||
hotKeyRegistry={hotKeyRegistry}
|
||||
children={children}
|
||||
activeEnvironment={activeEnvironment}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
@ -64,6 +64,7 @@ class SidebarRequestGroupRow extends PureComponent {
|
||||
isDraggingOver,
|
||||
workspace,
|
||||
hotKeyRegistry,
|
||||
activeEnvironment,
|
||||
} = this.props;
|
||||
|
||||
const { dragDirection } = this.state;
|
||||
@ -117,6 +118,7 @@ class SidebarRequestGroupRow extends PureComponent {
|
||||
workspace={workspace}
|
||||
requestGroup={requestGroup}
|
||||
hotKeyRegistry={hotKeyRegistry}
|
||||
activeEnvironment={activeEnvironment}
|
||||
right
|
||||
/>
|
||||
</div>
|
||||
@ -176,6 +178,7 @@ SidebarRequestGroupRow.propTypes = {
|
||||
|
||||
// Optional
|
||||
children: PropTypes.node,
|
||||
activeEnvironment: PropTypes.object,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -129,6 +129,7 @@ class Sidebar extends PureComponent {
|
||||
activeRequest={activeRequest}
|
||||
filter={filter || ''}
|
||||
hotKeyRegistry={hotKeyRegistry}
|
||||
activeEnvironment={activeEnvironment}
|
||||
/>
|
||||
|
||||
{enableSyncBeta && vcs && isLoggedIn() && (
|
||||
|
Loading…
Reference in New Issue
Block a user