New plugin API for showing custom UI inside a dialog (#2026)

* New dialog() method to show generic dialogs from Plugins

* Clarified deprecated api method

* Body now required in dialog()

* Made options arg optional too

* Fix tests
This commit is contained in:
Gregory Schier 2020-04-06 14:31:03 -07:00 committed by GitHub
parent b2429b7cdf
commit 68b9221b80
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 72 additions and 3 deletions

View File

@ -10,6 +10,7 @@ describe('init()', () => {
expect(Object.keys(result)).toEqual(['app']);
expect(Object.keys(result.app).sort()).toEqual([
'alert',
'dialog',
'getPath',
'prompt',
'showGenericModalDialog',

View File

@ -1,4 +1,5 @@
// @flow
import * as React from 'react';
import * as electron from 'electron';
import { showAlert, showModal, showPrompt } from '../../ui/components/modals';
import type { RenderPurpose } from '../../common/render';
@ -8,10 +9,12 @@ import {
RENDER_PURPOSE_SEND,
} from '../../common/render';
import WrapperModal from '../../ui/components/modals/wrapper-modal';
import HtmlElementWrapper from '../../ui/components/html-element-wrapper';
export function init(renderPurpose: RenderPurpose = RENDER_PURPOSE_GENERAL): { app: Object } {
const canShowDialogs =
renderPurpose === RENDER_PURPOSE_SEND || renderPurpose === RENDER_PURPOSE_NO_RENDER;
return {
app: {
alert(title: string, message?: string): Promise<void> {
@ -21,12 +24,23 @@ export function init(renderPurpose: RenderPurpose = RENDER_PURPOSE_GENERAL): { a
return showAlert({ title, message });
},
showGenericModalDialog(title: string, options?: { html: string } = {}): Promise<void> {
dialog(
title,
body: HTMLElement,
options?: {
onHide?: () => void,
tall?: boolean,
} = {},
): void {
if (renderPurpose !== RENDER_PURPOSE_SEND && renderPurpose !== RENDER_PURPOSE_NO_RENDER) {
return Promise.resolve();
return;
}
return showModal(WrapperModal, { title, bodyHTML: options.html });
showModal(WrapperModal, {
title,
body: <HtmlElementWrapper el={body} onUnmount={options.onHide} />,
tall: options.tall,
});
},
prompt(
title: string,
@ -81,6 +95,21 @@ export function init(renderPurpose: RenderPurpose = RENDER_PURPOSE_GENERAL): { a
});
});
},
// ~~~~~~~~~~~~~~~~~~ //
// Deprecated Methods //
// ~~~~~~~~~~~~~~~~~~ //
/** @deprecated as it was never officially supported */
showGenericModalDialog(title: string, options?: { html: string } = {}): void {
console.warn('app.showGenericModalDialog() is deprecated. Use app.dialog() instead.');
// Create DOM node so we can adapt to the new dialog() method
const body = document.createElement('div');
body.innerHTML = options.html;
return this.dialog(title, body);
},
},
};
}

View File

@ -0,0 +1,39 @@
// @flow
import * as React from 'react';
import autobind from 'autobind-decorator';
type Props = {|
el: HTMLElement,
onUnmount?: () => void,
|};
/**
* This component provides an easy way to place a raw DOM node inside a React
* application. This was created to facilitate the layer between UI plugins
* and the Insomnia application.
*/
@autobind
class HtmlElementWrapper extends React.Component<Props> {
_setRef(n: ?HTMLDivElement) {
if (!n) {
return;
}
// Add the element directly to the React ref
n.innerHTML = '';
n.appendChild(this.props.el);
}
componentWillUnmount() {
const { onUnmount } = this.props;
if (typeof onUnmount === 'function') {
onUnmount();
}
}
render() {
return <div ref={this._setRef} />;
}
}
export default HtmlElementWrapper;