williaster commented on a change in pull request #4962: Markdown for dashboard
URL:
https://github.com/apache/incubator-superset/pull/4962#discussion_r186937745
##########
File path: superset/assets/src/dashboard/components/gridComponents/Markdown.jsx
##########
@@ -0,0 +1,232 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import ReactMarkdown from 'react-markdown';
+import AceEditor from 'react-ace';
+import 'brace/mode/markdown';
+import 'brace/theme/textmate';
+
+import DeleteComponentButton from '../DeleteComponentButton';
+import DragDroppable from '../dnd/DragDroppable';
+import HoverMenu from '../menu/HoverMenu';
+import ResizableContainer from '../resizable/ResizableContainer';
+import IconButton from '../IconButton';
+import MarkdownModeDropdown from '../menu/MarkdownModeDropdown';
+import WithPopoverMenu from '../menu/WithPopoverMenu';
+import { componentShape } from '../../util/propShapes';
+import { ROW_TYPE, COLUMN_TYPE } from '../../util/componentTypes';
+import {
+ GRID_MIN_COLUMN_COUNT,
+ GRID_MIN_ROW_UNITS,
+ GRID_BASE_UNIT,
+} from '../../util/constants';
+
+const CHART_MARGIN = 32;
+
+const propTypes = {
+ id: PropTypes.string.isRequired,
+ parentId: PropTypes.string.isRequired,
+ component: componentShape.isRequired,
+ parentComponent: componentShape.isRequired,
+ index: PropTypes.number.isRequired,
+ depth: PropTypes.number.isRequired,
+ editMode: PropTypes.bool.isRequired,
+
+ // grid related
+ availableColumnCount: PropTypes.number.isRequired,
+ columnWidth: PropTypes.number.isRequired,
+ onResizeStart: PropTypes.func.isRequired,
+ onResize: PropTypes.func.isRequired,
+ onResizeStop: PropTypes.func.isRequired,
+
+ // dnd
+ deleteComponent: PropTypes.func.isRequired,
+ handleComponentDrop: PropTypes.func.isRequired,
+ updateComponents: PropTypes.func.isRequired,
+};
+
+const defaultProps = {};
+
+class Markdown extends React.PureComponent {
+ constructor(props) {
+ super(props);
+ this.state = {
+ isFocused: false,
+ markdownSrc: props.component.meta.code,
+ editorMode: props.component.meta.code ? 'preview' : 'edit', // show edit
mode when code is empty
+ };
+
+ this.handleChangeFocus = this.handleChangeFocus.bind(this);
+ this.handleChangeEditorMode = this.handleChangeEditorMode.bind(this);
+ this.handleMarkdownChange = this.handleMarkdownChange.bind(this);
+ this.handleDeleteComponent = this.handleDeleteComponent.bind(this);
+ }
+
+ handleChangeFocus(nextFocus) {
+ this.setState(() => ({ isFocused: Boolean(nextFocus) }));
+ }
+
+ handleChangeEditorMode(mode) {
+ // current mode: edit
+ if (this.state.editorMode === 'edit') {
+ const { updateComponents, component } = this.props;
+ if (component.meta.code !== this.state.markdownSrc) {
+ updateComponents({
+ [component.id]: {
+ ...component,
+ meta: {
+ ...component.meta,
+ code: this.state.markdownSrc,
+ },
+ },
+ });
+ }
+ }
+
+ this.setState(() => ({
+ editorMode: mode,
+ }));
+ }
+
+ handleMarkdownChange(nextValue) {
+ this.setState({
+ markdownSrc: nextValue,
+ });
+ }
+
+ handleDeleteComponent() {
+ const { deleteComponent, id, parentId } = this.props;
+ deleteComponent(id, parentId);
+ }
+
+ renderEditMode(size) {
+ const { width, height } = size;
+ return (
+ <AceEditor
+ mode={'markdown'}
+ theme="textmate"
+ onChange={this.handleMarkdownChange}
+ width={`${width}px`}
+ height={`${height}px`}
+ editorProps={{ $blockScrolling: true }}
+ value={this.state.markdownSrc}
+ readOnly={false}
+ onLoad={editor => {
+ editor.getSession().setUseWrapMode(true);
+ }}
+ />
+ );
+ }
+
+ renderPreviewMode() {
+ return <ReactMarkdown source={this.state.markdownSrc} escapeHtml={false}
/>;
+ }
+
+ render() {
+ const { isFocused } = this.state;
+
+ const {
+ component,
+ parentComponent,
+ index,
+ depth,
+ availableColumnCount,
+ columnWidth,
+ onResizeStart,
+ onResize,
+ onResizeStop,
+ handleComponentDrop,
+ editMode,
+ } = this.props;
+
+ // inherit the size of parent columns
+ const widthMultiple =
+ parentComponent.type === COLUMN_TYPE
+ ? parentComponent.meta.width || GRID_MIN_COLUMN_COUNT
+ : component.meta.width || GRID_MIN_COLUMN_COUNT;
+
+ const editorWidth = widthMultiple * columnWidth;
+ const editorHeight = component.meta.height * GRID_BASE_UNIT - CHART_MARGIN;
+
+ return (
+ <DragDroppable
+ component={component}
+ parentComponent={parentComponent}
+ orientation={depth % 2 === 1 ? 'column' : 'row'}
+ index={index}
+ depth={depth}
+ onDrop={handleComponentDrop}
+ disableDragDrop={isFocused}
+ editMode={editMode}
+ >
+ {({ dropIndicatorProps, dragSourceRef }) => (
+ <WithPopoverMenu
+ isFocused={this.state.isFocused}
+ onChangeFocus={this.handleChangeFocus}
+ disableClick
+ menuItems={[
+ <MarkdownModeDropdown
+ id={`${component.id}-mode`}
+ value={this.state.editorMode}
+ onChange={this.handleChangeEditorMode}
+ />,
+ ]}
+ editMode={editMode}
+ >
+ <div className="dashboard-markdown">
+ <ResizableContainer
+ id={component.id}
+ adjustableWidth={parentComponent.type === ROW_TYPE}
+ adjustableHeight
+ widthStep={columnWidth}
+ widthMultiple={widthMultiple}
+ heightStep={GRID_BASE_UNIT}
+ heightMultiple={component.meta.height}
+ minWidthMultiple={GRID_MIN_COLUMN_COUNT}
+ minHeightMultiple={GRID_MIN_ROW_UNITS}
+ maxWidthMultiple={availableColumnCount + widthMultiple}
+ onResizeStart={onResizeStart}
+ onResize={onResize}
+ onResizeStop={onResizeStop}
+ editMode={editMode}
+ >
+ <div
+ ref={dragSourceRef}
+ className="dashboard-component
dashboard-component-chart-holder"
+ >
+ {editMode && (
+ <HoverMenu position="top">
Review comment:
as discussed in design review, Delete can be moved to popover
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
[email protected]
With regards,
Apache Git Services
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]