diff --git a/ui/apps/platform/src/Containers/Violations/ViolationsTablePage.tsx b/ui/apps/platform/src/Containers/Violations/ViolationsTablePage.tsx index 49a3f873d16a5..9b3c86a394f66 100644 --- a/ui/apps/platform/src/Containers/Violations/ViolationsTablePage.tsx +++ b/ui/apps/platform/src/Containers/Violations/ViolationsTablePage.tsx @@ -167,6 +167,11 @@ function ViolationsTablePage(): ReactElement { setSearchFilter(updateSearchFilter(searchFilter, payload)); }; + useEffectAfterFirstRender(() => { + setSearchFilter({}); + setPage(1); + }, [filteredWorkflowView, setSearchFilter, setPage]); + useEffectAfterFirstRender(() => { if (hasExecutableFilter && !isViewFiltered) { // If the user applies a filter to a previously unfiltered table, return to page 1 @@ -350,6 +355,7 @@ function ViolationsTablePage(): ReactElement { onFilterChange={setSearchFilter} onSearch={onSearch} additionalContextFilter={additionalContextFilter} + filteredWorkflowView={filteredWorkflowView} hasActiveViolations={selectedViolationStateTab === 'ACTIVE'} isTableDataUpdating={isTableDataUpdating} /> diff --git a/ui/apps/platform/src/Containers/Violations/ViolationsTablePanel.tsx b/ui/apps/platform/src/Containers/Violations/ViolationsTablePanel.tsx index b09c137bead55..855b240642637 100644 --- a/ui/apps/platform/src/Containers/Violations/ViolationsTablePanel.tsx +++ b/ui/apps/platform/src/Containers/Violations/ViolationsTablePanel.tsx @@ -36,6 +36,7 @@ import type { ListAlert } from 'types/alert.proto'; import { getAxiosErrorMessage } from 'utils/responseErrorUtils'; import type { SearchFilter } from 'types/search'; import type { OnSearchCallback } from 'Components/CompoundSearchFilter/types'; +import type { FilteredWorkflowView } from 'Components/FilteredWorkflowViewSelector/types'; import ResolveConfirmation from './Modals/ResolveConfirmation'; import ExcludeConfirmation from './Modals/ExcludeConfirmation'; import ViolationsTableSearchFilter from './ViolationsTableSearchFilter'; @@ -81,6 +82,7 @@ type ViolationsTablePanelProps = { onFilterChange: (newFilter: SearchFilter) => void; onSearch: OnSearchCallback; additionalContextFilter: SearchFilter; + filteredWorkflowView: FilteredWorkflowView; hasActiveViolations: boolean; isTableDataUpdating: boolean; }; @@ -100,6 +102,7 @@ function ViolationsTablePanel({ onFilterChange, onSearch, additionalContextFilter, + filteredWorkflowView, hasActiveViolations, isTableDataUpdating, }: ViolationsTablePanelProps): ReactElement { @@ -240,6 +243,7 @@ function ViolationsTablePanel({ onFilterChange={onFilterChange} onSearch={onSearch} additionalContextFilter={additionalContextFilter} + filteredWorkflowView={filteredWorkflowView} /> diff --git a/ui/apps/platform/src/Containers/Violations/ViolationsTableSearchFilter.tsx b/ui/apps/platform/src/Containers/Violations/ViolationsTableSearchFilter.tsx index 82cb465a51466..c75333421079d 100644 --- a/ui/apps/platform/src/Containers/Violations/ViolationsTableSearchFilter.tsx +++ b/ui/apps/platform/src/Containers/Violations/ViolationsTableSearchFilter.tsx @@ -3,96 +3,19 @@ import { Toolbar, ToolbarContent, ToolbarGroup, ToolbarItem } from '@patternfly/ import type { SearchFilter } from 'types/search'; import useAnalytics from 'hooks/useAnalytics'; import { createFilterTracker } from 'utils/analyticsEventTracking'; -import type { - CompoundSearchFilterConfig, - OnSearchCallback, -} from 'Components/CompoundSearchFilter/types'; +import type { OnSearchCallback } from 'Components/CompoundSearchFilter/types'; import CompoundSearchFilter from 'Components/CompoundSearchFilter/components/CompoundSearchFilter'; import CompoundSearchFilterLabels from 'Components/CompoundSearchFilter/components/CompoundSearchFilterLabels'; -import { - Category as PolicyCategory, - LifecycleStage as PolicyLifecycleStage, - Name as PolicyName, - Severity as PolicySeverity, -} from 'Components/CompoundSearchFilter/attributes/policy'; -import { - EntityType as AlertEntityType, - ViolationTime as AlertViolationTime, -} from 'Components/CompoundSearchFilter/attributes/alert'; -import { - clusterIdAttribute, - clusterLabelAttribute, - clusterNameAttribute, -} from 'Components/CompoundSearchFilter/attributes/cluster'; -import { - Annotation as NamespaceAnnotation, - ID as NamespaceID, - Label as NamespaceLabel, - Name as NamespaceName, -} from 'Components/CompoundSearchFilter/attributes/namespace'; -import { - Annotation as DeploymentAnnotation, - ID as DeploymentID, - Inactive as DeploymentInactive, - Label as DeploymentLabel, - Name as DeploymentName, -} from 'Components/CompoundSearchFilter/attributes/deployment'; -import { Name as ResourceName } from 'Components/CompoundSearchFilter/attributes/resource'; -import { - Annotation as NodeAnnotation, - Label as NodeLabel, - Name as NodeName, -} from 'Components/CompoundSearchFilter/attributes/node'; +import type { FilteredWorkflowView } from 'Components/FilteredWorkflowViewSelector/types'; -const searchFilterConfig: CompoundSearchFilterConfig = [ - { - displayName: 'Cluster', - searchCategory: 'ALERTS', - attributes: [clusterIdAttribute, clusterLabelAttribute, clusterNameAttribute], - }, - { - displayName: 'Deployment', - searchCategory: 'ALERTS', - attributes: [ - DeploymentAnnotation, - DeploymentID, - DeploymentLabel, - DeploymentName, - DeploymentInactive, // Status - ], - }, - { - displayName: 'Namespace', - searchCategory: 'ALERTS', - attributes: [NamespaceAnnotation, NamespaceID, NamespaceLabel, NamespaceName], - }, - { - displayName: 'Policy', - searchCategory: 'ALERTS', - attributes: [PolicyCategory, PolicyLifecycleStage, PolicyName, PolicySeverity], - }, - { - displayName: 'Policy violation', - searchCategory: 'ALERTS', - attributes: [AlertViolationTime, AlertEntityType], // non-alphabetical because no Name - }, - { - displayName: 'Node', - searchCategory: 'ALERTS', - attributes: [NodeAnnotation, NodeLabel, NodeName], - }, - { - displayName: 'Resource', - searchCategory: 'ALERTS', - attributes: [ResourceName], - }, -]; +import { getSearchFilterConfig } from './ViolationsTableSearchFilter.utils'; export type ViolationsTableSearchFilterProps = { searchFilter: SearchFilter; onFilterChange: (newFilter: SearchFilter) => void; onSearch: OnSearchCallback; additionalContextFilter: SearchFilter; + filteredWorkflowView: FilteredWorkflowView; }; function ViolationsTableSearchFilter({ @@ -100,10 +23,13 @@ function ViolationsTableSearchFilter({ onFilterChange, onSearch, additionalContextFilter, + filteredWorkflowView, }: ViolationsTableSearchFilterProps) { const { analyticsTrack } = useAnalytics(); const trackAppliedFilter = createFilterTracker(analyticsTrack); + const searchFilterConfig = getSearchFilterConfig(filteredWorkflowView); + const onSearchHandler: OnSearchCallback = (payload) => { onSearch(payload); trackAppliedFilter('Policy Violations Filter Applied', payload); diff --git a/ui/apps/platform/src/Containers/Violations/ViolationsTableSearchFilter.utils.test.ts b/ui/apps/platform/src/Containers/Violations/ViolationsTableSearchFilter.utils.test.ts new file mode 100644 index 0000000000000..20cc10b6c1b09 --- /dev/null +++ b/ui/apps/platform/src/Containers/Violations/ViolationsTableSearchFilter.utils.test.ts @@ -0,0 +1,45 @@ +import { getSearchFilterConfig } from './ViolationsTableSearchFilter.utils'; + +describe('getSearchFilterConfig', () => { + it('should return exactly the expected entities for "Applications view"', () => { + const config = getSearchFilterConfig('Applications view'); + const names = config.map((e) => e.displayName).sort(); + + expect(names).toEqual( + ['Cluster', 'Deployment', 'Namespace', 'Policy', 'Policy violation'].sort() + ); + }); + + it('should return exactly the expected entities for "Platform view"', () => { + const config = getSearchFilterConfig('Platform view'); + const names = config.map((e) => e.displayName).sort(); + + expect(names).toEqual( + ['Cluster', 'Deployment', 'Namespace', 'Policy', 'Policy violation'].sort() + ); + }); + + it('should return exactly the expected entities for "Node view"', () => { + const config = getSearchFilterConfig('Node view'); + const names = config.map((e) => e.displayName).sort(); + + expect(names).toEqual(['Cluster', 'Node', 'Policy', 'Policy violation'].sort()); + }); + + it('should return all entities for "Full view"', () => { + const config = getSearchFilterConfig('Full view'); + const names = config.map((e) => e.displayName).sort(); + + expect(names).toEqual( + [ + 'Cluster', + 'Deployment', + 'Namespace', + 'Node', + 'Policy', + 'Policy violation', + 'Resource', + ].sort() + ); + }); +}); diff --git a/ui/apps/platform/src/Containers/Violations/ViolationsTableSearchFilter.utils.ts b/ui/apps/platform/src/Containers/Violations/ViolationsTableSearchFilter.utils.ts new file mode 100644 index 0000000000000..49aab95c4fe31 --- /dev/null +++ b/ui/apps/platform/src/Containers/Violations/ViolationsTableSearchFilter.utils.ts @@ -0,0 +1,108 @@ +import type { CompoundSearchFilterConfig } from 'Components/CompoundSearchFilter/types'; +import { + Category as PolicyCategory, + LifecycleStage as PolicyLifecycleStage, + Name as PolicyName, + Severity as PolicySeverity, +} from 'Components/CompoundSearchFilter/attributes/policy'; +import { + EntityType as AlertEntityType, + ViolationTime as AlertViolationTime, +} from 'Components/CompoundSearchFilter/attributes/alert'; +import { + clusterIdAttribute, + clusterLabelAttribute, + clusterNameAttribute, +} from 'Components/CompoundSearchFilter/attributes/cluster'; +import { + Annotation as NamespaceAnnotation, + ID as NamespaceID, + Label as NamespaceLabel, + Name as NamespaceName, +} from 'Components/CompoundSearchFilter/attributes/namespace'; +import { + Annotation as DeploymentAnnotation, + ID as DeploymentID, + Inactive as DeploymentInactive, + Label as DeploymentLabel, + Name as DeploymentName, +} from 'Components/CompoundSearchFilter/attributes/deployment'; +import { Name as ResourceName } from 'Components/CompoundSearchFilter/attributes/resource'; +import { + Annotation as NodeAnnotation, + Label as NodeLabel, + Name as NodeName, +} from 'Components/CompoundSearchFilter/attributes/node'; +import type { FilteredWorkflowView } from 'Components/FilteredWorkflowViewSelector/types'; + +type ViolationSearchEntityName = + | 'Cluster' + | 'Deployment' + | 'Namespace' + | 'Node' + | 'Policy' + | 'Policy violation' + | 'Resource'; + +const allSearchFilterEntities: CompoundSearchFilterConfig = [ + { + displayName: 'Cluster', + searchCategory: 'ALERTS', + attributes: [clusterIdAttribute, clusterLabelAttribute, clusterNameAttribute], + }, + { + displayName: 'Deployment', + searchCategory: 'ALERTS', + attributes: [ + DeploymentAnnotation, + DeploymentID, + DeploymentLabel, + DeploymentName, + DeploymentInactive, // Status + ], + }, + { + displayName: 'Namespace', + searchCategory: 'ALERTS', + attributes: [NamespaceAnnotation, NamespaceID, NamespaceLabel, NamespaceName], + }, + { + displayName: 'Node', + searchCategory: 'ALERTS', + attributes: [NodeAnnotation, NodeLabel, NodeName], + }, + { + displayName: 'Policy', + searchCategory: 'ALERTS', + attributes: [PolicyCategory, PolicyLifecycleStage, PolicyName, PolicySeverity], + }, + { + displayName: 'Policy violation', + searchCategory: 'ALERTS', + attributes: [AlertViolationTime, AlertEntityType], // non-alphabetical because no Name + }, + { + displayName: 'Resource', + searchCategory: 'ALERTS', + attributes: [ResourceName], + }, +]; + +const allowedEntitiesByView: Record = { + 'Applications view': ['Cluster', 'Deployment', 'Namespace', 'Policy', 'Policy violation'], + 'Platform view': ['Cluster', 'Deployment', 'Namespace', 'Policy', 'Policy violation'], + 'Node view': ['Cluster', 'Policy', 'Policy violation', 'Node'], + 'Full view': [], +}; + +export function getSearchFilterConfig( + filteredWorkflowView: FilteredWorkflowView +): CompoundSearchFilterConfig { + const allowed = allowedEntitiesByView[filteredWorkflowView]; + if (allowed.length === 0) { + return allSearchFilterEntities; + } + return allSearchFilterEntities.filter((entity) => + (allowed as readonly string[]).includes(entity.displayName) + ); +}