All checks were successful
Trigger Cloudarix Deploy / call-webhook (push) Successful in 2s
✨ New Features - Advanced data table with TanStack Table v8 + Server Actions - Server-side pagination (10/25/50/100 rows per page) - Multi-column sorting with visual indicators - Column management (show/hide, resize) persisted to localStorage - URL state synchronization for shareable filtered views - Sticky header with compact/comfortable density modes 📦 Components Added - PolicyTableV2.tsx - Main table with TanStack integration - PolicyTableColumns.tsx - 7 column definitions with sorting - PolicyTablePagination.tsx - Pagination controls - PolicyTableToolbar.tsx - Density toggle + column visibility menu - ColumnVisibilityMenu.tsx - Show/hide columns dropdown 🔧 Hooks Added - usePolicyTable.ts - TanStack Table initialization - useURLState.ts - URL query param sync with nuqs - useTablePreferences.ts - localStorage persistence 🎨 Server Actions Updated - getPolicySettingsV2 - Pagination + sorting + filtering + Zod validation - exportPolicySettingsCSV - Server-side CSV generation (max 5000 rows) 📚 Documentation Added - Intune Migration Guide (1400+ lines) - Reverse engineering strategy - Intune Reference Version tracking - Tasks completed: 22/62 (Phase 1-3) ✅ Zero TypeScript compilation errors ✅ All MVP success criteria met (pagination, sorting, column management) ✅ Ready for Phase 4-7 (filtering, export, detail view, polish) Refs: specs/004-policy-explorer-v2/tasks.md
82 lines
2.4 KiB
TypeScript
82 lines
2.4 KiB
TypeScript
/**
|
|
* ColumnVisibilityMenu
|
|
*
|
|
* Dropdown menu to show/hide table columns.
|
|
* Integrates with TanStack Table column visibility state.
|
|
*
|
|
* Features:
|
|
* - Checkbox list of all columns
|
|
* - Hide/show individual columns
|
|
* - "Reset to default" button
|
|
* - Persisted via localStorage
|
|
*/
|
|
|
|
'use client';
|
|
|
|
import { Button } from '@/components/ui/button';
|
|
import {
|
|
DropdownMenu,
|
|
DropdownMenuCheckboxItem,
|
|
DropdownMenuContent,
|
|
DropdownMenuLabel,
|
|
DropdownMenuSeparator,
|
|
DropdownMenuTrigger,
|
|
} from '@/components/ui/dropdown-menu';
|
|
import { Columns3 } from 'lucide-react';
|
|
import type { Table } from '@tanstack/react-table';
|
|
import type { PolicySettingRow } from '@/lib/types/policy-table';
|
|
|
|
interface ColumnVisibilityMenuProps {
|
|
table: Table<PolicySettingRow>;
|
|
}
|
|
|
|
export function ColumnVisibilityMenu({ table }: ColumnVisibilityMenuProps) {
|
|
const columns = table
|
|
.getAllColumns()
|
|
.filter((column) => column.getCanHide());
|
|
|
|
const hiddenCount = columns.filter((column) => !column.getIsVisible()).length;
|
|
|
|
return (
|
|
<DropdownMenu>
|
|
<DropdownMenuTrigger asChild>
|
|
<Button variant="outline" size="sm" className="ml-auto h-8 lg:flex">
|
|
<Columns3 className="mr-2 h-4 w-4" />
|
|
Columns
|
|
{hiddenCount > 0 && (
|
|
<span className="ml-1 rounded-full bg-primary px-2 py-0.5 text-xs text-primary-foreground">
|
|
{hiddenCount}
|
|
</span>
|
|
)}
|
|
</Button>
|
|
</DropdownMenuTrigger>
|
|
<DropdownMenuContent align="end" className="w-[180px]">
|
|
<DropdownMenuLabel>Toggle columns</DropdownMenuLabel>
|
|
<DropdownMenuSeparator />
|
|
{columns.map((column) => {
|
|
return (
|
|
<DropdownMenuCheckboxItem
|
|
key={column.id}
|
|
className="capitalize"
|
|
checked={column.getIsVisible()}
|
|
onCheckedChange={(value) => column.toggleVisibility(!!value)}
|
|
>
|
|
{/* Format column ID to human-readable label */}
|
|
{column.id.replace(/([A-Z])/g, ' $1').trim()}
|
|
</DropdownMenuCheckboxItem>
|
|
);
|
|
})}
|
|
<DropdownMenuSeparator />
|
|
<Button
|
|
variant="ghost"
|
|
size="sm"
|
|
className="w-full justify-start"
|
|
onClick={() => table.resetColumnVisibility()}
|
|
>
|
|
Reset to default
|
|
</Button>
|
|
</DropdownMenuContent>
|
|
</DropdownMenu>
|
|
);
|
|
}
|