From 627e6149fb00970db6c2d2ff74ec2937f03562fb Mon Sep 17 00:00:00 2001 From: "Adrian A. Baumann" Date: Sat, 28 Feb 2026 20:07:34 +0100 Subject: [PATCH] feat: add GenerateModal component --- frontend/src/components/GenerateModal.tsx | 94 +++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 frontend/src/components/GenerateModal.tsx diff --git a/frontend/src/components/GenerateModal.tsx b/frontend/src/components/GenerateModal.tsx new file mode 100644 index 0000000..1408780 --- /dev/null +++ b/frontend/src/components/GenerateModal.tsx @@ -0,0 +1,94 @@ +import { useState } from 'react' +import Dialog from '@mui/material/Dialog' +import DialogTitle from '@mui/material/DialogTitle' +import DialogContent from '@mui/material/DialogContent' +import DialogActions from '@mui/material/DialogActions' +import Button from '@mui/material/Button' +import Tabs from '@mui/material/Tabs' +import Tab from '@mui/material/Tab' +import Box from '@mui/material/Box' +import IconButton from '@mui/material/IconButton' +import Tooltip from '@mui/material/Tooltip' +import ContentCopyIcon from '@mui/icons-material/ContentCopy' +import DownloadIcon from '@mui/icons-material/Download' +import { configsApi } from '../api' + +interface GeneratedFiles { + zones: string + interfaces: string + policy: string + rules: string + masq: string +} + +interface Props { + open: boolean + configId: number + configName: string + onClose: () => void +} + +const TABS = ['zones', 'interfaces', 'policy', 'rules', 'masq'] as const + +export default function GenerateModal({ open, configId, configName, onClose }: Props) { + const [tab, setTab] = useState(0) + const [files, setFiles] = useState(null) + const [loading, setLoading] = useState(false) + + const handleOpen = async () => { + if (files) return + setLoading(true) + try { + const res = await configsApi.generate(configId, 'json') + setFiles(res.data) + } finally { + setLoading(false) + } + } + + const handleDownloadZip = async () => { + const res = await configsApi.generate(configId, 'zip') + const url = URL.createObjectURL(new Blob([res.data])) + const a = document.createElement('a') + a.href = url + a.download = `${configName}-shorewall.zip` + a.click() + URL.revokeObjectURL(url) + } + + const handleCopy = (text: string) => navigator.clipboard.writeText(text) + + if (open && !files && !loading) handleOpen() + + const currentFile = files ? files[TABS[tab]] : '' + + return ( + + Generated Shorewall Config — {configName} + + setTab(v)} sx={{ borderBottom: 1, borderColor: 'divider', px: 2 }}> + {TABS.map((t) => )} + + + + handleCopy(currentFile)}> + + + + + {loading ? 'Generating…' : currentFile} + + + + + + + + + ) +}