admin/accounts: show members of a group
Massimo Melina committed
Dec 14, 2024 at 12:53 UTC
ca6449e8f2cfa94da3d36156037ebb1f8226fff2
3 files changed
+19
-4
admin/src/AccountForm.ts
+7
-2
@@ -5,7 +5,7 @@ import { BoolField, Form, MultiSelectField, NumberField } from '@hfs/mui-grid-fo
5
import { Alert, Box } from '@mui/material'
6
import { apiCall } from './api'
7
import { alertDialog, useDialogBarColors } from './dialog'
8
-import { formatTimestamp, isEqualLax, prefix, useIsMobile, wantArray } from './misc'
8
+import { formatTimestamp, isEqualLax, prefix, reactJoin, useIsMobile, wantArray } from './misc'
9
import { IconBtn, propsForModifiedValues } from './mui'
10
import { Account } from './AccountsPage'
11
import { createVerifierAndSalt, SRPParameters, SRPRoutines } from 'tssrp6a'
@@ -30,6 +30,7 @@ export default function AccountForm({ account, done, groups, addToBar, reload }:
30
const group = !values.hasPassword
31
const ref = useRef<HTMLFormElement>()
32
const expired = Boolean(values.expire)
33
+ const { members } = account
34
return h(Form, {
35
formRef: ref,
36
values,
@@ -74,6 +75,10 @@ export default function AccountForm({ account, done, groups, addToBar, reload }:
75
...!account.admin && account.adminActualAccess && { value: true, disabled: true, helperText: "This permission is inherited. To disable it, act on the groups." },
76
},
77
{ k: 'disable_password_change', comp: BoolField, fromField: x=>!x, toField: x=>!x, label: "Allow password change", xs: true },
78
+ !members ? null
79
+ : group && !members.length ? h(Box, {}, "No members")
80
+ : members.length > 0 && h(Box, {}, `${members.length} members: `,
81
+ reactJoin(', ', account.members?.map((u: string) => h(groups.includes(u) ? 'i' : 'span', {}, u))) ),
82
group && h(Alert, { severity: 'info' }, `To add users to this group, select the user and then click "Inherit"`),
83
{ k: 'belongs', comp: MultiSelectField, label: "Inherit from groups", options: belongsOptions,
84
helperText: "Specify groups to inherit permissions from"
@@ -91,7 +96,7 @@ export default function AccountForm({ account, done, groups, addToBar, reload }:
96
save: {
97
...propsForModifiedValues(isModifiedConfig(values, account)),
98
async onClick() {
94
- const { password='', password2, adminActualAccess, hasPassword, invalidated, ...withoutPassword } = values
99
+ const { password='', password2, adminActualAccess, hasPassword, invalidated, canLogin, members, ...withoutPassword } = values
100
if (add) {
101
const got = await apiCall('add_account', withoutPassword)
102
if (password)
admin/src/AccountsPage.ts
+2
-1
@@ -147,7 +147,8 @@ export default function AccountsPage() {
147
hasPassword: sel === 'new-user',
148
adminActualAccess: false,
149
invalidated: undefined,
150
- canLogin: true
150
+ canLogin: true,
151
+ members: [],
152
} satisfies Account
153
}
154
src/api.accounts.ts
+10
-1
@@ -8,7 +8,7 @@ import {
8
import _ from 'lodash'
9
import { HTTP_BAD_REQUEST, HTTP_CONFLICT, HTTP_NOT_FOUND } from './const'
10
import { getCurrentUsername, invalidateSessionBefore } from './auth'
11
-import { apiAssertTypes, onlyTruthy } from './misc'
11
+import { apiAssertTypes, onlyTruthy, with_ } from './misc'
12
13
function prepareAccount(ac: Account | undefined) {
14
return ac && {
@@ -18,6 +18,15 @@ function prepareAccount(ac: Account | undefined) {
18
adminActualAccess: accountCanLoginAdmin(ac),
19
canLogin: accountHasPassword(ac) ? accountCanLogin(ac) : undefined,
20
invalidated: invalidateSessionBefore.get(ac.username),
21
+ members: with_(Object.values(accountsConfig.get()), accounts => {
22
+ const ret = []
23
+ let news = [ac.username]
24
+ while (news.length) {
25
+ news = accounts.filter(a => a.belongs?.some(x => news.includes(x))).map(x => x.username)
26
+ ret.push(...news)
27
+ }
28
+ return ret.sort()
29
+ })
30
}
31
}
32