Skip to content

Commit

Permalink
Update EditableText component (#299)
Browse files Browse the repository at this point in the history
* Fix some styling issues with react-markdown
* Update EditableText to use React Refs instead of ref callbacks
* Add configs for table and column description max lengths
  • Loading branch information
Daniel authored Sep 26, 2019
1 parent 17b9cd3 commit f1007c6
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 61 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import * as React from 'react';
import moment from 'moment-timezone';

import { OverlayTrigger, Popover } from 'react-bootstrap';
import moment from 'moment-timezone';

import AppConfig from 'config/config';
import ColumnDescEditableText from 'components/TableDetail/ColumnDescEditableText';
import { logClick } from 'ducks/utilMethods';
import { TableColumn } from 'interfaces';
Expand Down Expand Up @@ -132,6 +132,7 @@ class DetailListItem extends React.Component<DetailListItemProps, DetailListItem
columnIndex={this.props.index}
editable={metadata.is_editable}
value={metadata.description}
maxLength={AppConfig.editableText.columnDescLength}
/>
</div>
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,8 @@
padding-right: 32px;
}

// TODO - move to common styles
.truncated,
.truncated .editable-text {
.truncated .editable-text,
.truncated .editable-text p {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,7 @@ export class TableDetail extends React.Component<TableDetailProps & RouteCompone
<TableDescEditableText
value={ data.table_description }
editable={ data.is_editable }
maxLength={ AppConfig.editableText.tableDescLength }
/>
</div>
<div className="col-xs-12 col-md-5 float-md-right col-lg-4">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import autosize from 'autosize';
import * as React from 'react';
import ReactDOM from 'react-dom';
import { Overlay, Tooltip } from 'react-bootstrap';
import * as ReactMarkdown from 'react-markdown';
import { Overlay, Popover, Tooltip } from 'react-bootstrap';
import autosize from 'autosize';

// TODO: Use css-modules instead of 'import'
// TODO: Outdated approach (lines 148, 168). Replace with React.createRef(). See more at https://reactjs.org/docs/refs-and-the-dom.html
import './styles.scss';

export interface StateFromProps {
Expand Down Expand Up @@ -34,12 +32,12 @@ interface EditableTextState {
}

class EditableText extends React.Component<EditableTextProps, EditableTextState> {
private textAreaTarget: HTMLTextAreaElement;
private editAnchorTarget: HTMLAnchorElement;
private textAreaRef;
private editAnchorRef;

public static defaultProps: EditableTextProps = {
editable: true,
maxLength: 4000,
maxLength: 250,
onSubmitValue: null,
getLatestValue: null,
value: '',
Expand All @@ -52,6 +50,9 @@ class EditableText extends React.Component<EditableTextProps, EditableTextState>

constructor(props) {
super(props);
this.textAreaRef = React.createRef();
this.editAnchorRef = React.createRef();

this.state = {
editable: props.editable,
inEditMode: false,
Expand All @@ -63,19 +64,16 @@ class EditableText extends React.Component<EditableTextProps, EditableTextState>

componentDidUpdate() {
const { isDisabled, inEditMode, refreshValue, value } = this.state;
if (inEditMode) {
autosize(this.textAreaTarget);
if (refreshValue && refreshValue !== value && !isDisabled) {
// disable the component if a refresh is needed
this.setState({ isDisabled: true })
}
else {
// when entering edit mode, place focus in the textarea
const textArea = ReactDOM.findDOMNode(this.textAreaTarget);
if (textArea) {
textArea.focus();
}
}
const textArea = this.textAreaRef.current;
if (!inEditMode) return;

autosize(textArea);
if (refreshValue && refreshValue !== value && !isDisabled) {
// disable the component if a refresh is needed
this.setState({ isDisabled: true })
} else if (textArea) {
// when entering edit mode, place focus in the textarea
textArea.focus();
}
}

Expand All @@ -97,28 +95,27 @@ class EditableText extends React.Component<EditableTextProps, EditableTextState>
};

updateText = () => {
const newValue = ReactDOM.findDOMNode(this.textAreaTarget).value;
const newValue = this.textAreaRef.current.value;
const onSuccessCallback = () => { this.setState({value: newValue, inEditMode: false, refreshValue: undefined }); };
const onFailureCallback = () => { this.exitEditMode(); };

this.props.onSubmitValue(newValue, onSuccessCallback, onFailureCallback);
};

getTarget(type) {
if (type === 'editAnchor') {
return ReactDOM.findDOMNode(this.editAnchorTarget);
}
if (type === 'textArea') {
return ReactDOM.findDOMNode(this.textAreaTarget)
}
}
getAnchorTarget = () => {
return this.editAnchorRef.current;
};

getTextAreaTarget = () => {
return this.textAreaRef.current;
};

render() {
if (!this.state.editable) {
return (
<div id='editable-container' className='editable-container'>
<div id='editable-text' className='editable-text'>
<ReactMarkdown source={this.state.value}/>
<ReactMarkdown source={ this.state.value }/>
</div>
</div>
);
Expand All @@ -128,26 +125,24 @@ class EditableText extends React.Component<EditableTextProps, EditableTextState>
<div id='editable-container' className='editable-container'>
<Overlay
placement='top'
show={this.state.isDisabled}
target={this.getTarget.bind(this,'editAnchor')}
show={ this.state.isDisabled }
target={ this.getAnchorTarget }
>
<Tooltip id='error-tooltip'>
<div className="error-tooltip">
<text>This text is out of date, please refresh the component</text>
<button onClick={this.refreshText} className="btn btn-flat-icon">
<button onClick={ this.refreshText } className="btn btn-flat-icon">
<img className='icon icon-refresh'/>
</button>
</div>
</Tooltip>
</Overlay>
<div id='editable-text' className={"editable-text"}>
<ReactMarkdown source={this.state.value}/>
<div id='editable-text' className="editable-text">
<ReactMarkdown source={ this.state.value }/>
<a className={ "edit-link" + (this.state.value ? "" : " no-value") }
href="JavaScript:void(0)"
onClick={ this.enterEditMode }
ref={ anchor => {
this.editAnchorTarget = anchor;
}}
ref={ this.editAnchorRef }
>
{
this.state.value ? "edit" : "Add Description"
Expand All @@ -163,21 +158,17 @@ class EditableText extends React.Component<EditableTextProps, EditableTextState>
<textarea
id='editable-textarea'
className='editable-textarea'
rows={2}
maxLength={this.props.maxLength}
ref={textarea => {
this.textAreaTarget = textarea;
}}
>
{this.state.value}
</textarea>

rows={ 2 }
maxLength={ this.props.maxLength }
ref={ this.textAreaRef }
defaultValue={ this.state.value }
/>
<Overlay
placement='top'
show={true}
target={this.getTarget.bind(this,'textArea')}
show={ true }
target={ this.getTextAreaTarget }
>
<Tooltip>
<Tooltip id='save-tooltip'>
<button id='cancel' onClick={this.exitEditMode}>Cancel</button>
<button id='save' onClick={this.updateText}>Save</button>
</Tooltip>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@
.editable-text {
flex-grow: 0.1;
word-break: break-word;

// React-Markdown wraps editable text with a paragraph
> p {
margin: 0;
display: inline;
}
}

.editable-textarea {
Expand Down
10 changes: 7 additions & 3 deletions frontend/amundsen_application/static/js/config/config-default.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,18 @@ const configDefault: AppConfig = {
curatedTags: [],
showAllTags: true,
},
editableText: {
tableDescLength: 750,
columnDescLength: 250,
},
google: {
enabled: false,
key: 'default-key',
sampleRate: 100,
},
indexUsers: {
enabled: false,
},
logoPath: null,
navLinks: [
{
Expand Down Expand Up @@ -40,9 +47,6 @@ const configDefault: AppConfig = {
return `https://DEFAULT_EXPLORE_URL?schema=${schema}&cluster=${cluster}&db=${database}&table=${table}`;
}
},
indexUsers: {
enabled: false,
}
};

export default configDefault;
25 changes: 22 additions & 3 deletions frontend/amundsen_application/static/js/config/config-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,24 @@

export interface AppConfig {
browse: BrowseConfig;
editableText: EditableTextConfig;
google: GoogleAnalyticsConfig;
indexUsers: IndexUsersConfig;
logoPath: string | null;
navLinks: Array<LinkConfig>;
tableLineage: TableLineageConfig;
tableProfile: TableProfileConfig;
indexUsers: indexUsersConfig;
}

export interface AppConfigCustom {
browse?: BrowseConfig;
editableText?: EditableTextConfig;
google?: GoogleAnalyticsConfig
indexUsers?: IndexUsersConfig;
logoPath?: string;
navLinks?: Array<LinkConfig>;
tableLineage?: TableLineageConfig;
tableProfile?: TableProfileConfig;
indexUsers?: indexUsersConfig;
}

/**
Expand Down Expand Up @@ -83,6 +85,23 @@ export interface LinkConfig {
use_router: boolean;
}

interface indexUsersConfig {
/**
* IndexUsersConfig - When enabled, the IndexUsers feature will index users as searchable resources. This requires
* user objects are ingested via Databuilder
*
* enabled - Enables/disables this feature in the frontend only
*/
interface IndexUsersConfig {
enabled: boolean;
}

/**
* EditableTextConfig - Configure max length limits for editable fields
*
* tableDescLength - maxlength for table descriptions
* columnDescLength - maxlength for column descriptions
*/
interface EditableTextConfig {
tableDescLength: number;
columnDescLength: number;
}

0 comments on commit f1007c6

Please sign in to comment.