1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-22 11:57:34 +00:00

complete data-grid improve

This commit is contained in:
shanshuirenjia
2019-04-26 07:16:01 +08:00
parent be3f3093a8
commit 109afb9058
7 changed files with 3712 additions and 91 deletions

View File

@@ -118,9 +118,9 @@
}
},
"@seafile/react-data-grid": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/@seafile/react-data-grid/-/react-data-grid-6.0.1.tgz",
"integrity": "sha512-REBdUu5T5UwsbQwaVac2sbotRJzxN2N+ge8NzHOJwItezG6HnDMWs43g5XqxDIyFAp5JaE3KPc0LcKBr/m1h5A==",
"version": "6.1.3",
"resolved": "https://registry.npmjs.org/@seafile/react-data-grid/-/react-data-grid-6.1.3.tgz",
"integrity": "sha512-cCpsP9uTDxNftYP6m6jCtUffZ59OOdJZ3Bk+BHQjY8LePWzunhbsVeDoFw7mUj8m3BekayoKCrIfFZFydcQxGA==",
"requires": {
"object-assign": "^4.1.1",
"react-is-deprecated": "^0.1.2",
@@ -128,9 +128,9 @@
}
},
"@seafile/react-data-grid-addons": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/@seafile/react-data-grid-addons/-/react-data-grid-addons-6.0.1.tgz",
"integrity": "sha512-lH95qccHzS2fFeJVB4Bw4pExNG5i5prrxT8X1LqsIpacwow3PiqV4+tH/bOVaFVqLSRwZJ3TYKshW1fsd1EmvA==",
"version": "6.1.3",
"resolved": "https://registry.npmjs.org/@seafile/react-data-grid-addons/-/react-data-grid-addons-6.1.3.tgz",
"integrity": "sha512-vFBbflST0833T7cz2FGGmBkpkBhfi6MsUiq1HbOoV0b4yWKk3GI4tv0hFjDFabKI30EgVcVeqeS9T8Bu+7F47A==",
"requires": {
"react-contextmenu": "^2.10.0",
"react-dnd": "^2.6.0",
@@ -2284,12 +2284,12 @@
}
},
"browser-sync": {
"version": "2.26.3",
"resolved": "https://registry.npmjs.org/browser-sync/-/browser-sync-2.26.3.tgz",
"integrity": "sha512-VLzpjCA4uXqfzkwqWtMM6hvPm2PNHp2RcmzBXcbi6C9WpkUhhFb8SVAr4CFrCsFxDg+oY6HalOjn8F+egyvhag==",
"version": "2.26.5",
"resolved": "https://registry.npmjs.org/browser-sync/-/browser-sync-2.26.5.tgz",
"integrity": "sha512-zVa6MmadAFgl5Uk53Yy5cw5tGTO7xSGAWK3Yx70GJ1t5jK+r6B4q3xq+1XbYfLt1SbeFg7WoNWneNhMT4B9jFw==",
"requires": {
"browser-sync-client": "^2.26.2",
"browser-sync-ui": "^2.26.2",
"browser-sync-client": "^2.26.4",
"browser-sync-ui": "^2.26.4",
"bs-recipes": "1.3.4",
"bs-snippet-injector": "^2.0.1",
"chokidar": "^2.0.4",
@@ -2304,7 +2304,7 @@
"http-proxy": "1.15.2",
"immutable": "^3",
"localtunnel": "1.9.1",
"micromatch": "2.3.11",
"micromatch": "^3.1.10",
"opn": "5.3.0",
"portscanner": "2.1.1",
"qs": "6.2.3",
@@ -2329,26 +2329,6 @@
"normalize-path": "^2.1.1"
},
"dependencies": {
"micromatch": {
"version": "3.1.10",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
"integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
"requires": {
"arr-diff": "^4.0.0",
"array-unique": "^0.3.2",
"braces": "^2.3.1",
"define-property": "^2.0.2",
"extend-shallow": "^3.0.2",
"extglob": "^2.0.4",
"fragment-cache": "^0.2.1",
"kind-of": "^6.0.2",
"nanomatch": "^1.2.9",
"object.pick": "^1.3.0",
"regex-not": "^1.0.0",
"snapdragon": "^0.8.1",
"to-regex": "^3.0.2"
}
},
"normalize-path": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
@@ -2568,13 +2548,13 @@
}
},
"fsevents": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.7.tgz",
"integrity": "sha512-Pxm6sI2MeBD7RdD12RYsqaP0nMiwx8eZBXCa6z2L+mRHm2DYrOYwihmhjpkdjUHwQhslWQjRpEgNq4XvBmaAuw==",
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.8.tgz",
"integrity": "sha512-tPvHgPGB7m40CZ68xqFGkKuzN+RnpGmSV+hgeKxhRpbxdqKXUFJGC3yonBOLzQBcJyGpdZFDfCsdOC2KFsXzeA==",
"optional": true,
"requires": {
"nan": "^2.9.2",
"node-pre-gyp": "^0.10.0"
"nan": "^2.12.1",
"node-pre-gyp": "^0.12.0"
},
"dependencies": {
"abbrev": {
@@ -2635,11 +2615,11 @@
"optional": true
},
"debug": {
"version": "2.6.9",
"version": "4.1.1",
"bundled": true,
"optional": true,
"requires": {
"ms": "2.0.0"
"ms": "^2.1.1"
}
},
"deep-extend": {
@@ -2784,22 +2764,22 @@
}
},
"ms": {
"version": "2.0.0",
"version": "2.1.1",
"bundled": true,
"optional": true
},
"needle": {
"version": "2.2.4",
"version": "2.3.0",
"bundled": true,
"optional": true,
"requires": {
"debug": "^2.1.2",
"debug": "^4.1.0",
"iconv-lite": "^0.4.4",
"sax": "^1.2.4"
}
},
"node-pre-gyp": {
"version": "0.10.3",
"version": "0.12.0",
"bundled": true,
"optional": true,
"requires": {
@@ -2825,12 +2805,12 @@
}
},
"npm-bundled": {
"version": "1.0.5",
"version": "1.0.6",
"bundled": true,
"optional": true
},
"npm-packlist": {
"version": "1.2.0",
"version": "1.4.1",
"bundled": true,
"optional": true,
"requires": {
@@ -2949,7 +2929,7 @@
"optional": true
},
"semver": {
"version": "5.6.0",
"version": "5.7.0",
"bundled": true,
"optional": true
},
@@ -3132,11 +3112,37 @@
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
"integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA=="
},
"micromatch": {
"version": "3.1.10",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
"integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
"requires": {
"arr-diff": "^4.0.0",
"array-unique": "^0.3.2",
"braces": "^2.3.1",
"define-property": "^2.0.2",
"extend-shallow": "^3.0.2",
"extglob": "^2.0.4",
"fragment-cache": "^0.2.1",
"kind-of": "^6.0.2",
"nanomatch": "^1.2.9",
"object.pick": "^1.3.0",
"regex-not": "^1.0.0",
"snapdragon": "^0.8.1",
"to-regex": "^3.0.2"
}
},
"mime": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz",
"integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ=="
},
"nan": {
"version": "2.13.2",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.13.2.tgz",
"integrity": "sha512-TghvYc72wlMGMVMluVo9WRJc0mB8KxxF/gZ4YYFy7V2ZQX9l7rgbPg7vjS9mt6U5HXODVFVI2bOduCzwOMv/lw==",
"optional": true
},
"normalize-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
@@ -3163,28 +3169,6 @@
"graceful-fs": "^4.1.11",
"micromatch": "^3.1.10",
"readable-stream": "^2.0.2"
},
"dependencies": {
"micromatch": {
"version": "3.1.10",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
"integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
"requires": {
"arr-diff": "^4.0.0",
"array-unique": "^0.3.2",
"braces": "^2.3.1",
"define-property": "^2.0.2",
"extend-shallow": "^3.0.2",
"extglob": "^2.0.4",
"fragment-cache": "^0.2.1",
"kind-of": "^6.0.2",
"nanomatch": "^1.2.9",
"object.pick": "^1.3.0",
"regex-not": "^1.0.0",
"snapdragon": "^0.8.1",
"to-regex": "^3.0.2"
}
}
}
},
"send": {
@@ -3270,9 +3254,9 @@
}
},
"browser-sync-client": {
"version": "2.26.2",
"resolved": "https://registry.npmjs.org/browser-sync-client/-/browser-sync-client-2.26.2.tgz",
"integrity": "sha512-FEuVJD41fI24HJ30XOT2RyF5WcnEtdJhhTqeyDlnMk/8Ox9MZw109rvk9pdfRWye4soZLe+xcAo9tHSMxvgAdw==",
"version": "2.26.4",
"resolved": "https://registry.npmjs.org/browser-sync-client/-/browser-sync-client-2.26.4.tgz",
"integrity": "sha512-mQiDp5/tf79VezDS5j/EExU4Ze6f5DQYuL0Z7VdJgBbNLTHDfkYGi2R620qc6HkY9XZA0m4/UwihT7J42RBIJA==",
"requires": {
"etag": "1.8.1",
"fresh": "0.5.2",
@@ -3281,9 +3265,9 @@
}
},
"browser-sync-ui": {
"version": "2.26.2",
"resolved": "https://registry.npmjs.org/browser-sync-ui/-/browser-sync-ui-2.26.2.tgz",
"integrity": "sha512-LF7GMWo8ELOE0eAlxuRCfnGQT1ZxKP9flCfGgZdXFc6BwmoqaJHlYe7MmVvykKkXjolRXTz8ztXAKGVqNwJ3EQ==",
"version": "2.26.4",
"resolved": "https://registry.npmjs.org/browser-sync-ui/-/browser-sync-ui-2.26.4.tgz",
"integrity": "sha512-u20P3EsZoM8Pt+puoi3BU3KlbQAH1lAcV+/O4saF26qokrBqIDotmGonfWwoRbUmdxZkM9MBmA0K39ZTG1h4sA==",
"requires": {
"async-each-series": "0.1.1",
"connect-history-api-fallback": "^1",
@@ -9700,6 +9684,7 @@
"version": "2.10.0",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz",
"integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==",
"dev": true,
"optional": true
},
"nanomatch": {
@@ -15439,13 +15424,13 @@
"dependencies": {
"ansi-regex": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-1.1.1.tgz",
"resolved": "http://registry.npmjs.org/ansi-regex/-/ansi-regex-1.1.1.tgz",
"integrity": "sha1-QchHGUZGN15qGl0Qw8oFTvn8mA0=",
"dev": true
},
"strip-ansi": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-2.0.1.tgz",
"resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-2.0.1.tgz",
"integrity": "sha1-32LBqpTtLxFOHQ8h/R1QSCt5pg4=",
"dev": true,
"requires": {

View File

@@ -4,8 +4,8 @@
"private": true,
"dependencies": {
"@reach/router": "^1.2.0",
"@seafile/react-data-grid": "^6.0.1",
"@seafile/react-data-grid-addons": "^6.0.1",
"@seafile/react-data-grid": "^6.1.3",
"@seafile/react-data-grid-addons": "^6.1.3",
"@seafile/resumablejs": "^1.1.9",
"@seafile/seafile-editor": "^0.2.20",
"MD5": "^1.3.0",

View File

@@ -1,7 +1,12 @@
import React from 'react';
import PropTypes from 'prop-types';
import ReactDataGrid from '@seafile/react-data-grid/dist/react-data-grid';
import ReactDataGrid from '@seafile/react-data-grid/';
import update from 'immutability-helper';
import { Menu, Editors } from '@seafile/react-data-grid-addons';
import GridHeaderContextMenu from './grid-header-contextmenu';
import GridContentContextMenu from './grid-content-contextmenu';
import ModalPortal from '../../components/modal-portal';
import NewColumnDialog from './new-column-dialog';
const propTypes = {
initData: PropTypes.object.isRequired,
@@ -23,8 +28,9 @@ class AppMain extends React.Component {
let initData = props.initData;
this.state = {
columns: initData.columns.length ? initData.columns : this._columns,
rows: initData.rows.length ? initData.rows : this.createRows(1)
columns: initData.columns.length ? this.deseralizeGridData(initData.columns) : this._columns,
rows: initData.rows.length ? initData.rows : this.createRows(1),
isNewColumnDialogShow: false,
};
}
@@ -90,20 +96,42 @@ class AppMain extends React.Component {
}
onInsertColumn = () => {
var name = window.prompt('Place enter a column name', '');
if (!name || name.trim() === '') {
return;
this.setState({isNewColumnDialogShow: true});
}
onNewColumn = (columnName, columnType) => {
let editor = this.createEditor(columnType);
let newColumn = {
key: name,
name: name,
key: columnName,
name: columnName,
editor: editor,
editable: true,
width: 200,
resizable: true
};
let columns = this.state.columns.slice();
columns.push(newColumn);
this.setState({columns: columns});
this.onNewColumnCancel();
}
onNewColumnCancel = () => {
this.setState({isNewColumnDialogShow: false});
}
onRowDelete = (e, data) => {
let { rowIdx } = data;
let newRows = this.state.rows.slice(0); // copy array;
newRows.splice(rowIdx, 1);
this.setState({rows: newRows});
}
onColumnDelete = (e, data) => {
let column = data.column;
let key = column.key;
let columns = this.state.columns.filter(item => item.key !== key);
this.setState({columns: columns});
}
serializeGridData = () => {
@@ -115,14 +143,41 @@ class AppMain extends React.Component {
}
deseralizeGridData = (data) => {
let columns = data.columns;
let rows = data.rows;
let columns = JSON.parse(data.columns);
let rows = JSON.parse(data.rows);
columns = this.formatColumnsData(columns);
this.setState({
columns: JSON.parse(columns),
rows: JSON.parse(rows),
columns: columns,
rows: rows,
});
}
formatColumnsData = (columns) => {
return columns.map(column => {
if (column.editor) {
let editor = this.createEditor(column.editor);
column.editor = editor;
}
return column;
});
}
createEditor = (editorType) => {
let editor = null;
switch (editorType) {
case 'number':
editor = <Editors.NumberEditor />;
break;
case 'text':
editor = null;
break;
default:
break;
}
return editor;
}
render() {
let columns = this.getColumns();
return (
@@ -142,7 +197,18 @@ class AppMain extends React.Component {
enableInsertRow={true}
onInsertRow={this.onInsertRow}
onInsertColumn={this.onInsertColumn}
RowsContainer={Menu.ContextMenuTrigger}
headerContextMenu={<GridHeaderContextMenu id="grid-header-contxtmenu" onColumnDelete={this.onColumnDelete} />}
contextMenu={<GridContentContextMenu id="grid-content-contxtmenu" onRowDelete={this.onRowDelete} />}
/>
{this.state.isNewColumnDialogShow && (
<ModalPortal>
<NewColumnDialog
onNewColumnCancel={this.onNewColumnCancel}
onNewColumn={this.onNewColumn}
/>
</ModalPortal>
)}
</div>
);
}

View File

@@ -0,0 +1,33 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Menu } from '@seafile/react-data-grid-addons';
const propTypes = {
id: PropTypes.string.isRequired,
idx: PropTypes.number,
rowIdx: PropTypes.number,
onRowDelete: PropTypes.func.isRequired,
};
class GridContentContextMenu extends React.Component {
onRowDelete = (e, data) => {
if (typeof(this.props.onRowDelete) === 'function') {
this.props.onRowDelete(e, data);
}
};
render() {
const { idx, id, rowIdx } = this.props;
return (
<Menu.ContextMenu id={id}>
<Menu.MenuItem data={{ rowIdx, idx }} onClick={this.onRowDelete}>Delete Row</Menu.MenuItem>
</Menu.ContextMenu>
);
}
}
GridContentContextMenu.propTypes = propTypes;
export default GridContentContextMenu;

View File

@@ -0,0 +1,33 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Menu } from '@seafile/react-data-grid-addons';
const propTypes = {
id: PropTypes.string.isRequired,
column: PropTypes.object,
onColumnRename: PropTypes.func,
};
class GridHeaderContextMenu extends React.Component {
onColumnDelete = (e, data) => {
if (typeof(this.props.onColumnDelete) === 'function') {
this.props.onColumnDelete(e, data);
}
}
render() {
let { id, column } = this.props;
return (
<Menu.ContextMenu id={id}>
<Menu.MenuItem data={{ column }} onClick={this.onColumnDelete}>Delete</Menu.MenuItem>
</Menu.ContextMenu>
);
}
}
GridHeaderContextMenu.propTypes = propTypes;
export default GridHeaderContextMenu;

View File

@@ -0,0 +1,76 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Modal, ModalHeader, ModalBody, ModalFooter, Form, FormGroup, Label, Input, Alert, Button } from 'reactstrap';
import { gettext } from '../../utils/constants';
const propTypes = {
onNewColumnCancel: PropTypes.func,
onNewColumn: PropTypes.func,
};
class NewCoumnDialog extends React.Component {
constructor(props) {
super(props);
this.state = {
columnType: 'text',
columnName: '',
errMessage: '',
};
}
handleChange = (event) => {
let value = event.target.value.trim();
this.setState({columnName: value});
}
onSelectChange = (event) => {
let type = event.target.value;
this.setState({columnType: type});
}
toggle = () => {
this.props.onNewColumnCancel();
}
handleSubmit = () => {
let { columnName, columnType } = this.state;
if (!columnName) {
this.setState({errMessage: gettext('Name is required.')});
return;
}
this.props.onNewColumn(columnName, columnType);
}
render() {
return (
<Modal isOpen={true} toggle={this.toggle}>
<ModalHeader>{gettext('New Column')}</ModalHeader>
<ModalBody>
<Form>
<FormGroup>
<Label for="columnName">{gettext('Name')}</Label>
<Input id="columnName" value={this.state.columnName} innerRef={input => {this.newInput = input;}} onChange={this.handleChange} />
</FormGroup>
<FormGroup>
<Label for="typeSelect">{gettext('type')}</Label>
<Input id="typeSelect" type='select' name="select" onChange={this.onSelectChange}>
<option vlaue="text">{gettext('text')}</option>
<option value="number">{gettext('number')}</option>
</Input>
</FormGroup>
</Form>
{this.state.errMessage && <Alert color="danger" className="mt-2">{this.state.errMessage}</Alert>}
</ModalBody>
<ModalFooter>
<Button color="secondary" onClick={this.toggle}>{gettext('Cancel')}</Button>
<Button color="primary" onClick={this.handleSubmit}>{gettext('Submit')}</Button>
</ModalFooter>
</Modal>
);
}
}
NewCoumnDialog.propTypes = propTypes;
export default NewCoumnDialog;

3428
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff