From aa5c68dbca458069d93351edc0bc0287fe63b7e1 Mon Sep 17 00:00:00 2001 From: Harshvardhan Sharma <91624754+vardhan0604@users.noreply.github.com> Date: Sat, 6 Jul 2024 19:32:45 +0530 Subject: [PATCH] feat: Add relational filter conditions in data browser (#2576) --- README.md | 22 ++++ .../BrowserFilter/BrowserFilter.react.js | 100 +++++++++------- .../BrowserFilter/BrowserFilter.scss | 21 +++- .../BrowserFilter/FilterRow.react.js | 48 +++++++- src/components/Filter/Filter.react.js | 110 ++++++++++++++---- .../PushAudienceDialog.react.js | 4 +- src/dashboard/Data/Browser/Browser.react.js | 34 +++++- .../Data/Browser/BrowserToolbar.react.js | 43 +++++-- .../Data/Browser/DataBrowser.react.js | 23 ++++ .../Data/Browser/ObjectPickerDialog.react.js | 10 +- src/dashboard/Push/PushAudiencesData.react.js | 4 +- .../Push/PushAudiencesIndex.react.js | 4 +- src/dashboard/Push/PushNew.react.js | 9 +- src/lib/Filters.js | 44 +++++++ src/lib/queryFromFilters.js | 94 +++++++++++++-- 15 files changed, 468 insertions(+), 102 deletions(-) diff --git a/README.md b/README.md index 8d89b3190..329fdabca 100644 --- a/README.md +++ b/README.md @@ -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) @@ -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* diff --git a/src/components/BrowserFilter/BrowserFilter.react.js b/src/components/BrowserFilter/BrowserFilter.react.js index 4f04d2561..38aeba282 100644 --- a/src/components/BrowserFilter/BrowserFilter.react.js +++ b/src/components/BrowserFilter/BrowserFilter.react.js @@ -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, @@ -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, })); } @@ -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 = ( this.setState({ filters: filters })} onSearch={this.apply.bind(this)} + allClasses={this.props.allClassesSchema} + allClassesSchema={Filters.findRelatedClasses( + this.props.className, + this.props.allClassesSchema + )} renderRow={props => ( -