Skip to content
Snippets Groups Projects
Commit 509ff2b2 authored by Christophe's avatar Christophe
Browse files

fix(template): handle canonical cookiecutter 'yes/no's, fix double checkbox label

parent eac2954d
No related branches found
No related tags found
1 merge request!10Update ai4eosc branch with recent main (multiple templates)
......@@ -6,21 +6,30 @@ type CheckboxInput = {
field: CutterField;
flagged?: boolean;
className?: string;
truthy?: string | boolean;
falsy?: string | boolean;
};
const CheckboxInput: FC<CheckboxInput> = ({ field, flagged = false, className }) => {
const CheckboxInput: FC<CheckboxInput> = ({
field,
flagged = false,
className,
truthy = true,
falsy = false,
}) => {
const classes = clsx('rounded input mt-0 mb-1 mr-2', flagged && 'border-warning', className);
return (
<div>
<input type="hidden" name={field.name} value={falsy.toString()} />
<input
className={clsx(
'rounded input mt-0 mb-1 mr-2',
flagged && 'border-warning',
className
)}
className={classes}
type="checkbox"
name={field.name}
id={field.name}
// TODO: type assertion due to api typing not being good enough
defaultChecked={field.default as boolean}
// TODO: type assertion due to generator issues
defaultChecked={field.default === truthy}
value={truthy.toString()}
/>
<label htmlFor={field.name}>{field.prompt ?? field.name}</label>
</div>
......
import { BLANK_FIELD, LegalField, SelectField, StringField } from 'lib/template';
import { BLANK_FIELD } from 'lib/template';
import React, { FC } from 'react';
import SelectInput from './SelectInput';
import TextInput from './TextInput';
import Badge from 'components/Badge';
import { CutterField } from 'lib/client';
import CheckboxInput from 'components/template/CheckboxInput';
import ErrorBox from 'components/ErrorBox';
......@@ -14,8 +13,6 @@ const Formfield: FC<FormFieldProps> = ({ field, flagged }) => {
{field.default === BLANK_FIELD && <div>{field.prompt ?? field.name}</div>}
{field.default != BLANK_FIELD && (
<>
<label htmlFor={field.name}>{field.prompt ?? field.name}</label>{' '}
{flagged && <Badge type="warning">Missing</Badge>}
{field.type === 'text' ? (
<TextInput field={field} flagged={flagged} className="mt-1" />
) : field.type === 'select' ? (
......
import { FC } from 'react';
import clsx from 'clsx';
import { CutterField } from 'lib/client';
import CheckboxInput from 'components/template/CheckboxInput';
import { attemptDetermineYesNoOptions } from 'components/template/yesOrNo';
import Badge from 'components/Badge';
type SelectInputProps = {
field: CutterField;
......@@ -8,18 +11,35 @@ type SelectInputProps = {
className?: string;
};
const SelectInput: FC<SelectInputProps> = ({ field, flagged = false, className }) => {
const yesNoOptions = field.options != null && attemptDetermineYesNoOptions(field.options);
if (yesNoOptions !== false) {
return (
<CheckboxInput
field={field}
className="mt-1"
truthy={yesNoOptions.truthy}
falsy={yesNoOptions.falsy}
/>
);
}
return (
<select
name={field.name}
id={field.name}
className={clsx('rounded', flagged && 'border-warning', className)}
>
{field.options?.map((option) => (
<option value={option.name} key={option.name}>
{option.prompt ?? option.name}
</option>
))}
</select>
<>
<label htmlFor={field.name}>{field.prompt ?? field.name}</label>{' '}
{flagged && <Badge type="warning">Missing</Badge>}
<select
name={field.name}
id={field.name}
className={clsx('rounded', flagged && 'border-warning', className)}
>
{field.options?.map((option) => (
<option value={option.name} key={option.name}>
{option.prompt ?? option.name}
</option>
))}
</select>
</>
);
};
......
import { FC } from 'react';
import clsx from 'clsx';
import { CutterField } from 'lib/client';
import Badge from 'components/Badge';
type TextInputProps = {
field: CutterField;
......@@ -9,14 +10,18 @@ type TextInputProps = {
};
const TextInput: FC<TextInputProps> = ({ field, flagged = false, className }) => {
return (
<input
className={clsx('rounded input', flagged && 'border-warning', className)}
type="text"
name={field.name}
id={field.name}
// TODO: type assertion due to api typing not being good enough
placeholder={field.default as string}
/>
<>
<label htmlFor={field.name}>{field.prompt ?? field.name}</label>{' '}
{flagged && <Badge type="warning">Missing</Badge>}
<input
className={clsx('rounded input', flagged && 'border-warning', className)}
type="text"
name={field.name}
id={field.name}
// TODO: type assertion due to api typing not being good enough
placeholder={field.default as string}
/>
</>
);
};
......
// referencing defaults in https://cookiecutter.readthedocs.io/en/2.3.0/cookiecutter.html#cookiecutter.prompt.YesNoPrompt
import { CutterOption } from 'lib/client';
export const TRUTHY_DEFAULTS = ['1', 'true', 't', 'yes', 'y', 'on'];
export const FALSY_DEFAULTS = ['0', 'false', 'f', 'no', 'n', 'off'];
export const attemptDetermineYesNoOptions = (
options: CutterOption[]
):
| {
truthy: string;
falsy: string;
}
| false => {
if (options.length !== 2) {
return false;
}
// do not use a checkbox if the select options have a label because context may ge tlost
if (options.some((o) => o.prompt != null)) {
return false;
}
// ensure alphabetical order in checks!
const [first, second] = options.map((o) => o.name).sort();
if (
(first === '0' && second === '1') ||
(first === 'false' && second === 'true') ||
(first === 'f' && second === 't') ||
(first === 'no' && second === 'yes') ||
(first === 'n' && second === 'y') ||
(first === 'off' && second === 'on')
) {
return {
truthy: second,
falsy: first,
};
}
return false;
};
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment