From 30c911919efd28f8104b4e720db2d02df9cdb9df Mon Sep 17 00:00:00 2001 From: Christopher Council Date: Wed, 16 Jan 2019 23:28:38 -0800 Subject: [PATCH] Fix Text field to edit SQL snippet of a metric is not large enough (#6702) * Fix Text field to edit SQL snippet of a metric is not large enough for entire snippet * Fix Airbnb bug PRODUCT-62223 --- .../assets/src/components/EditableTitle.jsx | 67 +++++++++++++++---- .../src/datasource/DatasourceEditor.jsx | 4 +- superset/assets/stylesheets/superset.less | 29 +++++++- 3 files changed, 83 insertions(+), 17 deletions(-) diff --git a/superset/assets/src/components/EditableTitle.jsx b/superset/assets/src/components/EditableTitle.jsx index 1ef6e70c8..87a5160ca 100644 --- a/superset/assets/src/components/EditableTitle.jsx +++ b/superset/assets/src/components/EditableTitle.jsx @@ -25,19 +25,23 @@ import TooltipWrapper from './TooltipWrapper'; const propTypes = { title: PropTypes.string, canEdit: PropTypes.bool, + multiLine: PropTypes.bool, onSaveTitle: PropTypes.func, noPermitTooltip: PropTypes.string, showTooltip: PropTypes.bool, emptyText: PropTypes.node, style: PropTypes.object, + extraClasses: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.string), PropTypes.string]), }; const defaultProps = { title: t('Title'), canEdit: false, + multiLine: false, showTooltip: true, onSaveTitle: () => {}, emptyText: '', style: null, + extraClasses: null, }; export default class EditableTitle extends React.PureComponent { @@ -53,6 +57,9 @@ export default class EditableTitle extends React.PureComponent { this.handleChange = this.handleChange.bind(this); this.handleKeyUp = this.handleKeyUp.bind(this); this.handleKeyPress = this.handleKeyPress.bind(this); + + // Used so we can access the DOM element if a user clicks on this component. + this.contentRef = React.createRef(); } componentWillReceiveProps(nextProps) { @@ -68,7 +75,13 @@ export default class EditableTitle extends React.PureComponent { if (!this.props.canEdit || this.state.isEditing) { return; } - this.setState({ isEditing: true }); + + // For multi-line values, save the actual rendered size of the displayed text. + // Later, if a textarea is constructed for editing the value, we'll need this. + const contentBoundingRect = (this.contentRef.current) ? + this.contentRef.current.getBoundingClientRect() : null; + + this.setState({ isEditing: true, contentBoundingRect }); } handleBlur() { @@ -134,18 +147,43 @@ export default class EditableTitle extends React.PureComponent { } render() { + const { isEditing, title, contentBoundingRect } = this.state; + const { emptyText, multiLine, showTooltip, canEdit, + noPermitTooltip, style, extraClasses } = this.props; + let value; - if (this.state.title) { - value = this.state.title; - } else if (!this.state.isEditing) { - value = this.props.emptyText; + if (title) { + value = title; + } else if (!isEditing) { + value = emptyText; } - let input = ( + + // Construct an inline style based on previously-saved height of the rendered label. Only + // used in multi-line contexts. + const editStyle = (isEditing && contentBoundingRect) ? { height: `${contentBoundingRect.height}px` } : null; + + // Create a textarea when we're editing a multi-line value, otherwise create an input (which may + // be text or a button). + let input = multiLine && isEditing ? ( +