fix(raw apps): show the schemas the picked role can reach

This commit is contained in:
Diego Imbert
2026-09-01 03:39:06 +02:00
parent b2b6ee773b
commit 1f6aec5470
2 changed files with 63 additions and 4 deletions
@@ -21,9 +21,9 @@
import type { Runnable } from './rawAppPolicy'
import { type DataTableRef, type RawAppData, formatDataTableRef } from './dataTableRefUtils'
import {
createDatatableAccessResource,
createDatatablesResource,
createRolesResource,
createSchemasResource,
rolesWorthPicking,
toDatatableItems,
toSchemaItems
@@ -70,8 +70,10 @@
let opWs = $derived(getOpWs?.() ?? $workspaceStore)
const datatables = createDatatablesResource(() => opWs)
const schemas = createSchemasResource(
// What the picked role can reach, which is not what the data table holds.
const access = createDatatableAccessResource(
() => selectedDatatable,
() => (showRolePicker ? selectedRole : undefined),
() => opWs
)
const roles = createRolesResource(
@@ -95,7 +97,14 @@
})
const availableDatatables = $derived(datatables.current)
const availableSchemas = $derived(schemas.current)
const availableSchemas = $derived(access.current.schemas)
const canCreateSchema = $derived(access.current.canCreateSchema)
// A role that cannot create schemas has nothing to name, so the mode goes
// back to the one every role has.
$effect(() => {
if (schemaMode === 'new' && !canCreateSchema) schemaMode = 'none'
})
let hasAutoSelected = false
$effect(() => {
@@ -316,7 +325,17 @@
<ToggleButtonGroup bind:selected={schemaMode} noWFull>
{#snippet children({ item })}
<ToggleButton value="none" label="None" icon={Ban} {item} size="sm" />
<ToggleButton value="new" label="New" icon={Plus} {item} size="sm" />
<ToggleButton
value="new"
label="New"
icon={Plus}
disabled={!canCreateSchema}
tooltip={canCreateSchema
? undefined
: `${selectedRole ?? 'This role'} cannot create schemas in ${selectedDatatable}`}
{item}
size="sm"
/>
<ToggleButton
value="existing"
label="Existing"
@@ -87,6 +87,46 @@ export function createRolesResource(
)
}
/**
* Creates a resource that loads, for one data table read as one role, the
* schemas that role can reach and whether it may create more.
*
* Both answers are the connected role's, and one call carries them: asking the
* schema list of a role that cannot see a schema is the same question as asking
* what it may create in.
*/
export function createDatatableAccessResource(
getDatatable: () => string | undefined,
getRole: () => string | undefined,
getWorkspace: () => string | undefined = () => get(workspaceStore)
) {
return resource(
() => [getDatatable() ?? '', getRole() ?? '', getWorkspace() ?? ''] as const,
async ([datatable, role, workspace]): Promise<{
schemas: string[]
canCreateSchema: boolean
}> => {
if (!datatable || !workspace) return { schemas: [], canCreateSchema: false }
try {
const tables = await WorkspaceService.listDataTableTables({
workspace,
roleFor: datatable,
role: role || undefined
})
const entry = tables.find((t) => t.datatable_name === datatable)
return {
schemas: Object.keys(entry?.schemas ?? {}).sort(),
canCreateSchema: !!entry?.can_create_schema
}
} catch (e) {
console.error('Failed to load datatable access:', e)
return { schemas: [], canCreateSchema: false }
}
},
{ initialValue: { schemas: [], canCreateSchema: false } }
)
}
/**
* Whether naming a role says anything here: a data table without permissions has
* none to pick, and one whose single role is the implicit `admin` has no choice