PolicyDefinition.tsx119 lines · main
1import { usePrevious } from '@uidotdev/usehooks'
2import { noop } from 'lodash'
3import { HelpCircle } from 'lucide-react'
4import { useEffect } from 'react'
5import { Tooltip, TooltipContent, TooltipTrigger } from 'ui'
6
7import SqlEditor from '@/components/ui/SqlEditor'
8
9interface PolicyDefinitionProps {
10 operation: string
11 definition: string
12 check: string
13 onUpdatePolicyUsing: (using: string | undefined) => void
14 onUpdatePolicyCheck: (check: string | undefined) => void
15}
16
17const PolicyDefinition = ({
18 operation = '',
19 definition = '',
20 check = '',
21 onUpdatePolicyUsing = noop,
22 onUpdatePolicyCheck = noop,
23}: PolicyDefinitionProps) => {
24 const showUsing = (operation: string) =>
25 ['SELECT', 'UPDATE', 'DELETE', 'ALL'].includes(operation) || !operation
26 const showCheck = (operation: string) => ['INSERT', 'UPDATE', 'ALL'].includes(operation)
27
28 const previousOperation = usePrevious(operation) || ''
29 useEffect(() => {
30 if (showUsing(previousOperation) && !showUsing(operation)) onUpdatePolicyUsing(undefined)
31 if (showCheck(previousOperation) && !showCheck(operation)) onUpdatePolicyCheck(undefined)
32 }, [operation])
33
34 return (
35 <div className="space-y-4">
36 {showUsing(operation) && (
37 <div className="flex space-x-12">
38 <div className="flex w-1/3 flex-col space-y-2">
39 <div className="flex items-center space-x-2">
40 <label className="text-base text-foreground-light" htmlFor="policy-name">
41 USING expression
42 </label>
43 <Tooltip>
44 <TooltipTrigger>
45 <HelpCircle className="text-foreground-light" size={16} strokeWidth={1.5} />
46 </TooltipTrigger>
47
48 <TooltipContent side="bottom">
49 <div className="w-[300px] space-y-2">
50 <p className="text-xs text-foreground">
51 This expression will be added to queries that refer to the table if row-level
52 security is enabled.
53 </p>
54 <p className="text-xs text-foreground">
55 Rows for which the expression returns true will be visible. Any rows for which
56 the expression returns false or null will not be visible to the user (in a
57 SELECT), and will not be available for modification (in an UPDATE or DELETE).
58 </p>
59 <p className="text-xs text-foreground">
60 Such rows are silently suppressed - no error is reported.
61 </p>
62 </div>
63 </TooltipContent>
64 </Tooltip>
65 </div>
66 <p className="text-sm text-foreground-lighter">
67 Provide a SQL conditional expression that returns a boolean.
68 </p>
69 </div>
70 <div className={`w-2/3 ${showCheck(operation) ? 'h-32' : 'h-56'}`}>
71 <SqlEditor defaultValue={definition} onInputChange={onUpdatePolicyUsing} />
72 </div>
73 </div>
74 )}
75 {showCheck(operation) && (
76 <div className="flex space-x-12">
77 <div className="flex w-1/3 flex-col space-y-2">
78 <div className="flex items-center space-x-2">
79 <label className="text-base text-foreground-light" htmlFor="policy-name">
80 WITH CHECK expression
81 </label>
82 <Tooltip>
83 <TooltipTrigger>
84 <HelpCircle className="text-foreground-light" size={16} strokeWidth={1.5} />
85 </TooltipTrigger>
86
87 <TooltipContent side="bottom">
88 <div className="w-[300px] space-y-2">
89 <p className="text-xs text-foreground">
90 This expression will be used in INSERT and UPDATE queries against the table if
91 row-level security is enabled.
92 </p>
93 <p className="text-xs text-foreground">
94 Only rows for which the expression evaluates to true will be allowed. An error
95 will be thrown if the expression evaluates to false or null for any of the
96 records inserted or any of the records that result from the update.
97 </p>
98 <p className="text-xs text-foreground">
99 Note that this expression is evaluated against the proposed new contents of
100 the row, not the original contents.
101 </p>
102 </div>
103 </TooltipContent>
104 </Tooltip>
105 </div>
106 <p className="text-sm text-foreground-lighter">
107 Provide a SQL conditional expression that returns a boolean.
108 </p>
109 </div>
110 <div className={`w-2/3 ${showUsing(operation) ? 'h-32' : 'h-56'}`}>
111 <SqlEditor defaultValue={check} onInputChange={onUpdatePolicyCheck} />
112 </div>
113 </div>
114 )}
115 </div>
116 )
117}
118
119export default PolicyDefinition