Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import CopyButton from 'components/ui/CopyButton'
import NoSearchResults from 'components/ui/NoSearchResults'
import {
getGeneralPolicyTemplates,
getQueuePolicyTemplates,
getRealtimePolicyTemplates,
} from '../PolicyEditorModal/PolicyEditorModal.constants'

Expand All @@ -33,7 +34,9 @@ export const PolicyTemplates = ({
const templates =
schema === 'realtime'
? getRealtimePolicyTemplates()
: getGeneralPolicyTemplates(schema, table.length > 0 ? table : 'table_name')
: schema === 'pgmq'
? getQueuePolicyTemplates()
: getGeneralPolicyTemplates(schema, table.length > 0 ? table : 'table_name')

const baseTemplates =
selectedPolicy !== undefined
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -326,3 +326,21 @@ with check ( realtime.messages.extension = 'presence' AND realtime.topic() = 'ch
] as PolicyTemplate[]
return results
}

export const getQueuePolicyTemplates = (): PolicyTemplate[] => {
return [
{
id: 'policy-queues-1',
preview: false,
templateName: 'Allow access to queue',
statement: ``.trim(),
name: 'Allow anon and authenticated to access messages from queue',
description:
'Base policy to ensure that anon and authenticated can only access appropriate rows. USING and CHECK statements will need to be adjusted accordingly',
definition: 'true',
check: 'true',
command: 'ALL',
roles: ['anon', 'authenticated'],
},
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,37 +62,43 @@ const PolicyRow = ({
'w-full last:border-0 space-x-4 border-b py-4 lg:items-center'
)}
>
<div className="flex grow flex-col space-y-1">
<div className="flex items-center space-x-4">
<p className="font-mono text-xs text-foreground-light">{policy.command}</p>
<p className="text-sm text-foreground">{policy.name}</p>
<div className="flex grow flex-col gap-y-1">
<div className="flex items-start gap-x-4">
<p className="font-mono text-xs text-foreground-light translate-y-[2px] min-w-12">
{policy.command}
</p>

<div className="flex flex-col gap-y-1">
<p className="text-sm text-foreground">{policy.name}</p>
<div className="flex items-center gap-x-1">
<div className="text-foreground-lighter text-sm">
Applied to:
{policy.roles.slice(0, 3).map((role, i) => (
<code key={`policy-${role}-${i}`} className="text-foreground-light text-xs">
{role}
</code>
))}{' '}
role
</div>
{policy.roles.length > 3 && (
<Tooltip_Shadcn_>
<TooltipTrigger_Shadcn_ asChild>
<code key="policy-etc" className="text-foreground-light text-xs">
+ {policy.roles.length - 3} more roles
</code>
</TooltipTrigger_Shadcn_>
<TooltipContent_Shadcn_ side="bottom" align="center">
{policy.roles.slice(3).join(', ')}
</TooltipContent_Shadcn_>
</Tooltip_Shadcn_>
)}
</div>
</div>

{appliesToAnonymousUsers ? (
<Badge color="yellow">Applies to anonymous users</Badge>
) : null}
</div>
<div className="flex items-center gap-x-1 ml-[60px]">
<div className="text-foreground-lighter text-sm">
Applied to:
{policy.roles.slice(0, 3).map((role, i) => (
<code key={`policy-${role}-${i}`} className="text-foreground-light text-xs">
{role}
</code>
))}{' '}
role
</div>
{policy.roles.length > 3 && (
<Tooltip_Shadcn_>
<TooltipTrigger_Shadcn_ asChild>
<code key="policy-etc" className="text-foreground-light text-xs">
+ {policy.roles.length - 3} more roles
</code>
</TooltipTrigger_Shadcn_>
<TooltipContent_Shadcn_ side="bottom" align="center">
{policy.roles.slice(3).join(', ')}
</TooltipContent_Shadcn_>
</Tooltip_Shadcn_>
)}
</div>
</div>
<div>
{!isLocked && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
useEnumeratedTypesQuery,
} from 'data/enumerated-types/enumerated-types-query'
import { useQuerySchemaState } from 'hooks/misc/useSchemaQueryState'
import { EXCLUDED_SCHEMAS } from 'lib/constants/schemas'
import { PROTECTED_SCHEMAS } from 'lib/constants/schemas'
import {
Button,
DropdownMenu,
Expand Down Expand Up @@ -53,7 +53,7 @@ const EnumeratedTypes = () => {
: enumeratedTypes.filter((x) => x.schema === selectedSchema)

const protectedSchemas = (schemas ?? []).filter((schema) =>
EXCLUDED_SCHEMAS.includes(schema?.name ?? '')
PROTECTED_SCHEMAS.includes(schema?.name ?? '')
)
const schema = schemas?.find((schema) => schema.name === selectedSchema)
const isLocked = protectedSchemas.some((s) => s.id === schema?.id)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { useDatabaseExtensionsQuery } from 'data/database-extensions/database-ex
import { useDatabaseFunctionCreateMutation } from 'data/database-functions/database-functions-create-mutation'
import { DatabaseFunction } from 'data/database-functions/database-functions-query'
import { useDatabaseFunctionUpdateMutation } from 'data/database-functions/database-functions-update-mutation'
import { EXCLUDED_SCHEMAS } from 'lib/constants/schemas'
import { PROTECTED_SCHEMAS } from 'lib/constants/schemas'
import type { FormSchema } from 'types'
import {
Button,
Expand Down Expand Up @@ -203,7 +203,7 @@ const CreateFunction = ({ func, visible, setVisible }: CreateFunctionProps) => {
<FormControl_Shadcn_>
<SchemaSelector
selectedSchemaName={field.value}
excludedSchemas={EXCLUDED_SCHEMAS}
excludedSchemas={PROTECTED_SCHEMAS}
size="small"
onSelectSchema={(name) => field.onChange(name)}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { useDatabaseFunctionsQuery } from 'data/database-functions/database-func
import { useSchemasQuery } from 'data/database/schemas-query'
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
import { useQuerySchemaState } from 'hooks/misc/useSchemaQueryState'
import { EXCLUDED_SCHEMAS } from 'lib/constants/schemas'
import { PROTECTED_SCHEMAS } from 'lib/constants/schemas'
import { useAppStateSnapshot } from 'state/app-state'
import { AiIconAnimation, Input } from 'ui'
import ProtectedSchemaWarning from '../../ProtectedSchemaWarning'
Expand Down Expand Up @@ -63,7 +63,7 @@ const FunctionsList = ({
connectionString: project?.connectionString,
})
const [protectedSchemas] = partition(schemas ?? [], (schema) =>
EXCLUDED_SCHEMAS.includes(schema?.name ?? '')
PROTECTED_SCHEMAS.includes(schema?.name ?? '')
)
const foundSchema = schemas?.find((schema) => schema.name === selectedSchema)
const isLocked = protectedSchemas.some((s) => s.id === foundSchema?.id)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { DatabaseIndex, useIndexesQuery } from 'data/database/indexes-query'
import { useSchemasQuery } from 'data/database/schemas-query'
import { useExecuteSqlMutation } from 'data/sql/execute-sql-mutation'
import { useQuerySchemaState } from 'hooks/misc/useSchemaQueryState'
import { EXCLUDED_SCHEMAS } from 'lib/constants/schemas'
import { PROTECTED_SCHEMAS } from 'lib/constants/schemas'
import { AlertCircle, Search, Trash } from 'lucide-react'
import { Button, Input, SidePanel } from 'ui'
import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal'
Expand Down Expand Up @@ -64,7 +64,7 @@ const Indexes = () => {
})

const [protectedSchemas] = partition(schemas ?? [], (schema) =>
EXCLUDED_SCHEMAS.includes(schema?.name ?? '')
PROTECTED_SCHEMAS.includes(schema?.name ?? '')
)
const schema = schemas?.find((schema) => schema.name === selectedSchema)
const isLocked = protectedSchemas.some((s) => s.id === schema?.id)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useState } from 'react'
import { AlertDescription_Shadcn_, AlertTitle_Shadcn_, Alert_Shadcn_, Button, Modal } from 'ui'

import { EXCLUDED_SCHEMAS } from 'lib/constants/schemas'
import { PROTECTED_SCHEMAS } from 'lib/constants/schemas'
import { AlertCircle } from 'lucide-react'

export const ProtectedSchemaModal = ({
Expand Down Expand Up @@ -31,7 +31,7 @@ export const ProtectedSchemaModal = ({
access through the dashboard.
</p>
<div className="flex flex-wrap gap-1">
{EXCLUDED_SCHEMAS.map((schema) => (
{PROTECTED_SCHEMAS.map((schema) => (
<code key={schema} className="text-xs">
{schema}
</code>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import InformationBox from 'components/ui/InformationBox'
import { Loading } from 'components/ui/Loading'
import { useTablesQuery } from 'data/tables/tables-query'
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
import { EXCLUDED_SCHEMAS } from 'lib/constants/schemas'
import { PROTECTED_SCHEMAS } from 'lib/constants/schemas'
import { Button, Input } from 'ui'
import PublicationsTableItem from './PublicationsTableItem'
import { ChevronLeft, Search, AlertCircle } from 'lucide-react'
Expand Down Expand Up @@ -44,8 +44,8 @@ const PublicationsTables = ({ selectedPublication, onSelectBack }: PublicationsT
select(tables) {
return tables.filter((table) =>
filterString.length === 0
? !EXCLUDED_SCHEMAS.includes(table.schema)
: !EXCLUDED_SCHEMAS.includes(table.schema) && table.name.includes(filterString)
? !PROTECTED_SCHEMAS.includes(table.schema)
: !PROTECTED_SCHEMAS.includes(table.schema) && table.name.includes(filterString)
)
},
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { GenericSkeletonLoader } from 'components/ui/ShimmeringLoader'
import { useTableEditorQuery } from 'data/table-editor/table-editor-query'
import { isTableLike } from 'data/table-editor/table-editor-types'
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
import { EXCLUDED_SCHEMAS } from 'lib/constants/schemas'
import { PROTECTED_SCHEMAS } from 'lib/constants/schemas'
import {
Button,
DropdownMenu,
Expand Down Expand Up @@ -61,7 +61,7 @@ const ColumnList = ({
? selectedTable?.columns ?? []
: selectedTable?.columns?.filter((column: any) => column.name.includes(filterString))) ?? []

const isLocked = EXCLUDED_SCHEMAS.includes(selectedTable?.schema ?? '')
const isLocked = PROTECTED_SCHEMAS.includes(selectedTable?.schema ?? '')
const canUpdateColumns = useCheckPermissions(PermissionAction.TENANT_SQL_ADMIN_WRITE, 'columns')

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import { useTablesQuery } from 'data/tables/tables-query'
import { useViewsQuery } from 'data/views/views-query'
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
import { useQuerySchemaState } from 'hooks/misc/useSchemaQueryState'
import { EXCLUDED_SCHEMAS } from 'lib/constants/schemas'
import { PROTECTED_SCHEMAS } from 'lib/constants/schemas'
import {
Button,
Checkbox_Shadcn_,
Expand Down Expand Up @@ -185,7 +185,7 @@ const TableList = ({
(x) => visibleTypes.includes(x.type)
)

const isLocked = EXCLUDED_SCHEMAS.includes(selectedSchema)
const isLocked = PROTECTED_SCHEMAS.includes(selectedSchema)

const error = tablesError || viewsError || materializedViewsError || foreignTablesError
const isError = isErrorTables || isErrorViews || isErrorMaterializedViews || isErrorForeignTables
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { useDatabaseTriggerCreateMutation } from 'data/database-triggers/databas
import { useDatabaseTriggerUpdateMutation } from 'data/database-triggers/database-trigger-update-mutation'
import { useTablesQuery } from 'data/tables/tables-query'
import { BASE_PATH } from 'lib/constants'
import { EXCLUDED_SCHEMAS } from 'lib/constants/schemas'
import { PROTECTED_SCHEMAS } from 'lib/constants/schemas'
import { PauseCircle, PlayCircle, Terminal } from 'lucide-react'
import type { Dictionary } from 'types'
import ChooseFunctionForm from './ChooseFunctionForm'
Expand Down Expand Up @@ -148,7 +148,7 @@ class CreateTriggerStore implements ICreateTriggerStore {
setTables = (value: any[]) => {
this.tables = value
.sort((a, b) => a.schema.localeCompare(b.schema))
.filter((a) => !EXCLUDED_SCHEMAS.includes(a.schema)) as any
.filter((a) => !PROTECTED_SCHEMAS.includes(a.schema)) as any
this.setDefaultSelectedTable()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@ import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectConte
import Table from 'components/to-be-cleaned/Table'
import { useDatabaseTriggersQuery } from 'data/database-triggers/database-triggers-query'
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
import { Check, X, MoreVertical, Edit3, Trash } from 'lucide-react'
import { Check, X, MoreVertical, Edit3, Trash, Edit, Edit2 } from 'lucide-react'
import { useAppStateSnapshot } from 'state/app-state'
import { useIsAssistantV2Enabled } from 'components/interfaces/App/FeaturePreview/FeaturePreviewContext'
import { cn } from 'ui'
import { generateTriggerCreateSQL } from './TriggerList.utils'

interface TriggerListProps {
schema: string
Expand All @@ -35,6 +39,8 @@ const TriggerList = ({
deleteTrigger,
}: TriggerListProps) => {
const { project } = useProjectContext()
const { setAiAssistantPanel } = useAppStateSnapshot()
const isAssistantV2Enabled = useIsAssistantV2Enabled()

const { data: triggers } = useDatabaseTriggersQuery({
projectRef: project?.ref,
Expand Down Expand Up @@ -135,13 +141,42 @@ const TriggerList = ({
<DropdownMenuTrigger asChild>
<Button type="default" className="px-1" icon={<MoreVertical />} />
</DropdownMenuTrigger>
<DropdownMenuContent side="bottom" align="end" className="w-36">
<DropdownMenuContent
side="bottom"
align="end"
className={cn(isAssistantV2Enabled ? 'w-52' : 'w-36')}
>
<DropdownMenuItem className="space-x-2" onClick={() => editTrigger(x)}>
<Edit3 size="14" />
<Edit2 size={14} />
<p>Edit trigger</p>
</DropdownMenuItem>
{isAssistantV2Enabled && (
<DropdownMenuItem
className="space-x-2"
onClick={() => {
const sql = generateTriggerCreateSQL(x)
setAiAssistantPanel({
open: true,
initialInput: `Update this trigger which exists on the ${x.schema}.${x.table} table to...`,
suggestions: {
title:
'I can help you make a change to this trigger, here are a few example prompts to get you started:',
prompts: [
'Rename this trigger to ...',
'Change the events this trigger responds to ...',
'Modify this trigger to run after instead of before ...',
],
},
sqlSnippets: [sql],
})
}}
>
<Edit size={14} />
<p>Edit with Assistant</p>
</DropdownMenuItem>
)}
<DropdownMenuItem className="space-x-2" onClick={() => deleteTrigger(x)}>
<Trash stroke="red" size="14" />
<Trash stroke="red" size={14} />
<p>Delete trigger</p>
</DropdownMenuItem>
</DropdownMenuContent>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
interface PostgresTrigger {
activation: string
condition: string | null
enabled_mode: string
events: string[]
function_args: string[]
function_name: string
function_schema: string
id: number
name: string
orientation: string
schema: string
table: string
table_id: number
}

export const generateTriggerCreateSQL = (trigger: PostgresTrigger) => {
const events = trigger.events.join(' OR ')
const args = trigger.function_args.length > 0 ? `(${trigger.function_args.join(', ')})` : '()'

let sql = `
CREATE TRIGGER "${trigger.name}"
${trigger.activation} ${events}
ON "${trigger.schema}"."${trigger.table}"
FOR EACH ${trigger.orientation}
`

if (trigger.condition) {
sql += `WHEN (${trigger.condition})\n`
}

sql += `EXECUTE FUNCTION "${trigger.function_schema}"."${trigger.function_name}"${args};`

return sql.trim()
}
Loading
Loading