fix(rbac): Viewer-Rolle in Detail-Pages + ActionButtons — Edit ebenfalls sperren
- ActionButtons: Edit-Button wird für Viewer wie Delete gesperrt (Tooltip zeigt Reason) - Domains/Detail: isViewer-Flag an alle Sub-Panels weitergegeben; Save-, TLS-Cert-, Routing-Rules- und Headers-Buttons für Viewer disabled - Backends/Detail: Save-Button + ServerPanel Add-Button für Viewer disabled - i18n: domains.backendUp/backendDown Keys (waren noch hardkodiert) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -12,6 +12,7 @@ import { useTranslation } from 'react-i18next'
|
||||
import apiClient, { isEnvelope } from '../../api/client'
|
||||
import PageHeader from '../../components/PageHeader'
|
||||
import ActionButtons from '../../components/ActionButtons'
|
||||
import { useAuthStore } from '../../stores/auth'
|
||||
|
||||
const { Text } = Typography
|
||||
|
||||
@@ -90,6 +91,7 @@ export default function BackendDetailPage() {
|
||||
const navigate = useNavigate()
|
||||
const qc = useQueryClient()
|
||||
const backendID = Number(id)
|
||||
const isViewer = useAuthStore((s) => s.user?.role) === 'viewer'
|
||||
|
||||
const { data: backend, isLoading } = useQuery({
|
||||
queryKey: ['backend', backendID],
|
||||
@@ -213,9 +215,11 @@ export default function BackendDetailPage() {
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item>
|
||||
<Button type="primary" htmlType="submit" loading={update.isPending}>
|
||||
{t('common.save')}
|
||||
</Button>
|
||||
<Tooltip title={isViewer ? t('auth.viewerBadge') : undefined}>
|
||||
<Button type="primary" htmlType="submit" loading={update.isPending} disabled={isViewer}>
|
||||
{t('common.save')}
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Card>
|
||||
@@ -223,7 +227,7 @@ export default function BackendDetailPage() {
|
||||
|
||||
<Col xs={24} lg={14}>
|
||||
<Card size="small" title={t('backends.serversIn', { name: backend.name })}>
|
||||
<ServerPanel backendID={backendID} haproxyStats={haproxyStats ?? []} />
|
||||
<ServerPanel backendID={backendID} haproxyStats={haproxyStats ?? []} isViewer={isViewer} />
|
||||
</Card>
|
||||
</Col>
|
||||
</Row>
|
||||
@@ -231,7 +235,7 @@ export default function BackendDetailPage() {
|
||||
)
|
||||
}
|
||||
|
||||
function ServerPanel({ backendID, haproxyStats }: { backendID: number; haproxyStats: HAProxyStat[] }) {
|
||||
function ServerPanel({ backendID, haproxyStats, isViewer }: { backendID: number; haproxyStats: HAProxyStat[]; isViewer: boolean }) {
|
||||
const { t } = useTranslation()
|
||||
const qc = useQueryClient()
|
||||
const [open, setOpen] = useState(false)
|
||||
@@ -347,12 +351,14 @@ function ServerPanel({ backendID, haproxyStats }: { backendID: number; haproxySt
|
||||
return (
|
||||
<>
|
||||
<div className="mb-8" style={{ display: 'flex', justifyContent: 'flex-end' }}>
|
||||
<Button type="primary" icon={<PlusOutlined />} size="small" onClick={() => {
|
||||
setOpen(true); form.resetFields()
|
||||
form.setFieldsValue({ weight: 100, backup: false, active: true, port: 8080 })
|
||||
}}>
|
||||
{t('backends.server.add')}
|
||||
</Button>
|
||||
<Tooltip title={isViewer ? t('auth.viewerBadge') : undefined}>
|
||||
<Button type="primary" icon={<PlusOutlined />} size="small" disabled={isViewer} onClick={() => {
|
||||
setOpen(true); form.resetFields()
|
||||
form.setFieldsValue({ weight: 100, backup: false, active: true, port: 8080 })
|
||||
}}>
|
||||
{t('backends.server.add')}
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<Table
|
||||
size="small" rowKey="id" loading={isLoading}
|
||||
|
||||
Reference in New Issue
Block a user