@@ -10,27 +10,32 @@ import {
1010 CircularProgress ,
1111 InputAdornment ,
1212 Portal ,
13+ Button ,
1314} from "@mui/material" ;
1415import { Search as SearchIcon } from "@mui/icons-material" ;
1516import { ApiGetCall } from "../../api/ApiCall" ;
16- import { useSettings } from "../../hooks/use-settings" ;
1717import { useRouter } from "next/router" ;
1818import { BulkActionsMenu } from "../bulk-actions-menu" ;
19- import { Button } from "@mui/material" ;
19+ import { CippOffCanvas } from "../CippComponents/CippOffCanvas" ;
20+ import { CippBitlockerKeySearch } from "../CippComponents/CippBitlockerKeySearch" ;
2021
2122export const CippUniversalSearchV2 = React . forwardRef (
2223 ( { onConfirm = ( ) => { } , onChange = ( ) => { } , maxResults = 10 , value = "" } , ref ) => {
2324 const [ searchValue , setSearchValue ] = useState ( value ) ;
2425 const [ searchType , setSearchType ] = useState ( "Users" ) ;
26+ const [ bitlockerLookupType , setBitlockerLookupType ] = useState ( "keyId" ) ;
2527 const [ showDropdown , setShowDropdown ] = useState ( false ) ;
28+ const [ bitlockerDrawerVisible , setBitlockerDrawerVisible ] = useState ( false ) ;
29+ const [ bitlockerDrawerDefaults , setBitlockerDrawerDefaults ] = useState ( {
30+ searchTerm : "" ,
31+ searchType : "keyId" ,
32+ } ) ;
2633 const [ dropdownPosition , setDropdownPosition ] = useState ( { top : 0 , left : 0 , width : 0 } ) ;
2734 const containerRef = useRef ( null ) ;
2835 const textFieldRef = useRef ( null ) ;
2936 const router = useRouter ( ) ;
30- const settings = useSettings ( ) ;
31- const { currentTenant } = settings ;
3237
33- const search = ApiGetCall ( {
38+ const universalSearch = ApiGetCall ( {
3439 url : `/api/ExecUniversalSearchV2` ,
3540 data : {
3641 searchTerms : searchValue ,
@@ -41,6 +46,17 @@ export const CippUniversalSearchV2 = React.forwardRef(
4146 waiting : false ,
4247 } ) ;
4348
49+ const bitlockerSearch = ApiGetCall ( {
50+ url : "/api/ExecBitlockerSearch" ,
51+ data : {
52+ [ bitlockerLookupType ] : searchValue ,
53+ } ,
54+ queryKey : `bitlocker-universal-${ bitlockerLookupType } -${ searchValue } ` ,
55+ waiting : false ,
56+ } ) ;
57+
58+ const activeSearch = searchType === "BitLocker" ? bitlockerSearch : universalSearch ;
59+
4460 const handleChange = ( event ) => {
4561 const newValue = event . target . value ;
4662 setSearchValue ( newValue ) ;
@@ -71,7 +87,7 @@ export const CippUniversalSearchV2 = React.forwardRef(
7187 const handleSearch = ( ) => {
7288 if ( searchValue . length > 0 ) {
7389 updateDropdownPosition ( ) ;
74- search . refetch ( ) ;
90+ activeSearch . refetch ( ) ;
7591 setShowDropdown ( true ) ;
7692 }
7793 } ;
@@ -93,6 +109,21 @@ export const CippUniversalSearchV2 = React.forwardRef(
93109
94110 const handleTypeChange = ( type ) => {
95111 setSearchType ( type ) ;
112+ if ( type === "BitLocker" ) {
113+ setBitlockerLookupType ( "keyId" ) ;
114+ }
115+ setShowDropdown ( false ) ;
116+ } ;
117+
118+ const handleBitlockerResultClick = ( match ) => {
119+ setBitlockerDrawerDefaults ( {
120+ searchTerm :
121+ bitlockerLookupType === "deviceId"
122+ ? match ?. deviceId || searchValue
123+ : match ?. keyId || searchValue ,
124+ searchType : bitlockerLookupType ,
125+ } ) ;
126+ setBitlockerDrawerVisible ( true ) ;
96127 setShowDropdown ( false ) ;
97128 } ;
98129
@@ -107,6 +138,24 @@ export const CippUniversalSearchV2 = React.forwardRef(
107138 icon : "Group" ,
108139 onClick : ( ) => handleTypeChange ( "Groups" ) ,
109140 } ,
141+ {
142+ label : "BitLocker" ,
143+ icon : "FilePresent" ,
144+ onClick : ( ) => handleTypeChange ( "BitLocker" ) ,
145+ } ,
146+ ] ;
147+
148+ const bitlockerLookupActions = [
149+ {
150+ label : "Key ID" ,
151+ icon : "FilePresent" ,
152+ onClick : ( ) => setBitlockerLookupType ( "keyId" ) ,
153+ } ,
154+ {
155+ label : "Device ID" ,
156+ icon : "Laptop" ,
157+ onClick : ( ) => setBitlockerLookupType ( "deviceId" ) ,
158+ } ,
110159 ] ;
111160
112161 // Close dropdown when clicking outside
@@ -144,14 +193,23 @@ export const CippUniversalSearchV2 = React.forwardRef(
144193 }
145194 } , [ showDropdown ] ) ;
146195
147- const hasResults = Array . isArray ( search ?. data ) && search . data . length > 0 ;
196+ const bitlockerResults = Array . isArray ( bitlockerSearch ?. data ?. Results )
197+ ? bitlockerSearch . data . Results
198+ : [ ] ;
199+ const universalResults = Array . isArray ( universalSearch ?. data ) ? universalSearch . data : [ ] ;
200+ const hasResults =
201+ searchType === "BitLocker" ? bitlockerResults . length > 0 : universalResults . length > 0 ;
148202 const shouldShowDropdown = showDropdown && searchValue . length > 0 ;
149203
150204 const getLabel = ( ) => {
151205 if ( searchType === "Users" ) {
152206 return "Search users by UPN or Display Name" ;
153207 } else if ( searchType === "Groups" ) {
154208 return "Search groups by Display Name" ;
209+ } else if ( searchType === "BitLocker" ) {
210+ return bitlockerLookupType === "deviceId"
211+ ? "Search BitLocker by Device ID"
212+ : "Search BitLocker by Recovery Key ID" ;
155213 }
156214 return "Search" ;
157215 } ;
@@ -163,6 +221,12 @@ export const CippUniversalSearchV2 = React.forwardRef(
163221 buttonName = { searchType }
164222 actions = { typeMenuActions }
165223 />
224+ { searchType === "BitLocker" && (
225+ < BulkActionsMenu
226+ buttonName = { bitlockerLookupType === "deviceId" ? "Device ID" : "Key ID" }
227+ actions = { bitlockerLookupActions }
228+ />
229+ ) }
166230 < TextField
167231 ref = { ( node ) => {
168232 textFieldRef . current = node ;
@@ -187,7 +251,7 @@ export const CippUniversalSearchV2 = React.forwardRef(
187251 < SearchIcon color = "action" sx = { { fontSize : 20 } } />
188252 </ InputAdornment >
189253 ) ,
190- endAdornment : search . isFetching ? (
254+ endAdornment : activeSearch . isFetching ? (
191255 < InputAdornment position = "end" >
192256 < CircularProgress size = { 20 } />
193257 </ InputAdornment >
@@ -203,7 +267,7 @@ export const CippUniversalSearchV2 = React.forwardRef(
203267 < Button
204268 variant = "contained"
205269 onClick = { handleSearch }
206- disabled = { searchValue . length === 0 || search . isFetching }
270+ disabled = { searchValue . length === 0 || activeSearch . isFetching }
207271 startIcon = { < SearchIcon /> }
208272 sx = { { flexShrink : 0 } }
209273 >
@@ -229,18 +293,25 @@ export const CippUniversalSearchV2 = React.forwardRef(
229293 borderColor : "divider" ,
230294 } }
231295 >
232- { search . isFetching ? (
296+ { activeSearch . isFetching ? (
233297 < Box sx = { { p : 2 } } >
234298 < Skeleton height = { 60 } sx = { { mb : 1 } } />
235299 < Skeleton height = { 60 } />
236300 </ Box >
237301 ) : hasResults ? (
238- < Results
239- items = { search . data }
240- searchValue = { searchValue }
241- onResultClick = { handleResultClick }
242- searchType = { searchType }
243- />
302+ searchType === "BitLocker" ? (
303+ < BitlockerResults
304+ items = { bitlockerResults }
305+ onResultClick = { handleBitlockerResultClick }
306+ />
307+ ) : (
308+ < Results
309+ items = { universalResults }
310+ searchValue = { searchValue }
311+ onResultClick = { handleResultClick }
312+ searchType = { searchType }
313+ />
314+ )
244315 ) : (
245316 < Box sx = { { p : 3 , textAlign : "center" } } >
246317 < Typography variant = "body2" color = "text.secondary" >
@@ -251,6 +322,20 @@ export const CippUniversalSearchV2 = React.forwardRef(
251322 </ Paper >
252323 </ Portal >
253324 ) }
325+
326+ < CippOffCanvas
327+ title = "BitLocker Key Details"
328+ visible = { bitlockerDrawerVisible }
329+ onClose = { ( ) => setBitlockerDrawerVisible ( false ) }
330+ size = "xl"
331+ contentPadding = { 0 }
332+ >
333+ < CippBitlockerKeySearch
334+ initialSearchTerm = { bitlockerDrawerDefaults . searchTerm }
335+ initialSearchType = { bitlockerDrawerDefaults . searchType }
336+ autoSearch = { true }
337+ />
338+ </ CippOffCanvas >
254339 </ >
255340 ) ;
256341 } ,
@@ -337,3 +422,46 @@ const Results = ({ items = [], searchValue, onResultClick, searchType = "Users"
337422 </ >
338423 ) ;
339424} ;
425+
426+ const BitlockerResults = ( { items = [ ] , onResultClick } ) => {
427+ return (
428+ < >
429+ { items . map ( ( result , index ) => (
430+ < MenuItem
431+ key = { result . keyId || index }
432+ onClick = { ( ) => onResultClick ( result ) }
433+ sx = { {
434+ py : 1.5 ,
435+ px : 2 ,
436+ borderBottom : index < items . length - 1 ? "1px solid" : "none" ,
437+ borderColor : "divider" ,
438+ "&:hover" : {
439+ backgroundColor : "action.hover" ,
440+ } ,
441+ } }
442+ >
443+ < ListItemText
444+ primary = {
445+ < Typography variant = "body1" fontWeight = "medium" >
446+ { result . deviceName || "Unknown Device" }
447+ </ Typography >
448+ }
449+ secondary = {
450+ < Box >
451+ < Typography variant = "body2" color = "text.secondary" >
452+ Key ID: { result . keyId || "N/A" }
453+ </ Typography >
454+ < Typography variant = "body2" color = "text.secondary" >
455+ Device ID: { result . deviceId || "N/A" }
456+ </ Typography >
457+ < Typography variant = "caption" color = "text.secondary" sx = { { display : "block" , mt : 0.5 } } >
458+ Tenant: { result . tenant || "N/A" }
459+ </ Typography >
460+ </ Box >
461+ }
462+ />
463+ </ MenuItem >
464+ ) ) }
465+ </ >
466+ ) ;
467+ } ;
0 commit comments