Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 21 additions & 3 deletions backend/src/baserow/core/registries.py
Original file line number Diff line number Diff line change
Expand Up @@ -1024,11 +1024,29 @@ def get_objects_in_scopes(self, scopes: List[Any]) -> Dict[Any, Any]:
parent_scope_types.add(object_scope_type)

if parent_scopes:
query_result = list(
self.get_enhanced_queryset().filter(
self.get_filter_for_scopes(parent_scopes)
scopes_by_type = defaultdict(list)
for scope in parent_scopes:
scopes_by_type[object_scope_type_registry.get_by_model(scope)].append(
scope
)

enhanced_queryset = self.get_enhanced_queryset()
ordering = (
enhanced_queryset.query.order_by
or enhanced_queryset.model._meta.ordering
)

branches = [
enhanced_queryset.filter(
self.get_filter_for_scope_type(scope_type, typed_scopes)
).order_by()
for scope_type, typed_scopes in scopes_by_type.items()
]
combined = (
branches[0] if len(branches) == 1 else branches[0].union(*branches[1:])
)
combined = combined.order_by(*ordering)
query_result = list(combined)

# We have all the objects in the queryset, but now we want to sort them
# into buckets per original scope they are a child of.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"type": "bug",
"message": "Improve permissions endpoint query performance by using union instead of OR.",
"issue_origin": "github",
"issue_number": null,
"domain": "database",
"bullet_points": [],
"created_at": "2026-06-03"
}
68 changes: 40 additions & 28 deletions web-frontend/modules/core/components/crudTable/CrudTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -77,36 +77,47 @@
</tr>
</thead>
<tbody>
<tr
v-for="row in rows"
:key="'row-' + row.id"
class="data-table__table-row"
<slot
name="rows"
:rows="rows"
:columns="columns"
:update-row="updateRow"
:delete-row="deleteRow"
:refresh="refresh"
>
<td
v-for="col in columns"
:key="'col-' + col.key"
class="data-table__table-cell"
:class="{
'data-table__table-cell--sticky-left': col.stickyLeft,
'data-table__table-cell--sticky-right': col.stickyRight,
[`data-table__table-cell--${col.key}`]: true,
}"
@contextmenu="$emit('row-context', { col, row, event: $event })"
<tr
v-for="row in rows"
:key="'row-' + row.id"
class="data-table__table-row"
>
<div class="data-table__table-cell-content">
<component
:is="col.cellComponent"
:row="row"
:column="col"
v-on="$attrs"
@row-context="(payload) => $emit('row-context', payload)"
@row-update="updateRow"
@row-delete="deleteRow"
@refresh="refresh"
/>
</div>
</td>
</tr>
<td
v-for="col in columns"
:key="'col-' + col.key"
class="data-table__table-cell"
:class="{
'data-table__table-cell--sticky-left': col.stickyLeft,
'data-table__table-cell--sticky-right': col.stickyRight,
[`data-table__table-cell--${col.key}`]: true,
}"
@contextmenu="
$emit('row-context', { col, row, event: $event })
"
>
<div class="data-table__table-cell-content">
<component
:is="col.cellComponent"
:row="row"
:column="col"
v-on="$attrs"
@row-context="(payload) => $emit('row-context', payload)"
@row-update="updateRow"
@row-delete="deleteRow"
@refresh="refresh"
/>
</div>
</td>
</tr>
</slot>
</tbody>
</table>
</div>
Expand Down Expand Up @@ -145,6 +156,7 @@ import isObject from 'lodash/isObject'
* Two slot props are provided `updateRow` and `deleteRow` which are functions
* called when your menu has changed the row state which trigger the CrudTable
* to rerender the rows with the new data.
* #rows: Can optionally replace the rows in the table.
*/
export default {
name: 'CrudTable',
Expand Down
Loading