Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(autgrid): Add custom filtering option to columns #1911

Merged
merged 9 commits into from
Dec 28, 2023

Conversation

krissvaa
Copy link
Contributor

Fixes #1608, #1501

  • Provide headerFilterRender for users as a new property in columnOptions
  • Split headerRenderer and headerFilterRenderer to solve consistency issue with headerRenderer being responsible for two places.
  • Provide setPropertyFilter function to headerFilterRenderer as a property in columnOptions
  • Add identifier to andFilter and orFilter (key) for controlling (delete/replace/add) filter list
  • Change setPropertyFilter to accept any Filter, not only StringPropertyFilter
  • Enable adding headerFilterRenderer to custom columns
  • Enable setting headerRenderer from columnOptions as the primary source (overwriting default)
  • Provide types to users: ColumnOptions, HeaderFilterRendererProps

Copy link

codecov bot commented Dec 20, 2023

Codecov Report

Attention: 4 lines in your changes are missing coverage. Please review.

Comparison is base (bb4aced) 95.27% compared to head (7be51df) 95.24%.

Files Patch % Lines
packages/ts/react-crud/src/autogrid.tsx 92.85% 0 Missing and 2 partials ⚠️
packages/ts/react-crud/src/autogrid-columns.tsx 66.66% 0 Missing and 1 partial ⚠️
packages/ts/react-crud/src/util.tsx 85.71% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1911      +/-   ##
==========================================
- Coverage   95.27%   95.24%   -0.04%     
==========================================
  Files          52       52              
  Lines        3449     3469      +20     
  Branches      503      514      +11     
==========================================
+ Hits         3286     3304      +18     
+ Misses        136      134       -2     
- Partials       27       31       +4     
Flag Coverage Δ
unittests 95.24% <91.30%> (-0.04%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@@ -11,6 +11,8 @@
public class AndFilter extends Filter {
private List<Filter> children;

private String key;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems we only need this internally in order to be able to replace the correct filter instance in the root filter of the AutoGrid. If that is the case then adding this as a required property to the public API isn't a good solution (also a breaking change). I think it will also be confusing to developers what this key is and why they have to manage it.

I think we could manage this key internally / automatically. We could add a key parameter to AutoGrid's setPropertyFilter. The key could be the column's key, or an incremental number stored in a ref. When exposing the setPropertyFilter to the header filters, we do not pass the original function, but a wrapper function that automatically sets the key:

export function InternalHeaderFilterRenderer({ original }: HeaderRendererProps): JSX.Element | null {
  const {
    setPropertyFilter: setPropertyFilterOriginal,
    headerFilterRenderer: HeaderFilterRenderer,
    filterKey, // Would be determined somehow when rendering the context
  } = useContext(ColumnContext)!;

  function setPropertyFilter(filter: FilterUnion) {
    setPropertyFilterOriginal(filterKey, filter);
  }

  return <HeaderFilterRenderer original={original} setPropertyFilter={setPropertyFilter} />;
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree and I implemented your suggested changes.
Only code will use the key property for custom columns and property.name for model-type columns as identifiers for filter management.

@@ -105,15 +108,31 @@ export function getColumnOptions(
customColumnOptions: ColumnOptions | undefined,
): ColumnOptions {
const typeColumnOptions = getTypeColumnOptions(propertyInfo);
const finalHeaderRenderer =
customColumnOptions?.filterable === false ? NoHeaderFilter : typeColumnOptions.headerRenderer;
const HeaderFilterRenderer =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: IMO writing this in upper-case creates visual noise for no real benefit. It could just be headerFilterRenderer and then be cleanly applied in the object below with a shorthand assignment.

}
return columnOptions;
}

export function InternalHeaderFilterRenderer({ original }: HeaderRendererProps): JSX.Element | null {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these wrappers would a better fit for header-filter.tsx.

Since they effectively do the same, maybe combine them into one:

export function InternalHeaderFilterRenderer({ original }: HeaderRendererProps): JSX.Element | null {
  const { setPropertyFilter, headerFilterRenderer: HeaderFilterRenderer } = (useContext(ColumnContext) ?? useContext(CustomColumnContext))!;
  return <HeaderFilterRenderer original={original} setPropertyFilter={setPropertyFilter} />;
}

The name could also be improved to clarify its intent.

if (!columnOptions.headerRenderer) {
console.error(`No header renderer defined for column ${propertyInfo.name}`);
if (!columnOptions.headerFilterRenderer) {
console.error(`No filter renderer defined for column ${propertyInfo.name}`);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this serve a purpose? Should we just use NoHeaderFilter as a fallback?

if (HeaderFilterRenderer) {
return <HeaderFilterRenderer original={original} setPropertyFilter={setPropertyFilter} />;
}
return null;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can solve the missing code coverage here by making headerFilterRenderer required, and using NoHeaderFilter if no custom renderer is specified.

const { key } = column;
const { header, headerRenderer: HeaderRenderer } = column.props;
const customOptions = options.columnOptions?.[key!];
const { header: customHeader, headerRenderer: CustomHeaderRenderer, headerFilterRenderer } = customOptions ?? {};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Likewise, the uppercase here doesn't provide any benefit.

@@ -186,7 +219,7 @@ function addCustomColumns(columns: JSX.Element[], options: ColumnConfigurationOp

function useColumns(
properties: PropertyInfo[],
setPropertyFilter: (propertyFilter: PropertyStringFilter) => void,
setPropertyFilter: (filter: PropertyStringFilter) => void,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this use FilterUnion?

}
return null;
}
const isEmpty = (filter: FilterUnion): boolean => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this could use more test coverage. Maybe consider extracting this into a utility and testing it separately.

/**
* Custom renderer for the title/sorter in the header.
*/
headerRenderer?: ComponentType<HeaderRendererProps>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't look like this is needed, ColumnOptions already has headerRenderer from GridColumnProps.

* Allows to set custom filter for a property. This is used by the header filter components.
* @param filter - The filter to set in the filter list.
*/
setPropertyFilter(filter: FilterUnion): void;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As this accepts a filter union, it can do more than filtering single properties. Maybe we should rename this to setFilter. Internally we could use setColumnFilter as that's what it basically does now.

Fixes #1608, #1501

*Provide headerFilterRender for users as a new property in columnOptions
*Split headerRenderer and headerFilterRenderer to solve consistency issue with headerRenderer being responsible for two places.
*Provide setPropertyFilter function to headerFilterRenderer as a property in columnOptions
*Add identifier to andFilter and orFilter (key) for controlling (delete/replace/add) filter list
*Change setPropertyFilter to accept any Filter not only StringPropertyFilter
*Enable adding headerFilterRenderer to custom columns
*Enable setting headerRenderer from columnOptions as primary source (overwriting default)
*Provide types to users: ColumnOptions, HeaderFilterRendererProps
…lter working

Rename InternalHeaderFilterRenderer to HeaderFilterWrapper
Copy link

sonarcloud bot commented Dec 23, 2023

Quality Gate Passed Quality Gate passed

The SonarCloud Quality Gate passed, but some issues were introduced.

3 New issues
0 Security Hotspots
No data about Coverage
1.3% Duplication on New Code

See analysis details on SonarCloud

@platosha platosha merged commit faa56c8 into main Dec 28, 2023
13 of 15 checks passed
@platosha platosha deleted the feat/grid-custom-filters branch December 28, 2023 08:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[autogrid] Add support for custom header filters
3 participants