This is an automated email from the ASF dual-hosted git repository.
kristw pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-superset.git
The following commit(s) were added to refs/heads/master by this push:
new 30c9119 Fix Text field to edit SQL snippet of a metric is not large
enough (#6702)
30c9119 is described below
commit 30c911919efd28f8104b4e720db2d02df9cdb9df
Author: Christopher Council <[email protected]>
AuthorDate: Wed Jan 16 23:28:38 2019 -0800
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
---
superset/assets/src/components/EditableTitle.jsx | 67 +++++++++++++++++-----
.../assets/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 1ef6e70..87a5160 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: '<empty>',
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 ? (
+ <textarea
+ ref={this.contentRef}
+ required
+ value={value}
+ className={!title ? 'text-muted' : null}
+ onKeyUp={this.handleKeyUp}
+ onChange={this.handleChange}
+ onBlur={this.handleBlur}
+ onClick={this.handleClick}
+ onKeyPress={this.handleKeyPress}
+ style={editStyle}
+ />
+ ) : (
<input
+ ref={this.contentRef}
required
- type={this.state.isEditing ? 'text' : 'button'}
+ type={isEditing ? 'text' : 'button'}
value={value}
- className={!this.state.title ? 'text-muted' : null}
+ className={!title ? 'text-muted' : null}
onKeyUp={this.handleKeyUp}
onChange={this.handleChange}
onBlur={this.handleBlur}
@@ -153,12 +191,12 @@ export default class EditableTitle extends
React.PureComponent {
onKeyPress={this.handleKeyPress}
/>
);
- if (this.props.showTooltip && !this.state.isEditing) {
+ if (showTooltip && !isEditing) {
input = (
<TooltipWrapper
label="title"
- tooltip={this.props.canEdit ? t('click to edit') :
- this.props.noPermitTooltip || t('You don\'t have the rights to
alter this title.')}
+ tooltip={canEdit ? t('click to edit') :
+ noPermitTooltip || t('You don\'t have the rights to alter this
title.')}
>
{input}
</TooltipWrapper>
@@ -168,10 +206,11 @@ export default class EditableTitle extends
React.PureComponent {
<span
className={cx(
'editable-title',
- this.props.canEdit && 'editable-title--editable',
- this.state.isEditing && 'editable-title--editing',
+ extraClasses,
+ canEdit && 'editable-title--editable',
+ isEditing && 'editable-title--editing',
)}
- style={this.props.style}
+ style={style}
>
{input}
</span>
diff --git a/superset/assets/src/datasource/DatasourceEditor.jsx
b/superset/assets/src/datasource/DatasourceEditor.jsx
index f398ab1..cbc46c8 100644
--- a/superset/assets/src/datasource/DatasourceEditor.jsx
+++ b/superset/assets/src/datasource/DatasourceEditor.jsx
@@ -43,7 +43,6 @@ import withToasts from
'../messageToasts/enhancers/withToasts';
import './main.css';
const checkboxGenerator = (d, onChange) => <CheckboxControl value={d}
onChange={onChange} />;
-const styleMonospace = { fontFamily: 'monospace' };
const DATA_TYPES = ['STRING', 'NUMBER', 'DATETIME'];
function CollectionTabTitle({ title, collection }) {
@@ -540,7 +539,8 @@ export class DatasourceEditor extends React.PureComponent {
canEdit
title={v}
onSaveTitle={onChange}
- style={styleMonospace}
+ extraClasses={['datasource-sql-expression']}
+ multiLine
/>),
description: (v, onChange, label) => (
<StackedField
diff --git a/superset/assets/stylesheets/superset.less
b/superset/assets/stylesheets/superset.less
index 5e0e90e..5d44428 100644
--- a/superset/assets/stylesheets/superset.less
+++ b/superset/assets/stylesheets/superset.less
@@ -1,8 +1,10 @@
@import './less/index.less';
@import "./less/cosmo/variables.less";
+@datasource-sql-expression-width: 450px;
+
body {
- margin: 0px !important;
+ margin: 0 !important;
}
.caret {
@@ -230,12 +232,37 @@ table.table-no-hover tr:hover {
cursor: initial;
}
+.editable-title textarea {
+ outline: none;
+ background: transparent;
+ box-shadow: none;
+ cursor: initial;
+ border: 1px solid #ccc;
+ border-radius: 2px;
+}
+
.editable-title input[type="text"] {
border: 1px solid #ccc;
border-radius: 2px;
padding: 2px;
}
+.editable-title.datasource-sql-expression {
+ font-family: @font-family-monospace;
+ font-size: 95%;
+ display: inline-block;
+ min-width: @datasource-sql-expression-width;
+}
+
+.editable-title.datasource-sql-expression input {
+ width: 95%;
+ padding-bottom: 5px;
+}
+
+.editable-title.datasource-sql-expression textarea {
+ width: 95%;
+}
+
.editable-title input[type="button"] {
border-color: transparent;
background: transparent;