tenantpilot/components/policy-explorer/PolicyTableToolbar.tsx
Ahmed Darrazi c59400cd48
All checks were successful
Trigger Cloudarix Deploy / call-webhook (push) Successful in 2s
feat(policy-explorer-v2): implement Phase 4 - Enhanced Filtering
 New Features (Tasks T023-T028)
- PolicyTypeFilter component with multi-select checkboxes
- 8 common Intune policy types (deviceConfiguration, compliancePolicy, etc.)
- Active filter badges with individual remove buttons
- 'Clear All Filters' button when filters active
- Filter count badge in dropdown trigger

🔧 Updates
- PolicyTableToolbar now accepts filter props
- PolicyExplorerV2Client connects filters to URL state
- Filters sync with URL for shareable links
- Filter state triggers data refetch automatically

📦 Dependencies
- Added shadcn DropdownMenu component

 Zero TypeScript compilation errors
 All Phase 4 tasks complete (T023-T028)
 Ready for Phase 5 (CSV Export)

Refs: specs/004-policy-explorer-v2/tasks.md Phase 4
2025-12-10 00:28:35 +01:00

129 lines
3.7 KiB
TypeScript

/**
* PolicyTableToolbar
*
* Toolbar above the data table with:
* - Column visibility menu
* - Density mode toggle (compact/comfortable)
* - Export button (added later in Phase 5)
* - Filter controls (added later in Phase 4)
*/
'use client';
import { Button } from '@/components/ui/button';
import { ColumnVisibilityMenu } from './ColumnVisibilityMenu';
import { PolicyTypeFilter } from './PolicyTypeFilter';
import { LayoutList, LayoutGrid, X } from 'lucide-react';
import { Badge } from '@/components/ui/badge';
import type { Table } from '@tanstack/react-table';
import type { PolicySettingRow } from '@/lib/types/policy-table';
interface PolicyTableToolbarProps {
table: Table<PolicySettingRow>;
density: 'compact' | 'comfortable';
onDensityChange: (density: 'compact' | 'comfortable') => void;
// Filter props
selectedPolicyTypes: string[];
onSelectedPolicyTypesChange: (types: string[]) => void;
searchQuery: string;
onSearchQueryChange: (query: string) => void;
}
export function PolicyTableToolbar({
table,
density,
onDensityChange,
selectedPolicyTypes,
onSelectedPolicyTypesChange,
searchQuery,
onSearchQueryChange,
}: PolicyTableToolbarProps) {
const hasActiveFilters = selectedPolicyTypes.length > 0 || searchQuery.length > 0;
const handleClearFilters = () => {
onSelectedPolicyTypesChange([]);
onSearchQueryChange('');
};
return (
<div className="flex items-center justify-between">
<div className="flex flex-1 items-center space-x-2">
{/* Policy Type Filter */}
<PolicyTypeFilter
selectedTypes={selectedPolicyTypes}
onSelectedTypesChange={onSelectedPolicyTypesChange}
/>
{/* Active Filter Badges */}
{selectedPolicyTypes.length > 0 && (
<div className="flex items-center gap-1">
{selectedPolicyTypes.slice(0, 2).map((type) => (
<Badge
key={type}
variant="secondary"
className="h-6 px-2 text-xs"
>
{type}
<button
onClick={() =>
onSelectedPolicyTypesChange(
selectedPolicyTypes.filter((t) => t !== type)
)
}
className="ml-1 hover:text-destructive"
>
<X className="h-3 w-3" />
</button>
</Badge>
))}
{selectedPolicyTypes.length > 2 && (
<Badge variant="secondary" className="h-6 px-2 text-xs">
+{selectedPolicyTypes.length - 2} more
</Badge>
)}
</div>
)}
{/* Clear All Filters Button */}
{hasActiveFilters && (
<Button
variant="ghost"
size="sm"
onClick={handleClearFilters}
className="h-8 px-2 lg:px-3"
>
Clear filters
</Button>
)}
</div>
<div className="flex items-center space-x-2">
{/* Density Toggle */}
<Button
variant="outline"
size="sm"
className="h-8"
onClick={() => onDensityChange(density === 'compact' ? 'comfortable' : 'compact')}
>
{density === 'compact' ? (
<>
<LayoutGrid className="mr-2 h-4 w-4" />
Comfortable
</>
) : (
<>
<LayoutList className="mr-2 h-4 w-4" />
Compact
</>
)}
</Button>
{/* Column Visibility Menu */}
<ColumnVisibilityMenu table={table} />
{/* Export button will be added here in Phase 5 */}
</div>
</div>
);
}