Skip to content

Commit

Permalink
feat: Add relational filter conditions in data browser (#2576)
Browse files Browse the repository at this point in the history
  • Loading branch information
vardhan0604 committed Jul 6, 2024
1 parent 35eeb48 commit aa5c68d
Show file tree
Hide file tree
Showing 15 changed files with 468 additions and 102 deletions.
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ Parse Dashboard is a standalone dashboard for managing your [Parse Server](https
- [Configuring Localized Push Notifications](#configuring-localized-push-notifications)
- [Run with Docker](#run-with-docker)
- [Features](#features)
- [Data Browser](#data-browser)
- [Filters](#filters)
- [Browse as User](#browse-as-user)
- [Change Pointer Key](#change-pointer-key)
- [Limitations](#limitations)
Expand Down Expand Up @@ -815,6 +817,26 @@ If you are not familiar with Docker, ``--port 8080`` will be passed in as argume
# Features
*(The following is not a complete list of features but a work in progress to build a comprehensive feature list.)*

## Data Browser

### Filters

▶️ *Core > Browser > Filter*

The filter dialog allows to add relational filter conditions based on other classes that have a pointer to the current class.

For example, users in the `_User` class may have:

- purchases in a `Purchase` class with a `_User` pointer field
- transactions in a `Payment` class with a `_User` pointer field

A relational filter allows you filter all users who:

- purchased a specific item (in `Purchase` class)
- payed with a specific payment method (in `Payment` class)

To apply such a filter, simply go to the `_User` class and add the two required filter conditions with the `Purchase` and `Payment` classes.

## Browse as User

▶️ *Core > Browser > Browse*
Expand Down
100 changes: 60 additions & 40 deletions src/components/BrowserFilter/BrowserFilter.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,16 @@ export default class BrowserFilter extends React.Component {
toggle() {
let filters = this.props.filters;
if (this.props.filters.size === 0) {
const available = Filters.availableFilters(
this.props.schema,
null,
this.state.blacklistedFilters
const available = Filters.findRelatedClasses(
this.props.className,
this.props.allClassesSchema,
this.state.blacklistedFilters,
this.state.filters
);
const field = Object.keys(available)[0];
filters = new List([new Map({ field: field, constraint: available[field][0] })]);
const { filterClass, filterField, filterConstraint } = Filters.getFilterDetails(available);
filters = new List([
new Map({ class: filterClass, field: filterField, constraint: filterConstraint }),
]);
}
this.setState(prevState => ({
open: !prevState.open,
Expand All @@ -65,14 +68,17 @@ export default class BrowserFilter extends React.Component {
}

addRow() {
const available = Filters.availableFilters(
this.props.schema,
this.state.filters,
this.state.blacklistedFilters
const available = Filters.findRelatedClasses(
this.props.className,
this.props.allClassesSchema,
this.state.blacklistedFilters,
this.state.filters
);
const field = Object.keys(available)[0];
const { filterClass, filterField, filterConstraint } = Filters.getFilterDetails(available);
this.setState(({ filters }) => ({
filters: filters.push(new Map({ field: field, constraint: available[field][0] })),
filters: filters.push(
new Map({ class: filterClass, field: filterField, constraint: filterConstraint })
),
editMode: true,
}));
}
Expand Down Expand Up @@ -125,7 +131,12 @@ export default class BrowserFilter extends React.Component {
if (this.props.filters.size) {
popoverStyle.push(styles.active);
}
const available = Filters.availableFilters(this.props.schema, this.state.filters);
const available = Filters.findRelatedClasses(
this.props.className,
this.props.allClassesSchema,
this.state.blacklistedFilters,
this.state.filters
);
popover = (
<Popover
fixed={true}
Expand Down Expand Up @@ -154,6 +165,11 @@ export default class BrowserFilter extends React.Component {
filters={this.state.filters}
onChange={filters => this.setState({ filters: filters })}
onSearch={this.apply.bind(this)}
allClasses={this.props.allClassesSchema}
allClassesSchema={Filters.findRelatedClasses(
this.props.className,
this.props.allClassesSchema
)}
renderRow={props => (
<FilterRow
{...props}
Expand Down Expand Up @@ -194,33 +210,37 @@ export default class BrowserFilter extends React.Component {
)}
{!this.state.confirmName && (
<div className={styles.footer}>
<Button
color="white"
value="Save"
width="120px"
onClick={() => this.setState({ confirmName: true })}
/>
<Button
color="white"
value="Clear"
disabled={this.state.filters.size === 0}
width="120px"
onClick={() => this.clear()}
/>
<Button
color="white"
value="Add"
disabled={Object.keys(available).length === 0}
width="120px"
onClick={() => this.addRow()}
/>
<Button
color="white"
primary={true}
value="Apply"
width="120px"
onClick={() => this.apply()}
/>
<div className={styles.btnFlex}>
<Button
color="white"
value="Save"
width="120px"
onClick={() => this.setState({ confirmName: true })}
/>
<Button
color="white"
value="Clear"
disabled={this.state.filters.size === 0}
width="120px"
onClick={() => this.clear()}
/>
</div>
<div className={styles.btnFlex}>
<Button
color="white"
value="Add"
disabled={Object.keys(available).length === 0}
width="120px"
onClick={() => this.addRow()}
/>
<Button
color="white"
primary={true}
value="Apply"
width="120px"
onClick={() => this.apply()}
/>
</div>
</div>
)}
</div>
Expand Down
21 changes: 18 additions & 3 deletions src/components/BrowserFilter/BrowserFilter.scss
Original file line number Diff line number Diff line change
Expand Up @@ -85,19 +85,24 @@

.body {
position: absolute;
display: flex;
flex-direction: column;
max-height: 500px;
overflow: hidden;
top: 30px;
right: 0;
border-radius: 5px 0 5px 5px;
background: #797691;
width: 535px;
width: 685px;
font-size: 14px;
}

.footer {
background: rgba(0,0,0,0.2);
padding: 11px 0;
padding: 11px 16px;
text-align: center;

display: flex;
justify-content: space-between;
> button {
margin-right: 10px;

Expand Down Expand Up @@ -148,3 +153,13 @@
display: inline-block;
vertical-align: top;
}

.flex{
display: flex;
align-items: center;
}

.btnFlex{
display: flex;
gap: 12px;
}
48 changes: 45 additions & 3 deletions src/components/BrowserFilter/FilterRow.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,15 @@ function compareValue(
}

const FilterRow = ({
classes,
fields,
constraints,
compareInfo,
currentClass,
currentField,
currentConstraint,
compareTo,
onChangeClass,
onChangeField,
onChangeConstraint,
onChangeCompareTo,
Expand All @@ -119,13 +122,52 @@ const FilterRow = ({
}
}, []);

const buildSuggestions = input => {
const buildFieldSuggestions = input => {
const regex = new RegExp(input.split('').join('.*?'), 'i');
return fields.filter(f => regex.test(f));
};
const buildClassSuggestions = input => {
const regex = new RegExp(input.split('').join('.*?'), 'i');
return classes.filter(f => regex.test(f));
};

return (
<div className={styles.row}>
<div className={`${styles.row} ${styles.flex}`}>
<Autocomplete
inputStyle={{
transition: '0s background-color ease-in-out',
}}
suggestionsStyle={{
width: '140px',
maxHeight: '360px',
overflowY: 'auto',
fontSize: '14px',
background: '#343445',
borderBottomLeftRadius: '5px',
borderBottomRightRadius: '5px',
color: 'white',
cursor: 'pointer',
}}
suggestionsItemStyle={{
background: '#343445',
color: 'white',
height: '30px',
lineHeight: '30px',
borderBottom: '0px',
}}
containerStyle={{
display: 'inline-block',
width: '140px',
verticalAlign: 'top',
height: '30px',
}}
strict={true}
value={currentClass}
suggestions={classes}
onChange={onChangeClass}
buildSuggestions={buildClassSuggestions}
buildLabel={() => ''}
/>
<Autocomplete
inputStyle={{
transition: '0s background-color ease-in-out',
Expand Down Expand Up @@ -158,7 +200,7 @@ const FilterRow = ({
value={currentField}
suggestions={fields}
onChange={onChangeField}
buildSuggestions={buildSuggestions}
buildSuggestions={buildFieldSuggestions}
buildLabel={() => ''}
/>
<ChromeDropdown
Expand Down
Loading

0 comments on commit aa5c68d

Please sign in to comment.