Skip to content

Commit d544a76

Browse files
ByScriptsclaude
andcommitted
fix(xo6/role): count users inherited from groups in the users column
The column read `role.userIds`, which the server fills from the direct user-role assignments only. A role assigned to one user and to a group of eight was listed as having a single user, and the side panel, which counts the effective users, contradicted it on the same screen. The count now unions the direct users with the members of the role's groups, deduplicated since a user can hold the role both ways. The page waits for the groups collection so the column does not first show the direct count then jump to the effective one. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01USXniSefu5YSpDDAbo4nf1
1 parent 781cbfc commit d544a76

3 files changed

Lines changed: 19 additions & 2 deletions

File tree

‎@xen-orchestra/web/src/modules/role/components/list/RolesTable.vue‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@
2222
</template>
2323

2424
<script setup lang="ts">
25+
import { useXoGroupCollection } from '@/modules/group/remote-resources/use-xo-group-collection.ts'
2526
import type { FrontXoRole } from '@/modules/role/remote-resources/use-xo-role-collection.ts'
27+
import { getRoleUserIds } from '@/modules/role/utils/xo-role.util.ts'
2628
import VtsQueryBuilder from '@core/components/query-builder/VtsQueryBuilder.vue'
2729
import VtsRow from '@core/components/table/VtsRow.vue'
2830
import VtsTable from '@core/components/table/VtsTable.vue'
@@ -56,11 +58,13 @@ const {
5658
5759
const { t } = useI18n()
5860
61+
const { getGroupsByIds } = useXoGroupCollection()
62+
5963
const filterableRoles = computed<FilterableRole[]>(() =>
6064
rawRoles.map(role => ({
6165
...role,
6266
description: role.description ?? '',
63-
usersCount: role.userIds.length,
67+
usersCount: getRoleUserIds(role, getGroupsByIds(role.groupIds)).length,
6468
groupsCount: role.groupIds.length,
6569
privilegesCount: role.privilegeIds.length,
6670
}))
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import type { FrontXoGroup } from '@/modules/group/remote-resources/use-xo-group-collection.ts'
2+
import type { FrontXoRole } from '@/modules/role/remote-resources/use-xo-role-collection.ts'
3+
4+
// A user holds a role either directly or through one of its groups, and can hold it both ways at
5+
// once, so the same user is only counted once.
6+
export function getRoleUserIds(role: FrontXoRole, roleGroups: FrontXoGroup[]) {
7+
return Array.from(new Set([...roleGroups.flatMap(group => group.users), ...role.userIds]))
8+
}

‎@xen-orchestra/web/src/pages/admin/user-management/roles.vue‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,13 @@
77
</template>
88
</UiAlert>
99
<UiCard class="container">
10-
<RolesTable :roles :busy="!areRolesReady" :error="hasRoleFetchError" />
10+
<RolesTable :roles :busy="!areRolesReady || !areGroupsReady" :error="hasRoleFetchError || hasGroupFetchError" />
1111
</UiCard>
1212
</div>
1313
</template>
1414

1515
<script setup lang="ts">
16+
import { useXoGroupCollection } from '@/modules/group/remote-resources/use-xo-group-collection.ts'
1617
import RolesTable from '@/modules/role/components/list/RolesTable.vue'
1718
import { useXoRoleCollection } from '@/modules/role/remote-resources/use-xo-role-collection.ts'
1819
import UiAlert from '@core/components/ui/alert/UiAlert.vue'
@@ -24,6 +25,10 @@ const { t } = useI18n()
2425
2526
const { roles, areRolesReady, hasRoleFetchError } = useXoRoleCollection()
2627
28+
// The users column counts the users inherited from the role's groups, so the table is only
29+
// meaningful once the groups are loaded.
30+
const { areGroupsReady, hasGroupFetchError } = useXoGroupCollection()
31+
2732
const [isInfoVisible, hideInfo] = useHidePermanently('what-is-a-role')
2833
</script>
2934

0 commit comments

Comments
 (0)