mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-10-13 00:03:00 +00:00
fix(datatables): read a roles answer only for the workspace it was asked in
A fork and its parent each have their own roles on a data table of the same name, so an answer stamped with the name alone settled the role from the workspace the editor was acting on before. Also derive the AI table creation flag from the data replaced into the editor: data naming no data table left the flag on from before. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
4e1d5f9d02
commit
538d098a79
@@ -58,6 +58,7 @@
|
||||
if (!workspace || !datatable) return undefined
|
||||
try {
|
||||
return {
|
||||
workspace,
|
||||
datatable,
|
||||
...(await listUsableDatatableRoles(workspace, datatable))
|
||||
}
|
||||
@@ -65,16 +66,24 @@
|
||||
// Never leave the drawer waiting on this: fall back to the
|
||||
// unpermissioned shape so it opens and the server picks the role.
|
||||
console.error('Failed to load datatable roles:', e)
|
||||
return { datatable, permissioned: false, roles: [], default_role: ADMIN_DATATABLE_ROLE }
|
||||
return {
|
||||
workspace,
|
||||
datatable,
|
||||
permissioned: false,
|
||||
roles: [],
|
||||
default_role: ADMIN_DATATABLE_ROLE
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
// A resource keeps its previous value while refetching, and roles are per data
|
||||
// table: settling from the last one's answer would connect to the new data
|
||||
// table as a role it may not even have.
|
||||
// A resource keeps its previous value while refetching, and roles are per data table of one
|
||||
// workspace: settling from another answer would connect to this data table as a role it may
|
||||
// not even have.
|
||||
const rolesOfCurrent = $derived(
|
||||
usableRoles.current?.datatable === selectedDatatable ? usableRoles.current : undefined
|
||||
usableRoles.current?.datatable === selectedDatatable && usableRoles.current?.workspace === ws
|
||||
? usableRoles.current
|
||||
: undefined
|
||||
)
|
||||
|
||||
// Nothing that connects runs until the role is settled: a first round sent without a role
|
||||
|
||||
@@ -85,6 +85,7 @@
|
||||
if (!isOpen || !workspace || !datatable) return undefined
|
||||
try {
|
||||
return {
|
||||
workspace,
|
||||
datatable,
|
||||
...(await listUsableDatatableRoles(workspace, datatable))
|
||||
}
|
||||
@@ -93,6 +94,7 @@
|
||||
// that is refused.
|
||||
console.error('Failed to load datatable roles:', e)
|
||||
return {
|
||||
workspace,
|
||||
datatable,
|
||||
permissioned: false,
|
||||
roles: [] as string[],
|
||||
@@ -102,9 +104,12 @@
|
||||
}
|
||||
)
|
||||
|
||||
// A resource keeps its previous value while it refetches, and roles are per data table.
|
||||
// A resource keeps its previous value while it refetches, and roles are per data table of one
|
||||
// workspace: a fork and its parent both have a `main`, with their own roles on it.
|
||||
const rolesOfCurrent = $derived(
|
||||
usableRoles.current?.datatable === selectedDatatable ? usableRoles.current : undefined
|
||||
usableRoles.current?.datatable === selectedDatatable && usableRoles.current?.workspace === opWs
|
||||
? usableRoles.current
|
||||
: undefined
|
||||
)
|
||||
|
||||
// Mounting the manager fires its first queries, so it waits for the role: a round sent
|
||||
|
||||
@@ -747,6 +747,8 @@
|
||||
data = next
|
||||
aiChatManager.datatableCreationPolicy = {
|
||||
...aiChatManager.datatableCreationPolicy,
|
||||
// As on load: data that names no data table leaves nothing to create tables in.
|
||||
enabled: next.datatable !== undefined,
|
||||
datatable: next.datatable,
|
||||
schema: next.schema,
|
||||
roles: next.roles
|
||||
|
||||
@@ -86,10 +86,13 @@
|
||||
let selectedRole = $state<string | undefined>(undefined)
|
||||
|
||||
// Every reader waits for an answer stamped with the current selection: until then `current`
|
||||
// belongs to the previous data table or role.
|
||||
// belongs to the previous workspace, data table or role.
|
||||
// A data table whose name cannot carry a role in a reference is used as its default one.
|
||||
const rolesAnswered = $derived(
|
||||
roles.current.workspace === opWs && roles.current.datatable === selectedDatatable
|
||||
)
|
||||
const loadedRoles = $derived(
|
||||
roles.current.datatable === selectedDatatable &&
|
||||
rolesAnswered &&
|
||||
selectedDatatable !== undefined &&
|
||||
datatableNameTakesRole(selectedDatatable)
|
||||
? roles.current.roles
|
||||
@@ -114,8 +117,7 @@
|
||||
const hasNoDatatables = $derived(availableDatatables?.length === 0)
|
||||
|
||||
const rolesSettled = $derived(
|
||||
hasNoDatatables ||
|
||||
(selectedDatatable !== undefined && roles.current.datatable === selectedDatatable)
|
||||
hasNoDatatables || (selectedDatatable !== undefined && rolesAnswered)
|
||||
)
|
||||
|
||||
// A role is picked on one data table: two data tables can both define an `analyst` that
|
||||
@@ -123,7 +125,7 @@
|
||||
let rolesPickedOn = $state<string | undefined>(undefined)
|
||||
$effect(() => {
|
||||
const loaded = roles.current
|
||||
if (loaded.datatable !== selectedDatatable) return
|
||||
if (!rolesAnswered) return
|
||||
const switched = untrack(() => rolesPickedOn) !== selectedDatatable
|
||||
const current = untrack(() => selectedRole)
|
||||
if (switched || current === undefined || !loaded.roles.includes(current)) {
|
||||
@@ -173,6 +175,7 @@
|
||||
hasNoDatatables ||
|
||||
(rolesSettled &&
|
||||
selectedDatatable !== undefined &&
|
||||
access.current.workspace === opWs &&
|
||||
access.current.datatable === selectedDatatable &&
|
||||
access.current.role === effectiveRole)
|
||||
)
|
||||
|
||||
@@ -40,8 +40,9 @@ export function createDatatablesResource(getWorkspace: () => string | undefined)
|
||||
}
|
||||
|
||||
export type DatatableRoles = {
|
||||
/** The data table this answers for: while a switch is in flight, `current` still holds the
|
||||
* previous one's roles, which say nothing about the one now selected. */
|
||||
/** The workspace and data table this answers for: while a switch is in flight, `current` still
|
||||
* holds the previous ones' roles, and a fork and its parent both have a `main` of their own. */
|
||||
workspace: string | undefined
|
||||
datatable: string | undefined
|
||||
/** Whether the data table is under roles. Without roles `roles` is empty because there is
|
||||
* nothing to pick, which is not the same as a permissioned one this caller may use no role of. */
|
||||
@@ -61,6 +62,7 @@ export function createRolesResource(
|
||||
getWorkspace: () => string | undefined = () => get(workspaceStore)
|
||||
) {
|
||||
const initialValue: DatatableRoles = {
|
||||
workspace: undefined,
|
||||
datatable: undefined,
|
||||
permissioned: false,
|
||||
failed: false,
|
||||
@@ -71,7 +73,11 @@ export function createRolesResource(
|
||||
() => [getDatatable() ?? '', getWorkspace() ?? ''] as const,
|
||||
latestOnly(
|
||||
async ([datatableName, workspace]: readonly [string, string]): Promise<DatatableRoles> => {
|
||||
const empty = { ...initialValue, datatable: datatableName || undefined }
|
||||
const empty = {
|
||||
...initialValue,
|
||||
workspace: workspace || undefined,
|
||||
datatable: datatableName || undefined
|
||||
}
|
||||
if (!datatableName || !workspace) return empty
|
||||
try {
|
||||
const res = await listUsableDatatableRoles(workspace, datatableName)
|
||||
@@ -94,8 +100,9 @@ export function createRolesResource(
|
||||
}
|
||||
|
||||
export type DatatableAccess = {
|
||||
/** What this answers for. Until both match the selection, the schemas and the right to
|
||||
* create one belong to another data table or another role. */
|
||||
/** What this answers for. Until all three match the selection, the schemas and the right to
|
||||
* create one belong to another workspace, data table or role. */
|
||||
workspace: string | undefined
|
||||
datatable: string | undefined
|
||||
role: string | undefined
|
||||
/** The request failed, or the server kept the entry with an error (a role this caller may
|
||||
@@ -119,6 +126,7 @@ export function createDatatableAccessResource(
|
||||
getReady: () => boolean = () => true
|
||||
) {
|
||||
const initialValue: DatatableAccess = {
|
||||
workspace: undefined,
|
||||
datatable: undefined,
|
||||
role: undefined,
|
||||
failed: false,
|
||||
@@ -137,6 +145,7 @@ export function createDatatableAccessResource(
|
||||
]): Promise<DatatableAccess> => {
|
||||
const asked = {
|
||||
...initialValue,
|
||||
workspace: workspace || undefined,
|
||||
datatable: datatable || undefined,
|
||||
role: role || undefined
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user