SandboxManagement.tsx105 lines · main
1import { Box, Loader2, LogOut, RefreshCw } from 'lucide-react'
2import { Badge, Button } from 'ui'
3import { Admonition } from 'ui-patterns'
4
5import { ButtonTooltip } from '@/components/ui/ButtonTooltip'
6import { usePostgresSandbox } from '@/state/postgres-sandbox/sandbox'
7
8export const SandboxManagement = () => {
9 const { status, error, isSyncing, startSandbox, destroySandbox, syncSandbox } =
10 usePostgresSandbox()
11
12 if (status === 'idle') {
13 return (
14 <Admonition
15 type="default"
16 layout="horizontal"
17 className="min-h-min border-none [&>div>div>div>div>p]:!mb-0"
18 actions={[
19 <Button key="set-up" type="default" onClick={() => startSandbox()}>
20 Set up sandbox
21 </Button>,
22 ]}
23 >
24 <div className="flex items-center gap-x-2">
25 <p className="text-foreground !m-0">Set up sandbox for testing</p>
26 <Badge variant="success">Recommended</Badge>
27 </div>
28 <p className="text-foreground-light !m-0">
29 Ensure that queries do not affect your actual database
30 </p>
31 </Admonition>
32 )
33 }
34
35 if (status === 'loading') {
36 return (
37 <Admonition
38 showIcon={false}
39 type="default"
40 className="min-h-min border-none py-2 [&>div>div]:flex [&>div>div]:items-center [&>div>div]:justify-between"
41 >
42 <div className="flex items-center gap-x-3">
43 <div className="bg w-6 h-6 rounded border border-border flex items-center justify-center">
44 <Loader2 size={14} className="animate-spin" />
45 </div>
46 <p className="text-xs !mb-0 font-mono uppercase tracking-tight">Setting up sandbox</p>
47 </div>
48 </Admonition>
49 )
50 }
51
52 if (status === 'error') {
53 return (
54 <Admonition
55 type="warning"
56 layout="horizontal"
57 title="Unable to set up sandbox"
58 description={error ?? 'Please try again'}
59 className="min-h-min border-none"
60 actions={[
61 <Button key="set-up" type="default" onClick={() => startSandbox()}>
62 Retry set up
63 </Button>,
64 ]}
65 />
66 )
67 }
68
69 return (
70 <Admonition
71 showIcon={false}
72 type="default"
73 layout="horizontal"
74 className="min-h-min border-none py-2 [&>div>div>div>div>p]:!mb-0 [&>div>div]:gap-x-2"
75 actions={[
76 <ButtonTooltip
77 key="destroy"
78 type="default"
79 icon={<LogOut />}
80 className="w-7"
81 disabled={isSyncing}
82 tooltip={{ content: { side: 'bottom', text: 'Exit sandbox' } }}
83 onClick={() => destroySandbox()}
84 />,
85 <ButtonTooltip
86 key="refresh"
87 type="default"
88 icon={<RefreshCw />}
89 className="w-7"
90 loading={isSyncing}
91 tooltip={{ content: { side: 'bottom', text: 'Refresh schema' } }}
92 onClick={() => syncSandbox()}
93 />,
94 ]}
95 >
96 <div className="flex items-center gap-x-3">
97 <div className="bg-brand-300 w-6 h-6 rounded border border-brand-500 flex items-center justify-center">
98 <Box size={14} className="text-brand" />
99 </div>
100 <p className="text-xs text-foreground font-mono uppercase tracking-tight">Sandbox active</p>
101 <p className="text-xs text-foreground-lighter ">Your database is never modified</p>
102 </div>
103 </Admonition>
104 )
105}