import { useState, useEffect } from "react"; import { DashboardLayout } from "@/layouts/dashboard-layout"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Textarea } from "@/components/ui/textarea"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { useQuery, useMutation } from "@tanstack/react-query"; import { queryClient, apiRequest } from "@/lib/queryClient"; import { useToast } from "@/hooks/use-toast"; import { Loader2, Save, Trash, History, ArrowLeftRight, RefreshCw, Play } from "lucide-react"; import { useAuth } from "@/hooks/use-auth"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Table, TableBody, TableCaption, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; type LdapConnection = { id: number; name: string; server: string; domain: string; }; type LdapFilter = { id: number; name: string; description: string | null; filter: any; ldapFilter: string; connectionId: number; createdBy: number; createdAt: string; modifiedBy: number | null; modifiedAt: string | null; isActive: boolean; }; type LdapFilterRevision = { id: number; filterId: number; filter: any; ldapFilter: string; modifiedBy: number; modifiedAt: string; }; const LdapQueryBuilderPage = () => { const { user } = useAuth(); const { toast } = useToast(); const [selectedConnectionId, setSelectedConnectionId] = useState(); const [selectedFilter, setSelectedFilter] = useState(null); const [filterName, setFilterName] = useState(""); const [filterDescription, setFilterDescription] = useState(""); const [filterQuery, setFilterQuery] = useState(""); const [objectClass, setObjectClass] = useState("user"); const [showRevisionsDialog, setShowRevisionsDialog] = useState(false); const [showTestResultsDialog, setShowTestResultsDialog] = useState(false); const [testResults, setTestResults] = useState([]); const [isActive, setIsActive] = useState(true); const [filterBuilder, setFilterBuilder] = useState({ operator: "and", conditions: [{ attribute: "", operator: "equals", value: "" }] }); // Query to get LDAP connections const { data: connections = [], isLoading: connectionsLoading } = useQuery({ queryKey: ["/api/ldap-connections"], enabled: !!user }); // Query to get LDAP filters for the selected connection const { data: filters = [], isLoading: filtersLoading } = useQuery({ queryKey: ["/api/connections", selectedConnectionId, "ldap-filters"], enabled: !!selectedConnectionId, }); // Query to get LDAP filter revisions const { data: revisions = [], isLoading: revisionsLoading, refetch: refetchRevisions } = useQuery({ queryKey: ["/api/ldap-filters", selectedFilter?.id, "revisions"], enabled: !!selectedFilter?.id && showRevisionsDialog, }); // Mutation to save a new filter const createFilterMutation = useMutation({ mutationFn: async (newFilter: any) => { if (!selectedConnectionId) throw new Error("No connection selected"); const res = await apiRequest("POST", `/api/connections/${selectedConnectionId}/ldap-filters`, newFilter); return await res.json(); }, onSuccess: () => { toast({ title: "Success", description: "Filter created successfully", }); queryClient.invalidateQueries({ queryKey: ["/api/connections", selectedConnectionId, "ldap-filters"] }); resetForm(); }, onError: (error: Error) => { toast({ title: "Error creating filter", description: error.message, variant: "destructive", }); } }); // Mutation to update an existing filter const updateFilterMutation = useMutation({ mutationFn: async (updatedFilter: any) => { if (!selectedFilter) throw new Error("No filter selected"); const res = await apiRequest("PUT", `/api/ldap-filters/${selectedFilter.id}`, updatedFilter); return await res.json(); }, onSuccess: () => { toast({ title: "Success", description: "Filter updated successfully", }); queryClient.invalidateQueries({ queryKey: ["/api/connections", selectedConnectionId, "ldap-filters"] }); resetForm(); }, onError: (error: Error) => { toast({ title: "Error updating filter", description: error.message, variant: "destructive", }); } }); // Mutation to delete a filter const deleteFilterMutation = useMutation({ mutationFn: async () => { if (!selectedFilter) throw new Error("No filter selected"); return await apiRequest("DELETE", `/api/ldap-filters/${selectedFilter.id}`); }, onSuccess: () => { toast({ title: "Success", description: "Filter deleted successfully", }); queryClient.invalidateQueries({ queryKey: ["/api/connections", selectedConnectionId, "ldap-filters"] }); resetForm(); }, onError: (error: Error) => { toast({ title: "Error deleting filter", description: error.message, variant: "destructive", }); } }); // Mutation to revert to a previous version const revertToRevisionMutation = useMutation({ mutationFn: async (revisionId: number) => { if (!selectedFilter) throw new Error("No filter selected"); const res = await apiRequest("POST", `/api/ldap-filters/${selectedFilter.id}/revert/${revisionId}`, {}); return await res.json(); }, onSuccess: (data) => { toast({ title: "Success", description: "Filter reverted successfully", }); queryClient.invalidateQueries({ queryKey: ["/api/connections", selectedConnectionId, "ldap-filters"] }); setSelectedFilter(data); setFilterName(data.name); setFilterDescription(data.description || ""); setFilterQuery(data.ldapFilter); setIsActive(data.isActive); setShowRevisionsDialog(false); }, onError: (error: Error) => { toast({ title: "Error reverting filter", description: error.message, variant: "destructive", }); } }); // Mutation to test the LDAP filter const testFilterMutation = useMutation({ mutationFn: async () => { if (!selectedConnectionId) throw new Error("No connection selected"); const res = await apiRequest("POST", `/api/connections/${selectedConnectionId}/test-ldap-filter`, { ldapFilter: filterQuery, objectClass }); return await res.json(); }, onSuccess: (data) => { setTestResults(data); setShowTestResultsDialog(true); }, onError: (error: Error) => { toast({ title: "Error testing filter", description: error.message, variant: "destructive", }); } }); // Reset form const resetForm = () => { setSelectedFilter(null); setFilterName(""); setFilterDescription(""); setFilterQuery(""); setIsActive(true); }; // Select filter const handleSelectFilter = (filter: LdapFilter) => { setSelectedFilter(filter); setFilterName(filter.name); setFilterDescription(filter.description || ""); setFilterQuery(filter.ldapFilter); setIsActive(filter.isActive); }; // Save filter const handleSaveFilter = () => { if (!filterName || !filterQuery) { toast({ title: "Validation Error", description: "Filter name and query are required", variant: "destructive", }); return; } const filterData = { name: filterName, description: filterDescription || null, ldapFilter: filterQuery, filter: filterBuilder, isActive }; if (selectedFilter) { updateFilterMutation.mutate(filterData); } else { createFilterMutation.mutate(filterData); } }; // Render connections dropdown const renderConnectionsDropdown = () => { if (connectionsLoading) { return ; } return ( ); }; // Render filters list const renderFiltersList = () => { if (!selectedConnectionId) { return

Select a connection to view filters

; } if (filtersLoading) { return
; } if (!filters || filters.length === 0) { return

No filters found for this connection

; } return (
{filters.map((filter: LdapFilter) => (
handleSelectFilter(filter)} >

{filter.name}

{filter.description && (

{filter.description}

)}
{!filter.isActive && ( Inactive )}
))}
); }; // Render revisions dialog const renderRevisionsDialog = () => { return ( Revision History View and restore previous versions of "{selectedFilter?.name}" {revisionsLoading ? (
) : (
Date Modified By LDAP Filter Actions {revisions && revisions.length > 0 ? ( revisions.map((rev: LdapFilterRevision) => ( {new Date(rev.modifiedAt).toLocaleString()} User ID: {rev.modifiedBy} {rev.ldapFilter} )) ) : ( No revision history found )}
)}
); }; // Render test results dialog const renderTestResultsDialog = () => { return ( Test Results Results for LDAP filter: {filterQuery}
{testResults.length > 0 ? ( Found {testResults.length} results {Object.keys(testResults[0]).map((key) => ( {key} ))} {testResults.map((result, index) => ( {Object.entries(result).map(([key, value]) => ( {typeof value === 'object' ? JSON.stringify(value) : String(value)} ))} ))}
) : (

No results found for this filter

)}
); }; return (

LDAP Query Builder

Create, test and manage LDAP queries for Active Directory

{/* Left Side - Filters List */}
LDAP Filters Select a connection to view filters
{renderConnectionsDropdown()}

Saved Filters

{renderFiltersList()}
{/* Right Side - Filter Editor */}
{selectedFilter ? `Edit Filter: ${selectedFilter.name}` : 'Create New Filter'} {selectedFilter ? 'Update your LDAP filter and test it against your Active Directory' : 'Create a new LDAP filter and test it against your Active Directory'}
setFilterName(e.target.value)} placeholder="Enter a name for your filter" />
setFilterDescription(e.target.value)} placeholder="Enter a description" />
Manual LDAP Query Visual Query Builder (Coming Soon)