UNPKG

@t1mmen/srtd

Version:

Supabase Repeatable Template Definitions (srtd): 🪄 Live-reloading SQL templates for Supabase DX. Make your database changes reviewable and migrations maintainable! 🚀

145 lines • 6.48 kB
import { MultiSelect } from '@inkjs/ui'; import figures from 'figures'; import { Box, Text, useInput } from 'ink'; import { argument } from 'pastel'; import React from 'react'; import zod from 'zod'; import Branding from '../components/Branding.js'; import Quittable from '../components/Quittable.js'; import { COLOR_ERROR, COLOR_SUCCESS, COLOR_WARNING } from '../components/customTheme.js'; import { useTemplateState } from '../hooks/useTemplateState.js'; import { findProjectRoot } from '../utils/findProjectRoot.js'; import { registerTemplate } from '../utils/registerTemplate.js'; // Support both array of filenames as arguments and interactive selection export const args = zod .array(zod.string()) .optional() .describe(argument({ name: 'templates', description: 'Template files to register (optional)', })); export default function Register({ args: templateArgs }) { const { error, items } = useTemplateState(); const [selectedValues, setSelectedValues] = React.useState([]); const [successMessage, setSuccessMessage] = React.useState(''); const [errorMessage, setErrorMessage] = React.useState(''); const [showAll, setShowAll] = React.useState(false); useInput(input => { if (input === 'r') { setShowAll(!showAll); } }); const handleTemplateRegistration = React.useCallback(async (templates) => { setSuccessMessage(''); setErrorMessage(''); let successCount = 0; let failCount = 0; try { const projectRoot = await findProjectRoot(); for (const path of templates) { try { await registerTemplate(path, projectRoot); successCount++; } catch (err) { console.error(err); failCount++; } } } catch (err) { if (err instanceof Error) { setErrorMessage(err.message); } process.exit(1); } if (failCount > 0) { setErrorMessage(`Failed to register ${failCount} template(s).`); } if (successCount > 0) { setSuccessMessage(`Successfully registered ${successCount} template(s).`); } process.exit(failCount > 0 ? 1 : 0); }, []); React.useEffect(() => { // If templates were provided as arguments, register them directly if (templateArgs?.length) { handleTemplateRegistration(templateArgs); } }, [handleTemplateRegistration, templateArgs]); if (error) { return React.createElement(Text, { color: COLOR_ERROR }, "Error: ", error); } const renderStatus = () => { if (!errorMessage && !successMessage) return null; return (React.createElement(Box, { flexDirection: "column", marginTop: 1 }, !!errorMessage && (React.createElement(Text, { color: COLOR_ERROR }, figures.cross, " ", errorMessage)), !!successMessage && (React.createElement(Text, { color: COLOR_SUCCESS }, figures.tick, " ", successMessage)))); }; const isDone = !!successMessage || !!errorMessage; // If no templates were provided as arguments, show interactive selection if (!templateArgs?.length && !isDone) { const options = items .filter(t => { if (showAll) return true; return !t.buildState.lastMigrationFile; }) .sort((a, b) => { // If a template has a last migration file, it's considered registered, and sort it last. if (a.buildState.lastMigrationFile && !b.buildState.lastMigrationFile) return 1; if (!a.buildState.lastMigrationFile && b.buildState.lastMigrationFile) return -1; return a.name.localeCompare(b.name); }) .map(t => { const status = t.buildState.lastMigrationFile ? 'registered' : 'new'; return { label: `${t.name} (${status})`, value: t.path, }; }); return (React.createElement(Box, { flexDirection: "column" }, React.createElement(Branding, { subtitle: "\u270D\uFE0F Register templates" }), React.createElement(Box, { gap: 2 }, options.length === 0 ? (React.createElement(Box, { flexDirection: "column" }, React.createElement(Text, { color: COLOR_WARNING }, figures.warning, " No templates ", !showAll && 'unregistered', " found"), !showAll && !!items.length && (React.createElement(Text, { dimColor: true }, figures.info, " Press r to show registered templates")), !items.length && (React.createElement(Text, null, figures.info, "Start by creating a template in the templates directory.")))) : (React.createElement(React.Fragment, null, React.createElement(Text, null, selectedValues.length, " / ", options.length, " selected"), React.createElement(Text, { dimColor: true }, "Use arrow/space to select, then press Enter to register.")))), React.createElement(Box, { marginTop: 1, marginBottom: 1 }, React.createElement(MultiSelect, { visibleOptionCount: 30, options: options, onChange: vals => setSelectedValues(vals), onSubmit: vals => handleTemplateRegistration(vals) }), renderStatus()), React.createElement(Box, { gap: 1 }, React.createElement(Quittable, null), React.createElement(Box, { marginY: 1, gap: 1 }, React.createElement(Text, { dimColor: true }, "\u2022"), React.createElement(Text, { dimColor: true }, "Press"), React.createElement(Text, { underline: showAll }, "r"), showAll ? (React.createElement(Text, { dimColor: true }, "to hide registered templates")) : (React.createElement(Text, { dimColor: true }, "to show registered templates")))))); } return renderStatus(); } //# sourceMappingURL=register.js.map