Skip to content

Commit

Permalink
HelpTrigger to open in drawer
Browse files Browse the repository at this point in the history
  • Loading branch information
ranbena committed Feb 14, 2019
1 parent afaedb9 commit de8f246
Show file tree
Hide file tree
Showing 3 changed files with 151 additions and 9 deletions.
5 changes: 5 additions & 0 deletions client/app/assets/less/ant.less
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
}
134 changes: 125 additions & 9 deletions client/app/services/HelpTrigger.jsx
Original file line number Diff line number Diff line change
@@ -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',
Expand All @@ -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 (
<Tooltip title={`Guide: ${tooltip}`}>
{/* eslint-disable-next-line react/jsx-no-target-blank */}
<a href={href} target="_blank" rel="noopener">
<Icon type="question-circle" />
</a>
</Tooltip>
<React.Fragment>
<Tooltip title={`Guide: ${tooltip}`}>
<a href="javascript: void(0)" onClick={this.openDrawer}>
<Icon type="question-circle" />
</a>
</Tooltip>
<Drawer
placement="right"
onClose={this.closeDrawer}
visible={this.state.visible}
className="help-drawer"
destroyOnClose
width={450}
>
{/* iframe */}
{!this.state.error && (
<iframe
ref={this.iframeRef}
title="Redash Help"
src="about:blank"
className={cx({ ready: !this.state.loading })}
/>
)}

{/* loading indicator */}
{this.state.loading && (
<BigMessage icon="fa-spinner fa-2x fa-pulse" message="Loading..." className="help-message" />
)}

{/* error message */}
{this.state.error && (
<BigMessage icon="fa-exclamation-circle" className="help-message">
Something went wrong.<br />
{/* eslint-disable-next-line react/jsx-no-target-blank */}
<a href={this.helpUrl + '?s=help_error'} target="_blank" rel="noopener">Click here</a>{' '}
to open the document in a new window.
</BigMessage>
)}
</Drawer>
</React.Fragment>
);
}
}
21 changes: 21 additions & 0 deletions client/app/services/HelpTrigger.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
.help-drawer {
.ant-drawer-body {
padding: 0;
height: 100%; // to allow iframe full dimensions
display: flex;
align-items: center;
justify-content: center;
}

iframe {
width: 0;
visibility: hidden;
}

iframe.ready {
border: 0;
width: 100%;
height: 100%;
visibility: visible;
}
}

0 comments on commit de8f246

Please sign in to comment.