mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-06 00:02:13 +00:00
feat(datatables): a permissions drawer on a table
This commit is contained in:
@@ -363,8 +363,12 @@ fn plan_statements(
|
||||
}
|
||||
// Ownership cannot be set ahead of time: an object belongs to
|
||||
// whoever creates it. Default privileges are what keeps the owner
|
||||
// in reach of what the other roles create from here on.
|
||||
for other in other_pg_roles {
|
||||
// in reach of what the other roles create from here on — which only
|
||||
// means something for a schema, the thing objects are created in.
|
||||
for other in other_pg_roles
|
||||
.iter()
|
||||
.filter(|_| matches!(target, AclTarget::Schema { .. }))
|
||||
{
|
||||
for plural in ["TABLES", "SEQUENCES", "FUNCTIONS"] {
|
||||
statements.push(format!(
|
||||
"ALTER DEFAULT PRIVILEGES FOR ROLE {} IN SCHEMA {} GRANT ALL PRIVILEGES ON {} TO {}",
|
||||
@@ -375,7 +379,7 @@ fn plan_statements(
|
||||
));
|
||||
}
|
||||
}
|
||||
if existing_objects.is_empty() {
|
||||
if existing_objects.is_empty() && matches!(target, AclTarget::Schema { .. }) {
|
||||
warnings.push(format!(
|
||||
"{} holds no objects yet; only the schema itself changes hands.",
|
||||
target.label(dbname)
|
||||
@@ -1053,6 +1057,26 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_tables_owner_change_is_only_that_table() {
|
||||
let plan = plan_statements(
|
||||
&AclTarget::Table { schema: "analytics".to_string(), table: "orders".to_string() },
|
||||
&AclChange::SetOwner { role: "analyst".to_string() },
|
||||
"dt_probe",
|
||||
"wm_analyst_1",
|
||||
&["wm_admin".to_string()],
|
||||
&[],
|
||||
)
|
||||
.unwrap();
|
||||
// Default privileges are about what gets created in a schema, which
|
||||
// changing one table's owner says nothing about.
|
||||
assert_eq!(
|
||||
plan.statements,
|
||||
[r#"ALTER TABLE "analytics"."orders" OWNER TO "wm_analyst_1""#]
|
||||
);
|
||||
assert!(plan.warnings.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn several_objects_are_revoked_together() {
|
||||
let plan = plan_statements(
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
import PgAclEditor from './datatableAcl/PgAclEditor.svelte'
|
||||
import { favoriteManager } from './sidebar/FavoriteMenu.svelte'
|
||||
import DatatableRoleBadge from './DatatableRoleBadge.svelte'
|
||||
import type { Asset, DataTableTables } from '$lib/gen'
|
||||
import type { AclTarget, Asset, DataTableTables } from '$lib/gen'
|
||||
import { ADMIN_DATATABLE_ROLE, type DatatableRowAction } from './dbTypes'
|
||||
import TextInput from './text_input/TextInput.svelte'
|
||||
import Checkbox from './common/checkbox/Checkbox.svelte'
|
||||
@@ -287,8 +287,8 @@
|
||||
// overrides is what lets the current data table and selected schema — which
|
||||
// default to open — actually be folded; a plain "expanded" set could never
|
||||
// close them, since the default would keep winning.
|
||||
// The schema the permissions drawer is open on, if any.
|
||||
let schemaPermissions = $state<{ datatable: string | undefined; schema: string } | undefined>(
|
||||
// What the permissions drawer is open on, if anything: a schema, or a table.
|
||||
let aclDrawer = $state<{ datatable: string | undefined; target: AclTarget } | undefined>(
|
||||
undefined
|
||||
)
|
||||
|
||||
@@ -536,6 +536,12 @@
|
||||
)
|
||||
let newSchemaName = $state('')
|
||||
|
||||
/** What the drawer is about, for its title. */
|
||||
function aclLabel(target: AclTarget | undefined): string {
|
||||
if (!target) return ''
|
||||
return target.kind === 'table' ? `${target.schema}.${target.table}` : (target.schema ?? '')
|
||||
}
|
||||
|
||||
function closeSchemaDialog() {
|
||||
schemaDialog = undefined
|
||||
newSchemaName = ''
|
||||
@@ -727,9 +733,9 @@
|
||||
displayName: 'Permissions',
|
||||
icon: KeyRoundIcon,
|
||||
action: () =>
|
||||
(schemaPermissions = {
|
||||
(aclDrawer = {
|
||||
datatable: root.datatable,
|
||||
schema: sc.schemaKey
|
||||
target: { kind: 'schema', schema: sc.schemaKey }
|
||||
})
|
||||
},
|
||||
{
|
||||
@@ -805,6 +811,19 @@
|
||||
<DropdownV2
|
||||
enableFlyTransition
|
||||
items={() => [
|
||||
{
|
||||
displayName: 'Permissions',
|
||||
icon: KeyRoundIcon,
|
||||
action: () =>
|
||||
(aclDrawer = {
|
||||
datatable: root.datatable,
|
||||
target: {
|
||||
kind: 'table',
|
||||
schema: sc.schemaKey,
|
||||
table: tableKey
|
||||
}
|
||||
})
|
||||
},
|
||||
{
|
||||
displayName: 'Delete table',
|
||||
icon: Trash2Icon,
|
||||
@@ -886,20 +905,16 @@
|
||||
</Splitpanes>
|
||||
|
||||
<Portal>
|
||||
<Drawer open={!!schemaPermissions} size="900px" on:close={() => (schemaPermissions = undefined)}>
|
||||
<Drawer open={!!aclDrawer} size="900px" on:close={() => (aclDrawer = undefined)}>
|
||||
<DrawerContent
|
||||
title="Permissions — {schemaPermissions?.schema ?? ''}"
|
||||
on:close={() => (schemaPermissions = undefined)}
|
||||
tooltip="Who owns this schema, and what each role may do in it. Runs against the data table as its admin connection."
|
||||
title="Permissions — {aclLabel(aclDrawer?.target)}"
|
||||
on:close={() => (aclDrawer = undefined)}
|
||||
tooltip="Who owns this, and what each role may do with it. Runs against the data table as its admin connection."
|
||||
>
|
||||
{#if schemaPermissions && workspace}
|
||||
{@const dt = schemaPermissions.datatable ?? currentDatatable}
|
||||
{#if aclDrawer && workspace}
|
||||
{@const dt = aclDrawer.datatable ?? currentDatatable}
|
||||
{#if dt}
|
||||
<PgAclEditor
|
||||
{workspace}
|
||||
datatable={dt}
|
||||
target={{ kind: 'schema', schema: schemaPermissions.schema }}
|
||||
/>
|
||||
<PgAclEditor {workspace} datatable={dt} target={aclDrawer.target} />
|
||||
{/if}
|
||||
{/if}
|
||||
</DrawerContent>
|
||||
|
||||
@@ -106,9 +106,9 @@
|
||||
<div class="flex flex-col gap-0.5">
|
||||
<span class="text-sm font-semibold text-primary">Owner</span>
|
||||
<span class="text-xs text-secondary">
|
||||
The role that owns {target.kind === 'schema' ? 'the schema' : 'the table'} and everything
|
||||
already in it. Changing it also lets the new owner reach what the other roles create here
|
||||
later.
|
||||
{target.kind === 'schema'
|
||||
? 'The role that owns the schema and everything already in it. Changing it also lets the new owner reach what the other roles create here later.'
|
||||
: 'The role that owns the table. Its owner may always read and write it, and is who ALTER and DROP answer to.'}
|
||||
</span>
|
||||
</div>
|
||||
<Select
|
||||
|
||||
Reference in New Issue
Block a user