adminjs icon indicating copy to clipboard operation
adminjs copied to clipboard

Enhancement: Improve filters programming interface

Open wojtek-krysiak opened this issue 5 years ago • 12 comments

Problem

Right now filters are passed to BaseResource.find as an object and are parsed inside every adapter separately.

  • Passing object is ugly because we have to create it on AdminBro core and pass to the adapter
  • Current filter structure doesn't allow to filter by let say greater than in integers, or by relation.

We have to change Filter instance to a simple filter object with the strict interface.

Interface proposal (example)

type FilterQuery = {
    eq?: string,
    gt?: string,
    lt?: string,
    contain?: string, // for like
    in?: Array<string>
  }

type Filter = {
  [path: string]: FilterQuery | Array<FilterQuery> | {and: Array<FilterQuery>}
}

Array<FilterQuery> would be for "or"

Acceptance criteria

In this task:

  • unify the filters programming interface
  • the best would be if it will be backwards compatible
  • allow adapters to define which operations they support. Mybe some new adapter couldn't support in?
  • it should be possible to filter by nested properties

Possibilities after this change

  • we will be able to add filter to ResourceOptions which will restrict the list/search actions - or to list Action interface.
  • we could pass filter in useRecords hook
  • we could pass filter in PropertyOptions of the property responsible for handing one to many relationshipp

wojtek-krysiak avatar Dec 30 '19 16:12 wojtek-krysiak

It is not possible to change the filter label.

module.exports.actionLabels = {
  list: { label: 'Todos' },
  edit: { label: 'Editar' },
  show: { label: 'Detalle' },
  new: { label: 'Añadir Nuevo' },
  filter: { label: 'Search' },
  delete: { 
    label: 'Borrar',
    guard: '¿Seguro que quieres borrar este elemento?'  
  },
}

without filter everything works fine. with filter I see these errors into the browser console:

backend.js:6 The above error occurred in the <ActionButton> component:
    in ActionButton (created by Context.Consumer)
    in Connect(ActionButton) (created by Context.Consumer)
    in withRouter(Connect(ActionButton)) (created by ActionHeader)
    in div (created by Context.Consumer)
    in StyledComponent (created by action-header__HeaderButtons)
    in action-header__HeaderButtons (created by ActionHeader)
    in section (created by Context.Consumer)
    in StyledComponent (created by action-header__HeaderWrapper)
    in action-header__HeaderWrapper (created by ActionHeader)
    in ActionHeader (created by ResourceAction)
    in section (created by Context.Consumer)
    in StyledComponent (created by wrapper-box__StyledWrapperBox)
    in wrapper-box__StyledWrapperBox (created by WrapperBox)
    in WrapperBox (created by ResourceAction)
    in div (created by ResourceAction)
    in ResourceAction (created by Context.Consumer)
    in Connect(ResourceAction) (created by Context.Consumer)
    in Route (created by App)
    in Switch (created by App)
    in section (created by Context.Consumer)
    in StyledComponent (created by application__Core)
    in application__Core (created by App)
    in section (created by Context.Consumer)
    in StyledComponent (created by application__ApplicationWrapper)
    in application__ApplicationWrapper (created by App)
    in App
    in Router (created by BrowserRouter)
    in BrowserRouter
    in ThemeProvider
    in Provider

Consider adding an error boundary to your tree to customize error handling behavior.
Visit https://fb.me/react-error-boundaries to learn more about error boundaries.
r @ backend.js:6
logCapturedError @ global.bundle.js:40180
logError @ global.bundle.js:40217
update.callback @ global.bundle.js:41305
callCallback @ global.bundle.js:33418
commitUpdateEffects @ global.bundle.js:33456
commitUpdateQueue @ global.bundle.js:33446
commitLifeCycles @ global.bundle.js:40494
commitLayoutEffects @ global.bundle.js:43386
callCallback @ global.bundle.js:21148
invokeGuardedCallbackDev @ global.bundle.js:21197
invokeGuardedCallback @ global.bundle.js:21252
commitRootImpl @ global.bundle.js:43124
unstable_runWithPriority @ global.bundle.js:20181
runWithPriority$2 @ global.bundle.js:31785
commitRoot @ global.bundle.js:42964
finishSyncRender @ global.bundle.js:42397
performSyncWorkOnRoot @ global.bundle.js:42375
(anonymous) @ global.bundle.js:31835
unstable_runWithPriority @ global.bundle.js:20181
runWithPriority$2 @ global.bundle.js:31785
flushSyncCallbackQueueImpl @ global.bundle.js:31830
flushSyncCallbackQueue @ global.bundle.js:31818
discreteUpdates$1 @ global.bundle.js:42482
discreteUpdates @ global.bundle.js:22173
dispatchDiscreteEvent @ global.bundle.js:25932
backend.js:6 Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.
    in List$7 (created by Context.Consumer)
    in withRouter(List$7) (created by Context.Consumer)
    in Connect(withRouter(List$7)) (created by BaseActionComponent)
    in ErrorBoundary (created by BaseActionComponent)
    in BaseActionComponent (created by ResourceAction)
    in section (created by Context.Consumer)
    in StyledComponent (created by wrapper-box__StyledWrapperBox)
    in wrapper-box__StyledWrapperBox (created by WrapperBox)
    in WrapperBox (created by ResourceAction)
    in div (created by ResourceAction)
    in ResourceAction (created by Context.Consumer)
    in Connect(ResourceAction) (created by Context.Consumer)
    in Route (created by App)
    in Switch (created by App)
    in section (created by Context.Consumer)
    in StyledComponent (created by application__Core)
    in application__Core (created by App)
    in section (created by Context.Consumer)
    in StyledComponent (created by application__ApplicationWrapper)
    in application__ApplicationWrapper (created by App)
    in App
    in Router (created by BrowserRouter)
    in BrowserRouter
    in ThemeProvider
    in Provider
