williaster commented on a change in pull request #5186: Implement a React-based 
table editor
URL: 
https://github.com/apache/incubator-superset/pull/5186#discussion_r208045639
 
 

 ##########
 File path: superset/assets/src/CRUD/CollectionTable.jsx
 ##########
 @@ -0,0 +1,220 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import shortid from 'shortid';
+
+import Button from '../components/Button';
+import Fieldset from './Fieldset';
+import { recurseReactClone } from './utils';
+import './styles.css';
+
+const propTypes = {
+  collection: PropTypes.array,
+  itemGenerator: PropTypes.func,
+  columnLabels: PropTypes.object,
+  tableColumns: PropTypes.array,
+  columns: PropTypes.array,
+  onChange: PropTypes.func,
+  itemRenderers: PropTypes.object,
+  allowDeletes: PropTypes.bool,
+  expandFieldset: PropTypes.node,
+  emptyMessage: PropTypes.node,
+  extraButtons: PropTypes.node,
+  allowAddItem: PropTypes.bool,
+};
+const defaultProps = {
+  onChange: () => {},
+  itemRenderers: {},
+  columnLabels: {},
+  allowDeletes: false,
+  emptyMessage: 'No entries',
+  allowAddItem: false,
+  itemGenerator: () => ({}),
+};
+const Frame = props => (
+  <div className="frame">
+    {props.children}
+  </div>);
+Frame.propTypes = { children: PropTypes.node };
+
+function createKeyedCollection(arr) {
+  const newArr = arr.map(o => ({
+    ...o,
+    id: o.id || shortid.generate(),
+  }));
+  const map = {};
+  newArr.forEach((o) => {
+    map[o.id] = o;
+  });
+  return map;
+}
+
+export default class CRUDCollection extends React.PureComponent {
+  constructor(props) {
+    super(props);
+    this.state = {
+      expandedColumns: {},
+      collection: createKeyedCollection(props.collection),
+    };
+    this.renderItem = this.renderItem.bind(this);
+    this.onAddItem = this.onAddItem.bind(this);
+    this.renderExpandableSection = this.renderExpandableSection.bind(this);
+    this.getLabel = this.getLabel.bind(this);
+    this.onFieldsetChange = this.onFieldsetChange.bind(this);
+    this.renderTableBody = this.renderTableBody.bind(this);
+    this.changeCollection = this.changeCollection.bind(this);
+  }
+  componentWillReceiveProps(nextProps) {
+    if (nextProps.collection !== this.props.collection) {
+      this.setState({
+        collection: createKeyedCollection(nextProps.collection),
+      });
+    }
+  }
+  onCellChange(id, col, val) {
+    this.changeCollection({
+      ...this.state.collection,
+      [id]: {
+        ...this.state.collection[id],
+        [col]: val,
+      },
+    });
+
+  }
+  onAddItem() {
+    let newItem = this.props.itemGenerator();
+    if (!newItem.id) {
+      newItem = { ...newItem, id: shortid.generate() };
+    }
+    this.changeCollection({
+      ...this.state.collection,
+      [newItem.id]: newItem,
+    });
+  }
+  onFieldsetChange(item) {
+    this.changeCollection({
+      ...this.state.collection,
+      [item.id]: item,
+    });
+  }
+  getLabel(col) {
+    const { columnLabels } = this.props;
+    let label = columnLabels[col] ? columnLabels[col] : col;
+    if (label.startsWith('__')) {
+      label = '';
+    }
+    return label;
+  }
+  changeCollection(collection) {
+    this.setState({ collection });
+    this.props.onChange(Object.keys(collection).map(k => collection[k]));
+  }
+  deleteItem(id) {
+    const newColl = { ...this.state.collection };
+    delete newColl[id];
+    this.changeCollection(newColl);
+  }
+  effectiveTableColumns() {
+    const { tableColumns, allowDeletes, expandFieldset } = this.props;
+    const cols = allowDeletes ? tableColumns.concat(['__actions']) : 
tableColumns;
+    return expandFieldset ? ['__expand'].concat(cols) : cols;
+  }
+  toggleExpand(id) {
+    this.onCellChange(id, '__expanded', false);
+    this.setState({
+      expandedColumns: {
+        ...this.state.expandedColumns,
+        [id]: !this.state.expandedColumns[id],
+      },
+    });
+  }
+  renderHeaderRow() {
+    const cols = this.effectiveTableColumns();
+    return (
+      <thead>
+        <tr>
+          {this.props.expandFieldset && <th className="tiny-cell" />}
+          {cols.map(col => <th key={col}>{this.getLabel(col)}</th>)}
+          {this.props.allowDeletes && <th className="tiny-cell" />}
+        </tr>
+      </thead>
+    );
+  }
+  renderExpandableSection(item) {
+    const propsGenerator = () => ({ item, onChange: this.onFieldsetChange });
+    return recurseReactClone(this.props.expandFieldset, Fieldset, 
propsGenerator);
+  }
+  renderCell(record, col) {
+    const renderer = this.props.itemRenderers[col];
+    const val = record[col];
+    const onChange = this.onCellChange.bind(this, record.id, col);
+    return renderer ? renderer(val, onChange, this.getLabel(col)) : val;
+  }
+  renderItem(record) {
+    const { tableColumns, allowDeletes, expandFieldset } = this.props;
+    /* eslint-disable no-underscore-dangle */
+    const isExpanded = !!this.state.expandedColumns[record.id] || 
record.__expanded;
+    let tds = [];
+    if (expandFieldset) {
+      tds.push(
+        <td key="__expand" className="expand">
+          <i
+            className={`fa fa-caret-${isExpanded ? 'down' : 'right'} 
text-primary pointer`}
 
 Review comment:
   I think the convention that @elibrumbaugh has been pushing for is to have 
the arrow point in the direction that the click will cause. so `unexpanded = 
down`, `expanded = up`

----------------------------------------------------------------
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]

Reply via email to