this.setState({ open: true })}>
+
{this.props.title}
diff --git a/src/components/BrowserMenu/BrowserMenu.scss b/src/components/BrowserMenu/BrowserMenu.scss
index 7e9030a11e..189d8f1efa 100644
--- a/src/components/BrowserMenu/BrowserMenu.scss
+++ b/src/components/BrowserMenu/BrowserMenu.scss
@@ -24,6 +24,15 @@
fill: white;
}
}
+
+ &.disabled {
+ cursor: not-allowed;
+ color: #66637A;
+
+ &:hover svg {
+ fill: #66637A;
+ }
+ }
}
.title {
diff --git a/src/dashboard/Data/Browser/Browser.react.js b/src/dashboard/Data/Browser/Browser.react.js
index ecea5cbcff..fbab9aa92d 100644
--- a/src/dashboard/Data/Browser/Browser.react.js
+++ b/src/dashboard/Data/Browser/Browser.react.js
@@ -71,6 +71,9 @@ class Browser extends DashboardView {
lastNote: null,
relationCount: 0,
+
+ isUnique: false,
+ uniqueField: null,
};
this.prefetchData = this.prefetchData.bind(this);
@@ -333,7 +336,21 @@ class Browser extends DashboardView {
}
query.limit(200);
- const data = await query.find({ useMasterKey: true });
+
+ let promise = query.find({ useMasterKey: true });
+ let isUnique = false;
+ let uniqueField = null;
+ filters.forEach(async (filter) => {
+ if (filter.get('constraint') == 'unique') {
+ const field = filter.get('field');
+ promise = query.distinct(field);
+ isUnique = true;
+ uniqueField = field;
+ }
+ });
+ await this.setState({ isUnique, uniqueField });
+
+ const data = await promise;
return data;
}
@@ -347,7 +364,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];
}
@@ -372,7 +393,7 @@ class Browser extends DashboardView {
}
fetchNextPage() {
- if (!this.state.data) {
+ if (!this.state.data || this.state.isUnique) {
return null;
}
let className = this.props.params.className;
@@ -889,11 +910,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;
@@ -916,6 +943,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;
@@ -118,7 +121,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 })}
@@ -187,16 +190,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') {
@@ -222,27 +230,28 @@ export default class BrowserTable extends React.Component {
for (let i = 0; i < this.props.current.col; i++) {
wrapLeft += this.props.order[i].width;
}
-
- editor = (
- {
- if (newValue !== value) {
- this.props.updateRow(
- this.props.current.row,
- name,
- newValue
- );
- }
- this.props.setEditing(false);
- }} />
- );
+ if (!this.props.isUnique) {
+ editor = (
+ {
+ if (newValue !== value) {
+ this.props.updateRow(
+ this.props.current.row,
+ name,
+ newValue
+ );
+ }
+ this.props.setEditing(false);
+ }} />
+ );
+ }
}
}
@@ -264,7 +273,7 @@ export default class BrowserTable extends React.Component {
/>
);
- } else {
+ } else if (!this.props.isUnique) {
addRow = (