Skip to content

Commit 5776e69

Browse files
committed
feat:Add relational filter conditions (parse-community#2496)
1 parent 8854aa8 commit 5776e69

16 files changed

+379
-82
lines changed

Parse-Dashboard/parse-dashboard-config.json

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,9 @@
22
"apps": [
33
{
44
"serverURL": "http://localhost:1337/parse",
5-
"appId": "hello",
6-
"masterKey": "world",
7-
"appName": "",
8-
"iconName": "",
9-
"primaryBackgroundColor": "",
10-
"secondaryBackgroundColor": ""
5+
"appId": "1234",
6+
"masterKey": "12345",
7+
"appName": "MyApp"
118
}
12-
],
13-
"iconsFolder": "icons"
9+
]
1410
}

parse-dashboard@6.0.0-alpha.7

Whitespace-only changes.

src/components/BrowserFilter/BrowserFilter.react.js

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,18 @@ export default class BrowserFilter extends React.Component {
4646
toggle() {
4747
let filters = this.props.filters;
4848
if (this.props.filters.size === 0) {
49-
const available = Filters.availableFilters(
50-
this.props.schema,
51-
null,
52-
this.state.blacklistedFilters
49+
const available = Filters.findRelatedClasses(
50+
this.props.className,
51+
this.props.AllclassesSchema,
52+
this.state.blacklistedFilters,
53+
this.state.filters
5354
);
54-
const field = Object.keys(available)[0];
55-
filters = new List([new Map({ field: field, constraint: available[field][0] })]);
55+
const filterClass = Object.keys(available)[0];
56+
const filterField = Object.keys(available[filterClass])[0];
57+
const filterConstraint = available[filterClass][filterField][0];
58+
filters = new List([
59+
new Map({ class: filterClass, field: filterField, constraint: filterConstraint }),
60+
]);
5661
}
5762
this.setState(prevState => ({
5863
open: !prevState.open,
@@ -65,14 +70,19 @@ export default class BrowserFilter extends React.Component {
6570
}
6671

6772
addRow() {
68-
const available = Filters.availableFilters(
69-
this.props.schema,
70-
this.state.filters,
71-
this.state.blacklistedFilters
73+
const available = Filters.findRelatedClasses(
74+
this.props.className,
75+
this.props.AllclassesSchema,
76+
this.state.blacklistedFilters,
77+
this.state.filters
7278
);
73-
const field = Object.keys(available)[0];
79+
const filterClass = Object.keys(available)[0];
80+
const filterField = Object.keys(available[filterClass])[0];
81+
const filterConstraint = available[filterClass][filterField][0];
7482
this.setState(({ filters }) => ({
75-
filters: filters.push(new Map({ field: field, constraint: available[field][0] })),
83+
filters: filters.push(
84+
new Map({ class: filterClass, field: filterField, constraint: filterConstraint })
85+
),
7686
editMode: true,
7787
}));
7888
}
@@ -125,7 +135,12 @@ export default class BrowserFilter extends React.Component {
125135
if (this.props.filters.size) {
126136
popoverStyle.push(styles.active);
127137
}
128-
const available = Filters.availableFilters(this.props.schema, this.state.filters);
138+
const available = Filters.findRelatedClasses(
139+
this.props.className,
140+
this.props.AllclassesSchema,
141+
this.state.blacklistedFilters,
142+
this.state.filters
143+
);
129144
popover = (
130145
<Popover
131146
fixed={true}
@@ -154,6 +169,11 @@ export default class BrowserFilter extends React.Component {
154169
filters={this.state.filters}
155170
onChange={filters => this.setState({ filters: filters })}
156171
onSearch={this.apply.bind(this)}
172+
Allclasses={this.props.AllclassesSchema}
173+
AllclassesSchema={Filters.findRelatedClasses(
174+
this.props.className,
175+
this.props.AllclassesSchema
176+
)}
157177
renderRow={props => (
158178
<FilterRow
159179
{...props}

src/components/BrowserFilter/BrowserFilter.scss

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,11 +85,15 @@
8585

8686
.body {
8787
position: absolute;
88+
display: flex;
89+
flex-direction: column;
90+
max-height: 500px;
91+
overflow: hidden;
8892
top: 30px;
8993
right: 0;
9094
border-radius: 5px 0 5px 5px;
9195
background: #797691;
92-
width: 535px;
96+
width: 685px;
9397
font-size: 14px;
9498
}
9599

@@ -148,3 +152,8 @@
148152
display: inline-block;
149153
vertical-align: top;
150154
}
155+
156+
.flex{
157+
display: flex;
158+
align-items: center;
159+
}

src/components/BrowserFilter/FilterRow.react.js

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,12 +98,15 @@ function compareValue(
9898
}
9999

100100
const FilterRow = ({
101+
classes,
101102
fields,
102103
constraints,
103104
compareInfo,
105+
currentClass,
104106
currentField,
105107
currentConstraint,
106108
compareTo,
109+
onChangeClass,
107110
onChangeField,
108111
onChangeConstraint,
109112
onChangeCompareTo,
@@ -119,13 +122,52 @@ const FilterRow = ({
119122
}
120123
}, []);
121124

122-
const buildSuggestions = input => {
125+
const buildFieldSuggestions = input => {
123126
const regex = new RegExp(input.split('').join('.*?'), 'i');
124127
return fields.filter(f => regex.test(f));
125128
};
129+
const buildClassSuggestions = input => {
130+
const regex = new RegExp(input.split('').join('.*?'), 'i');
131+
return classes.filter(f => regex.test(f));
132+
};
126133

127134
return (
128-
<div className={styles.row}>
135+
<div className={`${styles.row} ${styles.flex}`}>
136+
<Autocomplete
137+
inputStyle={{
138+
transition: '0s background-color ease-in-out',
139+
}}
140+
suggestionsStyle={{
141+
width: '140px',
142+
maxHeight: '360px',
143+
overflowY: 'auto',
144+
fontSize: '14px',
145+
background: '#343445',
146+
borderBottomLeftRadius: '5px',
147+
borderBottomRightRadius: '5px',
148+
color: 'white',
149+
cursor: 'pointer',
150+
}}
151+
suggestionsItemStyle={{
152+
background: '#343445',
153+
color: 'white',
154+
height: '30px',
155+
lineHeight: '30px',
156+
borderBottom: '0px',
157+
}}
158+
containerStyle={{
159+
display: 'inline-block',
160+
width: '140px',
161+
verticalAlign: 'top',
162+
height: '30px',
163+
}}
164+
strict={true}
165+
value={currentClass}
166+
suggestions={classes}
167+
onChange={onChangeClass}
168+
buildSuggestions={buildClassSuggestions}
169+
buildLabel={() => ''}
170+
/>
129171
<Autocomplete
130172
inputStyle={{
131173
transition: '0s background-color ease-in-out',
@@ -158,7 +200,7 @@ const FilterRow = ({
158200
value={currentField}
159201
suggestions={fields}
160202
onChange={onChangeField}
161-
buildSuggestions={buildSuggestions}
203+
buildSuggestions={buildFieldSuggestions}
162204
buildLabel={() => ''}
163205
/>
164206
<ChromeDropdown

src/components/Filter/Filter.react.js

Lines changed: 72 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,28 +12,58 @@ import React from 'react';
1212
import stringCompare from 'lib/stringCompare';
1313
import { CurrentApp } from 'context/currentApp';
1414

15-
function changeField(schema, filters, index, newField) {
16-
const allowedConstraints = Filters.FieldConstraints[schema[newField].type];
15+
function changeClass(schema, filters, index, newClassName) {
16+
const current = filters.get(index);
17+
const field = current.get('field');
18+
const constraint = current.get('constraint');
19+
20+
const newClassFields = Object.keys(schema[newClassName]);
21+
const isFieldValid = newClassFields.includes(field);
22+
23+
const newField = isFieldValid ? field : newClassFields[0];
24+
const allowedConstraints = Filters.FieldConstraints[schema[newClassName][newField].type];
25+
const isConstraintValid = allowedConstraints.includes(constraint);
26+
27+
const newConstraint = isConstraintValid ? constraint : allowedConstraints[0];
28+
29+
const defaultCompare = Filters.DefaultComparisons[schema[newClassName][newField].type];
30+
31+
const newFilter = new Map({
32+
class: newClassName,
33+
field: newField,
34+
constraint: newConstraint,
35+
compareTo: defaultCompare,
36+
});
37+
38+
return filters.set(index, newFilter);
39+
}
40+
41+
function changeField(schema, currentClassName, filters, index, newField) {
42+
const allowedConstraints = Filters.FieldConstraints[schema[currentClassName][newField].type];
1743
const current = filters.get(index);
1844
const constraint = current.get('constraint');
1945
const compare = current.get('compareTo');
20-
const defaultCompare = Filters.DefaultComparisons[schema[newField].type];
46+
const defaultCompare = Filters.DefaultComparisons[schema[currentClassName][newField].type];
2147
const useExisting = allowedConstraints.includes(constraint);
2248
const newFilter = new Map({
49+
class: currentClassName,
2350
field: newField,
24-
constraint: useExisting ? constraint : Filters.FieldConstraints[schema[newField].type][0],
51+
constraint: useExisting
52+
? constraint
53+
: Filters.FieldConstraints[schema[currentClassName][newField].type][0],
2554
compareTo: useExisting && typeof defaultCompare === typeof compare ? compare : defaultCompare,
2655
});
2756
return filters.set(index, newFilter);
2857
}
2958

30-
function changeConstraint(schema, filters, index, newConstraint, prevCompareTo) {
59+
function changeConstraint(schema, currentClassName, filters, index, newConstraint, prevCompareTo) {
3160
const field = filters.get(index).get('field');
32-
let compareType = schema[field].type;
61+
let compareType = schema[currentClassName][field].type;
3362
if (Object.prototype.hasOwnProperty.call(Filters.Constraints[newConstraint], 'field')) {
3463
compareType = Filters.Constraints[newConstraint].field;
3564
}
3665
const newFilter = new Map({
66+
class: currentClassName,
3767
field: field,
3868
constraint: newConstraint,
3969
compareTo: prevCompareTo ?? Filters.DefaultComparisons[compareType],
@@ -50,18 +80,37 @@ function deleteRow(filters, index) {
5080
return filters.delete(index);
5181
}
5282

53-
const Filter = ({ schema, filters, renderRow, onChange, onSearch, blacklist, className }) => {
83+
const Filter = ({
84+
schema,
85+
filters,
86+
Allclasses,
87+
AllclassesSchema,
88+
renderRow,
89+
onChange,
90+
onSearch,
91+
blacklist,
92+
className,
93+
}) => {
5494
const currentApp = React.useContext(CurrentApp);
5595
blacklist = blacklist || [];
56-
const available = Filters.availableFilters(schema, filters);
96+
const available = Filters.findRelatedClasses(className, Allclasses, blacklist, filters);
97+
const classes = Object.keys(available).concat([]);
5798
return (
58-
<div>
99+
<div
100+
style={{
101+
flex: 1,
102+
overflowY: 'auto',
103+
}}
104+
>
59105
{filters.toArray().map((filter, i) => {
106+
const currentClassName = filter.get('class');
60107
const field = filter.get('field');
61108
const constraint = filter.get('constraint');
62109
const compareTo = filter.get('compareTo');
63-
64-
const fields = Object.keys(available).concat([]);
110+
let fields = [];
111+
if (available[currentClassName]) {
112+
fields = Object.keys(available[currentClassName]).concat([]);
113+
}
65114
if (fields.indexOf(field) < 0) {
66115
fields.push(field);
67116
}
@@ -97,31 +146,36 @@ const Filter = ({ schema, filters, renderRow, onChange, onSearch, blacklist, cla
97146
else {
98147
fields.sort();
99148
}
100-
101-
const constraints = Filters.FieldConstraints[schema[field].type].filter(
149+
const constraints = Filters.FieldConstraints[schema[currentClassName][field].type].filter(
102150
c => blacklist.indexOf(c) < 0
103151
);
104-
let compareType = schema[field].type;
152+
let compareType = schema[currentClassName][field].type;
105153
if (Object.prototype.hasOwnProperty.call(Filters.Constraints[constraint], 'field')) {
106154
compareType = Filters.Constraints[constraint].field;
107155
}
108156
return renderRow({
157+
classes,
109158
fields,
110159
constraints,
111160
compareInfo: {
112161
type: compareType,
113-
targetClass: schema[field].targetClass,
162+
targetClass: schema[currentClassName][field].targetClass,
114163
},
164+
currentClass: currentClassName,
115165
currentField: field,
116166
currentConstraint: constraint,
117167
compareTo,
118168
key: field + '-' + constraint + '-' + i,
119-
169+
onChangeClass: newClassName => {
170+
onChange(changeClass(schema, filters, i, newClassName));
171+
},
120172
onChangeField: newField => {
121-
onChange(changeField(schema, filters, i, newField));
173+
onChange(changeField(schema, currentClassName, filters, i, newField));
122174
},
123175
onChangeConstraint: (newConstraint, prevCompareTo) => {
124-
onChange(changeConstraint(schema, filters, i, newConstraint, prevCompareTo));
176+
onChange(
177+
changeConstraint(schema, currentClassName, filters, i, newConstraint, prevCompareTo)
178+
);
125179
},
126180
onChangeCompareTo: newCompare => {
127181
onChange(changeCompareTo(schema, filters, i, compareType, newCompare));

src/components/PushAudienceDialog/PushAudienceDialog.react.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,14 +118,14 @@ export default class PushAudienceDialog extends React.Component {
118118
this.setState({ saveForFuture: value });
119119
}
120120

121-
fetchAudienceSize() {
121+
async fetchAudienceSize() {
122122
if (!this.context) {
123123
//so we don't break the PIG demo
124124
return;
125125
}
126126

127127
let query = {};
128-
const parseQuery = queryFromFilters('_Installation', this.state.filters);
128+
const parseQuery = await queryFromFilters('_Installation', this.state.filters);
129129

130130
if (parseQuery && parseQuery.toJSON()) {
131131
query = parseQuery.toJSON().where || {};

0 commit comments

Comments
 (0)