UNPKG

vanta-auditor-tui

Version:

Beautiful terminal UI for exporting Vanta audit evidence with ZIP support and progress tracking

83 lines 6.92 kB
import React, { useMemo, useState } from "react"; import { Box, Text, useInput } from "ink"; import { SelectInput, TextInput } from "../lib/inkModules.js"; import { theme } from "../theme.js"; import { FormSection } from "./ui/FormSection.js"; import path from "node:path"; export function ExportOptions({ auditId, onSubmit }) { const [structure, setStructure] = useState("single"); const [prefix, setPrefix] = useState("CSP-001"); const [createZip, setCreateZip] = useState(true); const defaultDir = useMemo(() => { const now = new Date(); const stamp = `${now.getFullYear()}${String(now.getMonth() + 1).padStart(2, "0")}${String(now.getDate()).padStart(2, "0")}-${String(now.getHours()).padStart(2, "0")}${String(now.getMinutes()).padStart(2, "0")}`; return path.resolve(process.cwd(), "exports", `${auditId}-${stamp}`); }, [auditId]); const [dir, setDir] = useState(defaultDir); const [zipName, setZipName] = useState(`audit-${auditId}.zip`); const [focusedInput, setFocusedInput] = useState("dir"); // Navigate between inputs with Tab useInput((input, key) => { if (key.tab) { const inputs = ["dir", "structure"]; if (structure === "separate") inputs.push("prefix"); inputs.push("zip"); if (createZip) inputs.push("zipName"); inputs.push("submit"); const currentIndex = inputs.indexOf(focusedInput); const nextIndex = key.shift ? (currentIndex - 1 + inputs.length) % inputs.length : (currentIndex + 1) % inputs.length; setFocusedInput(inputs[nextIndex]); } }); return (React.createElement(Box, { flexDirection: "column" }, React.createElement(FormSection, { title: "\uD83D\uDCC1 Export Configuration", subtitle: "Configure how your audit evidence will be exported" }, React.createElement(Box, null, React.createElement(Text, { color: theme.colors.primaryLight }, "Output directory:"), React.createElement(Box, { borderStyle: focusedInput === "dir" ? "double" : "single", borderColor: focusedInput === "dir" ? theme.colors.primary : theme.colors.border, paddingX: 1, marginTop: 1 }, focusedInput === "dir" ? (React.createElement(TextInput, { value: dir, onChange: setDir, onSubmit: () => setFocusedInput("structure") })) : (React.createElement(Text, null, dir)))), React.createElement(Box, { flexDirection: "column", marginTop: 2 }, React.createElement(Text, { color: theme.colors.primaryLight }, "Folder structure:"), React.createElement(Box, { borderStyle: focusedInput === "structure" ? "double" : "single", borderColor: focusedInput === "structure" ? theme.colors.primary : theme.colors.border, paddingX: 1, paddingY: 1, marginTop: 1 }, focusedInput === "structure" ? (React.createElement(SelectInput, { items: [ { label: "Single folder (all files together)", value: "single" }, { label: "Separate folder per evidence", value: "separate" } ], onSelect: (i) => { setStructure(i.value); setFocusedInput(structure === "single" && i.value === "separate" ? "prefix" : "zip"); } })) : (React.createElement(Text, null, structure === "single" ? "Single folder (all files together)" : "Separate folder per evidence")))), structure === "separate" && (React.createElement(Box, { marginTop: 2 }, React.createElement(Text, { color: theme.colors.primaryLight }, "Folder prefix:"), React.createElement(Box, { borderStyle: focusedInput === "prefix" ? "double" : "single", borderColor: focusedInput === "prefix" ? theme.colors.primary : theme.colors.border, paddingX: 1, marginLeft: 1 }, focusedInput === "prefix" ? (React.createElement(TextInput, { value: prefix, onChange: setPrefix, onSubmit: () => setFocusedInput("zip") })) : (React.createElement(Text, null, prefix))))), React.createElement(Box, { flexDirection: "column", marginTop: 2 }, React.createElement(Text, { color: theme.colors.primaryLight }, "Create ZIP archive:"), React.createElement(Box, { borderStyle: focusedInput === "zip" ? "double" : "single", borderColor: focusedInput === "zip" ? theme.colors.primary : theme.colors.border, paddingX: 1, paddingY: 1, marginTop: 1 }, focusedInput === "zip" ? (React.createElement(SelectInput, { items: [ { label: "Yes - Create a ZIP file", value: "yes" }, { label: "No - Keep files in folder", value: "no" } ], onSelect: (i) => { setCreateZip(i.value === "yes"); setFocusedInput(i.value === "yes" ? "zipName" : "submit"); } })) : (React.createElement(Text, null, createZip ? "Yes - Create a ZIP file" : "No - Keep files in folder")))), createZip && (React.createElement(Box, { marginTop: 2 }, React.createElement(Text, { color: theme.colors.primaryLight }, "ZIP filename:"), React.createElement(Box, { borderStyle: focusedInput === "zipName" ? "double" : "single", borderColor: focusedInput === "zipName" ? theme.colors.primary : theme.colors.border, paddingX: 1, marginLeft: 1 }, focusedInput === "zipName" ? (React.createElement(TextInput, { value: zipName, onChange: setZipName, onSubmit: () => setFocusedInput("submit") })) : (React.createElement(Text, null, zipName))))), React.createElement(Box, { marginTop: 2 }, React.createElement(Text, { color: theme.colors.text, dimColor: true }, "\uD83D\uDCA1 Use Tab/Shift+Tab to navigate between fields")), React.createElement(Box, { marginTop: 1, borderStyle: focusedInput === "submit" ? "double" : "single", borderColor: focusedInput === "submit" ? theme.colors.success : theme.colors.border, paddingX: 2, paddingY: 1 }, React.createElement(Text, { color: theme.colors.success, bold: true }, focusedInput === "submit" ? "✨ Press Enter to start downloading evidence" : "Navigate here and press Enter to start")), focusedInput === "submit" && (React.createElement(Box, { marginTop: 1 }, React.createElement(TextInput, { value: "", onChange: () => { }, onSubmit: () => onSubmit({ outputDir: dir, structure, folderPrefix: structure === "separate" ? prefix : undefined, createZip, zipName: createZip ? zipName : undefined }), focus: true })))))); } export default ExportOptions; //# sourceMappingURL=ExportOptions.js.map