Skip to content

Commit 0c3e013

Browse files
Merge commit '9f2d7e07fdb155b3c56d718976ba2077cc4e96a0'
* commit '9f2d7e07fdb155b3c56d718976ba2077cc4e96a0': 2.0.2 (parse-community#1278) Fix: Filter tab not working for classes starting with _ (parse-community#1275) Fix: DataBrowser is not updating accordingly (parse-community#1276) feat(Database Browser): Copy cell value using CTRL+C (parse-community#1272) Update parse to the latest version 🚀 (parse-community#1274) Update babel7 to the latest version 🚀 (parse-community#1273) Update webpack-cli to the latest version 🚀 (parse-community#1268) Update eslint-plugin-jest to the latest version 🚀 (parse-community#1267) Update NodeJS required version (parse-community#1265)
2 parents 25677db + 9f2d7e0 commit 0c3e013

File tree

10 files changed

+595
-920
lines changed

10 files changed

+595
-920
lines changed

CHANGELOG.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,17 @@
11
## Parse Dashboard Changelog
22

33
### master
4-
[Full Changelog](https://github.com/parse-community/parse-dashboard/compare/2.0.1...master)
4+
[Full Changelog](https://github.com/parse-community/parse-dashboard/compare/2.0.2...master)
55

66
* _Contributing to this repo? Add info about your change here to be included in next release_
77

8+
### 2.0.2
9+
[Full Changelog](https://github.com/parse-community/parse-dashboard/compare/2.0.1...2.0.2)
10+
* Fix: filter tab not working for _User, and ohter classes starting with _ ([#1275](https://github.com/parse-community/parse-dashboard/pull/1275)), thanks to [Antonio Davi Macedo Coelho de Castro](https://github.com/davimacedo)
11+
* Fix: Data Browser is not updating accordingly ([#1276](https://github.com/parse-community/parse-dashboard/pull/1276)), thanks to [Antonio Davi Macedo Coelho de Castro](https://github.com/davimacedo)
12+
* NEW: Copy cell value using CTRL+C ([#1272](https://github.com/parse-community/parse-dashboard/pull/1272)), thanks to [Douglas Muaroka](https://github.com/douglasmuraoka)
13+
* Docs: Update NodeJS required version in README ([#1265](https://github.com/parse-community/parse-dashboard/pull/1265)), thanks to [Jerome](https://github.com/JeromeDeLeon)
14+
815
### 2.0.1
916
[Full Changelog](https://github.com/parse-community/parse-dashboard/compare/2.0.0...2.0.1)
1017
* Publishing it again since there is an old test 2.0.0 release already published to npm

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ Parse Dashboard is a standalone dashboard for managing your [Parse Server](https
3939

4040
# Getting Started
4141

42-
[Node.js](https://nodejs.org) version >= 4.3 is required to run the dashboard. You also need to be using Parse Server version 2.1.4 or higher.
42+
[Node.js](https://nodejs.org) version >= 8.9 is required to run the dashboard. You also need to be using Parse Server version 2.1.4 or higher.
4343

4444
# Local Installation
4545

package-lock.json

Lines changed: 519 additions & 866 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
],
2222
"homepage": "https://github.com/ParsePlatform/parse-dashboard",
2323
"bugs": "https://github.com/ParsePlatform/parse-dashboard/issues",
24-
"version": "2.0.1",
24+
"version": "2.0.2",
2525
"repository": {
2626
"type": "git",
2727
"url": "https://github.com/ParsePlatform/parse-dashboard"
@@ -34,13 +34,14 @@
3434
"LICENSE"
3535
],
3636
"dependencies": {
37-
"@babel/runtime": "7.5.5",
37+
"@babel/runtime": "7.6.0",
3838
"bcryptjs": "2.3.0",
3939
"body-parser": "1.19.0",
4040
"codemirror-graphql": "github:timsuchanek/codemirror-graphql#details-fix",
4141
"commander": "3.0.1",
4242
"connect-flash": "0.1.1",
4343
"cookie-session": "2.0.0-beta.3",
44+
"copy-to-clipboard": "^3.2.0",
4445
"create-react-class": "15.6.3",
4546
"csurf": "1.10.0",
4647
"express": "4.17.1",
@@ -52,7 +53,7 @@
5253
"js-beautify": "1.10.2",
5354
"json-file-plus": "3.2.0",
5455
"package-json": "6.5.0",
55-
"parse": "2.7.0",
56+
"parse": "2.7.1",
5657
"passport": "0.4.0",
5758
"passport-local": "1.0.0",
5859
"prismjs": "1.17.0",
@@ -70,11 +71,11 @@
7071
"semver": "^6.3.0"
7172
},
7273
"devDependencies": {
73-
"@babel/core": "7.5.5",
74-
"@babel/plugin-proposal-decorators": "7.4.4",
74+
"@babel/core": "7.6.0",
75+
"@babel/plugin-proposal-decorators": "7.6.0",
7576
"@babel/plugin-transform-regenerator": "7.4.5",
76-
"@babel/plugin-transform-runtime": "7.5.5",
77-
"@babel/preset-env": "7.5.5",
77+
"@babel/plugin-transform-runtime": "7.6.0",
78+
"@babel/preset-env": "7.6.0",
7879
"@babel/preset-react": "7.0.0",
7980
"babel-eslint": "10.0.3",
8081
"babel-loader": "8.0.6",
@@ -83,7 +84,7 @@
8384
"cross-env": "5.2.1",
8485
"css-loader": "3.2.0",
8586
"eslint": "6.3.0",
86-
"eslint-plugin-jest": "22.16.0",
87+
"eslint-plugin-jest": "22.17.0",
8788
"eslint-plugin-react": "7.14.3",
8889
"file-loader": "4.2.0",
8990
"http-server": "0.11.1",
@@ -101,7 +102,7 @@
101102
"style-loader": "1.0.0",
102103
"svg-prep": "1.0.4",
103104
"webpack": "4.39.3",
104-
"webpack-cli": "3.3.7"
105+
"webpack-cli": "3.3.8"
105106
},
106107
"scripts": {
107108
"dev": "node ./Parse-Dashboard/index.js & webpack --config webpack/build.config.js --devtool eval-source-map --progress --watch",

src/components/BrowserCell/BrowserCell.react.js

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export default class BrowserCell extends Component {
1818
super();
1919

2020
this.cellRef = React.createRef();
21+
this.copyableValue = undefined;
2122
}
2223

2324
componentDidUpdate() {
@@ -36,6 +37,10 @@ export default class BrowserCell extends Component {
3637
} else if (top < topBoundary || bottom > window.innerHeight) {
3738
node.scrollIntoView({ block: 'nearest', inline: 'nearest' });
3839
}
40+
41+
if (!this.props.hidden) {
42+
this.props.setCopyableValue(this.copyableValue);
43+
}
3944
}
4045
}
4146

@@ -58,21 +63,22 @@ export default class BrowserCell extends Component {
5863
}
5964

6065
render() {
61-
let { type, value, hidden, width, current, onSelect, onEditChange, setRelation, onPointerClick, row, col } = this.props;
66+
let { type, value, hidden, width, current, onSelect, onEditChange, setCopyableValue, setRelation, onPointerClick, row, col } = this.props;
6267
let content = value;
68+
this.copyableValue = content;
6369
let classes = [styles.cell, unselectable];
6470
if (hidden) {
6571
content = '(hidden)';
6672
classes.push(styles.empty);
6773
} else if (value === undefined) {
6874
if (type === 'ACL') {
69-
content = 'Public Read + Write';
75+
this.copyableValue = content = 'Public Read + Write';
7076
} else {
71-
content = '(undefined)';
77+
this.copyableValue = content = '(undefined)';
7278
classes.push(styles.empty);
7379
}
7480
} else if (value === null) {
75-
content = '(null)';
81+
this.copyableValue = content = '(null)';
7682
classes.push(styles.empty);
7783
} else if (value === '') {
7884
content = <span>&nbsp;</span>;
@@ -88,23 +94,22 @@ export default class BrowserCell extends Component {
8894
<Pill value={value.id} />
8995
</a>
9096
);
97+
this.copyableValue = value.id;
9198
} else if (type === 'Date') {
9299
if (typeof value === 'object' && value.__type) {
93100
value = new Date(value.iso);
94101
} else if (typeof value === 'string') {
95102
value = new Date(value);
96103
}
97-
content = dateStringUTC(value);
104+
this.copyableValue = content = dateStringUTC(value);
98105
} else if (type === 'Boolean') {
99-
content = value ? 'True' : 'False';
106+
this.copyableValue = content = value ? 'True' : 'False';
100107
} else if (type === 'Object' || type === 'Bytes' || type === 'Array') {
101-
content = JSON.stringify(value);
108+
this.copyableValue = content = JSON.stringify(value);
102109
} else if (type === 'File') {
103-
if (value.url()) {
104-
content = <Pill value={getFileName(value)} />;
105-
} else {
106-
content = <Pill value={'Uploading\u2026'} />;
107-
}
110+
const fileName = value.url() ? getFileName(value) : 'Uploading\u2026';
111+
content = <Pill value={fileName} />;
112+
this.copyableValue = fileName;
108113
} else if (type === 'ACL') {
109114
let pieces = [];
110115
let json = value.toJSON();
@@ -125,17 +130,18 @@ export default class BrowserCell extends Component {
125130
if (pieces.length === 0) {
126131
pieces.push('Master Key Only');
127132
}
128-
content = pieces.join(', ');
133+
this.copyableValue = content = pieces.join(', ');
129134
} else if (type === 'GeoPoint') {
130-
content = `(${value.latitude}, ${value.longitude})`;
135+
this.copyableValue = content = `(${value.latitude}, ${value.longitude})`;
131136
} else if (type === 'Polygon') {
132-
content = value.coordinates.map(coord => `(${coord})`)
137+
this.copyableValue = content = value.coordinates.map(coord => `(${coord})`)
133138
} else if (type === 'Relation') {
134139
content = (
135140
<div style={{ textAlign: 'center', cursor: 'pointer' }}>
136141
<Pill onClick={() => setRelation(value)} value='View relation' />
137142
</div>
138143
);
144+
this.copyableValue = undefined;
139145
}
140146

141147
if (current) {
@@ -146,7 +152,10 @@ export default class BrowserCell extends Component {
146152
ref={this.cellRef}
147153
className={classes.join(' ')}
148154
style={{ width }}
149-
onClick={() => onSelect({ row, col })}
155+
onClick={() => {
156+
onSelect({ row, col });
157+
setCopyableValue(hidden ? undefined : this.copyableValue);
158+
}}
150159
onDoubleClick={() => {
151160
if (type !== 'Relation') {
152161
onEditChange(true)

src/components/BrowserRow/BrowserRow.react.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ export default class BrowserRow extends Component {
1818
}
1919

2020
render() {
21-
const { className, columns, currentCol, isUnique, obj, onPointerClick, order, readOnlyFields, row, rowWidth, selection, selectRow, setCurrent, setEditing, setRelation } = this.props;
21+
const { className, columns, currentCol, isUnique, obj, onPointerClick, order, readOnlyFields, row, rowWidth, selection, selectRow, setCopyableValue, setCurrent, setEditing, setRelation } = this.props;
2222
let attributes = obj.attributes;
2323
return (
2424
<div className={styles.tableRow} style={{ minWidth: rowWidth }}>
@@ -71,7 +71,8 @@ export default class BrowserRow extends Component {
7171
onPointerClick={onPointerClick}
7272
setRelation={setRelation}
7373
value={attr}
74-
hidden={hidden} />
74+
hidden={hidden}
75+
setCopyableValue={setCopyableValue} />
7576
);
7677
})}
7778
</div>

src/dashboard/Data/Browser/Browser.react.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ class Browser extends DashboardView {
113113
this.createClass = this.createClass.bind(this);
114114
this.addColumn = this.addColumn.bind(this);
115115
this.removeColumn = this.removeColumn.bind(this);
116+
this.showNote = this.showNote.bind(this);
116117
}
117118

118119
componentWillMount() {
@@ -974,7 +975,8 @@ class Browser extends DashboardView {
974975
setRelation={this.setRelation}
975976
onAddColumn={this.showAddColumn}
976977
onAddRow={this.addRow}
977-
onAddClass={this.showCreateClass} />
978+
onAddClass={this.showCreateClass}
979+
showNote={this.showNote} />
978980
);
979981
}
980982
}

src/dashboard/Data/Browser/BrowserTable.react.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,8 @@ export default class BrowserTable extends React.Component {
135135
selectRow={this.props.selectRow}
136136
setCurrent={this.props.setCurrent}
137137
setEditing={this.props.setEditing}
138-
setRelation={this.props.setRelation} />
138+
setRelation={this.props.setRelation}
139+
setCopyableValue={this.props.setCopyableValue} />
139140
</div>
140141
);
141142
}
@@ -167,7 +168,8 @@ export default class BrowserTable extends React.Component {
167168
selectRow={this.props.selectRow}
168169
setCurrent={this.props.setCurrent}
169170
setEditing={this.props.setEditing}
170-
setRelation={this.props.setRelation} />
171+
setRelation={this.props.setRelation}
172+
setCopyableValue={this.props.setCopyableValue} />
171173
}
172174

173175
if (this.props.editing) {

src/dashboard/Data/Browser/BrowserToolbar.react.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import Toolbar from 'components/Toolbar/Toolbar.react';
2020

2121
let BrowserToolbar = ({
2222
className,
23-
classNameForPermissionsEditor,
23+
classNameForEditors,
2424
count,
2525
perms,
2626
schema,
@@ -145,7 +145,7 @@ let BrowserToolbar = ({
145145

146146
const userPointers = [];
147147
const schemaSimplifiedData = {};
148-
const classSchema = schema.data.get('classes').get(className);
148+
const classSchema = schema.data.get('classes').get(classNameForEditors);
149149
if (classSchema) {
150150
classSchema.forEach(({ type, targetClass }, col) => {
151151
if (name === 'objectId' || isUnique && name !== uniqueField) {
@@ -189,13 +189,13 @@ let BrowserToolbar = ({
189189
schema={schemaSimplifiedData}
190190
filters={filters}
191191
onChange={onFilterChange}
192-
className={className} />
192+
className={classNameForEditors} />
193193
<div className={styles.toolbarSeparator} />
194194
{enableSecurityDialog ? <SecurityDialog
195195
setCurrent={setCurrent}
196196
disabled={!!relation || !!isUnique}
197197
perms={perms}
198-
className={classNameForPermissionsEditor}
198+
className={classNameForEditors}
199199
onChangeCLP={onChangeCLP}
200200
userPointers={userPointers} /> : <noscript />}
201201
{enableSecurityDialog ? <div className={styles.toolbarSeparator} /> : <noscript/>}

src/dashboard/Data/Browser/DataBrowser.react.js

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
* This source code is licensed under the license found in the LICENSE file in
66
* the root directory of this source tree.
77
*/
8+
import copy from 'copy-to-clipboard';
89
import BrowserTable from 'dashboard/Data/Browser/BrowserTable.react';
910
import BrowserToolbar from 'dashboard/Data/Browser/BrowserToolbar.react';
1011
import * as ColumnPreferences from 'lib/ColumnPreferences';
@@ -32,6 +33,7 @@ export default class DataBrowser extends React.Component {
3233
order: order,
3334
current: null,
3435
editing: false,
36+
copyableValue: undefined
3537
};
3638

3739
this.handleKey = this.handleKey.bind(this);
@@ -40,27 +42,11 @@ export default class DataBrowser extends React.Component {
4042
this.setCurrent = this.setCurrent.bind(this);
4143
this.setEditing = this.setEditing.bind(this);
4244
this.handleColumnsOrder = this.handleColumnsOrder.bind(this);
45+
this.setCopyableValue = this.setCopyableValue.bind(this);
4346

4447
this.saveOrderTimeout = null;
4548
}
4649

47-
shouldComponentUpdate(nextProps, nextState) {
48-
const shallowVerifyStates = [...new Set(Object.keys(this.state).concat(Object.keys(nextState)))]
49-
.filter(stateName => stateName !== 'order');
50-
if (shallowVerifyStates.some(stateName => this.state[stateName] !== nextState[stateName])) {
51-
return true;
52-
}
53-
if (JSON.stringify(this.state.order) !== JSON.stringify(nextState.order)) {
54-
return true;
55-
}
56-
const shallowVerifyProps = [...new Set(Object.keys(this.props).concat(Object.keys(nextProps)))]
57-
.filter(propName => propName !== 'columns');
58-
if (shallowVerifyProps.some(propName => this.props[propName] !== nextProps[propName])) {
59-
return true;
60-
}
61-
return JSON.stringify(this.props.columns) !== JSON.stringify(nextProps.columns);
62-
}
63-
6450
componentWillReceiveProps(props, context) {
6551
if (props.className !== this.props.className) {
6652
let order = ColumnPreferences.getOrder(
@@ -195,6 +181,13 @@ export default class DataBrowser extends React.Component {
195181
});
196182
e.preventDefault();
197183
break;
184+
case 67: // C
185+
if ((e.ctrlKey || e.metaKey) && this.state.copyableValue !== undefined) {
186+
copy(this.state.copyableValue); // Copies current cell value to clipboard
187+
this.props.showNote('Value copied to clipboard', false)
188+
e.preventDefault()
189+
}
190+
break;
198191
}
199192
}
200193

@@ -209,6 +202,12 @@ export default class DataBrowser extends React.Component {
209202
this.setState({ current });
210203
}
211204
}
205+
206+
setCopyableValue(copyableValue) {
207+
if (this.state.copyableValue !== copyableValue) {
208+
this.setState({ copyableValue });
209+
}
210+
}
212211

213212
handleColumnsOrder(order) {
214213
this.setState({ order: [ ...order ] }, () => {
@@ -230,12 +229,13 @@ export default class DataBrowser extends React.Component {
230229
handleResize={this.handleResize}
231230
setEditing={this.setEditing}
232231
setCurrent={this.setCurrent}
232+
setCopyableValue={this.setCopyableValue}
233233
{...other} />
234234
<BrowserToolbar
235235
count={count}
236236
hidePerms={className === '_Installation'}
237237
className={SpecialClasses[className] || className}
238-
classNameForPermissionsEditor={className}
238+
classNameForEditors={className}
239239
setCurrent={this.setCurrent}
240240
enableDeleteAllRows={this.context.currentApp.serverInfo.features.schemas.clearAllDataFromClass && !preventSchemaEdits}
241241
enableExportClass={this.context.currentApp.serverInfo.features.schemas.exportClass && !preventSchemaEdits}

0 commit comments

Comments
 (0)