UNPKG

@letanure/resend-cli

Version:

A command-line interface for Resend email API

115 lines 7.24 kB
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { Alert, Spinner } from '@inkjs/ui'; import { Box, Text, useInput } from 'ink'; import React from 'react'; import { ErrorDisplay } from '../ui/ErrorDisplay.js'; import { Layout } from '../ui/layout.js'; import { config } from '../../config/config.js'; import { useDryRun } from '../../contexts/DryRunProvider.js'; import { useResend } from '../../contexts/ResendProvider.js'; import { clipContent } from '../../utils/clipContent.js'; const DEFAULT_LOAD_DATA = {}; const SelectableTable = ({ data, fields, selectedIndex, title }) => { if (data.length === 0) { return (_jsxs(Box, { flexDirection: "column", children: [title && (_jsx(Box, { marginBottom: 1, children: _jsx(Text, { bold: true, children: title }) })), _jsx(Text, { dimColor: true, children: "No data found" })] })); } // Calculate column widths based on content const columnWidths = {}; for (const field of fields) { // Start with header width columnWidths[field.name] = field.label.length; // Check data widths (using clipped content for width calculation) for (const row of data) { const rawValue = String(row[field.name] || ''); const clippedValue = clipContent(rawValue, field.name); const currentWidth = columnWidths[field.name] || 0; columnWidths[field.name] = Math.max(currentWidth, clippedValue.length); } // Add some padding and set minimum width const finalWidth = columnWidths[field.name] || 0; columnWidths[field.name] = Math.max(finalWidth + 2, 8); } return (_jsxs(Box, { flexDirection: "column", children: [title && (_jsx(Box, { marginBottom: 1, children: _jsx(Text, { bold: true, children: title }) })), _jsx(Box, { children: fields.map((field) => { const width = columnWidths[field.name] || 8; return (_jsx(Box, { width: width, children: _jsx(Text, { bold: true, color: "blue", children: field.label.padEnd(width - 1) }) }, field.name)); }) }), _jsx(Box, { children: fields.map((field) => { const width = columnWidths[field.name] || 8; return (_jsx(Box, { width: width, children: _jsx(Text, { dimColor: true, children: '-'.repeat(width - 1) }) }, field.name)); }) }), data.map((row, index) => { const isSelected = index === selectedIndex; return (_jsx(Box, { children: fields.map((field, fieldIndex) => { const width = columnWidths[field.name] || 8; const rawValue = String(row[field.name] || ''); const clippedValue = clipContent(rawValue, field.name); let displayValue; if (fieldIndex === 0) { // First column gets selection indicator const prefix = isSelected ? '► ' : ' '; const availableWidth = width - 1 - prefix.length; const truncatedValue = clippedValue.length > availableWidth ? clippedValue.substring(0, availableWidth) : clippedValue; displayValue = `${prefix}${truncatedValue}`.padEnd(width - 1); } else { // Other columns just get padded displayValue = clippedValue.padEnd(width - 1); } return (_jsx(Box, { width: width, children: _jsx(Text, { color: isSelected ? 'cyan' : 'white', bold: isSelected, children: displayValue }) }, field.name)); }) }, String(row.id || index))); }), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { dimColor: true, children: [data.length, " ", data.length === 1 ? 'item' : 'items', " total"] }) })] })); }; export function SelectableListDisplay({ title, isOpen, onSelect, onCancel, loadFunction, formatData, displayFields, loadData = DEFAULT_LOAD_DATA, noDataMessage = 'No items found.', }) { const [result, setResult] = React.useState(null); const [loading, setLoading] = React.useState(false); const [selectedIndex, setSelectedIndex] = React.useState(0); const { isDryRun } = useDryRun(); const { apiKey } = useResend(); const handleLoad = React.useCallback(async () => { setLoading(true); const loadResult = await loadFunction(loadData, apiKey); setResult(loadResult); setLoading(false); }, [loadFunction, loadData, apiKey]); React.useEffect(() => { if (isOpen && !isDryRun) { handleLoad(); } }, [isOpen, handleLoad, isDryRun]); useInput((input, key) => { if (!isOpen) { return; } if (key.escape || key.leftArrow || input === 'q') { onCancel(); } else if (result?.success && result.data?.data) { const items = result.data.data; if (key.upArrow) { setSelectedIndex(Math.max(0, selectedIndex - 1)); } else if (key.downArrow) { setSelectedIndex(Math.min(items.length - 1, selectedIndex + 1)); } else if (key.return || input === ' ') { const selectedItem = items[selectedIndex]; if (selectedItem) { onSelect(selectedItem); } } } }); if (!isOpen) { return null; } if (loading) { return (_jsx(Layout, { headerText: `${config.baseTitle} - ${title} - Select`, showNavigationInstructions: false, navigationContext: "none", children: _jsx(Box, { marginBottom: 1, children: _jsx(Spinner, { label: `Loading ${title.toLowerCase()}...` }) }) })); } if (result) { if (result.success && result.data?.data) { const tableData = formatData(result.data); return (_jsx(Layout, { headerText: `${config.baseTitle} - ${title} - Select`, showNavigationInstructions: true, navigationContext: "result", footerText: "\u2191/\u2193 navigate \u2022 Space/Enter select \u2022 Esc/\u2190 cancel", children: _jsx(Box, { flexDirection: "column", children: tableData.length === 0 ? (_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "gray", children: noDataMessage }) })) : (_jsx(SelectableTable, { data: tableData, fields: displayFields, selectedIndex: selectedIndex, title: title })) }) })); } return (_jsx(Layout, { headerText: `${config.baseTitle} - ${title} - Select`, showNavigationInstructions: true, navigationContext: "result", footerText: "Press Esc/\u2190 to cancel", children: _jsx(ErrorDisplay, { message: result.error || `Failed to load ${title.toLowerCase()}` }) })); } return (_jsx(Layout, { headerText: `${config.baseTitle} - ${title} - Select`, showNavigationInstructions: true, navigationContext: "result", footerText: "Press Esc/\u2190 to cancel", children: isDryRun && (_jsx(Box, { marginBottom: 1, children: _jsx(Alert, { variant: "warning", children: "DRY RUN MODE - No API calls will be made" }) })) })); } //# sourceMappingURL=SelectableListDisplay.js.map