@letanure/resend-cli
Version:
A command-line interface for Resend email API
115 lines • 7.24 kB
JavaScript
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