feat(rbac): Viewer-Rolle auf alle verbleibenden CRUD-Seiten durchsetzen — v1.1.92
DNS, NTP, ForwardProxy, RoutingRules, Networks (Interfaces + Routes), IPAddresses, WireGuard (Servers + Clients + Peers), Backups/RemoteTargets, SSL: Add-Buttons, quickToggle-Switches und Settings-Save-Buttons für Viewer deaktiviert. ActionButtons-Komponente schützt Edit/Delete bereits zentral; hier wurden nur die verbleibenden Mutationspunkte (Add, Switch, Submit) nachgezogen. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -10,6 +10,7 @@ import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
import apiClient, { isEnvelope } from '../../api/client'
|
||||
import { useAuthStore } from '../../stores/auth'
|
||||
import EmptyState from '../../components/EmptyState'
|
||||
|
||||
const { Text } = Typography
|
||||
@@ -50,6 +51,7 @@ interface RouteFormValues {
|
||||
export default function RoutesTab() {
|
||||
const { t } = useTranslation()
|
||||
const qc = useQueryClient()
|
||||
const isViewer = useAuthStore((s) => s.user?.role) === 'viewer'
|
||||
|
||||
const managed = useQuery({
|
||||
queryKey: ['routes', 'managed'],
|
||||
@@ -129,6 +131,7 @@ export default function RoutesTab() {
|
||||
<Switch
|
||||
size="small"
|
||||
checked={v}
|
||||
disabled={isViewer}
|
||||
loading={quickToggle.isPending && quickToggle.variables?.id === row.id}
|
||||
onChange={(checked) => quickToggle.mutate({ id: row.id, row, checked })}
|
||||
/>
|
||||
@@ -140,22 +143,25 @@ export default function RoutesTab() {
|
||||
title: t('common.actions'), key: 'a', width: 160,
|
||||
render: (_, r) => (
|
||||
<Space size={4}>
|
||||
<Button size="small" onClick={() => {
|
||||
setEdit(r)
|
||||
form.setFieldsValue({
|
||||
destination: r.destination,
|
||||
gateway: r.gateway ?? undefined,
|
||||
dev: r.dev ?? undefined,
|
||||
metric: r.metric,
|
||||
table_name: r.table_name,
|
||||
active: r.active,
|
||||
comment: r.comment ?? undefined,
|
||||
})
|
||||
}}>{t('common.edit')}</Button>
|
||||
<Popconfirm title={t('routes.confirmDelete', { dest: r.destination })}
|
||||
onConfirm={() => del.mutate(r.id)}>
|
||||
<Button size="small" danger>{t('common.delete')}</Button>
|
||||
</Popconfirm>
|
||||
<Tooltip title={isViewer ? t('auth.viewerBadge') : undefined}>
|
||||
<Button size="small" disabled={isViewer} onClick={() => {
|
||||
setEdit(r)
|
||||
form.setFieldsValue({
|
||||
destination: r.destination,
|
||||
gateway: r.gateway ?? undefined,
|
||||
dev: r.dev ?? undefined,
|
||||
metric: r.metric,
|
||||
table_name: r.table_name,
|
||||
active: r.active,
|
||||
comment: r.comment ?? undefined,
|
||||
})
|
||||
}}>{t('common.edit')}</Button>
|
||||
</Tooltip>
|
||||
{isViewer
|
||||
? <Tooltip title={t('auth.viewerBadge')}><Button size="small" danger disabled>{t('common.delete')}</Button></Tooltip>
|
||||
: <Popconfirm title={t('routes.confirmDelete', { dest: r.destination })} onConfirm={() => del.mutate(r.id)}>
|
||||
<Button size="small" danger>{t('common.delete')}</Button>
|
||||
</Popconfirm>}
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
@@ -232,10 +238,12 @@ export default function RoutesTab() {
|
||||
size="small"
|
||||
title={t('routes.managedTitle')}
|
||||
extra={
|
||||
<Button type="primary" size="small" icon={<PlusOutlined />}
|
||||
onClick={openCreate}>
|
||||
{t('routes.add')}
|
||||
</Button>
|
||||
<Tooltip title={isViewer ? t('auth.viewerBadge') : undefined}>
|
||||
<Button type="primary" size="small" icon={<PlusOutlined />}
|
||||
disabled={isViewer} onClick={openCreate}>
|
||||
{t('routes.add')}
|
||||
</Button>
|
||||
</Tooltip>
|
||||
}
|
||||
>
|
||||
<Text type="secondary">{t('routes.managedIntro')}</Text>
|
||||
@@ -252,9 +260,11 @@ export default function RoutesTab() {
|
||||
title={t('routes.emptyTitle')}
|
||||
description={t('routes.emptyDesc')}
|
||||
action={
|
||||
<Button type="primary" icon={<PlusOutlined />} onClick={openCreate}>
|
||||
{t('routes.add')}
|
||||
</Button>
|
||||
<Tooltip title={isViewer ? t('auth.viewerBadge') : undefined}>
|
||||
<Button type="primary" icon={<PlusOutlined />} disabled={isViewer} onClick={openCreate}>
|
||||
{t('routes.add')}
|
||||
</Button>
|
||||
</Tooltip>
|
||||
}
|
||||
/>
|
||||
) }}
|
||||
|
||||
Reference in New Issue
Block a user