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:
137
frontend/package-lock.json
generated
137
frontend/package-lock.json
generated
@@ -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": {
|
||||
|
@@ -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",
|
||||
|
@@ -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>
|
||||
);
|
||||
}
|
||||
|
33
frontend/src/pages/data-grid/grid-content-contextmenu.js
Normal file
33
frontend/src/pages/data-grid/grid-content-contextmenu.js
Normal 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;
|
33
frontend/src/pages/data-grid/grid-header-contextmenu.js
Normal file
33
frontend/src/pages/data-grid/grid-header-contextmenu.js
Normal 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;
|
||||
|
||||
|
76
frontend/src/pages/data-grid/new-column-dialog.js
Normal file
76
frontend/src/pages/data-grid/new-column-dialog.js
Normal 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
3428
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user