feat(fwd-proxy): move-up/down buttons for ACL priority ordering

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Debian
2026-05-25 13:36:22 +02:00
parent f6615fd27d
commit f29d74bad7
5 changed files with 41 additions and 6 deletions

View File

@@ -1 +1 @@
1.1.103 1.1.104

View File

@@ -60,7 +60,7 @@ import (
usersvc "git.netcell-it.de/projekte/edgeguard-native/internal/services/users" usersvc "git.netcell-it.de/projekte/edgeguard-native/internal/services/users"
) )
var version = "1.1.103" var version = "1.1.104"
func main() { func main() {
addr := os.Getenv("EDGEGUARD_API_ADDR") addr := os.Getenv("EDGEGUARD_API_ADDR")

View File

@@ -11,7 +11,7 @@ import (
"git.netcell-it.de/projekte/edgeguard-native/internal/services/setup" "git.netcell-it.de/projekte/edgeguard-native/internal/services/setup"
) )
var version = "1.1.103" var version = "1.1.104"
const usage = `edgeguard-ctl — EdgeGuard CLI const usage = `edgeguard-ctl — EdgeGuard CLI

View File

@@ -35,7 +35,7 @@ import (
"git.netcell-it.de/projekte/edgeguard-native/internal/services/tlscerts" "git.netcell-it.de/projekte/edgeguard-native/internal/services/tlscerts"
) )
var version = "1.1.103" var version = "1.1.104"
const ( const (
// renewTickInterval — how often we re-evaluate expiring certs. // renewTickInterval — how often we re-evaluate expiring certs.

View File

@@ -1,9 +1,9 @@
import { useState } from 'react' import { useMemo, useState } from 'react'
import { import {
Alert, Button, Form, Input, InputNumber, Modal, Select, Space, Switch, Tag, Tooltip, Typography, message, Alert, Button, Form, Input, InputNumber, Modal, Select, Space, Switch, Tag, Tooltip, Typography, message,
} from 'antd' } from 'antd'
import type { ColumnsType } from 'antd/es/table' import type { ColumnsType } from 'antd/es/table'
import { CheckCircleOutlined, CloseCircleOutlined, CloudServerOutlined, PlusOutlined } from '@ant-design/icons' import { ArrowDownOutlined, ArrowUpOutlined, CheckCircleOutlined, CloseCircleOutlined, CloudServerOutlined, PlusOutlined } from '@ant-design/icons'
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
@@ -97,6 +97,20 @@ export default function ForwardProxyPage() {
onError: (e: Error) => message.error(e.message), onError: (e: Error) => message.error(e.message),
}) })
const sortedACLs = useMemo(
() => [...(data ?? [])].sort((a, b) => a.priority - b.priority),
[data],
)
const swapACLs = useMutation({
mutationFn: async ({ a, b }: { a: ACL; b: ACL }) => {
const stripMeta = ({ id: _id, created_at: _ca, updated_at: _ua, ...r }: ACL) => r
await apiClient.put(`/forward-proxy/acls/${a.id}`, { ...stripMeta(a), priority: b.priority })
await apiClient.put(`/forward-proxy/acls/${b.id}`, { ...stripMeta(b), priority: a.priority })
},
onSuccess: () => { void qc.invalidateQueries({ queryKey: ['fwd-proxy', 'acls'] }) },
onError: (e: Error) => message.error(e.message),
})
const cols: ColumnsType<ACL> = [ const cols: ColumnsType<ACL> = [
{ title: t('fwd.priority'), dataIndex: 'priority', key: 'priority', width: 90 }, { title: t('fwd.priority'), dataIndex: 'priority', key: 'priority', width: 90 },
{ title: t('fwd.name'), dataIndex: 'name', key: 'name', render: (s: string) => <code>{s}</code> }, { title: t('fwd.name'), dataIndex: 'name', key: 'name', render: (s: string) => <code>{s}</code> },
@@ -120,6 +134,27 @@ export default function ForwardProxyPage() {
/> />
), ),
}, },
{
title: '', key: 'move', width: 64,
render: (_, row) => {
const idx = sortedACLs.findIndex(r => r.id === row.id)
const swapping = swapACLs.isPending
return (
<Space size={2}>
<Tooltip title={t('fw.rule.moveUp')}>
<Button size="small" icon={<ArrowUpOutlined />}
disabled={isViewer || idx <= 0 || swapping}
onClick={() => swapACLs.mutate({ a: row, b: sortedACLs[idx - 1] })} />
</Tooltip>
<Tooltip title={t('fw.rule.moveDown')}>
<Button size="small" icon={<ArrowDownOutlined />}
disabled={isViewer || idx >= sortedACLs.length - 1 || swapping}
onClick={() => swapACLs.mutate({ a: row, b: sortedACLs[idx + 1] })} />
</Tooltip>
</Space>
)
},
},
{ {
title: t('common.actions'), key: 'actions', title: t('common.actions'), key: 'actions',
render: (_, row) => ( render: (_, row) => (