@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
JavaScript
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