feat(datatables): a shared data table is listed in the settings, read only

A fork could use its parent's data table but had nowhere to see that it
had one: the settings form reads the config, and the pointer lives outside
`datatables`. It is now a row of its own, naming the workspace it belongs
to, with no name to edit, no database to repoint and no delete — it is
configured, and its permissions administered, where it lives.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S5arH3G2Sa1Qqm32veJQ1n
This commit is contained in:
Diego Imbert
2026-09-04 23:01:06 +02:00
co-authored by Claude Opus 5
parent 497f24bca7
commit 0faedba495
3 changed files with 43 additions and 3 deletions
+13
View File
@@ -33920,6 +33920,19 @@ components:
type: object
description: Schema snapshot at fork time
additionalProperties: true
shared_datatables:
type: object
description: >-
Data tables of other workspaces that this one uses. Read-only here:
they are configured, and their permissions administered, in the
workspace named by `from`.
additionalProperties:
type: object
required: [from]
properties:
from:
type: string
description: The workspace this data table belongs to
DatatableMigration:
type: object
required: [datatable, timestamp, name, code_up]
@@ -13,12 +13,16 @@
resource_path?: string | undefined
}
}[]
/// Data tables of other workspaces that this one uses. Not this form's to
/// edit — they are configured, and their permissions administered, where
/// they live — so they are listed and left out of what it saves.
sharedDataTables: { name: string; from: string }[]
}
export function convertDataTableSettingsFromBackend(
settings: GetSettingsResponse['datatable']
): DataTableSettingsType {
const s: DataTableSettingsType = { dataTables: [] }
const s: DataTableSettingsType = { dataTables: [], sharedDataTables: [] }
if (settings?.datatables) {
for (const [name, rest] of Object.entries(settings.datatables)) {
s.dataTables.push({
@@ -28,6 +32,9 @@
})
}
}
for (const [name, entry] of Object.entries(settings?.shared_datatables ?? {})) {
s.sharedDataTables.push({ name, from: entry.from })
}
return s
}
export function convertDataTableSettingsToBackend(
@@ -316,7 +323,7 @@
</tr>
</Head>
<tbody class="divide-y bg-surface-tertiary">
{#if tempSettings.dataTables.length == 0}
{#if tempSettings.dataTables.length == 0 && tempSettings.sharedDataTables.length == 0}
<Row>
{#if wizardEnabled}
<Cell colspan={tableHeadNames.length} class="py-8">
@@ -492,6 +499,26 @@
</Cell>
</Row>
{/each}
{#each tempSettings.sharedDataTables as shared (shared.name)}
<Row>
<Cell first class="w-48">
<span class="text-sm">{shared.name}</span>
</Cell>
<Cell>
<span class="text-xs text-secondary">
Shared from <span class="font-medium">{shared.from}</span>
</span>
<Tooltip>
This data table belongs to {shared.from}. Everyone here reaches it with the roles
that workspace gives them, and it is configured there.
</Tooltip>
</Cell>
<Cell class="whitespace-nowrap">
<ExploreAssetButton asset={{ kind: 'datatable', path: shared.name }} />
</Cell>
<Cell class="w-12"></Cell>
</Row>
{/each}
{#if !wizardEnabled || tempSettings.dataTables.length > 0}
<Row class="!border-0">
<Cell colspan={tableHeadNames.length} class="pt-0 pb-2">
@@ -252,7 +252,7 @@
volumeStorage: undefined
})
let dataTableSettings: DataTableSettingsType = $state({ dataTables: [] })
let dataTableSettings: DataTableSettingsType = $state({ dataTables: [], sharedDataTables: [] })
let dataTableSettingsComponent: DataTableSettings | undefined = $state(undefined)
let dbtSettings: DbtSettingsType = $state({ warehouses: [] })