fix(users): viewer-Rolle — Add/Edit/Delete/Set-PW/Active-Toggle deaktivieren

Users-Seite fehlte `isViewer` komplett: Viewer sahen alle Mutations-
Controls aktiv und bekamen erst nach dem Klick einen Backend-403.
Jetzt: „Benutzer hinzufügen"-Button + KeyOutlined-Set-PW-Button +
Active-Switch tragen `disabled={isViewer}`, ActionButtons-Pair liest
isViewer schon intern aus dem Auth-Store.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Debian
2026-05-28 10:27:12 +02:00
parent 192384c448
commit 44f184d505
5 changed files with 26 additions and 19 deletions

View File

@@ -1 +1 @@
1.1.122 1.1.123

View File

@@ -60,7 +60,7 @@ import (
usersvc "git.netcell-it.de/projekte/edgeguard-native/internal/services/users" usersvc "git.netcell-it.de/projekte/edgeguard-native/internal/services/users"
) )
var version = "1.1.122" var version = "1.1.123"
func main() { func main() {
addr := os.Getenv("EDGEGUARD_API_ADDR") addr := os.Getenv("EDGEGUARD_API_ADDR")

View File

@@ -11,7 +11,7 @@ import (
"git.netcell-it.de/projekte/edgeguard-native/internal/services/setup" "git.netcell-it.de/projekte/edgeguard-native/internal/services/setup"
) )
var version = "1.1.122" var version = "1.1.123"
const usage = `edgeguard-ctl — EdgeGuard CLI const usage = `edgeguard-ctl — EdgeGuard CLI

View File

@@ -41,7 +41,7 @@ import (
"git.netcell-it.de/projekte/edgeguard-native/internal/services/tlscerts" "git.netcell-it.de/projekte/edgeguard-native/internal/services/tlscerts"
) )
var version = "1.1.122" var version = "1.1.123"
const ( const (
// renewTickInterval — how often we re-evaluate expiring certs. // renewTickInterval — how often we re-evaluate expiring certs.

View File

@@ -41,6 +41,7 @@ export default function UsersPage() {
const { t } = useTranslation() const { t } = useTranslation()
const qc = useQueryClient() const qc = useQueryClient()
const me = useAuthStore((s) => s.user) const me = useAuthStore((s) => s.user)
const isViewer = me?.role === 'viewer'
const { data: users, isLoading } = useQuery({ queryKey: ['users'], queryFn: listUsers }) const { data: users, isLoading } = useQuery({ queryKey: ['users'], queryFn: listUsers })
@@ -109,6 +110,7 @@ export default function UsersPage() {
<Switch <Switch
size="small" size="small"
checked={v} checked={v}
disabled={isViewer}
loading={quickToggle.isPending && quickToggle.variables?.id === row.id} loading={quickToggle.isPending && quickToggle.variables?.id === row.id}
onChange={(checked) => quickToggle.mutate({ id: row.id, row, checked })} onChange={(checked) => quickToggle.mutate({ id: row.id, row, checked })}
/> />
@@ -128,8 +130,9 @@ export default function UsersPage() {
title: t('common.actions'), key: 'actions', width: 120, title: t('common.actions'), key: 'actions', width: 120,
render: (_, row) => ( render: (_, row) => (
<Space size={4}> <Space size={4}>
<Tooltip title={t('users.setPassword')}> <Tooltip title={isViewer ? t('auth.viewerBadge') : t('users.setPassword')}>
<Button type="text" size="small" icon={<KeyOutlined />} <Button type="text" size="small" icon={<KeyOutlined />}
disabled={isViewer}
onClick={() => { setPwTarget(row); pwForm.resetFields() }} /> onClick={() => { setPwTarget(row); pwForm.resetFields() }} />
</Tooltip> </Tooltip>
<ActionButtons <ActionButtons
@@ -159,13 +162,15 @@ export default function UsersPage() {
dataSource={users ?? []} dataSource={users ?? []}
columns={columns} columns={columns}
extraActions={ extraActions={
<Button type="primary" icon={<PlusOutlined />} onClick={() => { <Tooltip title={isViewer ? t('auth.viewerBadge') : undefined}>
setCreating(true) <Button type="primary" icon={<PlusOutlined />} disabled={isViewer} onClick={() => {
createForm.resetFields() setCreating(true)
createForm.setFieldsValue({ role: 'admin', active: true }) createForm.resetFields()
}}> createForm.setFieldsValue({ role: 'admin', active: true })
{t('users.addUser')} }}>
</Button> {t('users.addUser')}
</Button>
</Tooltip>
} }
emptyContent={ emptyContent={
<EmptyState <EmptyState
@@ -173,13 +178,15 @@ export default function UsersPage() {
title={t('users.emptyTitle')} title={t('users.emptyTitle')}
description={t('users.emptyDesc')} description={t('users.emptyDesc')}
action={ action={
<Button type="primary" icon={<PlusOutlined />} onClick={() => { <Tooltip title={isViewer ? t('auth.viewerBadge') : undefined}>
setCreating(true) <Button type="primary" icon={<PlusOutlined />} disabled={isViewer} onClick={() => {
createForm.resetFields() setCreating(true)
createForm.setFieldsValue({ role: 'admin', active: true }) createForm.resetFields()
}}> createForm.setFieldsValue({ role: 'admin', active: true })
{t('users.addUser')} }}>
</Button> {t('users.addUser')}
</Button>
</Tooltip>
} }
/> />
} }