feat(firewall): Inline-Note + Labels direkt in der Tabelle
- Migration 0035: note TEXT + labels TEXT[] für firewall_rules + nat_rules - PATCH /firewall/rules/:id + /nat-rules/:id für note/labels Updates - InlineNote: gold Tag mit MessageOutlined, Klick zum Bearbeiten (Enter/Blur speichert) - InlineLabels: geekblue Tags mit X-Button zum Entfernen, "+" zum Hinzufügen - Name-Spalte: Name + Labels + Note in Zeile 1, comment/auto-desc in Zeile 2 - Gleiche UX für NAT-Regeln Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
13cb9a8fc4
commit
b48ba65ce3
@@ -10,6 +10,7 @@ import {
|
||||
ArrowDownOutlined, ArrowUpOutlined, CopyOutlined, DeleteOutlined, EditOutlined,
|
||||
EyeOutlined, FireOutlined, PlusOutlined, WarningOutlined,
|
||||
} from '@ant-design/icons'
|
||||
import { InlineNote, InlineLabels } from './InlineEditors'
|
||||
|
||||
const { Text } = Typography
|
||||
|
||||
@@ -251,6 +252,22 @@ export default function RulesTab() {
|
||||
onError: (e: Error) => message.error(e.message),
|
||||
})
|
||||
|
||||
const patchNote = useMutation({
|
||||
mutationFn: async ({ id, note }: { id: number; note: string }) => {
|
||||
await apiClient.patch(`/firewall/rules/${id}`, { note })
|
||||
},
|
||||
onSuccess: () => { void qc.invalidateQueries({ queryKey: ['fw', 'rules'] }) },
|
||||
onError: (e: Error) => message.error(e.message),
|
||||
})
|
||||
|
||||
const patchLabels = useMutation({
|
||||
mutationFn: async ({ id, labels }: { id: number; labels: string[] }) => {
|
||||
await apiClient.patch(`/firewall/rules/${id}`, { labels })
|
||||
},
|
||||
onSuccess: () => { void qc.invalidateQueries({ queryKey: ['fw', 'rules'] }) },
|
||||
onError: (e: Error) => message.error(e.message),
|
||||
})
|
||||
|
||||
const duplicate = useMutation({
|
||||
mutationFn: async (r: FwRule) => {
|
||||
const { id: _id, created_at: _ca, updated_at: _ua, ...rest } = r as FwRule & { created_at?: unknown; updated_at?: unknown }
|
||||
@@ -337,14 +354,24 @@ export default function RulesTab() {
|
||||
title: t('fw.rule.name'), key: 'name', ellipsis: true,
|
||||
render: (_, r) => (
|
||||
<div>
|
||||
{r.name
|
||||
? <div className="fw-rule-name" style={{ fontWeight: 500, fontSize: 12, color: '#0F172A' }}>{r.name}</div>
|
||||
: <div className="fw-rule-name" style={{ fontSize: 12, color: '#94A3B8', fontStyle: 'italic' }}>
|
||||
{t('fw.rule.unnamed')}
|
||||
</div>
|
||||
}
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 4, flexWrap: 'wrap' }}>
|
||||
{r.name
|
||||
? <span className="fw-rule-name" style={{ fontWeight: 500, fontSize: 12, color: '#0F172A' }}>{r.name}</span>
|
||||
: <span className="fw-rule-name" style={{ fontSize: 12, color: '#94A3B8', fontStyle: 'italic' }}>{t('fw.rule.unnamed')}</span>
|
||||
}
|
||||
<InlineLabels
|
||||
labels={r.labels ?? []}
|
||||
disabled={isViewer}
|
||||
onSave={labels => patchLabels.mutate({ id: r.id, labels })}
|
||||
/>
|
||||
<InlineNote
|
||||
value={r.note}
|
||||
disabled={isViewer}
|
||||
onSave={note => patchNote.mutate({ id: r.id, note })}
|
||||
/>
|
||||
</div>
|
||||
{r.comment
|
||||
? <div style={{ fontSize: 11, color: '#64748B', marginTop: 1 }}>{r.comment}</div>
|
||||
? <div style={{ fontSize: 11, color: '#64748B', marginTop: 2 }}>{r.comment}</div>
|
||||
: <div className="fw-rule-desc">{autoDescription(r)}</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user