-
Notifications
You must be signed in to change notification settings - Fork 2.8k
[WEB-5099] improvement: enhance rich filters with new components and configurations #7916
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
base: preview
Are you sure you want to change the base?
Conversation
- Added `AdditionalFilterValueInput` for unsupported filter types. - Introduced `FilterItem` and related components for better filter item management. - Updated filter configurations to include new properties and support for multiple values. - Improved loading states and error handling in filter components. - Refactored existing filter logic to streamline operations and enhance performance.
WalkthroughIntroduces new rich-filters UI components and dropdown flow, centralizes shared props/constants, adds config readiness flag and initialization, expands operator/type utilities (including multi-value operators), updates work-item filter adapters/configs, and refactors add-filter and filter-item composition. Adds loader utility and UI dropdown sizing updates. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor U as User
participant B as AddFilterButton
participant D as AddFilterDropdown
participant CM as filter.configManager
participant F as filter
U->>B: Click custom button
B->>D: Open dropdown
D->>CM: Read allAvailableConfigs
D->>U: Show options (or "All filters applied")
U->>D: Select option
D->>D: getOperatorForPayload(property)
alt valid config
D->>B: handleFilterSelect(property, operator, isNegation)
B->>F: addCondition(AND, {property, operator, value: undefined}, isNegation)
else invalid
D->>U: Toast error
end
sequenceDiagram
autonumber
actor U as User
participant P as FilterItemProperty
participant D as AddFilterDropdown
participant F as filter
participant H as helper (_updateCondition)
U->>P: Click property
P->>D: Open dropdown
U->>D: Select new property/operator
D->>P: handleFilterSelect(property, operator, isNegation)
P->>F: updateConditionProperty(conditionId, property, operator, isNegation)
F->>H: handleConditionPropertyUpdate(...)
H-->>F: Updated expression | null
alt updated
F->>F: notifyChanges()
else no update
note right of F: No-op
end
sequenceDiagram
autonumber
participant HOC as WorkItemFilterRoot (HOC)
participant CFG as workItemFiltersConfig
participant CM as filter.configManager
HOC->>HOC: compute workItemFiltersConfig
HOC->>CM: setAreConfigsReady(CFG.areAllConfigsInitialized)
HOC->>CM: registerAll(configs)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…ctionality - Moved AddFilterButton and AddFilterDropdown to a new directory structure for better organization. - Updated FilterItemProperty to handle filter selection and condition updates more effectively. - Enhanced the FilterInstance class with methods to update condition properties and operators, improving filter management. - Added new functionality to handle invalid filter states and improve user feedback.
Linked to Plane Work Item(s) This comment was auto-generated by Plane |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/shared-state/src/store/rich-filters/filter-helpers.ts (1)
173-275
: Negation handling removed from condition updatesThe new
_updateCondition
helper just mutates the targeted node and returns, ignoring theisNegation
flag. BothhandleConditionPropertyUpdate
andrestructureExpressionForOperatorChange
now funnel through this helper, so any scenario that previously required wrapping/unwrapping the condition in a NOT-group (e.g., switching between negative and positive operators) stops working—the tree never restructures. This regresses negated filter updates. Please restore the negation-aware restructuring the old path provided_before landing this refactor.
♻️ Duplicate comments (2)
packages/utils/src/work-item-filters/configs/filters/priority.ts (1)
59-59
: LGTM! Consistent with param spreading pattern.The change aligns with the refactor to support additional filter properties through parameter spreading, matching the pattern in other filter configs.
packages/utils/src/work-item-filters/configs/filters/date.ts (1)
25-25
: LGTM! Consistent parameter spreading.Both filter configs now spread all params, consistent with the refactor pattern across other filter configuration files.
Also applies to: 43-43
🧹 Nitpick comments (5)
packages/shared-state/src/store/work-item-filters/adapter.ts (2)
212-213
: Document the expected behavior for non-string values.The parameter type changed from
string
toTFilterValue
, but the function name and logic still imply string parsing. The early return on line 213 handles falsy values, but the behavior for numbers, booleans, and Date objects is implicit (they're returned as-is).Consider adding documentation or renaming to clarify intent:
/** * Parses filter value from string format + * Non-string values and falsy values are returned as-is * @param value - The string value to parse * @returns Parsed value as string or array of strings */ - private _parseFilterValue = (value: TFilterValue): SingleOrArray<TFilterValue> => { + private _parseFilterValue = (value: TFilterValue): SingleOrArray<TFilterValue> => { if (!value) return value; - + // Non-string values are returned as-is if (typeof value !== "string") return value; // Handle empty string if (value === "") return value; // Split by comma if contains comma, otherwise return as single value if (value.includes(",")) { // Split and trim each value, filter out empty strings const splitValues = value .split(",") .map((v) => v.trim()) .filter((v) => v.length > 0); // Return single value if only one non-empty value after split return splitValues.length === 1 ? splitValues[0] : splitValues; } return value; };
202-202
: Ensure _parseFilterValue covers all edge cases and add tests
- Handle invalid
operator
casts,null
/undefined
, numbers, booleans,Date
objects, and whenrawValue
is already an array.- Add unit tests in packages/shared-state/src/store/work-item-filters/adapter.ts to validate each scenario.
apps/web/core/components/rich-filters/filter-item/loader.tsx (1)
3-7
: LGTM! Simple and effective loader component.The component provides a clean loading state for filter items. The fixed dimensions (28px × 180px) work well for the current use case.
If you anticipate needing different loader sizes across the application, consider making dimensions configurable via props:
-export const FilterItemLoader = () => ( +export const FilterItemLoader = ({ height = "28px", width = "180px" }: { height?: string; width?: string } = {}) => ( <Loader> - <Loader.Item height="28px" width="180px" /> + <Loader.Item height={height} width={width} /> </Loader> );packages/utils/src/rich-filters/factories/configs/shared.ts (1)
36-39
: Consider constraining theobject
type in TFilterIconType.The
object
type is too permissive and allows any object. Consider making it more specific to prevent unintended usage.If icon data has known shapes, consider:
-export type TFilterIconType = string | number | boolean | object | undefined; +export type TFilterIconType = string | number | boolean | Record<string, unknown> | undefined;Or better yet, if you know the specific icon data structures, define them explicitly:
export type TFilterIconType = string | number | boolean | TKnownIconData | undefined;packages/shared-state/src/store/rich-filters/filter.ts (1)
369-388
: Document the extra parametersThe docblock still lists only the
property
argument, but the method now accepts operator and negation as well—could you expand the comment so future readers don’t miss those inputs?
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (49)
apps/web/ce/components/rich-filters/filter-value-input/root.tsx
(1 hunks)apps/web/ce/helpers/work-item-filters/project-level.ts
(1 hunks)apps/web/ce/hooks/work-item-filters/use-work-item-filters-config.tsx
(5 hunks)apps/web/core/components/rich-filters/add-filters-button.tsx
(0 hunks)apps/web/core/components/rich-filters/add-filters/button.tsx
(1 hunks)apps/web/core/components/rich-filters/add-filters/dropdown.tsx
(1 hunks)apps/web/core/components/rich-filters/filter-item/close-button.tsx
(1 hunks)apps/web/core/components/rich-filters/filter-item/container.tsx
(1 hunks)apps/web/core/components/rich-filters/filter-item/invalid.tsx
(1 hunks)apps/web/core/components/rich-filters/filter-item/loader.tsx
(1 hunks)apps/web/core/components/rich-filters/filter-item/property.tsx
(1 hunks)apps/web/core/components/rich-filters/filter-item/root.tsx
(5 hunks)apps/web/core/components/rich-filters/filter-value-input/date/range.tsx
(2 hunks)apps/web/core/components/rich-filters/filter-value-input/date/single.tsx
(2 hunks)apps/web/core/components/rich-filters/filter-value-input/root.tsx
(3 hunks)apps/web/core/components/rich-filters/filter-value-input/select/selected-options-display.tsx
(2 hunks)apps/web/core/components/rich-filters/filters-row.tsx
(4 hunks)apps/web/core/components/rich-filters/filters-toggle.tsx
(1 hunks)apps/web/core/components/rich-filters/shared.ts
(1 hunks)apps/web/core/components/work-item-filters/filters-hoc/base.tsx
(1 hunks)apps/web/core/components/work-item-filters/filters-hoc/project-level.tsx
(1 hunks)packages/shared-state/src/store/rich-filters/config-manager.ts
(5 hunks)packages/shared-state/src/store/rich-filters/filter-helpers.ts
(5 hunks)packages/shared-state/src/store/rich-filters/filter.ts
(4 hunks)packages/shared-state/src/store/work-item-filters/adapter.ts
(4 hunks)packages/types/src/rich-filters/config/filter-config.ts
(1 hunks)packages/types/src/rich-filters/operators/core.ts
(1 hunks)packages/types/src/rich-filters/operators/extended.ts
(1 hunks)packages/types/src/rich-filters/operators/index.ts
(2 hunks)packages/types/src/view-props.ts
(1 hunks)packages/ui/src/dropdowns/custom-search-select.tsx
(2 hunks)packages/ui/src/dropdowns/helper.tsx
(1 hunks)packages/utils/src/index.ts
(1 hunks)packages/utils/src/loader.ts
(1 hunks)packages/utils/src/rich-filters/factories/configs/index.ts
(1 hunks)packages/utils/src/rich-filters/factories/configs/properties/date.ts
(1 hunks)packages/utils/src/rich-filters/factories/configs/properties/index.ts
(1 hunks)packages/utils/src/rich-filters/factories/configs/properties/member-picker.ts
(1 hunks)packages/utils/src/rich-filters/factories/configs/properties/shared.ts
(1 hunks)packages/utils/src/rich-filters/factories/configs/shared.ts
(1 hunks)packages/utils/src/rich-filters/factories/index.ts
(1 hunks)packages/utils/src/work-item-filters/configs/filters/cycle.ts
(1 hunks)packages/utils/src/work-item-filters/configs/filters/date.ts
(3 hunks)packages/utils/src/work-item-filters/configs/filters/label.ts
(1 hunks)packages/utils/src/work-item-filters/configs/filters/module.ts
(1 hunks)packages/utils/src/work-item-filters/configs/filters/priority.ts
(1 hunks)packages/utils/src/work-item-filters/configs/filters/project.ts
(2 hunks)packages/utils/src/work-item-filters/configs/filters/state.ts
(4 hunks)packages/utils/src/work-item-filters/configs/filters/user.ts
(5 hunks)
💤 Files with no reviewable changes (1)
- apps/web/core/components/rich-filters/add-filters-button.tsx
🧰 Additional context used
🧬 Code graph analysis (26)
apps/web/core/components/rich-filters/filter-value-input/date/range.tsx (1)
apps/web/core/components/rich-filters/shared.ts (1)
EMPTY_FILTER_PLACEHOLDER_TEXT
(11-11)
apps/web/core/components/rich-filters/filter-item/loader.tsx (1)
packages/ui/src/loader.tsx (1)
Loader
(30-30)
packages/utils/src/loader.ts (1)
packages/types/src/issues/base.ts (1)
TLoader
(10-10)
packages/utils/src/rich-filters/factories/configs/properties/date.ts (3)
packages/utils/src/rich-filters/factories/configs/shared.ts (3)
TCreateDateFilterParams
(54-54)TCreateFilterConfig
(76-76)createFilterConfig
(21-23)packages/types/src/rich-filters/expression.ts (1)
TFilterProperty
(19-19)packages/utils/src/rich-filters/factories/configs/properties/shared.ts (1)
getSupportedDateOperators
(54-60)
apps/web/core/components/rich-filters/filter-value-input/date/single.tsx (1)
apps/web/core/components/rich-filters/shared.ts (1)
EMPTY_FILTER_PLACEHOLDER_TEXT
(11-11)
apps/web/core/components/rich-filters/filter-item/container.tsx (3)
packages/types/src/utils.ts (1)
SingleOrArray
(9-9)packages/types/src/rich-filters/expression.ts (1)
TFilterValue
(24-24)packages/utils/src/rich-filters/validators/core.ts (1)
hasValidValue
(12-26)
apps/web/ce/hooks/work-item-filters/use-work-item-filters-config.tsx (5)
packages/types/src/rich-filters/config/filter-config.ts (1)
TFilterConfig
(11-20)packages/types/src/view-props.ts (1)
TWorkItemFilterProperty
(104-104)packages/types/src/rich-filters/expression.ts (1)
TFilterValue
(24-24)packages/types/src/users.ts (1)
IUserLite
(20-29)packages/utils/src/loader.ts (1)
isLoaderReady
(4-4)
apps/web/core/components/rich-filters/shared.ts (3)
packages/types/src/rich-filters/expression.ts (3)
TFilterProperty
(19-19)TFilterValue
(24-24)TFilterConditionNodeForDisplay
(55-60)packages/types/src/rich-filters/field-types/index.ts (1)
TSupportedFilterFieldConfigs
(19-21)packages/types/src/utils.ts (1)
SingleOrArray
(9-9)
packages/utils/src/rich-filters/factories/configs/properties/member-picker.ts (5)
packages/types/src/users.ts (1)
IUserLite
(20-29)packages/utils/src/rich-filters/factories/configs/properties/shared.ts (2)
TCreateUserFilterParams
(24-27)getMemberMultiSelectConfig
(34-50)packages/types/src/rich-filters/expression.ts (1)
TFilterProperty
(19-19)packages/utils/src/rich-filters/factories/configs/shared.ts (3)
TCreateFilterConfig
(76-76)createFilterConfig
(21-23)createOperatorConfigEntry
(64-71)packages/types/src/rich-filters/operators/index.ts (1)
EQUALITY_OPERATOR
(25-28)
apps/web/core/components/rich-filters/filter-item/property.tsx (6)
packages/types/src/rich-filters/expression.ts (1)
TFilterProperty
(19-19)packages/types/src/rich-filters/adapter.ts (1)
TExternalFilter
(7-7)packages/shared-state/src/store/rich-filters/filter.ts (1)
IFilterInstance
(64-119)packages/types/src/rich-filters/operators/index.ts (1)
TSupportedOperators
(56-56)apps/web/core/components/rich-filters/add-filters/dropdown.tsx (1)
AddFilterDropdown
(20-86)apps/web/core/components/rich-filters/shared.ts (1)
COMMON_FILTER_ITEM_BORDER_CLASSNAME
(9-9)
packages/ui/src/dropdowns/custom-search-select.tsx (1)
packages/ui/src/utils/classname.tsx (1)
cn
(4-4)
packages/utils/src/rich-filters/factories/configs/properties/shared.ts (6)
packages/utils/src/rich-filters/factories/configs/shared.ts (4)
TCreateFilterConfigParams
(29-34)IFilterIconConfig
(46-49)TCreateDateFilterParams
(54-54)createOperatorConfigEntry
(64-71)packages/types/src/users.ts (1)
IUserLite
(20-29)packages/types/src/rich-filters/operators/index.ts (3)
TSupportedOperators
(56-56)EQUALITY_OPERATOR
(25-28)COMPARISON_OPERATOR
(35-38)packages/utils/src/rich-filters/factories/configs/core.ts (3)
getMultiSelectConfig
(69-89)getDatePickerConfig
(114-118)getDateRangePickerConfig
(125-129)packages/types/src/rich-filters/operator-configs/index.ts (1)
TOperatorConfigMap
(48-51)packages/types/src/project/projects.ts (1)
IProject
(38-54)
apps/web/core/components/rich-filters/add-filters/button.tsx (6)
packages/types/src/rich-filters/expression.ts (1)
TFilterProperty
(19-19)packages/types/src/rich-filters/adapter.ts (1)
TExternalFilter
(7-7)packages/propel/src/button/helper.tsx (2)
TButtonVariant
(1-12)getButtonStyling
(109-120)packages/shared-state/src/store/rich-filters/filter.ts (1)
IFilterInstance
(64-119)packages/types/src/rich-filters/operators/index.ts (2)
TSupportedOperators
(56-56)LOGICAL_OPERATOR
(20-23)apps/web/core/components/rich-filters/add-filters/dropdown.tsx (1)
AddFilterDropdown
(20-86)
apps/web/core/components/rich-filters/filter-value-input/select/selected-options-display.tsx (1)
apps/web/core/components/rich-filters/shared.ts (1)
EMPTY_FILTER_PLACEHOLDER_TEXT
(11-11)
apps/web/core/components/rich-filters/filter-item/invalid.tsx (6)
packages/types/src/rich-filters/expression.ts (1)
TFilterProperty
(19-19)packages/types/src/rich-filters/adapter.ts (1)
TExternalFilter
(7-7)apps/web/core/components/rich-filters/filter-item/root.tsx (1)
IFilterItemProps
(24-29)apps/web/core/components/rich-filters/filter-item/container.tsx (1)
FilterItemContainer
(16-64)apps/web/core/components/rich-filters/filter-item/property.tsx (1)
FilterItemProperty
(20-40)apps/web/core/components/rich-filters/filter-item/close-button.tsx (1)
FilterItemCloseButton
(13-32)
apps/web/core/components/rich-filters/filter-value-input/root.tsx (1)
apps/web/ce/components/rich-filters/filter-value-input/root.tsx (1)
AdditionalFilterValueInput
(8-15)
packages/types/src/rich-filters/operators/index.ts (2)
packages/types/src/rich-filters/operators/core.ts (1)
CORE_MULTI_VALUE_OPERATORS
(32-32)packages/types/src/rich-filters/operators/extended.ts (1)
EXTENDED_MULTI_VALUE_OPERATORS
(24-24)
apps/web/ce/components/rich-filters/filter-value-input/root.tsx (2)
packages/types/src/rich-filters/expression.ts (2)
TFilterProperty
(19-19)TFilterValue
(24-24)apps/web/core/components/rich-filters/shared.ts (1)
TFilterValueInputProps
(13-18)
packages/shared-state/src/store/rich-filters/filter.ts (4)
packages/types/src/rich-filters/operators/index.ts (1)
TSupportedOperators
(56-56)packages/utils/src/rich-filters/operations/traversal/core.ts (1)
findNodeById
(91-103)packages/types/src/rich-filters/expression.ts (1)
FILTER_NODE_TYPE
(10-13)packages/utils/src/rich-filters/validators/core.ts (1)
hasValidValue
(12-26)
apps/web/core/components/rich-filters/add-filters/dropdown.tsx (5)
packages/types/src/rich-filters/expression.ts (1)
TFilterProperty
(19-19)packages/types/src/rich-filters/adapter.ts (1)
TExternalFilter
(7-7)packages/shared-state/src/store/rich-filters/filter.ts (1)
IFilterInstance
(64-119)packages/utils/src/rich-filters/operators/shared.ts (1)
getOperatorForPayload
(16-24)packages/ui/src/dropdowns/custom-search-select.tsx (1)
CustomSearchSelect
(14-225)
packages/shared-state/src/store/rich-filters/filter-helpers.ts (3)
packages/types/src/rich-filters/expression.ts (3)
TFilterExpression
(86-88)TFilterConditionNode
(45-50)TFilterValue
(24-24)packages/types/src/rich-filters/operators/index.ts (1)
TSupportedOperators
(56-56)packages/utils/src/rich-filters/operations/manipulation/core.ts (1)
updateNodeInExpression
(84-107)
packages/shared-state/src/store/work-item-filters/adapter.ts (4)
packages/types/src/view-props.ts (2)
WORK_ITEM_FILTER_PROPERTY_KEYS
(89-103)TWorkItemFilterConditionKey
(106-106)packages/types/src/rich-filters/operators/index.ts (2)
TSupportedOperators
(56-56)MULTI_VALUE_OPERATORS
(40-43)packages/types/src/rich-filters/expression.ts (1)
TFilterValue
(24-24)packages/types/src/utils.ts (1)
SingleOrArray
(9-9)
packages/utils/src/work-item-filters/configs/filters/user.ts (2)
packages/utils/src/rich-filters/factories/configs/shared.ts (1)
createOperatorConfigEntry
(64-71)packages/utils/src/rich-filters/factories/configs/properties/shared.ts (1)
getMemberMultiSelectConfig
(34-50)
packages/utils/src/work-item-filters/configs/filters/state.ts (2)
packages/types/src/rich-filters/operators/index.ts (3)
TSupportedOperators
(56-56)COLLECTION_OPERATOR
(30-33)EQUALITY_OPERATOR
(25-28)packages/utils/src/rich-filters/factories/configs/shared.ts (1)
createOperatorConfigEntry
(64-71)
apps/web/core/components/rich-filters/filter-item/close-button.tsx (3)
packages/types/src/rich-filters/expression.ts (1)
TFilterProperty
(19-19)packages/types/src/rich-filters/adapter.ts (1)
TExternalFilter
(7-7)packages/shared-state/src/store/rich-filters/filter.ts (1)
IFilterInstance
(64-119)
apps/web/core/components/rich-filters/filter-item/root.tsx (8)
packages/types/src/rich-filters/expression.ts (3)
TFilterProperty
(19-19)TFilterConditionNodeForDisplay
(55-60)TFilterValue
(24-24)packages/types/src/rich-filters/adapter.ts (1)
TExternalFilter
(7-7)packages/shared-state/src/store/rich-filters/filter.ts (1)
IFilterInstance
(64-119)apps/web/core/components/rich-filters/filter-item/loader.tsx (1)
FilterItemLoader
(3-7)apps/web/core/components/rich-filters/filter-item/invalid.tsx (1)
InvalidFilterItem
(12-36)apps/web/core/components/rich-filters/filter-item/container.tsx (1)
FilterItemContainer
(16-64)apps/web/core/components/rich-filters/filter-item/property.tsx (1)
FilterItemProperty
(20-40)apps/web/core/components/rich-filters/filter-item/close-button.tsx (1)
FilterItemCloseButton
(13-32)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Build and lint web apps
🔇 Additional comments (35)
packages/types/src/view-props.ts (1)
108-110
: No downstream changes required. The type widening only affects typings; the filter adapter always serializes values to strings, so existing string operations and serialization logic remain safe.apps/web/ce/helpers/work-item-filters/project-level.ts (1)
1-20
: LGTM! Type extension for future use.The addition of
entityType: EIssuesStoreType
extends the type definition without changing the current implementation behavior. The field is intentionally unused ingetAdditionalProjectLevelFiltersHOCProps
, likely reserved for future filtering enhancements or to maintain consistency with other HOC parameter patterns.packages/utils/src/loader.ts (1)
1-4
: LGTM! Clean utility function.The
isLoaderReady
utility provides a clear abstraction for checking initialization state. The logic correctly identifies when loading has progressed beyond the initial state.packages/ui/src/dropdowns/custom-search-select.tsx (1)
142-167
: LGTM! UI refinements align with type updates.The spacing adjustments and expanded
maxHeight
handling correctly implement support for the new"xl"
and"2xl"
options while removing"full"
. The changes improve layout consistency:
- Tighter alignment with margin-based spacing (
mx-2
on line 149)- Explicit scrollbar styling for better UX
- Preserved mappings for existing breakpoints
packages/types/src/rich-filters/config/filter-config.ts (1)
18-19
: LGTM! Well-documented type extension.The addition of optional
rightContent
andtooltipContent
fields extends the filter configuration API with clear UI hooks. The documentation comments clearly explain their purpose and usage context.packages/ui/src/dropdowns/helper.tsx (1)
27-27
: Breaking change: removed “full” maxHeight option.
No internal usages ofmaxHeight="full"
detected. Ensure external consumers (docs, published API) are updated and bump the major version accordingly.packages/utils/src/work-item-filters/configs/filters/label.ts (1)
59-69
: Spreadingparams
is safe –TCreateLabelFilterParams
only includesisEnabled
,allowedOperators
, optionalrightContent
/tooltipContent
,filterIcon
andlabels
, all of whichcreateFilterConfig
’sTFilterConfig<'label', string>
expects.apps/web/core/components/rich-filters/filter-value-input/date/single.tsx (1)
7-7
: LGTM! Good use of shared constants.Replacing the hard-coded placeholder with
EMPTY_FILTER_PLACEHOLDER_TEXT
improves maintainability and ensures consistency across the application.Also applies to: 37-37
apps/web/core/components/work-item-filters/filters-hoc/project-level.tsx (1)
169-173
: LGTM! Proper prop forwarding.The addition of
entityType: props.entityType
correctly forwards the new property togetAdditionalProjectLevelFiltersHOCProps
, aligning with the updated type signature.apps/web/core/components/rich-filters/filters-toggle.tsx (1)
8-8
: LGTM! Import path correctly updated.The import path change reflects the reorganization of
AddFilterButton
into a new directory structure.apps/web/core/components/rich-filters/filter-value-input/select/selected-options-display.tsx (1)
6-6
: LGTM! Consistent use of shared constants.Replacing the hard-coded
"--"
withEMPTY_FILTER_PLACEHOLDER_TEXT
ensures consistency with other filter components.Also applies to: 17-17
apps/web/core/components/rich-filters/filter-value-input/date/range.tsx (1)
9-9
: LGTM! Good use of shared constants.Replacing the hard-coded placeholder with
EMPTY_FILTER_PLACEHOLDER_TEXT
maintains consistency across date input components.Also applies to: 45-45
packages/utils/src/rich-filters/factories/configs/index.ts (1)
3-3
: LGTM! Proper public API extension.The new export for
"./properties"
appropriately extends the public API to include the properties module.packages/utils/src/work-item-filters/configs/filters/project.ts (1)
23-32
: Spread...params
includesisEnabled
TCreateProjectFilterParams
extendsTCreateFilterConfigParams
, which declaresisEnabled: boolean
, so...params
already brings inisEnabled
.packages/utils/src/rich-filters/factories/index.ts (1)
3-3
: LGTM! API surface expansion for property configurations.The new re-export exposes property-based filter configurations, aligning with the PR's goal to enhance rich filters with new components and configurations.
packages/utils/src/rich-filters/factories/configs/shared.ts (1)
32-33
: LGTM! Good extensibility for UI content.Adding
rightContent
andtooltipContent
as optional ReactNode properties provides flexible extension points for filter UI customization.packages/utils/src/work-item-filters/configs/filters/date.ts (1)
4-9
: LGTM! Cleaner import organization.Consolidating imports from the same module improves readability.
apps/web/ce/components/rich-filters/filter-value-input/root.tsx (1)
8-15
: LGTM! Clean fallback implementation.The component provides a clear fallback UI for unsupported filter types. Using
observer
from mobx-react and ignoring props (prefixed with_
) is appropriate for a static fallback component.packages/types/src/rich-filters/operators/core.ts (1)
29-32
: LGTM! Well-defined multi-value operator constant.The new constant clearly identifies which core operators support multiple values. Using
as const
ensures type safety and immutability.packages/utils/src/work-item-filters/configs/filters/module.ts (1)
56-56
: Parameter spreading is consistent across all filter configs.packages/utils/src/work-item-filters/configs/filters/cycle.ts (1)
63-63
: LGTM: Cleaner parameter propagation.Spreading all params instead of explicit assignment is more maintainable and aligns with the broader refactor pattern across other filter configs.
apps/web/core/components/work-item-filters/filters-hoc/base.tsx (1)
97-97
: LGTM: Proper readiness propagation.Setting the configs ready state before registration ensures the config manager has accurate initialization status during the registration phase.
packages/types/src/rich-filters/operators/extended.ts (1)
21-24
: LGTM: Consistent multi-value operator infrastructure.The empty array is appropriate for extended operators and maintains consistency with the core multi-value operator pattern.
apps/web/core/components/rich-filters/filter-item/close-button.tsx (1)
1-32
: LGTM: Clean close button implementation.The component correctly handles filter removal with proper accessibility attributes and MobX reactivity.
apps/web/core/components/rich-filters/shared.ts (1)
1-18
: LGTM: Good centralization of shared types and constants.Consolidating EMPTY_FILTER_PLACEHOLDER_TEXT and TFilterValueInputProps improves maintainability and consistency across filter components.
packages/utils/src/rich-filters/factories/configs/properties/index.ts (1)
1-3
: LGTM: Standard barrel export pattern.The index file correctly consolidates and re-exports from the properties config modules.
packages/types/src/rich-filters/operators/index.ts (1)
40-43
: LGTM: Proper multi-value operator aggregation.The constant correctly combines core and extended multi-value operators with appropriate typing for a readonly array.
apps/web/core/components/rich-filters/filter-item/property.tsx (1)
1-67
: LGTM: Well-structured property filter component.The component correctly handles both disabled and enabled states, properly delegates filter selection, and uses good composition patterns with the internal PropertyButton and AddFilterDropdown integration.
packages/utils/src/rich-filters/factories/configs/properties/date.ts (1)
17-27
: Date property factory reads cleanNice job parameterizing the factory and reusing the shared date operator map—this keeps the property configs consistent and extensible.
packages/shared-state/src/store/rich-filters/filter.ts (1)
446-461
: Value no-op guard is appreciatedUsing
isEqual
to bail when the value doesn’t change should trim a lot of redundant notifications—thanks for tightening this up.apps/web/core/components/rich-filters/filter-item/container.tsx (1)
21-48
: Entrance animation is well-containedWrapping the transition behind
showTransition
and skipping it once the value is valid keeps the effect predictable—looks good.apps/web/core/components/rich-filters/add-filters/dropdown.tsx (1)
55-82
: Dropdown wiring looks solidThe option mapping plus the fallback toast make the selection flow resilient—nicely handled.
packages/utils/src/work-item-filters/configs/filters/state.ts (1)
90-125
: State configs align with multi-value supportPassing the single-value operator through keeps the multi-select helper flexible—looks great.
packages/utils/src/rich-filters/factories/configs/properties/member-picker.ts (1)
17-29
: Member picker factory is consistentThis mirrors the shared multi-select helper neatly and keeps the property config API uniform—nice work.
packages/utils/src/rich-filters/factories/configs/properties/shared.ts (1)
34-99
: Shared helpers nicely abstractedCentralizing the member/project multi-select builders and date operator map keeps the property factories lightweight—great abstraction.
// observables | ||
filterConfigs: Map<P, IFilterConfig<P, TFilterValue>>; // filter property -> config | ||
configOptions: TConfigOptions; | ||
areConfigsReady: boolean; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
🧩 Analysis chain
Verify the default value of areConfigsReady.
The new areConfigsReady
flag is correctly implemented as a MobX observable with an action setter. However, the default value of true
(line 75) may be counterintuitive—shouldn't configs start as not ready until initialization completes?
According to the AI summary, this flag influences loading states in the UI. Confirm whether defaulting to true
is the intended behavior or if it should start as false
and be set to true
after initialization:
Also applies to: 36-36, 62-62, 75-75, 82-82, 89-89, 155-161
🏁 Script executed:
#!/bin/bash
# Description: Check how areConfigsReady is used in the initialization flow
# Find where setAreConfigsReady is called
rg -n 'setAreConfigsReady' -A 3 -B 3
# Find where areConfigsReady is read/used
rg -n 'areConfigsReady' -A 2 -B 2
Length of output: 6973
🏁 Script executed:
#!/bin/bash
sed -n '50,150p' apps/web/core/components/work-item-filters/filters-hoc/base.tsx
Length of output: 1699
Initialize areConfigsReady
to false
Defaulting to true
allows the UI to treat configs as ready before they’re actually initialized—change the constructor (line 75) to this.areConfigsReady = false
so readiness is only granted via setAreConfigsReady(true)
.
🤖 Prompt for AI Agents
In packages/shared-state/src/store/rich-filters/config-manager.ts around line 27
(declaration) and line 75 (constructor), areConfigsReady is defaulting to true
which lets the UI treat configs as ready prematurely; change the initialization
in the constructor at line 75 to explicitly set this.areConfigsReady = false so
readiness is only granted by calling setAreConfigsReady(true).
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
if (!WORK_ITEM_FILTER_PROPERTY_KEYS.includes(property as any) && !property.startsWith("customproperty_")) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Address the type-safety issue instead of disabling the linter.
The eslint-disable
comment and any
type cast suggest a type-safety issue that should be resolved properly rather than suppressed. The validation allows any key starting with "customproperty_"
, but this bypasses TypeScript's type checking.
Consider defining a type guard or helper that properly types custom properties:
private _isValidWorkItemFilterConditionKey = (key: string): key is TWorkItemFilterConditionKey => {
if (typeof key !== "string" || key.length === 0) return false;
// Find the last occurrence of '__' to separate property from operator
const lastDoubleUnderscoreIndex = key.lastIndexOf("__");
if (
lastDoubleUnderscoreIndex === -1 ||
lastDoubleUnderscoreIndex === 0 ||
lastDoubleUnderscoreIndex === key.length - 2
) {
return false;
}
const property = key.substring(0, lastDoubleUnderscoreIndex);
const operator = key.substring(lastDoubleUnderscoreIndex + 2);
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- if (!WORK_ITEM_FILTER_PROPERTY_KEYS.includes(property as any) && !property.startsWith("customproperty_")) {
+ const isKnownProperty = (WORK_ITEM_FILTER_PROPERTY_KEYS as readonly string[]).includes(property);
+ const isCustomProperty = property.startsWith("customproperty_");
+ if (!isKnownProperty && !isCustomProperty) {
return false;
}
// Validate operator is not empty
return operator.length > 0;
};
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
// eslint-disable-next-line @typescript-eslint/no-explicit-any | |
if (!WORK_ITEM_FILTER_PROPERTY_KEYS.includes(property as any) && !property.startsWith("customproperty_")) { | |
const isKnownProperty = (WORK_ITEM_FILTER_PROPERTY_KEYS as readonly string[]).includes(property); | |
const isCustomProperty = property.startsWith("customproperty_"); | |
if (!isKnownProperty && !isCustomProperty) { | |
return false; | |
} |
🤖 Prompt for AI Agents
In packages/shared-state/src/store/work-item-filters/adapter.ts around lines
165-166, remove the eslint-disable and the use of "any" and replace the loose
runtime check with a proper typed guard: introduce a helper/type guard that
narrows property to the union of WORK_ITEM_FILTER_PROPERTY_KEYS (e.g., keyof
WorkItemFilterProperty) or to a CustomPropertyKey type (e.g., template literal
type "customproperty_${string}"), then use that guard here instead of casting to
any; this preserves type safety while still allowing keys that start with
"customproperty_".
const lastDoubleUnderscoreIndex = key.lastIndexOf("__"); | ||
const property = key.substring(0, lastDoubleUnderscoreIndex); | ||
const operator = key.substring(lastDoubleUnderscoreIndex + 2); | ||
const operator = key.substring(lastDoubleUnderscoreIndex + 2) as TSupportedOperators; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Verify operator validity before casting.
The explicit cast to TSupportedOperators
on line 197 bypasses type safety. If an invalid operator is provided, it will only be caught at runtime (if at all), not at compile time.
Consider adding runtime validation before casting:
const lastDoubleUnderscoreIndex = key.lastIndexOf("__");
const property = key.substring(0, lastDoubleUnderscoreIndex);
- const operator = key.substring(lastDoubleUnderscoreIndex + 2) as TSupportedOperators;
+ const operatorString = key.substring(lastDoubleUnderscoreIndex + 2);
+
+ // Validate operator is supported
+ const SUPPORTED_OPERATORS = [...MULTI_VALUE_OPERATORS, /* add other operators */] as const;
+ if (!SUPPORTED_OPERATORS.includes(operatorString as TSupportedOperators)) {
+ console.error(`Unsupported operator: ${operatorString}`);
+ return null;
+ }
+ const operator = operatorString as TSupportedOperators;
Run the following script to check if there are operator validation utilities available:
🏁 Script executed:
#!/bin/bash
# Search for operator validation functions or constants
rg -nP --type=ts 'function.*validate.*operator|const.*OPERATORS.*=.*\[' packages/types/src/rich-filters/
Length of output: 411
🏁 Script executed:
#!/bin/bash
sed -n '1,80p' packages/shared-state/src/store/work-item-filters/adapter.ts
echo '--- operator context ---'
sed -n '180,240p' packages/shared-state/src/store/work-item-filters/adapter.ts
Length of output: 5107
Validate operator before casting (adapter.ts:197). Import and combine the existing operator lists—MULTI_VALUE_OPERATORS
, CORE_MULTI_VALUE_OPERATORS
, and EXTENDED_MULTI_VALUE_OPERATORS
from @plane/types
—and verify that the substringed operatorString
is included before casting to TSupportedOperators
to prevent invalid operators at runtime.
🤖 Prompt for AI Agents
In packages/shared-state/src/store/work-item-filters/adapter.ts around line 197,
the code blindly casts the substringed operator to TSupportedOperators; update
it to first import MULTI_VALUE_OPERATORS, CORE_MULTI_VALUE_OPERATORS, and
EXTENDED_MULTI_VALUE_OPERATORS from @plane/types, combine them into a single
set/list, extract the operatorString via substring as before, check that this
operatorString exists in the combined list, and only then cast to
TSupportedOperators; if the operatorString is not found, handle it
deterministically (e.g., throw a clear Error or return a safe default) instead
of casting an invalid value.
Description
FilterItem
and related components for better filter item management.Type of Change
Summary by CodeRabbit
New Features
Improvements