149 lines
4.6 KiB
TypeScript
149 lines
4.6 KiB
TypeScript
'use client';
|
|
|
|
import { useState, useTransition, useCallback } from 'react';
|
|
import { SearchInput } from '@/components/search/SearchInput';
|
|
import { ResultsTable } from '@/components/search/ResultsTable';
|
|
import { EmptyState } from '@/components/search/EmptyState';
|
|
import {
|
|
searchPolicySettings,
|
|
seedMyTenantData,
|
|
type PolicySettingSearchResult,
|
|
} from '@/lib/actions/policySettings';
|
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
|
import { Button } from '@/components/ui/button';
|
|
import { toast } from 'sonner';
|
|
import { Database } from 'lucide-react';
|
|
import { useRouter } from 'next/navigation';
|
|
|
|
export default function SearchPage() {
|
|
const router = useRouter();
|
|
const [results, setResults] = useState<PolicySettingSearchResult[]>([]);
|
|
const [searchTerm, setSearchTerm] = useState('');
|
|
const [hasSearched, setHasSearched] = useState(false);
|
|
const [isPending, startTransition] = useTransition();
|
|
const [isSeeding, startSeedTransition] = useTransition();
|
|
|
|
const handleSearch = useCallback((query: string) => {
|
|
setSearchTerm(query);
|
|
|
|
if (query.length === 0) {
|
|
setResults([]);
|
|
setHasSearched(false);
|
|
return;
|
|
}
|
|
|
|
if (query.length < 2) {
|
|
return;
|
|
}
|
|
|
|
startTransition(async () => {
|
|
try {
|
|
const result = await searchPolicySettings(query);
|
|
|
|
if (result.success) {
|
|
setResults(result.data ?? []);
|
|
setHasSearched(true);
|
|
} else {
|
|
toast.error(result.error ?? 'Search failed');
|
|
setResults([]);
|
|
setHasSearched(true);
|
|
}
|
|
} catch (error) {
|
|
toast.error('An unexpected error occurred');
|
|
setResults([]);
|
|
setHasSearched(true);
|
|
}
|
|
});
|
|
}, []);
|
|
|
|
const handleSeedData = () => {
|
|
startSeedTransition(async () => {
|
|
try {
|
|
const result = await seedMyTenantData();
|
|
|
|
if (result.success) {
|
|
toast.success(result.message ?? 'Test data created successfully');
|
|
router.refresh();
|
|
} else {
|
|
toast.error(result.error ?? 'Failed to seed data');
|
|
}
|
|
} catch (error) {
|
|
toast.error('An unexpected error occurred');
|
|
}
|
|
});
|
|
};
|
|
|
|
return (
|
|
<main className="flex flex-1 flex-col gap-4 p-4 md:gap-8 md:p-8">
|
|
<div className="mx-auto w-full max-w-6xl">
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Global Policy Search</CardTitle>
|
|
<CardDescription>
|
|
Search across all your Intune policy settings by keyword
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="flex flex-col gap-6">
|
|
<SearchInput onSearch={handleSearch} isSearching={isPending} />
|
|
|
|
{isPending && (
|
|
<div className="flex items-center justify-center py-8">
|
|
<div className="flex items-center gap-2">
|
|
<div className="h-5 w-5 animate-spin rounded-full border-2 border-primary border-t-transparent" />
|
|
<span className="text-sm text-muted-foreground">
|
|
Searching...
|
|
</span>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{!isPending && hasSearched && (
|
|
<>
|
|
{results.length > 0 ? (
|
|
<div className="space-y-4">
|
|
<p className="text-sm text-muted-foreground">
|
|
Found {results.length} result{results.length !== 1 ? 's' : ''}
|
|
</p>
|
|
<ResultsTable results={results} />
|
|
</div>
|
|
) : (
|
|
<EmptyState searchTerm={searchTerm} />
|
|
)}
|
|
</>
|
|
)}
|
|
|
|
{!hasSearched && !isPending && (
|
|
<EmptyState />
|
|
)}
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* Seed Data Button - Development Helper */}
|
|
<div className="mt-4 flex justify-end">
|
|
<Button
|
|
onClick={handleSeedData}
|
|
disabled={isSeeding}
|
|
variant="outline"
|
|
size="sm"
|
|
className="gap-2"
|
|
>
|
|
{isSeeding ? (
|
|
<>
|
|
<div className="h-4 w-4 animate-spin rounded-full border-2 border-primary border-t-transparent" />
|
|
Seeding...
|
|
</>
|
|
) : (
|
|
<>
|
|
<Database className="h-4 w-4" />
|
|
Seed My Data
|
|
</>
|
|
)}
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
);
|
|
}
|