tenantpilot/lib/db/schema/policySettings.ts
Ahmed Darrazi 41e80b6c0c
All checks were successful
Trigger Cloudarix Deploy / call-webhook (push) Successful in 2s
feat(policy-explorer-v2): implement MVP Phase 1-3
 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
2025-12-10 00:18:05 +01:00

63 lines
1.7 KiB
TypeScript

import { pgTable, text, timestamp, index, unique } from 'drizzle-orm/pg-core';
import { createId } from '@paralleldrive/cuid2';
export const POLICY_TYPES = [
'deviceConfiguration',
'compliancePolicy',
'windowsUpdateForBusiness',
'endpointSecurity',
'appConfiguration',
'enrollmentRestriction',
'conditionalAccess',
] as const;
export type PolicyType = (typeof POLICY_TYPES)[number];
export const policySettings = pgTable(
'policy_settings',
{
id: text('id')
.primaryKey()
.$defaultFn(() => createId()),
tenantId: text('tenant_id').notNull(),
policyName: text('policy_name').notNull(),
policyType: text('policy_type').notNull(),
settingName: text('setting_name').notNull(),
settingValue: text('setting_value').notNull(),
graphPolicyId: text('graph_policy_id').notNull(),
lastSyncedAt: timestamp('last_synced_at', { mode: 'date' })
.defaultNow()
.notNull(),
createdAt: timestamp('created_at', { mode: 'date' }).defaultNow().notNull(),
},
(table) => ({
tenantIdIdx: index('policy_settings_tenant_id_idx').on(table.tenantId),
settingNameIdx: index('policy_settings_setting_name_idx').on(
table.settingName
),
// Composite index for sorting performance (pagination + sorting queries)
sortingIdx: index('policy_settings_sorting_idx').on(
table.tenantId,
table.policyType,
table.settingName
),
// Unique constraint for ON CONFLICT upsert
upsertUnique: unique('policy_settings_upsert_unique').on(
table.tenantId,
table.graphPolicyId,
table.settingName
),
})
);
export type PolicySetting = typeof policySettings.$inferSelect;
export type NewPolicySetting = typeof policySettings.$inferInsert;