From de8f246b5590bb1b23479c33840ec8db6c9a8cf4 Mon Sep 17 00:00:00 2001 From: Ran Byron Date: Thu, 14 Feb 2019 14:00:53 +0200 Subject: [PATCH 1/4] HelpTrigger to open in drawer --- client/app/assets/less/ant.less | 5 + client/app/services/HelpTrigger.jsx | 134 +++++++++++++++++++++++++-- client/app/services/HelpTrigger.less | 21 +++++ 3 files changed, 151 insertions(+), 9 deletions(-) create mode 100644 client/app/services/HelpTrigger.less diff --git a/client/app/assets/less/ant.less b/client/app/assets/less/ant.less index d6a387cefb..a5700d491f 100644 --- a/client/app/assets/less/ant.less +++ b/client/app/assets/less/ant.less @@ -19,6 +19,7 @@ @import '~antd/lib/tag/style/index'; @import '~antd/lib/grid/style/index'; @import '~antd/lib/switch/style/index'; +@import '~antd/lib/drawer/style/index'; @import 'inc/ant-variables'; // Remove bold in labels for Ant checkboxes and radio buttons @@ -204,4 +205,8 @@ color: @text-color-secondary; font-weight: normal; margin-top: 4px; +} + +.ant-popover { + z-index: 1000; // make sure it doesn't cover drawer } \ No newline at end of file diff --git a/client/app/services/HelpTrigger.jsx b/client/app/services/HelpTrigger.jsx index fef0d7228b..b8e79b4c92 100644 --- a/client/app/services/HelpTrigger.jsx +++ b/client/app/services/HelpTrigger.jsx @@ -1,9 +1,20 @@ import React from 'react'; import PropTypes from 'prop-types'; +import cx from 'classnames'; import Tooltip from 'antd/lib/tooltip'; import Icon from 'antd/lib/icon'; +import Drawer from 'antd/lib/drawer'; +import { BigMessage } from '@/components/BigMessage'; -const BASE_URL = 'https://redash.io/help/user-guide/'; +import './HelpTrigger.less'; + +const DOMAIN = 'https://redash.io'; +const HELP_PATH = '/help/user-guide/'; +const MESSAGES = { + HELP_DRAWER_READY: 'drawer_ready', + HELP_DRAWER_REQUEST: 'drawer_request', +}; +const IFRAME_TIMEOUT = 5000; const TYPES = { VALUE_SOURCE_OPTIONS: [ 'querying/query-parameters#Value-Source-Options', @@ -20,16 +31,121 @@ export default class HelpTrigger extends React.PureComponent { type: PropTypes.oneOf(Object.keys(TYPES)).isRequired, } + iframeRef = null + + iframeLoadingTimeout = null; + + constructor(props) { + super(props); + this.iframeRef = React.createRef(); + } + + state = { + visible: false, + loading: false, + error: false, + } + + componentWillUnmount() { + this.onDrawerClosed(); + } + + get helpUrl() { + const [pagePath] = TYPES[this.props.type]; + return DOMAIN + HELP_PATH + pagePath; + } + + onIframeLoaded = () => { + const { contentWindow } = this.iframeRef.current; + contentWindow.postMessage(MESSAGES.HELP_DRAWER_REQUEST, DOMAIN); + } + + onIframeError = () => { + this.setState({ error: true, loading: false }); + } + + onIframeReady = () => { + this.setState({ loading: false }); + this.removeIframeListeners(); + } + + onPostMessageReceived = (event) => { + if (event.origin === DOMAIN && event.data === MESSAGES.HELP_DRAWER_READY) { + this.onIframeReady(); + } + } + + openDrawer = () => { + this.setState({ visible: true, loading: true, error: false }); + setTimeout(this.onDrawerOpened, 300); // to prevent animation jank + } + + closeDrawer = () => { + this.setState({ visible: false }); + this.removeIframeListeners(); + } + + onDrawerOpened = () => { + this.addIframeListeners(); + this.iframeRef.current.src = this.helpUrl; + } + + addIframeListeners = () => { + window.addEventListener('message', this.onPostMessageReceived, DOMAIN); + this.iframeRef.current.addEventListener('load', this.onIframeLoaded); + this.iframeLoadingTimeout = setTimeout(this.onIframeError, IFRAME_TIMEOUT); + } + + removeIframeListeners = () => { + window.removeEventListener('message', this.onPostMessageReceived); + this.iframeRef.current.removeEventListener('load', this.onIframeLoaded); + window.clearTimeout(this.iframeLoadingTimeout); + } + render() { - const [path, tooltip] = TYPES[this.props.type]; - const href = BASE_URL + path; + const [, tooltip] = TYPES[this.props.type]; + return ( - - {/* eslint-disable-next-line react/jsx-no-target-blank */} - - - - + + + + + + + + {/* iframe */} + {!this.state.error && ( +