mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-05 16:03:47 +00:00
fix(datatables): an answer about another role settles nothing
What a role may create in is the question the access resource asks, so an answer computed as a different one is not an answer to it — and there is always one of those: the role getter is empty until the role list settles, so every switch fetches once with no role, which the server reads as the data table's configured default. That answer stamped the data table alone, passed the check, and its one-way flip took the modal off `New` for a role that can create schemas. Both halves of the key are stamped and compared now, and Start waits for that answer too: a new schema name checked against a list from another question is not checked. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S5arH3G2Sa1Qqm32veJQ1n
This commit is contained in:
co-authored by
Claude Opus 5
parent
8868c5ff72
commit
2d8a99d2a3
@@ -74,7 +74,7 @@
|
||||
// What the picked role can reach, which is not what the data table holds.
|
||||
const access = createDatatableAccessResource(
|
||||
() => selectedDatatable,
|
||||
() => (showRolePicker ? effectiveRole : undefined),
|
||||
() => accessRole,
|
||||
() => opWs
|
||||
)
|
||||
const roles = createRolesResource(
|
||||
@@ -122,15 +122,22 @@
|
||||
})
|
||||
|
||||
const availableDatatables = $derived(datatables.current)
|
||||
// Read like the role list: only once it answers for the data table selected.
|
||||
// At mount it is the initial value, and during a switch it is the previous
|
||||
// table's — neither says anything about this one.
|
||||
// The role the access question is asked as. Until the role list settles this
|
||||
// is `undefined`, which the server reads as the data table's configured
|
||||
// default — a different question, and one whose answer says nothing about what
|
||||
// the role finally selected may create.
|
||||
const accessRole = $derived(showRolePicker ? effectiveRole : undefined)
|
||||
// Read like the role list: only once it answers for what is selected now. At
|
||||
// mount it is the initial value, during a switch the previous data table's,
|
||||
// and in between the same data table asked as another role.
|
||||
const accessSettled = $derived(
|
||||
access.current.datatable === selectedDatatable && access.current.role === accessRole
|
||||
)
|
||||
const loadedAccess = $derived(
|
||||
access.current.datatable === selectedDatatable
|
||||
accessSettled
|
||||
? access.current
|
||||
: { datatable: selectedDatatable, schemas: [], canCreateSchema: false }
|
||||
: { datatable: selectedDatatable, role: accessRole, schemas: [], canCreateSchema: false }
|
||||
)
|
||||
const accessSettled = $derived(access.current.datatable === selectedDatatable)
|
||||
const availableSchemas = $derived(loadedAccess.schemas)
|
||||
const canCreateSchema = $derived(loadedAccess.canCreateSchema)
|
||||
|
||||
@@ -512,7 +519,10 @@
|
||||
variant="default"
|
||||
size="sm"
|
||||
on:click={() => start(false)}
|
||||
disabled={!templates[selectedTemplateIndex] || newSchemaAlreadyExists || !rolesSettled}
|
||||
disabled={!templates[selectedTemplateIndex] ||
|
||||
newSchemaAlreadyExists ||
|
||||
!rolesSettled ||
|
||||
!accessSettled}
|
||||
>
|
||||
{$copilotInfo.workspaceDisabled ? 'Start' : 'Start without AI'}
|
||||
</Button>
|
||||
@@ -521,6 +531,7 @@
|
||||
variant="accent"
|
||||
on:click={() => start(true)}
|
||||
disabled={!rolesSettled ||
|
||||
!accessSettled ||
|
||||
!templates[selectedTemplateIndex] ||
|
||||
!initialPrompt.trim() ||
|
||||
newSchemaAlreadyExists}
|
||||
|
||||
@@ -90,15 +90,18 @@ export function createDatatableAccessResource(
|
||||
return resource(
|
||||
() => [getDatatable() ?? '', getRole() ?? '', getWorkspace() ?? ''] as const,
|
||||
async ([datatable, role, workspace]): Promise<{
|
||||
/** What this answers for: until it matches the selection, the schemas and
|
||||
* the right to create one are the previous data table's, and at mount
|
||||
* they are the initial value rather than an answer at all. */
|
||||
/** What this answers for — both halves of it. Until they match the
|
||||
* selection, the schemas and the right to create one belong to another
|
||||
* data table or to another role, and at mount they are the initial value
|
||||
* rather than an answer at all. What a role may create in is exactly the
|
||||
* question, so an answer computed as a different one settles nothing. */
|
||||
datatable: string | undefined
|
||||
role: string | undefined
|
||||
schemas: string[]
|
||||
canCreateSchema: boolean
|
||||
}> => {
|
||||
if (!datatable || !workspace)
|
||||
return { datatable: datatable || undefined, schemas: [], canCreateSchema: false }
|
||||
const asked = { datatable: datatable || undefined, role: role || undefined }
|
||||
if (!datatable || !workspace) return { ...asked, schemas: [], canCreateSchema: false }
|
||||
try {
|
||||
const tables = await WorkspaceService.listDataTableTables({
|
||||
workspace,
|
||||
@@ -107,16 +110,16 @@ export function createDatatableAccessResource(
|
||||
})
|
||||
const entry = tables.find((t) => t.datatable_name === datatable)
|
||||
return {
|
||||
datatable,
|
||||
...asked,
|
||||
schemas: Object.keys(entry?.schemas ?? {}).sort(),
|
||||
canCreateSchema: !!entry?.can_create_schema
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Failed to load datatable access:', e)
|
||||
return { datatable, schemas: [], canCreateSchema: false }
|
||||
return { ...asked, schemas: [], canCreateSchema: false }
|
||||
}
|
||||
},
|
||||
{ initialValue: { datatable: undefined, schemas: [], canCreateSchema: false } }
|
||||
{ initialValue: { datatable: undefined, role: undefined, schemas: [], canCreateSchema: false } }
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user