From 39080cea83e6b1da43d5ee24edae34f6ffc3dfb0 Mon Sep 17 00:00:00 2001 From: alphaeusmote <41258468-alphaeusmote@users.noreply.replit.com> Date: Wed, 9 Apr 2025 03:26:53 +0000 Subject: [PATCH] Enhance LDAP query builder with drag-and-drop functionality for filter groups. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 705f2157-ef97-4fbd-89e4-8c7f2ecaea90 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/7ed01c5f-a82d-405a-b728-b2e3d127c60c/734add71-6306-4281-af3d-a32d5349dd4c.jpg --- client/src/pages/ldap-query-builder-page.tsx | 1167 +++++++------- .../src/pages/ldap-query-builder-page.tsx.bak | 1362 +++++++++++++++++ package-lock.json | 56 + package.json | 3 + 4 files changed, 2061 insertions(+), 527 deletions(-) create mode 100644 client/src/pages/ldap-query-builder-page.tsx.bak diff --git a/client/src/pages/ldap-query-builder-page.tsx b/client/src/pages/ldap-query-builder-page.tsx index b89c21c..73714d9 100644 --- a/client/src/pages/ldap-query-builder-page.tsx +++ b/client/src/pages/ldap-query-builder-page.tsx @@ -10,8 +10,27 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@ 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, Plus, FolderPlus, X } from "lucide-react"; +import { Loader2, Save, Trash, History, ArrowLeftRight, RefreshCw, Play, Plus, FolderPlus, X, Copy, GripVertical } from "lucide-react"; import { useAuth } from "@/hooks/use-auth"; + +// Drag and drop imports +import { + DndContext, + closestCenter, + KeyboardSensor, + PointerSensor, + useSensor, + useSensors, + DragEndEvent +} from '@dnd-kit/core'; +import { + arrayMove, + SortableContext, + sortableKeyboardCoordinates, + useSortable, + verticalListSortingStrategy +} from '@dnd-kit/sortable'; +import { CSS } from '@dnd-kit/utilities'; import { Dialog, DialogContent, @@ -61,6 +80,238 @@ type LdapFilterRevision = { modifiedAt: string; }; +// Sortable Group component for drag-and-drop +interface SortableGroupProps { + id: string; + group: any; + groupIndex: number; + filterBuilder: any; + setFilterBuilder: (value: any) => void; + ldapAttributes: string[]; + isLoadingAttributes: boolean; +} + +const SortableGroup = ({ + id, + group, + groupIndex, + filterBuilder, + setFilterBuilder, + ldapAttributes, + isLoadingAttributes +}: SortableGroupProps) => { + const { + attributes, + listeners, + setNodeRef, + transform, + transition, + isDragging + } = useSortable({ id }); + + const style = { + transform: CSS.Transform.toString(transform), + transition, + zIndex: isDragging ? 1 : 0, + opacity: isDragging ? 0.5 : 1 + }; + + return ( +
+
+
+
+ +
+ + +
+ + +
+ +
+ {group.conditions.map((condition: any, condIndex: number) => ( +
+
+ {ldapAttributes.length > 0 ? ( + + ) : ( + { + const updatedGroups = [...filterBuilder.groups]; + updatedGroups[groupIndex].conditions[condIndex].attribute = e.target.value; + setFilterBuilder({ + ...filterBuilder, + groups: updatedGroups + }); + }} + /> + )} + {condition.attribute === "custom" && ( + { + const updatedGroups = [...filterBuilder.groups]; + updatedGroups[groupIndex].conditions[condIndex].attribute = e.target.value; + setFilterBuilder({ + ...filterBuilder, + groups: updatedGroups + }); + }} + /> + )} +
+
+ +
+
+ { + const updatedGroups = [...filterBuilder.groups]; + updatedGroups[groupIndex].conditions[condIndex].value = e.target.value; + setFilterBuilder({ + ...filterBuilder, + groups: updatedGroups + }); + }} + /> +
+
+ +
+
+ ))} + + +
+
+ ); +}; + const LdapQueryBuilderPage = () => { const { user } = useAuth(); const { toast } = useToast(); @@ -81,6 +332,48 @@ const LdapQueryBuilderPage = () => { operator: "and", groups: [] }); + + // Set up sensors for drag and drop + const sensors = useSensors( + useSensor(PointerSensor, { + activationConstraint: { + distance: 8, + }, + }), + useSensor(KeyboardSensor, { + coordinateGetter: sortableKeyboardCoordinates, + }) + ); + + // Handle drag end event for group reordering + const handleDragEnd = (event: DragEndEvent) => { + const { active, over } = event; + + if (over && active.id !== over.id) { + const activeId = active.id.toString(); + const overId = over.id.toString(); + + const activeIndex = filterBuilder.groups.findIndex( + (_: any, i: number) => `group-${i}` === activeId + ); + const overIndex = filterBuilder.groups.findIndex( + (_: any, i: number) => `group-${i}` === overId + ); + + if (activeIndex !== -1 && overIndex !== -1) { + const newGroups = arrayMove( + filterBuilder.groups, + activeIndex, + overIndex + ); + + setFilterBuilder({ + ...filterBuilder, + groups: newGroups + }); + } + } + }; // Query to get LDAP connections const { @@ -263,9 +556,7 @@ const LdapQueryBuilderPage = () => { : filter.filter; // Make sure it has valid structure - if (filterData && - filterData.operator && - Array.isArray(filterData.conditions)) { + if (filterData && filterData.operator) { setFilterBuilder(filterData); } } catch (err) { @@ -483,59 +774,42 @@ const LdapQueryBuilderPage = () => { - Date + Version Modified By + Date 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 + {revisions.map((rev: LdapFilterRevision) => ( + + v{rev.id} + User #{rev.modifiedBy} + {new Date(rev.modifiedAt).toLocaleString()} + {rev.ldapFilter} + + - )} + ))}
)} - + - @@ -548,49 +822,44 @@ const LdapQueryBuilderPage = () => { const renderTestResultsDialog = () => { return ( - + Test Results - Results for LDAP filter: {filterQuery} + LDAP filter test results for "{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)} - - ))} +
+

Found {testResults.length} results:

+
+ + + Distinguished Name + Name - ))} - -
+ + + {testResults.map((result: any, index: number) => ( + + {result.dn} + {result.cn || result.name || result.displayName || result.sAMAccountName} + + ))} + + +
) : ( -

No results found for this filter

+
+

No results found matching this filter.

+
)} - + - @@ -600,151 +869,194 @@ const LdapQueryBuilderPage = () => { }; 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()} -
+
+ {/* Sidebar */} + + + LDAP Filters + Saved LDAP query filters + + +
+
+ + {renderConnectionsDropdown()}
- - -
- - {/* 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" - /> -
-
- - -
-
- + + {renderFiltersList()} +
+
+
+ + {/* Main content */} + + + + {selectedFilter ? `Edit: ${selectedFilter.name}` : "Create New LDAP Filter"} + + + Build and test LDAP filters for your Active Directory queries + + + +
+
- - setFilterDescription(e.target.value)} - placeholder="Enter a description" + + setFilterName(e.target.value)} + placeholder="My LDAP Filter" />
+
+ + +
+
+ +
+ +