From 68b9221b8015b229a54d5e37bf92b9831847631f Mon Sep 17 00:00:00 2001 From: Gregory Schier Date: Mon, 6 Apr 2020 14:31:03 -0700 Subject: [PATCH] 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 --- .../app/plugins/context/__tests__/app.test.js | 1 + .../insomnia-app/app/plugins/context/app.js | 35 +++++++++++++++-- .../app/ui/components/html-element-wrapper.js | 39 +++++++++++++++++++ 3 files changed, 72 insertions(+), 3 deletions(-) create mode 100644 packages/insomnia-app/app/ui/components/html-element-wrapper.js diff --git a/packages/insomnia-app/app/plugins/context/__tests__/app.test.js b/packages/insomnia-app/app/plugins/context/__tests__/app.test.js index b9f4302ba..19d9c213a 100644 --- a/packages/insomnia-app/app/plugins/context/__tests__/app.test.js +++ b/packages/insomnia-app/app/plugins/context/__tests__/app.test.js @@ -10,6 +10,7 @@ describe('init()', () => { expect(Object.keys(result)).toEqual(['app']); expect(Object.keys(result.app).sort()).toEqual([ 'alert', + 'dialog', 'getPath', 'prompt', 'showGenericModalDialog', diff --git a/packages/insomnia-app/app/plugins/context/app.js b/packages/insomnia-app/app/plugins/context/app.js index f1e95ed42..bc48d41d5 100644 --- a/packages/insomnia-app/app/plugins/context/app.js +++ b/packages/insomnia-app/app/plugins/context/app.js @@ -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 { @@ -21,12 +24,23 @@ export function init(renderPurpose: RenderPurpose = RENDER_PURPOSE_GENERAL): { a return showAlert({ title, message }); }, - showGenericModalDialog(title: string, options?: { html: string } = {}): Promise { + 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: , + 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); + }, }, }; } diff --git a/packages/insomnia-app/app/ui/components/html-element-wrapper.js b/packages/insomnia-app/app/ui/components/html-element-wrapper.js new file mode 100644 index 000000000..b603e56cb --- /dev/null +++ b/packages/insomnia-app/app/ui/components/html-element-wrapper.js @@ -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 { + _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
; + } +} + +export default HtmlElementWrapper;