r @ backend.js:6
warningWithoutStack @ global.bundle.js:21342
warnAboutUpdateOnUnmountedFiberInDEV @ global.bundle.js:43745
scheduleUpdateOnFiber @ global.bundle.js:41749
enqueueSetState @ global.bundle.js:33583
Component.setState @ global.bundle.js:524
(anonymous) @ list.tsx:90
Promise.then (async)
_fetchData @ list.tsx:88
shouldComponentUpdate @ list.tsx:63
checkShouldComponentUpdate @ global.bundle.js:33631
updateClassInstance @ global.bundle.js:34127
updateClassComponent @ global.bundle.js:37755
beginWork$1 @ global.bundle.js:39250
beginWork$$1 @ global.bundle.js:43763
performUnitOfWork @ global.bundle.js:42737
workLoopSync @ global.bundle.js:42713
performSyncWorkOnRoot @ global.bundle.js:42338
(anonymous) @ global.bundle.js:31835
unstable_runWithPriority @ global.bundle.js:20181
runWithPriority$2 @ global.bundle.js:31785
flushSyncCallbackQueueImpl @ global.bundle.js:31830
flushSyncCallbackQueue @ global.bundle.js:31818
discreteUpdates$1 @ global.bundle.js:42482
discreteUpdates @ global.bundle.js:22173
dispatchDiscreteEvent @ global.bundle.js:25932
backend.js:6 Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
    in ResourceAction (created by Context.Consumer)
    in Connect(ResourceAction) (created by Context.Consumer)
    in Route (created by App)
    in Switch (created by App)
    in section (created by Context.Consumer)
    in StyledComponent (created by application__Core)
    in application__Core (created by App)
    in section (created by Context.Consumer)
    in StyledComponent (created by application__ApplicationWrapper)
    in application__ApplicationWrapper (created by App)
    in App
    in Router (created by BrowserRouter)
    in BrowserRouter
    in ThemeProvider
    in Provider

MariaRoblesSpin avatar Feb 14 '20 11:02 MariaRoblesSpin

@MariaRoblesSpin in v2.0 we added i18n support. Check out the docs here: https://softwarebrothers.github.io/admin-bro-dev/v2/tutorial-09-i18n.html (v2 is in beta right now)

wojtek-krysiak avatar Feb 27 '20 07:02 wojtek-krysiak

Regarding the feature of filtering a numeric attribute by a range of values, is it available now at v3.1?

mohamed-nazmi avatar Sep 02 '20 20:09 mohamed-nazmi

nope - I will reopen this task. This is very high priority. This month it should be fixed

wojtek-krysiak avatar Sep 02 '20 21:09 wojtek-krysiak

Any news on this?

danchello avatar Aug 30 '21 07:08 danchello

Any news on this?

rafa-js avatar Feb 18 '22 10:02 rafa-js

Will this be implemented soon? Or can you share an example of writing our own list handler(including pagination?)

Asher-JH avatar Apr 07 '22 03:04 Asher-JH

Any update on this?

Damilare-alesh99 avatar Nov 29 '22 21:11 Damilare-alesh99

We don't have an ETA yet, but we want to include this as a part of v7

dziraf avatar Nov 30 '22 08:11 dziraf

I think this didn't make it to v7 after all?

tomups avatar Jun 06 '23 18:06 tomups

Any news on that?

C0RE1312 avatar Mar 25 '24 14:03 C0RE1312

I am using adminJS v7.4.1 and the nested filters don't seem to work so I suppose it was not included in V7. The QueryFilter interface is also not exposed.

Non working example with nested fields:

      const createdAt = {
        $gte: new Date(`${previousYear}-01-01`),
        $lt: new Date(`${year}-01-01`)
      }
      const filter = new Filter({ createdAt }, resource)

Working example with non nested fields:

      const schemaVersion = 2
      const filter = new Filter({ schemaVersion }, resource)

rgcunha avatar Apr 05 '24 00:04 rgcunha