Files
edgeguard-native/management-ui/src/components/ActionButtons.tsx
Debian 2d027b3044 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>
2026-05-24 13:10:29 +02:00

80 lines
2.6 KiB
TypeScript

import { Button, Popconfirm, Space, Tooltip } from 'antd'
import { DeleteOutlined, EditOutlined } from '@ant-design/icons'
import { useTranslation } from 'react-i18next'
import { useAuthStore } from '../stores/auth'
// ActionButtons is the standard "Edit / Delete" pair used at the
// end of every CRUD table row. Centralising it means we only style
// the action column once across the app.
//
// Either prop may be omitted to suppress that button — useful for
// rows that aren't editable (e.g. builtin services).
// Viewer-role accounts get both buttons disabled — mutations are
// blocked at the API level too, but disabling here avoids confusing
// "access denied" errors for read-only users.
interface ActionButtonsProps {
onEdit?: () => void
onDelete?: () => void
deleteConfirm?: string
editTooltip?: string
deleteTooltip?: string
editDisabled?: boolean
deleteDisabled?: boolean
editDisabledReason?: string
deleteDisabledReason?: string
}
export default function ActionButtons({
onEdit, onDelete,
deleteConfirm,
editTooltip, deleteTooltip,
editDisabled, deleteDisabled,
editDisabledReason, deleteDisabledReason,
}: ActionButtonsProps) {
const { t } = useTranslation()
const role = useAuthStore((s) => s.user?.role)
const isViewer = role === 'viewer'
const viewerReason = isViewer ? t('auth.viewerBadge') : undefined
const editDis = editDisabled || isViewer
const editDisReason = isViewer ? viewerReason : editDisabledReason
const delDisabled = deleteDisabled || isViewer
const delDisabledReason = isViewer ? viewerReason : deleteDisabledReason
return (
<Space size={4}>
{onEdit && (
<Tooltip title={editDis ? editDisReason : (editTooltip ?? t('common.edit'))}>
<Button
type="text"
size="small"
icon={<EditOutlined />}
disabled={editDis}
onClick={onEdit}
/>
</Tooltip>
)}
{onDelete && (
delDisabled ? (
<Tooltip title={delDisabledReason ?? t('common.delete')}>
<Button type="text" size="small" danger icon={<DeleteOutlined />} disabled />
</Tooltip>
) : (
<Popconfirm
title={deleteConfirm ?? t('common.deleteConfirm')}
okText={t('common.yes')}
cancelText={t('common.no')}
onConfirm={onDelete}
>
<Tooltip title={deleteTooltip ?? t('common.delete')}>
<Button type="text" size="small" danger icon={<DeleteOutlined />} />
</Tooltip>
</Popconfirm>
)
)}
</Space>
)
}