- 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>
80 lines
2.6 KiB
TypeScript
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>
|
|
)
|
|
}
|