diff --git a/README.md b/README.md index eded72c5e0..0e4b11f018 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,13 @@ parse-dashboard --dev --appId yourAppId --masterKey yourMasterKey --serverURL "h You may set the host, port and mount path by supplying the `--host`, `--port` and `--mountPath` options to parse-dashboard. You can use anything you want as the app name, or leave it out in which case the app ID will be used. -NB: the `--dev` parameter is disabling production-ready security features, do not use this parameter when starting the dashboard in production. This parameter is useful if you are running on docker. +The `--dev` parameter disables production-ready security features. This parameter is useful when running Parse Dashboard on Docker. Using this parameter will: + +- allow insecure http connections from anywhere, bypassing the option `allowInsecureHTTP` +- allow the Parse Server `masterKey` to be transmitted in cleartext without encryption +- allow dashboard access without user authentication + +> ⚠️ Do not use this parameter when deploying Parse Dashboard in a production environment. After starting the dashboard, you can visit http://localhost:4040 in your browser: diff --git a/changelogs/CHANGELOG_alpha.md b/changelogs/CHANGELOG_alpha.md new file mode 100644 index 0000000000..ba770873c6 --- /dev/null +++ b/changelogs/CHANGELOG_alpha.md @@ -0,0 +1,6 @@ +## [3.2.1-alpha.1](https://github.com/ParsePlatform/parse-dashboard/compare/3.2.0...3.2.1-alpha.1) (2021-10-08) + + +### Bug Fixes + +* enabling context menu for read-only cells ([#1844](https://github.com/ParsePlatform/parse-dashboard/issues/1844)) ([a38a885](https://github.com/ParsePlatform/parse-dashboard/commit/a38a885db23e3a76c1e24f880e061dc882e1d37f)) diff --git a/package-lock.json b/package-lock.json index 363306904e..3fc5e71f62 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "parse-dashboard", - "version": "3.2.0", + "version": "3.2.1-alpha.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index ad4bbdd1c7..1ba026e5d4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parse-dashboard", - "version": "3.2.0", + "version": "3.2.1-alpha.1", "repository": { "type": "git", "url": "https://github.com/ParsePlatform/parse-dashboard" diff --git a/src/components/BrowserCell/BrowserCell.react.js b/src/components/BrowserCell/BrowserCell.react.js index ccf8da4f2f..a2106503dd 100644 --- a/src/components/BrowserCell/BrowserCell.react.js +++ b/src/components/BrowserCell/BrowserCell.react.js @@ -25,6 +25,7 @@ export default class BrowserCell extends Component { this.state = { showTooltip: false } + this.onContextMenu = this.onContextMenu.bind(this); } @@ -97,7 +98,7 @@ export default class BrowserCell extends Component { } getContextMenuOptions(constraints) { - let { onEditSelectedRow } = this.props; + let { onEditSelectedRow, readonly } = this.props; const contextMenuOptions = []; const setFilterContextMenuOption = this.getSetFilterContextMenuOption(constraints); @@ -109,7 +110,7 @@ export default class BrowserCell extends Component { const relatedObjectsContextMenuOption = this.getRelatedObjectsContextMenuOption(); relatedObjectsContextMenuOption && contextMenuOptions.push(relatedObjectsContextMenuOption); - onEditSelectedRow && contextMenuOptions.push({ + !readonly && onEditSelectedRow && contextMenuOptions.push({ text: 'Edit row', callback: () => { let { objectId, onEditSelectedRow } = this.props; @@ -117,7 +118,7 @@ export default class BrowserCell extends Component { } }); - if ( this.props.type === 'Pointer' ) { + if (this.props.type === 'Pointer') { onEditSelectedRow && contextMenuOptions.push({ text: 'Open pointer in new tab', callback: () => { @@ -135,7 +136,10 @@ export default class BrowserCell extends Component { return { text: 'Set filter...', items: constraints.map(constraint => { const definition = Filters.Constraints[constraint]; - const text = `${this.props.field} ${definition.name}${definition.comparable ? (' ' + this.copyableValue) : ''}`; + // Smart ellipsis for value - if it's long trim it in the middle: Lorem ipsum dolor si... aliqua + const value = this.copyableValue.length < 30 ? this.copyableValue : + `${this.copyableValue.substr(0, 20)}...${this.copyableValue.substr(this.copyableValue.length - 7)}`; + const text = `${this.props.field} ${definition.name}${definition.comparable ? (' ' + value) : ''}`; return { text, callback: this.pickFilter.bind(this, constraint) @@ -264,10 +268,10 @@ export default class BrowserCell extends Component { this.copyableValue = value.id; } else if (type === 'Array') { - if ( value[0] && typeof value[0] === 'object' && value[0].__type === 'Pointer' ) { + if (value[0] && typeof value[0] === 'object' && value[0].__type === 'Pointer') { const array = []; - value.map( (v, i) => { - if ( typeof v !== 'object' || v.__type !== 'Pointer' ) { + value.map((v, i) => { + if (typeof v !== 'object' || v.__type !== 'Pointer') { throw new Error('Invalid type found in pointer array'); } const object = new Parse.Object(v.className); @@ -282,10 +286,10 @@ export default class BrowserCell extends Component { ); }); content =