diff --git a/apps/web/src/frontend/app/store/useSqlEditorStore.ts b/apps/web/src/frontend/app/store/useSqlEditorStore.ts index 001e69b5..6639af67 100644 --- a/apps/web/src/frontend/app/store/useSqlEditorStore.ts +++ b/apps/web/src/frontend/app/store/useSqlEditorStore.ts @@ -28,6 +28,7 @@ import { buildSampleBookmarks } from '@/features/sql-editor/lib/sqlEditorSamples import { buildForeignKeyDrilldown, buildOrphanPeek, + fkKey, buildRowLookup, buildTablePreview, composePeekSql, @@ -1849,7 +1850,7 @@ export const useSqlEditorStore = create()( if ('error' in composed) return; const entry: DataPeekEntry = { id: `peek-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`, - title: `${childTable} · orphans via ${fk.name || (fk.columns ?? []).join(', ')}`, + title: `${childTable} · orphans via ${fkKey(fk)}`, tableName: childTable, baseSql: built.sql, baseParams: built.params, diff --git a/apps/web/src/frontend/features/access/components/AccessPermissionPanel.tsx b/apps/web/src/frontend/features/access/components/AccessPermissionPanel.tsx index 1d75f21e..989df8c0 100644 --- a/apps/web/src/frontend/features/access/components/AccessPermissionPanel.tsx +++ b/apps/web/src/frontend/features/access/components/AccessPermissionPanel.tsx @@ -573,15 +573,25 @@ export const AccessPermissionPanel: React.FC<{ const AccountStage: React.FC<{ principal: DbPrincipal; /** The catalog's privileges, so a drop can be described before it is run. */ - privileges?: readonly DbPrivilege[]; - dialect?: string; + privileges: readonly DbPrivilege[]; + dialect: string; onManageUsers?: () => void; -}> = ({ principal, privileges = [], dialect, onManageUsers }) => { - const support = dialect ? userManagementSupport(dialect) : null; - const alterations = support - ? availableAlterations(support, principal.kind === 'user' ? 'user' : 'role') - : []; - const dropNotes = dropSafetyNotes(principal, privileges); +}> = ({ principal, privileges, dialect, onManageUsers }) => { + // Both memoised: this is an unmemoised child of a panel that owns the + // principal filter, so every keystroke re-ran dropSafetyNotes, which walks + // the whole privileges array. + const alterations = useMemo( + () => + availableAlterations( + userManagementSupport(dialect), + principal.kind === 'user' ? 'user' : 'role' + ), + [dialect, principal.kind] + ); + const dropNotes = useMemo( + () => dropSafetyNotes(principal, privileges), + [principal, privileges] + ); const login = principal.canLogin === true ? 'Can log in' @@ -615,9 +625,7 @@ const AccountStage: React.FC<{ Alteration {alterations.length === 0 ? (

- {support - ? 'This engine has no edit actions for this kind of account.' - : 'Choose a connection to see what this engine can change.'} + This engine has no edit actions for this kind of account.

) : (