Repository navigation
[Customer portal] [web] : Refactor Cases Table Filters, Improve Project Metadata UI, and Update Security Report Analysis Flow - #320
Conversation
Replace the old FilterPopover with an inline CasesFilters component and update the header API accordingly. Import Divider and Box to layout the new filter section and render CasesFilters when isFilterOpen is true. Remove the FilterPopover import and multiple obsolete handlers and derived values (handleFilterSearch, handleRemoveFilter, handleAllCases, handleCreateCase, activeFilterFields, mappedAppliedFilters). Update CasesTableHeader props to use isFiltersOpen and onFilterToggle (which clears filters if any) and simplify handleClearFilters. Overall this simplifies filter state handling and moves filter controls into the main table layout.
Adjust test suite to match refactored CasesTableHeader API: replace many old mock props with isFiltersOpen and onFilterToggle, update the Filters button test to expect onFilterToggle, remove tests for Create and All button handlers and the ActiveFilters rendering, and add a test that verifies the "Reset Filters" text appears when activeFiltersCount is non-zero.
Introduce a new CasesFilters React component for the customer-portal dashboard to render select-based filter dropdowns. The component accepts filters, filterFields and onFilterChange props, renders only fields of type "select", provides an "All <label>" option, and maps field options (string or {label,value}) into MenuItems. Uses @wso2/oxygen-ui components and TypeScript types for safety. Includes Apache-2.0 license header.
Update getAvailableCaseActions to no longer include the "Closed" option for CaseStatus.SOLUTION_PROPOSED, leaving only "Accept Solution" and "Reject Solution". This prevents closing a case while a solution is proposed and aligns the UI with the intended case workflow.
Replace the previous ActiveFilters integration and multiple filter handlers with a simplified header that uses isFiltersOpen and onFilterToggle. Add navigation logic (useNavigate/useParams) and getNoveraChatEnabled feature flag to route Create button to either chat describe flow or create-case with skipChat state. Update icons (RotateCcw, ChevronUp/ChevronDown) and adjust button states/labels (Filters / Reset Filters) and layout accordingly.
Wrap project-type, support-tier and SLA chips with Tooltip and an extracted chipStyle to enforce ellipsis, max width and consistent styling. Update imports to include Tooltip, adjust Grid to space columns evenly, and make item alignment responsive (created date left, type/tier centered, SLA right). Minor formatting and layout tweaks for better responsiveness and UX.
Rework the ProductVulnerabilities table header layout and filter control. Replace the filter icon/ActiveFilters integration with a single Filters button (onFilterIconClick -> onFilterToggle) that shows filter state: when activeFiltersCount > 0 it displays "Reset Filters" with a RotateCcw icon, otherwise shows a ListFilter icon and a chevron (up/down) driven by isFiltersOpen. Simplify the search TextField styling and adornments, add new icon imports (ChevronDown, ChevronUp, RotateCcw), and remove the ActiveFilters component and its related props (appliedFilters, filterFields, onRemoveFilter, onClearAll, onUpdateFilter). Update prop list to include isFiltersOpen and adjust layout for responsive spacing.
Introduce ProductVulnerabilitiesFilters React/TypeScript component to render a severity filter dropdown for product vulnerabilities. Uses @wso2/oxygen-ui FormControl, Select, MenuItem and Grid; accepts filters, severityOptions (default empty) and onFilterChange props. Selection changes call onFilterChange('severityId', value). Includes a default "All Severity" option and basic typing for FilterOption and props.
Replace the old FilterPopover-based UI with an inline ProductVulnerabilitiesFilters section and related layout changes. Update imports (add Divider, Box; remove FilterPopover/FilterField), widen filters state to accept numbers, and adjust handleUpdateFilter typing. Remove dynamicFilterFields and related handlers (handleFilterSearch, handleRemoveFilter, displayFiltersForPopover) and the metaData error flag usage. Convert applied filter values to strings for display and compute active filter fields from severityOptions. Change filter toggle behavior to clear existing filters when toggling on if any exist, and expose isFiltersOpen to the header. Overall this simplifies filter handling and moves filter controls into the component tree instead of a popover.
📝 WalkthroughWalkthroughRefactors filtering UI from popover-based to inline collapsible panels. Adds reusable select filter components (CasesFilters, ProductVulnerabilitiesFilters). Simplifies table header props to Changes
Sequence Diagram(s)mermaid Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ 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 |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (3)
apps/customer-portal/webapp/src/components/security/ProductVulnerabilitiesTable.tsx (1)
150-160: Minor inconsistency between toggle condition and active filters display.The
onFilterTogglehandler checksObject.keys(filters).length > 0, while the button label usesactiveFiltersCountderived fromappliedFilterswhich excludes empty values (line 131). If a user selects "All Severity" (empty string value),filters = { severityId: "" }:
Object.keys(filters).length === 1→ triggershandleClearFilters()activeFiltersCount === 0→ button shows "Filters" (not "Reset Filters")The UI is correct, but clicking unnecessarily calls clear. Consider aligning the check with the same logic:
♻️ Suggested alignment
onFilterToggle={() => { - if (Object.keys(filters).length > 0) { + if (Object.values(filters).some((v) => Boolean(v))) { handleClearFilters(); } else { setIsFilterOpen(!isFilterOpen); } }}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/customer-portal/webapp/src/components/security/ProductVulnerabilitiesTable.tsx` around lines 150 - 160, The toggle handler uses Object.keys(filters).length to decide between handleClearFilters() and toggling the filter panel, which mismatches the activeFiltersCount logic that counts only non-empty appliedFilters; update the onFilterToggle logic to use the same non-empty-filter check as activeFiltersCount (i.e., count activeFilterFields.filter(f => appliedFilters[f.id]) length or otherwise check appliedFilters values for non-empty entries) so that it calls handleClearFilters() only when there are actually applied (non-empty) filters; leave setIsFilterOpen and isFilterOpen behavior unchanged.apps/customer-portal/webapp/src/components/security/ProductVulnerabilitiesTableHeader.tsx (1)
85-105: Minor redundancy:fullWidthprop andsx.width: "100%"are both set.Both achieve the same effect. Consider removing one for clarity.
♻️ Suggested cleanup
<TextField sx={{ - width: "100%", + // fullWidth prop handles width }} value={searchValue} onChange={handleSearchChange} placeholder="Search CVE or component" size="small" fullWidthOr simply remove the
sxprop entirely if no other styles are needed:- <Box sx={{ width: "100%", flexGrow: 1 }}> - <TextField - sx={{ - width: "100%", - }} + <Box sx={{ flexGrow: 1 }}> + <TextField value={searchValue} onChange={handleSearchChange} placeholder="Search CVE or component" size="small" fullWidth🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/customer-portal/webapp/src/components/security/ProductVulnerabilitiesTableHeader.tsx` around lines 85 - 105, The TextField in ProductVulnerabilitiesTableHeader currently sets both fullWidth and sx={{ width: "100%" }} which is redundant; edit the TextField (used with props searchValue and onChange=handleSearchChange) to remove one of them — either drop the fullWidth prop or remove the width from sx (or remove the entire sx prop if no other styles are needed) so only a single width declarative remains.apps/customer-portal/webapp/src/components/dashboard/cases-table/CasesFilters.tsx (1)
29-32: NarrowfilterFieldsto the select-only contract.The prop type accepts every
FilterField, but the render path silently drops anything whosetype !== "select". That makes the exported API broader than the UI can actually render, so unsupported filters can disappear at runtime.♻️ Suggested refactor
import type { JSX } from "react"; import type { SelectChangeEvent } from "@wso2/oxygen-ui"; import type { FilterField } from "@components/common/filter-panel/FilterPopover"; +type SelectFilterField = Omit<FilterField, "type"> & { type: "select" }; + export interface CasesFiltersProps { filters: Record<string, string | number>; - filterFields: FilterField[]; + filterFields: SelectFilterField[]; onFilterChange: (field: string, value: string | number) => void; } @@ - {filterFields.map((field) => { - if (field.type !== "select") return null; - + {filterFields.map((field) => {Also applies to: 54-55
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/customer-portal/webapp/src/components/dashboard/cases-table/CasesFilters.tsx` around lines 29 - 32, The component accepts a broad FilterField union but only renders fields with type === "select", so narrow the prop to the select-only contract: change CasesFiltersProps.filterFields from FilterField[] to the specific SelectFilterField[] (or the union variant representing type: "select") and update any other occurrences of this prop type in the file (the other CasesFiltersProps usages noted) and imports accordingly; ensure onFilterChange signature remains compatible and remove/adjust any code that assumed other FilterField variants are present.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@apps/customer-portal/webapp/src/components/dashboard/cases-table/__tests__/CasesTableHeader.test.tsx`:
- Around line 55-74: Tests render CasesTableHeader but don’t mock react-router
hooks, causing useNavigate/useParams to run without router context; add a module
mock for "react-router" at the top of this test file that returns a stubbed
useNavigate (vi.fn()) and a useParams returning { projectId: "project-1" } (same
pattern as CasesTable.test.tsx), or alternatively wrap each render(...) of
CasesTableHeader in a MemoryRouter so useNavigate/useParams have router context.
In
`@apps/customer-portal/webapp/src/components/dashboard/cases-table/CasesTable.tsx`:
- Around line 228-237: The header's active filter count and the onFilterToggle
logic treat any key in filters as active even when its value is the empty string
(""), so change the logic that computes activeFiltersCount and the toggle branch
to ignore empty/nullable values: use a filtered count like
Object.values(filters).filter(v => v !== "" && v != null).length (or a small
helper such as getActiveFiltersCount) and base CasesTableHeader's
activeFiltersCount and the conditional inside onFilterToggle on that count
instead of Object.keys(filters).length; update references to filters,
onFilterToggle, handleClearFilters, setIsFilterOpen, and CasesTableHeader
accordingly.
In
`@apps/customer-portal/webapp/src/components/project-details/project-overview/project-information/ProjectMetadata.tsx`:
- Around line 116-128: The ProjectMetadata UI renders chips even when the
metadata fetch has failed; update the rendering in ProjectMetadata.tsx to honor
isError alongside isLoading so the three chip sections (the block using
isLoading, the blocks around lines where variables like type, client, and owner
are rendered) show a single error/fallback state when isError is true.
Concretely, change the conditional logic that currently checks isLoading to
instead check if (isLoading || isError) and render a consistent fallback (e.g.,
Skeleton or an error placeholder) when isError is true; references to symbols to
update include isLoading, isError, type, getProjectTypeColor, chipStyle, Tooltip
and Chip so all three sections behave consistently when metadata request fails.
---
Nitpick comments:
In
`@apps/customer-portal/webapp/src/components/dashboard/cases-table/CasesFilters.tsx`:
- Around line 29-32: The component accepts a broad FilterField union but only
renders fields with type === "select", so narrow the prop to the select-only
contract: change CasesFiltersProps.filterFields from FilterField[] to the
specific SelectFilterField[] (or the union variant representing type: "select")
and update any other occurrences of this prop type in the file (the other
CasesFiltersProps usages noted) and imports accordingly; ensure onFilterChange
signature remains compatible and remove/adjust any code that assumed other
FilterField variants are present.
In
`@apps/customer-portal/webapp/src/components/security/ProductVulnerabilitiesTable.tsx`:
- Around line 150-160: The toggle handler uses Object.keys(filters).length to
decide between handleClearFilters() and toggling the filter panel, which
mismatches the activeFiltersCount logic that counts only non-empty
appliedFilters; update the onFilterToggle logic to use the same non-empty-filter
check as activeFiltersCount (i.e., count activeFilterFields.filter(f =>
appliedFilters[f.id]) length or otherwise check appliedFilters values for
non-empty entries) so that it calls handleClearFilters() only when there are
actually applied (non-empty) filters; leave setIsFilterOpen and isFilterOpen
behavior unchanged.
In
`@apps/customer-portal/webapp/src/components/security/ProductVulnerabilitiesTableHeader.tsx`:
- Around line 85-105: The TextField in ProductVulnerabilitiesTableHeader
currently sets both fullWidth and sx={{ width: "100%" }} which is redundant;
edit the TextField (used with props searchValue and onChange=handleSearchChange)
to remove one of them — either drop the fullWidth prop or remove the width from
sx (or remove the entire sx prop if no other styles are needed) so only a single
width declarative remains.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: b28e8354-e758-4786-8ec6-2c0134d5f4bc
📒 Files selected for processing (9)
apps/customer-portal/webapp/src/components/dashboard/cases-table/CasesFilters.tsxapps/customer-portal/webapp/src/components/dashboard/cases-table/CasesTable.tsxapps/customer-portal/webapp/src/components/dashboard/cases-table/CasesTableHeader.tsxapps/customer-portal/webapp/src/components/dashboard/cases-table/__tests__/CasesTableHeader.test.tsxapps/customer-portal/webapp/src/components/project-details/project-overview/project-information/ProjectMetadata.tsxapps/customer-portal/webapp/src/components/security/ProductVulnerabilitiesFilters.tsxapps/customer-portal/webapp/src/components/security/ProductVulnerabilitiesTable.tsxapps/customer-portal/webapp/src/components/security/ProductVulnerabilitiesTableHeader.tsxapps/customer-portal/webapp/src/utils/support.ts
Add a SelectFilterField type to enforce select-only filter fields and remove the runtime type check in CasesFilters. Introduce getActiveFiltersCount in CasesTable to count only non-empty filters and use it for the header badge and clear-toggle logic. Update ProductVulnerabilitiesTable to determine active filters from activeFilterFields/appliedFilters instead of Object.keys(filters). Show skeleton UI when there is an error (isError) as well as while loading in ProjectMetadata. Simplify ProductVulnerabilitiesTableHeader by removing an unnecessary TextField sx wrapper. Update app shell icon from Home to LayoutDashboard. Also add react-router mocks in CasesTableHeader tests to avoid hook errors.
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (6)
apps/customer-portal/webapp/src/components/security/ProductVulnerabilitiesTableHeader.tsx (1)
36-36: Consider makingonFilterTogglerequired.The interface marks
onFilterToggleas optional, but the button at line 108 relies on it without any disabled state or fallback behavior. The context snippet fromProductVulnerabilitiesTable.tsxconfirms this prop is always provided.If the toggle is always required for the button to function, removing the optional marker improves type safety and catches missing props at compile time.
🔧 Suggested fix
- onFilterToggle?: () => void; + onFilterToggle: () => void;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/customer-portal/webapp/src/components/security/ProductVulnerabilitiesTableHeader.tsx` at line 36, The prop onFilterToggle is marked optional but the component ProductVulnerabilitiesTableHeader uses it unguarded (e.g., the filter toggle button), so remove the optional marker and make onFilterToggle required in the component props/interface (change onFilterToggle?: () => void to onFilterToggle: () => void) to enforce callers provide the handler; then run TypeScript checks and update any callers that do not pass onFilterToggle (e.g., ProductVulnerabilitiesTable) to supply the callback if necessary.apps/customer-portal/webapp/src/components/security/ProductVulnerabilitiesTable.tsx (2)
49-54: Consider handling metadata loading and error states.Only
datais destructured fromuseGetVulnerabilitiesMetaData, but per the hook definition (context snippet 1), it returnsisErrorandisLoadingas well. If the metadata fetch fails,severityOptionswill silently be an empty array, and users won't understand why the severity dropdown has no options.Consider destructuring at minimum
isLoadingto show a loading state for the filter dropdown, orisErrorto display feedback when metadata fails to load.Suggested improvement
- const { data: metaData } = useGetVulnerabilitiesMetaData(); + const { data: metaData, isLoading: isMetaLoading, isError: isMetaError } = useGetVulnerabilitiesMetaData();Then pass
isMetaLoadingorisMetaErrortoProductVulnerabilitiesFiltersif needed for UI feedback.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/customer-portal/webapp/src/components/security/ProductVulnerabilitiesTable.tsx` around lines 49 - 54, Destructure isLoading and isError from useGetVulnerabilitiesMetaData (in addition to data) and use them to avoid silently showing an empty severityOptions: when isLoading is true, render or pass an isMetaLoading flag to ProductVulnerabilitiesFilters so the severity dropdown can show a loading state; when isError is true, pass an isMetaError flag (or render an error message) so the UI can display feedback instead of an empty list. Update the severityOptions computation to still safely derive options from metaData but rely on the new flags to control display/feedback in ProductVulnerabilitiesFilters.
150-162: Extract duplicated filter count calculation.The expression
activeFilterFields.filter((f) => appliedFilters[f.id]).lengthis computed twice (lines 151-152 and 161). Consider extracting this to a variable for clarity and to follow DRY principles.Suggested refactor
Compute once and reuse:
+ const activeFiltersCount = activeFilterFields.filter((f) => appliedFilters[f.id]).length; <ProductVulnerabilitiesTableHeader ... onFilterToggle={() => { - if ( - activeFilterFields.filter((f) => appliedFilters[f.id]).length > 0 - ) { + if (activeFiltersCount > 0) { handleClearFilters(); } else { setIsFilterOpen(!isFilterOpen); } }} isFiltersOpen={isFilterOpen} - activeFiltersCount={ - activeFilterFields.filter((f) => appliedFilters[f.id]).length - } + activeFiltersCount={activeFiltersCount} />🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/customer-portal/webapp/src/components/security/ProductVulnerabilitiesTable.tsx` around lines 150 - 162, Extract the duplicated filter-count expression into a single variable (e.g., const activeFilterCount = activeFilterFields.filter(f => appliedFilters[f.id]).length) near where activeFilterFields and appliedFilters are available, then replace both occurrences used in the onFilterToggle callback and the activeFiltersCount prop with that variable; ensure the onFilterToggle logic still calls handleClearFilters() when activeFilterCount > 0 and toggles isFilterOpen via setIsFilterOpen otherwise, and keep isFiltersOpen prop unchanged.apps/customer-portal/webapp/src/components/project-details/project-overview/project-information/ProjectMetadata.tsx (1)
119-127: Consider guarding against empty tooltip titles.When
type?.labelis undefined/null, the Tooltip title becomes an empty string, which may render an awkward empty tooltip bubble on hover. The same applies tosupportTierandslaStatusat lines 151 and 183.You could skip the Tooltip wrapper when the value is empty, or this may be acceptable if these values are guaranteed by the API.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/customer-portal/webapp/src/components/project-details/project-overview/project-information/ProjectMetadata.tsx` around lines 119 - 127, The Tooltip wrappers around the Chip components (e.g., the Tooltip around the Chip using type?.label with getProjectTypeColor) can render an awkward empty bubble when the title is empty; update the render logic to only wrap the Chip with Tooltip when the corresponding value is non-empty (e.g., type?.label, supportTier?.label, slaStatus?.label) — otherwise render the Chip alone — so check those values before returning the Tooltip and use the existing Chip props (label, size, variant, color, sx) unchanged when not wrapped.apps/customer-portal/webapp/src/components/dashboard/cases-table/__tests__/CasesTableHeader.test.tsx (1)
79-82: Exercise the reset branch, not just the label.This only proves the copy change. Add a click assertion so the
activeFiltersCount > 0path also verifiesonFilterToggleis still wired when the button switches toReset Filters.🧪 Suggested test update
it("should show Reset Filters when filters are active", () => { - render(<CasesTableHeader {...mockProps} activeFiltersCount={1} />); + const onFilterToggle = vi.fn(); + render( + <CasesTableHeader + {...mockProps} + activeFiltersCount={1} + onFilterToggle={onFilterToggle} + />, + ); expect(screen.getByText("Reset Filters")).toBeInTheDocument(); + fireEvent.click(screen.getByText("Reset Filters")); + expect(onFilterToggle).toHaveBeenCalled(); });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/customer-portal/webapp/src/components/dashboard/cases-table/__tests__/CasesTableHeader.test.tsx` around lines 79 - 82, Render CasesTableHeader with activeFiltersCount={1} and a jest.fn() for onFilterToggle (from mockProps), find the "Reset Filters" button via screen.getByText("Reset Filters"), simulate a click (userEvent.click or fireEvent.click) on that element, and assert that the onFilterToggle mock was called to verify the reset branch wiring in the CasesTableHeader component.apps/customer-portal/webapp/src/components/dashboard/cases-table/CasesTable.tsx (1)
25-27: Move the shared filter-field type out ofFilterPopover.
CasesTablenow rendersCasesFilters, but its field contract still comes from the old popover module. That keeps the replacement coupled to the component it is displacing and makes the eventualFilterPopovercleanup harder.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/customer-portal/webapp/src/components/dashboard/cases-table/CasesTable.tsx` around lines 25 - 27, The FilterField type is still imported from FilterPopover, coupling CasesTable/CasesFilters to the old popover; create or move the FilterField type to a shared location (e.g., a new types module for filters) and update CasesTable and CasesFilters to import FilterField from that shared module instead of "@components/common/filter-panel/FilterPopover"; also update the FilterPopover file to import the type from the new shared module (and remove its own export) so all components reference the single shared type (symbols to change: FilterField import, CasesTable, CasesFilters, and FilterPopover).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@apps/customer-portal/webapp/src/components/dashboard/cases-table/CasesTable.tsx`:
- Around line 232-241: The test's sibling mock still destructures the old header
callbacks (onFilterClick, onRemoveFilter, onUpdateFilter, onClearAll) but the
real CasesTable now renders CasesTableHeader with props activeFiltersCount,
isFiltersOpen, and onFilterToggle; update the mock in CasesTable.test.tsx to
accept and expose those three props instead, remove references to the old
callbacks, and rewrite assertions to exercise the new flow (simulate calling
onFilterToggle and assert isFiltersOpen behavior and the new reset behavior for
CasesFilters/reset flow) while keeping any checks for activeFiltersCount where
applicable.
In
`@apps/customer-portal/webapp/src/components/project-details/project-overview/project-information/ProjectMetadata.tsx`:
- Around line 53-62: The sx object uses an invalid key `font: "caption"`; update
the MUI sx usage to use `typography: "caption"` instead. Replace `font:
"caption"` with `typography: "caption"` in the chipStyle object inside
ProjectMetadata (symbol: chipStyle in ProjectMetadata.tsx) and make the same
change where `font: "caption"` is used in ProjectName.tsx (look for the
component or variable applying that sx). Ensure you do not alter other CSS
properties and keep the nested `& .MuiChip-label` block intact.
---
Nitpick comments:
In
`@apps/customer-portal/webapp/src/components/dashboard/cases-table/__tests__/CasesTableHeader.test.tsx`:
- Around line 79-82: Render CasesTableHeader with activeFiltersCount={1} and a
jest.fn() for onFilterToggle (from mockProps), find the "Reset Filters" button
via screen.getByText("Reset Filters"), simulate a click (userEvent.click or
fireEvent.click) on that element, and assert that the onFilterToggle mock was
called to verify the reset branch wiring in the CasesTableHeader component.
In
`@apps/customer-portal/webapp/src/components/dashboard/cases-table/CasesTable.tsx`:
- Around line 25-27: The FilterField type is still imported from FilterPopover,
coupling CasesTable/CasesFilters to the old popover; create or move the
FilterField type to a shared location (e.g., a new types module for filters) and
update CasesTable and CasesFilters to import FilterField from that shared module
instead of "@components/common/filter-panel/FilterPopover"; also update the
FilterPopover file to import the type from the new shared module (and remove its
own export) so all components reference the single shared type (symbols to
change: FilterField import, CasesTable, CasesFilters, and FilterPopover).
In
`@apps/customer-portal/webapp/src/components/project-details/project-overview/project-information/ProjectMetadata.tsx`:
- Around line 119-127: The Tooltip wrappers around the Chip components (e.g.,
the Tooltip around the Chip using type?.label with getProjectTypeColor) can
render an awkward empty bubble when the title is empty; update the render logic
to only wrap the Chip with Tooltip when the corresponding value is non-empty
(e.g., type?.label, supportTier?.label, slaStatus?.label) — otherwise render the
Chip alone — so check those values before returning the Tooltip and use the
existing Chip props (label, size, variant, color, sx) unchanged when not
wrapped.
In
`@apps/customer-portal/webapp/src/components/security/ProductVulnerabilitiesTable.tsx`:
- Around line 49-54: Destructure isLoading and isError from
useGetVulnerabilitiesMetaData (in addition to data) and use them to avoid
silently showing an empty severityOptions: when isLoading is true, render or
pass an isMetaLoading flag to ProductVulnerabilitiesFilters so the severity
dropdown can show a loading state; when isError is true, pass an isMetaError
flag (or render an error message) so the UI can display feedback instead of an
empty list. Update the severityOptions computation to still safely derive
options from metaData but rely on the new flags to control display/feedback in
ProductVulnerabilitiesFilters.
- Around line 150-162: Extract the duplicated filter-count expression into a
single variable (e.g., const activeFilterCount = activeFilterFields.filter(f =>
appliedFilters[f.id]).length) near where activeFilterFields and appliedFilters
are available, then replace both occurrences used in the onFilterToggle callback
and the activeFiltersCount prop with that variable; ensure the onFilterToggle
logic still calls handleClearFilters() when activeFilterCount > 0 and toggles
isFilterOpen via setIsFilterOpen otherwise, and keep isFiltersOpen prop
unchanged.
In
`@apps/customer-portal/webapp/src/components/security/ProductVulnerabilitiesTableHeader.tsx`:
- Line 36: The prop onFilterToggle is marked optional but the component
ProductVulnerabilitiesTableHeader uses it unguarded (e.g., the filter toggle
button), so remove the optional marker and make onFilterToggle required in the
component props/interface (change onFilterToggle?: () => void to onFilterToggle:
() => void) to enforce callers provide the handler; then run TypeScript checks
and update any callers that do not pass onFilterToggle (e.g.,
ProductVulnerabilitiesTable) to supply the callback if necessary.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: ebe67bbc-53b0-4ba5-8df5-c2a50a23c6dc
📒 Files selected for processing (7)
apps/customer-portal/webapp/src/components/dashboard/cases-table/CasesFilters.tsxapps/customer-portal/webapp/src/components/dashboard/cases-table/CasesTable.tsxapps/customer-portal/webapp/src/components/dashboard/cases-table/__tests__/CasesTableHeader.test.tsxapps/customer-portal/webapp/src/components/project-details/project-overview/project-information/ProjectMetadata.tsxapps/customer-portal/webapp/src/components/security/ProductVulnerabilitiesTable.tsxapps/customer-portal/webapp/src/components/security/ProductVulnerabilitiesTableHeader.tsxapps/customer-portal/webapp/src/constants/appLayoutConstants.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/customer-portal/webapp/src/components/dashboard/cases-table/CasesFilters.tsx
Route security report creation to a dedicated path and tighten component props. - SecurityReportAnalysis: navigate to /:projectId/support/security-report/create instead of using the query param + state. - CreateCasePage: detect security report creation by checking the pathname for "security-report" in addition to the existing query param so skipChat logic still applies. - ProductVulnerabilitiesTableHeader: make onFilterToggle a required prop (remove optional).
Add a new nested route for security-report/create and update GetHelpDropdown navigation to use the new path. Apply minor typing cast for dynamicFilterFields in CasesTable. Replace invalid sx font prop with typography and improve ProjectMetadata/ProjectName handling: show Chips without Tooltips when labels are absent and use safe color helpers. Memoize and reuse activeFilterCount in ProductVulnerabilitiesTable to avoid repeated calculations and simplify filter toggle logic.
f66463d
into
wso2-open-operations:customer-portal-milestone-1
Description
This pull request introduces a significant refactor and user experience improvement for the cases table and filtering UI in the customer portal. The main focus is on replacing the popover-based filter panel with an inline dropdown filter experience, simplifying the header actions, and improving the layout and accessibility of project metadata chips.
Key changes include:
Cases Table Filtering and Header Refactor:
FilterPopoverandActiveFilters) with a new inline dropdown filter component,CasesFilters, for a more intuitive and streamlined filtering experience. The filter controls are now displayed directly below the table header when activated. [1] [2] [3] [4]CasesTableHeadercomponent to remove the "All" button and the complex filter state management props. The header now features a single "Filters" button (which toggles the filter dropdown or resets filters), and a "Create" button. The filter button changes to "Reset Filters" when filters are active. [1] [2]Project Metadata Layout and Accessibility:
ProjectMetadatacomponent by distributing columns more evenly and aligning content for better readability. [1] [2]Testing Updates:
CasesTableHeaderto reflect the new props and behaviors, including the removal of the "All" button and the new filter toggle logic. [1] [2]Cases Table Filtering and Header Refactor:
CasesFilterscomponent to replace the popover filter UI with inline dropdowns, and removed related legacy filter management code fromCasesTable. [1] [2] [3] [4]CasesTableHeaderto simplify the filter and create actions, removed unused props, and updated the filter button to toggle/reset filters as appropriate. [1] [2]Project Metadata Layout and Accessibility:
Testing Updates:
CasesTableHeadertests to match the new props and behaviors, removing tests for deleted buttons and adding tests for the new filter toggle logic. [1] [2]