From 4df7e3a7ce72e348dae2d93784ad2d06ca8ebe22 Mon Sep 17 00:00:00 2001 From: Diamond Lewis Date: Fri, 26 Oct 2018 14:19:54 -0500 Subject: [PATCH 1/6] Add Distinct / Unique Filter --- .../BrowserCell/BrowserCell.react.js | 8 +++++ src/dashboard/Data/Browser/Browser.react.js | 36 ++++++++++++++++--- .../Data/Browser/BrowserTable.react.js | 32 ++++++++++------- .../Data/Browser/BrowserToolbar.react.js | 14 +++++--- src/lib/Filters.js | 17 +++++---- 5 files changed, 81 insertions(+), 26 deletions(-) diff --git a/src/components/BrowserCell/BrowserCell.react.js b/src/components/BrowserCell/BrowserCell.react.js index fe6b81eb8c..5d73a615bf 100644 --- a/src/components/BrowserCell/BrowserCell.react.js +++ b/src/components/BrowserCell/BrowserCell.react.js @@ -33,12 +33,20 @@ let BrowserCell = ({ type, value, hidden, width, current, onSelect, onEditChange content =  ; classes.push(styles.empty); } else if (type === 'Pointer') { + if (value && value.__type) { + const object = new Parse.Object(value.className); + object.id = value.objectId; + value = object; + } content = ( ); } else if (type === 'Date') { + if (typeof value === 'object' && value.__type) { + value = new Date(value.iso); + } content = dateStringUTC(value); } else if (type === 'Boolean') { content = value ? 'True' : 'False'; diff --git a/src/dashboard/Data/Browser/Browser.react.js b/src/dashboard/Data/Browser/Browser.react.js index f308a6d72a..1867f753f1 100644 --- a/src/dashboard/Data/Browser/Browser.react.js +++ b/src/dashboard/Data/Browser/Browser.react.js @@ -68,6 +68,9 @@ class Browser extends DashboardView { lastNote: null, relationCount: 0, + + isUnique: false, + uniqueField: null, }; this.prefetchData = this.prefetchData.bind(this); @@ -322,7 +325,17 @@ class Browser extends DashboardView { } query.limit(200); - const data = await query.find({ useMasterKey: true }); + + let promise = query.find({ useMasterKey: true }); + await this.setState({ isUnique: false }); + filters.forEach(async (filter) => { + if (filter.get('constraint') == 'unique') { + const field = filter.get('field'); + promise = query.distinct(field); + await this.setState({ isUnique: true, uniqueField: field }); + } + }); + const data = await promise; return data; } @@ -336,7 +349,11 @@ class Browser extends DashboardView { const data = await this.fetchParseData(source, filters); var filteredCounts = { ...this.state.filteredCounts }; if (filters.size > 0) { - filteredCounts[source] = await this.fetchParseDataCount(source,filters); + if (this.state.isUnique) { + filteredCounts[source] = data.length; + } else { + filteredCounts[source] = await this.fetchParseDataCount(source, filters); + } } else { delete filteredCounts[source]; } @@ -396,8 +413,11 @@ class Browser extends DashboardView { } query.addDescending('createdAt'); query.limit(200); - - query.find({ useMasterKey: true }).then((nextPage) => { + let promise = query.find({ useMasterKey: true }); + if (this.state.isUnique) { + promise = query.distinct(this.state.uniqueField); + } + promise.then((nextPage) => { if (className === this.props.params.className) { this.setState((state) => ({ data: state.data.concat(nextPage)})); } @@ -842,11 +862,17 @@ class Browser extends DashboardView { let columns = { objectId: { type: 'String' } }; + if (this.state.isUnique) { + columns = {}; + } let userPointers = []; classes.get(className).forEach((field, name) => { if (name === 'objectId') { return; } + if (this.state.isUnique && name !== this.state.uniqueField) { + return; + } let info = { type: field.type }; if (field.targetClass) { info.targetClass = field.targetClass; @@ -869,6 +895,8 @@ class Browser extends DashboardView { } browser = ( {this.props.order.map(({ name, width }, j) => { let type = this.props.columns[name].type; - let attr = attributes[name]; - if (name === 'objectId') { - attr = obj.id; - } else if (name === 'ACL' && this.props.className === '_User' && !attr) { - attr = new Parse.ACL({ '*': { read: true }, [obj.id]: { read: true, write: true }}); - } else if (type === 'Relation' && !attr && obj.id) { - attr = new Parse.Relation(obj, name); - attr.targetClassName = this.props.columns[name].targetClass; + let attr = obj; + if (!this.props.isUnique) { + attr = attributes[name]; + if (name === 'objectId') { + attr = obj.id; + } else if (name === 'ACL' && this.props.className === '_User' && !attr) { + attr = new Parse.ACL({ '*': { read: true }, [obj.id]: { read: true, write: true }}); + } else if (type === 'Relation' && !attr && obj.id) { + attr = new Parse.Relation(obj, name); + attr.targetClassName = this.props.columns[name].targetClass; + } } let current = this.props.current && this.props.current.row === row && this.props.current.col === j; let hidden = false; @@ -116,7 +119,7 @@ export default class BrowserTable extends React.Component { -1} + readonly={this.props.isUnique || READ_ONLY.indexOf(name) > -1} width={width} current={current} onSelect={() => this.props.setCurrent({ row: row, col: j })} @@ -185,16 +188,21 @@ export default class BrowserTable extends React.Component { if (visible) { let { name, width } = this.props.order[this.props.current.col]; let { type, targetClass } = this.props.columns[name]; - let readonly = READ_ONLY.indexOf(name) > -1; + let readonly = this.props.isUnique || READ_ONLY.indexOf(name) > -1; if (name === 'sessionToken') { if (this.props.className === '_User' || this.props.className === '_Session') { readonly = true; } } let obj = this.props.current.row < 0 ? this.props.newObject : this.props.data[this.props.current.row]; - let value = obj.get(name); + let value = obj; + if (!this.props.isUnique) { + value = obj.get(name); + } if (name === 'objectId') { - value = obj.id; + if (!this.props.isUnique) { + value = obj.id; + } } else if (name === 'ACL' && this.props.className === '_User' && !value) { value = new Parse.ACL({ '*': { read: true }, [obj.id]: { read: true, write: true }}); } else if (name === 'password' && this.props.className === '_User') { diff --git a/src/dashboard/Data/Browser/BrowserToolbar.react.js b/src/dashboard/Data/Browser/BrowserToolbar.react.js index d67ef9d419..2a25270f80 100644 --- a/src/dashboard/Data/Browser/BrowserToolbar.react.js +++ b/src/dashboard/Data/Browser/BrowserToolbar.react.js @@ -44,6 +44,8 @@ let BrowserToolbar = ({ enableDeleteAllRows, enableExportClass, enableSecurityDialog, + + isUnique, }) => { let selectionLength = Object.keys(selection).length; let details = []; @@ -91,7 +93,7 @@ let BrowserToolbar = ({ } else { menu = ( - + @@ -102,11 +104,11 @@ let BrowserToolbar = ({ /> onDeleteRows(selection)} /> - {enableDeleteAllRows ? onDeleteRows({ '*': true })} /> :