Skip to content

Commit a299180

Browse files
SaxonFjoshenlim
andauthored
update realtime and storage policies (supabase#38229)
* update realtime and storage policies * Small refactors * Tiny fix * Fix typo --------- Co-authored-by: Joshen Lim <[email protected]>
1 parent 0af359a commit a299180

File tree

9 files changed

+104
-119
lines changed

9 files changed

+104
-119
lines changed

apps/studio/components/interfaces/Auth/Policies/PolicyEditor/PolicyName.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ interface PolicyNameProps {
88

99
const PolicyName = ({ name = '', limit = 100, onUpdatePolicyName }: PolicyNameProps) => {
1010
return (
11-
<div className="flex flex-col md:flew-row gap-4 md:gap-12">
11+
<div className="flex flex-col md:flex-row gap-4 md:gap-12">
1212
<div className="flex md:w-1/3 flex-col space-y-2">
1313
<label className="text-base text-foreground-light" htmlFor="policy-name">
1414
Policy name

apps/studio/components/interfaces/Auth/Policies/PolicyEditor/PolicyRoles.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ const PolicyRoles = ({ selectedRoles, onUpdateSelectedRoles }: PolicyRolesProps)
3434
})
3535

3636
return (
37-
<div className="flex flex-col md:flew-row gap-4 md:gap-12">
37+
<div className="flex flex-col md:flex-row gap-4 md:gap-12">
3838
<div className="flex md:w-1/3 flex-col space-y-2">
3939
<label className="text-foreground-light text-base" htmlFor="policy-name">
4040
Target roles

apps/studio/components/interfaces/Auth/Policies/PolicyTableRow/PolicyRow.tsx

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@ import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
1010
import { useAiAssistantStateSnapshot } from 'state/ai-assistant-state'
1111
import {
1212
Button,
13-
TableRow,
14-
TableCell,
1513
DropdownMenu,
1614
DropdownMenuContent,
1715
DropdownMenuItem,
1816
DropdownMenuSeparator,
1917
DropdownMenuTrigger,
18+
TableCell,
19+
TableRow,
2020
Tooltip,
2121
TooltipContent,
2222
TooltipTrigger,
@@ -27,12 +27,12 @@ interface PolicyRowProps {
2727
policy: PostgresPolicy
2828
onSelectEditPolicy: (policy: PostgresPolicy) => void
2929
onSelectDeletePolicy: (policy: PostgresPolicy) => void
30-
isLocked: boolean
30+
isLocked?: boolean
3131
}
3232

33-
const PolicyRow = ({
33+
export const PolicyRow = ({
3434
policy,
35-
isLocked: isLockedDefault,
35+
isLocked: isLockedDefault = false,
3636
onSelectEditPolicy = noop,
3737
onSelectDeletePolicy = noop,
3838
}: PolicyRowProps) => {
@@ -169,5 +169,3 @@ const PolicyRow = ({
169169
</TableRow>
170170
)
171171
}
172-
173-
export default PolicyRow

apps/studio/components/interfaces/Auth/Policies/PolicyTableRow/PolicyTableRowHeader.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ interface PolicyTableRowHeaderProps {
2626
onSelectCreatePolicy: () => void
2727
}
2828

29-
const PolicyTableRowHeader = ({
29+
export const PolicyTableRowHeader = ({
3030
table,
3131
isLocked,
3232
onSelectToggleRLS = noop,
@@ -134,5 +134,3 @@ const PolicyTableRowHeader = ({
134134
</div>
135135
)
136136
}
137-
138-
export default PolicyTableRowHeader

apps/studio/components/interfaces/Auth/Policies/PolicyTableRow/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ import {
2020
TableRow,
2121
} from 'ui'
2222
import ShimmeringLoader from 'ui-patterns/ShimmeringLoader'
23-
import PolicyRow from './PolicyRow'
24-
import PolicyTableRowHeader from './PolicyTableRowHeader'
23+
import { PolicyRow } from './PolicyRow'
24+
import { PolicyTableRowHeader } from './PolicyTableRowHeader'
2525

2626
export interface PolicyTableRowProps {
2727
table: {

apps/studio/components/interfaces/Realtime/Policies.tsx

Lines changed: 16 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import { useState } from 'react'
44
import { Policies } from 'components/interfaces/Auth/Policies/Policies'
55
import { PolicyEditorPanel } from 'components/interfaces/Auth/Policies/PolicyEditorPanel'
66
import AlertError from 'components/ui/AlertError'
7-
import { FormHeader } from 'components/ui/Forms/FormHeader'
87
import { GenericSkeletonLoader } from 'components/ui/ShimmeringLoader'
98
import { useTablesQuery } from 'data/tables/tables-query'
109
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
@@ -30,34 +29,26 @@ export const RealtimePolicies = () => {
3029
const filteredTables = (tables ?? []).filter((table) => table.name === 'messages')
3130

3231
return (
33-
<div className="flex min-h-full w-full flex-col p-4 gap-y-4">
34-
<FormHeader
35-
className="!mb-0"
36-
title="Realtime policies"
37-
description="You can use RLS policies to control access to Realtime Channels"
38-
/>
39-
32+
<>
4033
{isLoading && <GenericSkeletonLoader />}
4134

4235
{isError && <AlertError error={error} subject="Failed to retrieve tables" />}
4336

4437
{isSuccess && (
45-
<div className="space-y-4">
46-
<Policies
47-
schema="realtime"
48-
tables={filteredTables}
49-
hasTables
50-
isLocked={false}
51-
onSelectCreatePolicy={() => {
52-
setSelectedPolicyToEdit(undefined)
53-
setShowPolicyEditor(true)
54-
}}
55-
onSelectEditPolicy={(policy) => {
56-
setSelectedPolicyToEdit(policy)
57-
setShowPolicyEditor(true)
58-
}}
59-
/>
60-
</div>
38+
<Policies
39+
schema="realtime"
40+
tables={filteredTables}
41+
hasTables
42+
isLocked={false}
43+
onSelectCreatePolicy={() => {
44+
setSelectedPolicyToEdit(undefined)
45+
setShowPolicyEditor(true)
46+
}}
47+
onSelectEditPolicy={(policy) => {
48+
setSelectedPolicyToEdit(policy)
49+
setShowPolicyEditor(true)
50+
}}
51+
/>
6152
)}
6253

6354
<PolicyEditorPanel
@@ -68,6 +59,6 @@ export const RealtimePolicies = () => {
6859
onSelectCancel={() => setShowPolicyEditor(false)}
6960
authContext="realtime"
7061
/>
71-
</div>
62+
</>
7263
)
7364
}

apps/studio/components/interfaces/Storage/StoragePolicies/StoragePolicies.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
1818
import { Loader } from 'lucide-react'
1919
import ConfirmModal from 'ui-patterns/Dialogs/ConfirmDialog'
2020
import { formatPoliciesForStorage } from '../Storage.utils'
21-
import StoragePoliciesBucketRow from './StoragePoliciesBucketRow'
21+
import { StoragePoliciesBucketRow } from './StoragePoliciesBucketRow'
2222
import StoragePoliciesEditPolicyModal from './StoragePoliciesEditPolicyModal'
2323
import StoragePoliciesPlaceholder from './StoragePoliciesPlaceholder'
2424

Lines changed: 55 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,108 +1,86 @@
1-
import Panel from 'components/ui/Panel'
2-
import { isEmpty } from 'lodash'
3-
import { Archive, Edit, MoreVertical, Trash } from 'lucide-react'
1+
import { PostgresPolicy } from '@supabase/postgres-meta'
2+
import { noop } from 'lodash'
3+
import { Archive } from 'lucide-react'
4+
5+
import { PolicyRow } from 'components/interfaces/Auth/Policies/PolicyTableRow/PolicyRow'
6+
import { Bucket } from 'data/storage/buckets-query'
47
import {
58
Badge,
69
Button,
710
Card,
811
CardContent,
912
CardHeader,
1013
CardTitle,
11-
DropdownMenu,
12-
DropdownMenuContent,
13-
DropdownMenuItem,
14-
DropdownMenuSeparator,
15-
DropdownMenuTrigger,
14+
Table,
15+
TableBody,
16+
TableHead,
17+
TableHeader,
18+
TableRow,
1619
} from 'ui'
1720

18-
interface PolicyRowProps {
19-
policy: any
20-
table: any
21-
bucketName: string
22-
onSelectPolicyEdit: (p: any, s: string, t: any) => void
23-
onSelectPolicyDelete: (s: string) => void
21+
interface StoragePoliciesBucketRowProps {
22+
table: string
23+
label: string
24+
bucket?: Bucket
25+
policies: PostgresPolicy[]
26+
onSelectPolicyAdd: (bucketName: string, table: string) => void
27+
onSelectPolicyEdit: (policy: PostgresPolicy, bucketName: string, table: string) => void
28+
onSelectPolicyDelete: (policy: PostgresPolicy) => void
2429
}
2530

26-
const PolicyRow = ({
27-
policy,
28-
table,
29-
bucketName,
30-
onSelectPolicyEdit = () => {},
31-
onSelectPolicyDelete = () => {},
32-
}: PolicyRowProps) => {
33-
const { name, command } = policy
34-
return (
35-
<CardContent className="group flex justify-between gap-2 border-b border-overlay py-4">
36-
<div className="flex flex-col gap-3 lg:flex-row lg:items-center">
37-
<div className="font-mono text-xs text-foreground-lighter">{command}</div>
38-
<div className="flex flex-col gap-2 lg:flex-row">
39-
<span className="truncate text-sm text-foreground">{name}</span>
40-
</div>
41-
</div>
42-
<DropdownMenu>
43-
<DropdownMenuTrigger>
44-
<Button type="default" className="px-1.5" icon={<MoreVertical />} />
45-
</DropdownMenuTrigger>
46-
<DropdownMenuContent side="bottom" align="end">
47-
<DropdownMenuItem
48-
className="gap-x-2"
49-
onClick={() => onSelectPolicyEdit(policy, bucketName, table)}
50-
>
51-
<Edit size={14} />
52-
<p>Edit</p>
53-
</DropdownMenuItem>
54-
<DropdownMenuSeparator />
55-
<DropdownMenuItem className="gap-x-2" onClick={() => onSelectPolicyDelete(policy)}>
56-
<Trash size={14} />
57-
<p>Delete</p>
58-
</DropdownMenuItem>
59-
</DropdownMenuContent>
60-
</DropdownMenu>
61-
</CardContent>
62-
)
63-
}
64-
65-
const StoragePoliciesBucketRow = ({
31+
export const StoragePoliciesBucketRow = ({
6632
table = '',
6733
label = '',
68-
bucket = {},
34+
bucket,
6935
policies = [],
70-
onSelectPolicyAdd = () => {},
71-
onSelectPolicyEdit = () => {},
72-
onSelectPolicyDelete = () => {},
73-
}: any) => {
36+
onSelectPolicyAdd = noop,
37+
onSelectPolicyEdit = noop,
38+
onSelectPolicyDelete = noop,
39+
}: StoragePoliciesBucketRowProps) => {
7440
return (
7541
<Card>
7642
<CardHeader className="flex flex-row w-full items-center justify-between gap-0 space-y-0">
7743
<div className="flex items-center gap-3">
7844
<Archive className="text-foreground-light" size={16} strokeWidth={1.5} />
7945
<CardTitle>{label}</CardTitle>
80-
{bucket.public && <Badge variant="warning">Public</Badge>}
46+
{bucket?.public && <Badge variant="warning">Public</Badge>}
8147
</div>
82-
<Button type="outline" onClick={() => onSelectPolicyAdd(bucket.name, table)}>
83-
New policy
84-
</Button>
48+
{!!bucket && (
49+
<Button type="outline" onClick={() => onSelectPolicyAdd(bucket.name, table)}>
50+
New policy
51+
</Button>
52+
)}
8553
</CardHeader>
8654
{policies.length === 0 ? (
8755
<CardContent>
8856
<p className="text-sm text-foreground-lighter">No policies created yet</p>
8957
</CardContent>
9058
) : (
91-
<div>
92-
{policies.map((policy: any) => (
93-
<PolicyRow
94-
key={policy.name}
95-
policy={policy}
96-
table={table}
97-
bucketName={bucket.name}
98-
onSelectPolicyEdit={onSelectPolicyEdit}
99-
onSelectPolicyDelete={onSelectPolicyDelete}
100-
/>
101-
))}
102-
</div>
59+
<CardContent className="p-0">
60+
<Table className="table-fixed">
61+
<TableHeader>
62+
<TableRow>
63+
<TableHead className="w-[40%]">Name</TableHead>
64+
<TableHead className="w-[20%]">Command</TableHead>
65+
<TableHead className="w-[30%]">Applied to</TableHead>
66+
<TableHead className="w-0 text-right">
67+
<span className="sr-only">Actions</span>
68+
</TableHead>
69+
</TableRow>
70+
</TableHeader>
71+
<TableBody>
72+
{policies.map((policy) => (
73+
<PolicyRow
74+
key={policy.id ?? policy.name}
75+
policy={policy}
76+
onSelectEditPolicy={(p) => onSelectPolicyEdit(p, bucket?.name ?? '', table)}
77+
onSelectDeletePolicy={onSelectPolicyDelete}
78+
/>
79+
))}
80+
</TableBody>
81+
</Table>
82+
</CardContent>
10383
)}
10484
</Card>
10585
)
10686
}
107-
108-
export default StoragePoliciesBucketRow

apps/studio/pages/project/[ref]/realtime/policies.tsx

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,35 @@ import { RealtimePolicies } from 'components/interfaces/Realtime/Policies'
22
import type { NextPageWithLayout } from 'types'
33

44
import DefaultLayout from 'components/layouts/DefaultLayout'
5+
import { PageLayout } from 'components/layouts/PageLayout/PageLayout'
56
import RealtimeLayout from 'components/layouts/RealtimeLayout/RealtimeLayout'
7+
import { ScaffoldContainer, ScaffoldSection } from 'components/layouts/Scaffold'
8+
import { DocsButton } from 'components/ui/DocsButton'
69

710
const RealtimePoliciesPage: NextPageWithLayout = () => {
8-
return <RealtimePolicies />
11+
return (
12+
<ScaffoldContainer size="full">
13+
<ScaffoldSection isFullWidth>
14+
<RealtimePolicies />
15+
</ScaffoldSection>
16+
</ScaffoldContainer>
17+
)
918
}
1019

1120
RealtimePoliciesPage.getLayout = (page) => (
1221
<DefaultLayout>
13-
<RealtimeLayout title="Policies">{page}</RealtimeLayout>
22+
<RealtimeLayout title="Policies">
23+
<PageLayout
24+
title="Policies"
25+
subtitle="Control access to your realtime channels"
26+
primaryActions={
27+
<DocsButton href="https://supabase.com/docs/guides/realtime/authorization" />
28+
}
29+
size="large"
30+
>
31+
{page}
32+
</PageLayout>
33+
</RealtimeLayout>
1434
</DefaultLayout>
1535
)
1636

0 commit comments

Comments
 (0)