- Found {results.length} result{results.length !== 1 ? 's' : ''} -
-diff --git a/app/(app)/search/PolicyExplorerClient.tsx b/app/(app)/search/PolicyExplorerClient.tsx
new file mode 100644
index 0000000..afffef9
--- /dev/null
+++ b/app/(app)/search/PolicyExplorerClient.tsx
@@ -0,0 +1,37 @@
+'use client';
+
+import { useState } from 'react';
+import { PolicySearchContainer } from '@/components/policy-explorer/PolicySearchContainer';
+import { PolicyDetailSheet } from '@/components/policy-explorer/PolicyDetailSheet';
+import type { PolicySettingSearchResult } from '@/lib/actions/policySettings';
+
+interface PolicyExplorerClientProps {
+ initialPolicies: PolicySettingSearchResult[];
+}
+
+export function PolicyExplorerClient({
+ initialPolicies,
+}: PolicyExplorerClientProps) {
+ const [selectedPolicy, setSelectedPolicy] = useState
- Found {results.length} result{results.length !== 1 ? 's' : ''}
- {policy.policyName}
+ {policy.policyType.replace(/([A-Z])/g, ' $1').trim()}
+ {policy.settingName}
+ {displayValue}
+
+ {formatDistanceToNow(new Date(policy.lastSyncedAt), {
+ addSuffix: true,
+ locale: de,
+ })}
+
+ {new Date(policy.lastSyncedAt).toLocaleString('de-DE')}
+ Keine Policies gefunden - Starten Sie einen Sync
+ Policy Name
+
+
+ Policy Type
+
+
+ Setting Name
+
+
+ Setting Value
+
+ {isJson ? (
+
+
+ ) : (
+ {displayValue}
+
+ Last Synced
+
+
+
+
- Enter a search term to find policy settings + No policy settings available. Trigger a sync to import policies from Intune.
)} diff --git a/components/ui/badge.tsx b/components/ui/badge.tsx new file mode 100644 index 0000000..f000e3e --- /dev/null +++ b/components/ui/badge.tsx @@ -0,0 +1,36 @@ +import * as React from "react" +import { cva, type VariantProps } from "class-variance-authority" + +import { cn } from "@/lib/utils" + +const badgeVariants = cva( + "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2", + { + variants: { + variant: { + default: + "border-transparent bg-primary text-primary-foreground hover:bg-primary/80", + secondary: + "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80", + destructive: + "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80", + outline: "text-foreground", + }, + }, + defaultVariants: { + variant: "default", + }, + } +) + +export interface BadgeProps + extends React.HTMLAttributes` tag with Tailwind prose classes for readability in `PolicyDetailSheet`
-- [ ] T021 [P] [US2] Render non-JSON values as normal text in `PolicyDetailSheet`
-- [ ] T022 [P] [US2] Add Sheet styling - proper width (e.g., `w-[600px]`), padding, close button, scroll for long content (`max-height` + `overflow-auto`)
-- [ ] T023 [US2] Integrate `PolicyDetailSheet` into `PolicySearchContainer` - add state for selected policy and sheet open/close
-- [ ] T024 [US2] Connect row click handler from `PolicyTable` to open detail sheet with clicked policy data
-- [ ] T025 [US2] Test detail sheet with various data - nested JSON objects, arrays, long strings (>10KB), plain text values, malformed JSON
+- [X] T017 [P] [US2] Create `PolicyDetailSheet.tsx` component in `components/policy-explorer/PolicyDetailSheet.tsx` - uses Shadcn Sheet, accepts `policy`, `open`, `onOpenChange` props
+- [X] T018 [P] [US2] Implement JSON detection logic in `PolicyDetailSheet` - check if `settingValue.trim().startsWith('{')` or `startsWith('[')`
+- [X] T019 [P] [US2] Implement JSON formatting utility - `JSON.stringify(JSON.parse(value), null, 2)` wrapped in try/catch, fallback to plain text on error
+- [X] T020 [P] [US2] Render JSON values in `` tag with Tailwind prose classes for readability in `PolicyDetailSheet`
+- [X] T021 [P] [US2] Render non-JSON values as normal text in `PolicyDetailSheet`
+- [X] T022 [P] [US2] Add Sheet styling - proper width (e.g., `w-[600px]`), padding, close button, scroll for long content (`max-height` + `overflow-auto`)
+- [X] T023 [US2] Integrate `PolicyDetailSheet` into `PolicySearchContainer` - add state for selected policy and sheet open/close
+- [X] T024 [US2] Connect row click handler from `PolicyTable` to open detail sheet with clicked policy data
+- [X] T025 [US2] Test detail sheet with various data - nested JSON objects, arrays, long strings (>10KB), plain text values, malformed JSON
**Checkpoint**: Clicking rows opens detail sheet, JSON is formatted, sheet closes properly
@@ -96,12 +96,12 @@
### Implementation for User Story 3
-- [ ] T026 [US3] Integrate existing `SearchInput` component into `PolicySearchContainer` in `components/policy-explorer/PolicySearchContainer.tsx`
-- [ ] T027 [US3] Add search handler in `PolicySearchContainer` - calls `searchPolicySettings()` Server Action with search term
-- [ ] T028 [US3] Implement search state management using `useTransition()` hook for pending state
-- [ ] T029 [US3] Update table to show search results when search term is entered, show initial 50 policies when search is cleared
-- [ ] T030 [US3] Verify null values are filtered from search results (handled by Server Action from T006)
-- [ ] T031 [US3] Add loading indicator while search is in progress (use `isPending` from `useTransition`)
+- [X] T026 [US3] Integrate existing `SearchInput` component into `PolicySearchContainer` in `components/policy-explorer/PolicySearchContainer.tsx`
+- [X] T027 [US3] Add search handler in `PolicySearchContainer` - calls `searchPolicySettings()` Server Action with search term
+- [X] T028 [US3] Implement search state management using `useTransition()` hook for pending state
+- [X] T029 [US3] Update table to show search results when search term is entered, show initial 50 policies when search is cleared
+- [X] T030 [US3] Verify null values are filtered from search results (handled by Server Action from T006)
+- [X] T031 [US3] Add loading indicator while search is in progress (use `isPending` from `useTransition`)
**Checkpoint**: Search works, results exclude null values, loading states correct
@@ -115,11 +115,11 @@
### Implementation for User Story 4
-- [ ] T032 [P] [US4] Define policy type to badge color mapping - create utility function or constant (e.g., Compliance=blue, Configuration=gray, Security=red, etc.)
-- [ ] T033 [P] [US4] Implement badge rendering in `PolicyTable` - replace plain text `policyType` with Shadcn Badge component
-- [ ] T034 [P] [US4] Apply badge variant/color based on policy type in `PolicyTable` component
-- [ ] T035 [US4] Test badge colors with real data - verify at least 3 distinct colors are visible and accessible (contrast check)
-- [ ] T036 [US4] Verify hover effects on table rows - cursor changes to pointer, background color changes
+- [X] T032 [P] [US4] Define policy type to badge color mapping - create utility function or constant (e.g., Compliance=blue, Configuration=gray, Security=red, etc.)
+- [X] T033 [P] [US4] Implement badge rendering in `PolicyTable` - replace plain text `policyType` with Shadcn Badge component
+- [X] T034 [P] [US4] Apply badge variant/color based on policy type in `PolicyTable` component
+- [X] T035 [US4] Test badge colors with real data - verify at least 3 distinct colors are visible and accessible (contrast check)
+- [X] T036 [US4] Verify hover effects on table rows - cursor changes to pointer, background color changes
**Checkpoint**: Badges show distinct colors, hover effects smooth, visual hierarchy improved
@@ -129,9 +129,9 @@
**Purpose**: Update navigation and routing to consolidate under "Policy Explorer"
-- [ ] T037 Update `config/nav.ts` - replace `{ title: "Search", href: "/search" }` with `{ title: "Policy Explorer", href: "/search" }` (keep /search route for now)
-- [ ] T038 Remove "All Settings" menu item from `config/nav.ts` if it exists (from settings-overview feature)
-- [ ] T039 Update page metadata (title, description) in `app/(app)/search/page.tsx` to reflect "Policy Explorer" branding
+- [X] T037 Update `config/nav.ts` - replace `{ title: "Search", href: "/search" }` with `{ title: "Policy Explorer", href: "/search" }` (keep /search route for now)
+- [X] T038 Remove "All Settings" menu item from `config/nav.ts` if it exists (from settings-overview feature)
+- [X] T039 Update page metadata (title, description) in `app/(app)/search/page.tsx` to reflect "Policy Explorer" branding
- [ ] T040 Add redirect from `/settings-overview` to `/search` if that route exists (optional, for backwards compatibility)
**Checkpoint**: Navigation shows single "Policy Explorer" entry, old routes redirect if needed
@@ -142,7 +142,7 @@
**Purpose**: Final refinements and end-to-end validation
-- [ ] T041 Update `EmptyState` component message in `components/search/EmptyState.tsx` - change to Policy Explorer context if still used
+- [X] T041 Update `EmptyState` component message in `components/search/EmptyState.tsx` - change to Policy Explorer context if still used
- [ ] T042 Add loading skeleton to table (optional) - show placeholder rows while initial data loads
- [ ] T043 Verify responsive layout - test table and detail sheet on mobile viewport (< 768px)
- [ ] T044 Add error boundary for detail sheet - graceful error handling if sheet rendering fails