@@ -6,8 +6,9 @@ import { Button } from '@comp/ui/button';
66import { Card , CardContent , CardHeader , CardTitle } from '@comp/ui/card' ;
77import { cn } from '@comp/ui/cn' ;
88import { Select , SelectContent , SelectItem , SelectTrigger , SelectValue } from '@comp/ui/select' ;
9+ import { Tooltip , TooltipContent , TooltipProvider , TooltipTrigger } from '@comp/ui/tooltip' ;
910import type { Member } from '@db' ;
10- import { CheckCircle2 , Circle , Download , Loader2 , XCircle } from 'lucide-react' ;
11+ import { CheckCircle2 , Circle , Download , HelpCircle , Loader2 , XCircle } from 'lucide-react' ;
1112import Image from 'next/image' ;
1213import { useEffect , useMemo , useState } from 'react' ;
1314import { toast } from 'sonner' ;
@@ -32,10 +33,20 @@ export function DeviceAgentAccordionItem({
3233 [ detectedOS ] ,
3334 ) ;
3435
36+ const mdmEnabledStatus = useMemo ( ( ) => {
37+ return {
38+ id : 'mdm' ,
39+ response : host ?. mdm . enrollment_status === 'On' ? 'pass' : 'fail' ,
40+ name : 'MDM Enabled' ,
41+ } ;
42+ } , [ host ] ) ;
43+
3544 const hasInstalledAgent = host !== null ;
36- const allPoliciesPass =
37- fleetPolicies . length === 0 || fleetPolicies . every ( ( policy ) => policy . response === 'pass' ) ;
38- const isCompleted = hasInstalledAgent && allPoliciesPass ;
45+ const failedPoliciesCount = useMemo ( ( ) => {
46+ return fleetPolicies . filter ( ( policy ) => policy . response !== 'pass' ) . length + ( ! isMacOS || mdmEnabledStatus . response === 'pass' ? 0 : 1 ) ;
47+ } , [ fleetPolicies , mdmEnabledStatus , isMacOS ] ) ;
48+
49+ const isCompleted = hasInstalledAgent && failedPoliciesCount === 0 ;
3950
4051 const handleDownload = async ( ) => {
4152 setIsDownloading ( true ) ;
@@ -130,9 +141,9 @@ export function DeviceAgentAccordionItem({
130141 < span className = { cn ( 'text-base' , isCompleted && 'text-muted-foreground line-through' ) } >
131142 Download and install Comp AI Device Agent
132143 </ span >
133- { hasInstalledAgent && ! allPoliciesPass && (
144+ { hasInstalledAgent && failedPoliciesCount > 0 && (
134145 < span className = "text-amber-600 dark:text-amber-400 text-xs ml-auto" >
135- { fleetPolicies . filter ( ( p ) => p . response !== 'pass' ) . length } policies failing
146+ { failedPoliciesCount } policies failing
136147 </ span >
137148 ) }
138149 </ div >
@@ -245,28 +256,81 @@ export function DeviceAgentAccordionItem({
245256 </ CardHeader >
246257 < CardContent className = "space-y-3" >
247258 { fleetPolicies . length > 0 ? (
248- fleetPolicies . map ( ( policy ) => (
249- < div
250- key = { policy . id }
251- className = { cn (
252- 'hover:bg-muted/50 flex items-center justify-between rounded-md border border-l-4 p-3 shadow-sm transition-colors' ,
253- policy . response === 'pass' ? 'border-l-green-500' : 'border-l-red-500' ,
254- ) }
255- >
256- < p className = "text-sm font-medium" > { policy . name } </ p >
257- { policy . response === 'pass' ? (
258- < div className = "flex items-center gap-1 text-green-600 dark:text-green-400" >
259- < CheckCircle2 size = { 16 } />
260- < span className = "text-sm" > Pass</ span >
261- </ div >
262- ) : (
263- < div className = "flex items-center gap-1 text-red-600 dark:text-red-400" >
264- < XCircle size = { 16 } />
265- < span className = "text-sm" > Fail</ span >
259+ < >
260+ { fleetPolicies . map ( ( policy ) => (
261+ < div
262+ key = { policy . id }
263+ className = { cn (
264+ 'hover:bg-muted/50 flex items-center justify-between rounded-md border border-l-4 p-3 shadow-sm transition-colors' ,
265+ policy . response === 'pass' ? 'border-l-green-500' : 'border-l-red-500' ,
266+ ) }
267+ >
268+ < p className = "text-sm font-medium" > { policy . name } </ p >
269+ { policy . response === 'pass' ? (
270+ < div className = "flex items-center gap-1 text-green-600 dark:text-green-400" >
271+ < CheckCircle2 size = { 16 } />
272+ < span className = "text-sm" > Pass</ span >
273+ </ div >
274+ ) : (
275+ < div className = "flex items-center gap-1 text-red-600 dark:text-red-400" >
276+ < XCircle size = { 16 } />
277+ < span className = "text-sm" > Fail</ span >
278+ </ div >
279+ ) }
280+ </ div >
281+ ) ) }
282+ { isMacOS && (
283+ < div
284+ className = { cn (
285+ 'hover:bg-muted/50 flex items-center justify-between rounded-md border border-l-4 p-3 shadow-sm transition-colors' ,
286+ mdmEnabledStatus . response === 'pass' ? 'border-l-green-500' : 'border-l-red-500' ,
287+ ) }
288+ >
289+ < div className = "flex items-center gap-2" >
290+ < p className = "text-sm font-medium" > { mdmEnabledStatus . name } </ p >
291+ { mdmEnabledStatus . response === 'fail' && host ?. id && (
292+ < TooltipProvider >
293+ < Tooltip >
294+ < TooltipTrigger asChild >
295+ < button
296+ type = "button"
297+ className = "text-muted-foreground hover:text-foreground transition-colors"
298+ >
299+ < HelpCircle size = { 14 } />
300+ </ button >
301+ </ TooltipTrigger >
302+ < TooltipContent className = "max-w-xs" >
303+ < p >
304+ There are additional steps required to enable MDM. Please check{ ' ' }
305+ < a
306+ href = "https://trycomp.ai/docs/device-agent#mdm-user-guide"
307+ target = "_blank"
308+ rel = "noopener noreferrer"
309+ className = "text-blue-600 dark:text-blue-400 hover:underline"
310+ >
311+ this documentation
312+ </ a >
313+ .
314+ </ p >
315+ </ TooltipContent >
316+ </ Tooltip >
317+ </ TooltipProvider >
318+ ) }
266319 </ div >
267- ) }
268- </ div >
269- ) )
320+ { mdmEnabledStatus . response === 'pass' ? (
321+ < div className = "flex items-center gap-1 text-green-600 dark:text-green-400" >
322+ < CheckCircle2 size = { 16 } />
323+ < span className = "text-sm" > Pass</ span >
324+ </ div >
325+ ) : (
326+ < div className = "flex items-center gap-1 text-red-600 dark:text-red-400" >
327+ < XCircle size = { 16 } />
328+ < span className = "text-sm" > Fail</ span >
329+ </ div >
330+ ) }
331+ </ div >
332+ ) }
333+ </ >
270334 ) : (
271335 < p className = "text-muted-foreground text-sm" >
272336 No policies configured for this device.
0 commit comments