-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathInstanceStatusCell.tsx
More file actions
107 lines (99 loc) · 4.05 KB
/
InstanceStatusCell.tsx
File metadata and controls
107 lines (99 loc) · 4.05 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
import { useInstanceClientIdParams } from '@/config/useInstanceClient';
import { useOrganizationClusterInstancePermissions } from '@/hooks/usePermissions';
import { Instance } from '@/integrations/api/api.patch';
import { getStatusQueryOptions } from '@/integrations/api/instance/status/getStatus';
import { useSetStatus } from '@/integrations/api/instance/status/setStatus';
import { getOperationsUrlForInstance } from '@/lib/urls/getOperationsUrlForInstance';
import { useQuery } from '@tanstack/react-query';
import { LoaderCircleIcon, ShieldCheckIcon, ShieldXIcon } from 'lucide-react';
import { useEffect, useMemo, useState } from 'react';
const DEFAULT_200_MSG = 'Status endpoint is reporting for duty.';
const DEFAULT_404_MSG = 'Status endpoint is reporting downtime.';
export function InstanceStatusCell(
{ instance }: { readonly instance: Instance },
) {
const operationsUrl = useMemo(() => getOperationsUrlForInstance(instance), [instance]);
const instanceParams = useInstanceClientIdParams({ operationsUrl, instanceId: instance.id });
const { update: canManage } = useOrganizationClusterInstancePermissions();
const { mutate: setStatus, isPending: isSettingStatus } = useSetStatus();
// We want to spread the initial requests across 5 seconds.
const [randomOffset] = useState(() => Math.floor(Math.random() * 5_000));
const [ready, setReady] = useState(false);
useEffect(() => {
const timer = setTimeout(() => setReady(true), randomOffset);
return () => clearTimeout(timer);
}, [randomOffset]);
const { data: statusResponse, isLoading, isFetching } = useQuery(getStatusQueryOptions(instanceParams, ready));
const isAvailable = statusResponse?.systemStatus?.[0]?.status === 'Available';
const isUnavailable = statusResponse?.systemStatus?.[0]?.status === 'Unavailable';
const statusMessage = typeof statusResponse?.data === 'string'
? statusResponse.data
: (isAvailable ? DEFAULT_200_MSG : (isUnavailable ? DEFAULT_404_MSG : 'Unknown status'));
return (
<div className="flex items-center gap-2">
<Tooltip>
<TooltipTrigger asChild>
<div className="flex items-center">
{isLoading || !ready || (isFetching && !statusResponse)
? <LoaderCircleIcon className="animate-spin size-5 text-muted-foreground" />
: (
<Badge
variant={isAvailable ? 'success' : isUnavailable ? 'destructive' : 'default'}
className="size-4 rounded-full p-0"
>
<span className="sr-only">{isAvailable ? 'Online' : 'Offline'}</span>
</Badge>
)}
</div>
</TooltipTrigger>
<TooltipContent>
{isFetching && statusResponse ? 'Refreshing... ' : ''}
{statusMessage}
</TooltipContent>
</Tooltip>
{canManage && (
<div className="flex gap-1">
{isAvailable && (
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="destructiveGhost"
size="icon"
className="size-7"
onClick={() => setStatus({ ...instanceParams, id: 'availability', status: 'Unavailable' })}
disabled={isSettingStatus}
>
{isSettingStatus
? <LoaderCircleIcon className="animate-spin size-4" />
: <ShieldXIcon className="size-4" />}
</Button>
</TooltipTrigger>
<TooltipContent>Bring out of rotation</TooltipContent>
</Tooltip>
)}
{isUnavailable && (
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="ghost"
size="icon"
className="size-7"
onClick={() => setStatus({ ...instanceParams, id: 'availability', status: 'Available' })}
disabled={isSettingStatus}
>
{isSettingStatus
? <LoaderCircleIcon className="animate-spin size-4" />
: <ShieldCheckIcon className="size-4" />}
</Button>
</TooltipTrigger>
<TooltipContent>Bring back into rotation</TooltipContent>
</Tooltip>
)}
</div>
)}
</div>
);
}