Local modifications to ClusterLabs/Anvil by Alteeve
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

173 lines
4.2 KiB

import { Box, List as MUIList, ListItem as MUIListItem } from '@mui/material';
import { FC, ReactElement } from 'react';
import { REP_LABEL_PASSW } from '../lib/consts/REG_EXP_PATTERNS';
import disassembleCamel from '../lib/disassembleCamel';
import FlexBox from './FlexBox';
import { BodyText, MonoText, SensitiveText } from './Text';
const renderEntryValueWithMono: RenderFormValueFunction = ({ entry }) => (
<MonoText whiteSpace="nowrap">{String(entry)}</MonoText>
);
const renderEntryValueWithPassword: RenderFormValueFunction = (args) => {
const { entry, key } = args;
return REP_LABEL_PASSW.test(key) ? (
<SensitiveText monospaced>{String(entry)}</SensitiveText>
) : (
renderEntryValueWithMono(args)
);
};
const renderEntryValueBase: RenderFormValueFunction = (args) => {
const { entry, hasPassword } = args;
if (
['', null, undefined].some((bad) => entry === bad) ||
Number.isNaN(entry)
) {
return <BodyText>none</BodyText>;
}
return hasPassword
? renderEntryValueWithPassword(args)
: renderEntryValueWithMono(args);
};
const renderEntryBase: RenderFormEntryFunction = (args) => {
const { depth, entry, getLabel, hasPassword, key, nest, renderValue } = args;
return (
<FlexBox fullWidth growFirst row maxWidth="100%">
<BodyText>
{getLabel({ cap: disassembleCamel, depth, entry, hasPassword, key })}
</BodyText>
<Box sx={{ maxWidth: '100%', overflowX: 'scroll' }}>
{!nest &&
renderValue(renderEntryValueBase, { depth, entry, hasPassword, key })}
</Box>
</FlexBox>
);
};
const skipBase: SkipFormEntryFunction = ({ key }) => !/confirm|uuid/i.test(key);
const buildEntryList = <T extends FormEntries>({
depth = 0,
entries,
getEntryLabel,
getListProps,
getListItemProps,
hasPassword,
listKey,
maxDepth,
renderEntry,
renderEntryValue,
skip,
}: {
depth?: number;
entries: FormEntries;
getEntryLabel: GetFormEntryLabelFunction;
getListProps?: GetFormEntriesPropsFunction;
getListItemProps?: GetFormEntryPropsFunction;
listKey?: string;
} & Required<
Pick<
FormSummaryProps<T>,
'hasPassword' | 'maxDepth' | 'renderEntry' | 'renderEntryValue' | 'skip'
>
>): ReactElement => {
const result: ReactElement[] = [];
Object.entries(entries).forEach(([itemKey, entry]) => {
const itemId = `form-summary-entry-${itemKey}`;
const nest = entry !== null && typeof entry === 'object';
const value = nest ? null : entry;
const fnArgs: CommonFormEntryHandlerArgs = {
depth,
entry: value,
hasPassword,
key: itemKey,
};
if (skip(skipBase, fnArgs)) {
result.push(
<MUIListItem
key={itemId}
sx={{ paddingLeft: `${depth}em` }}
{...getListItemProps?.call(null, fnArgs)}
>
{renderEntry({
depth,
entry: value,
getLabel: getEntryLabel,
hasPassword,
key: itemKey,
nest,
renderValue: renderEntryValue,
})}
</MUIListItem>,
);
}
if (nest && depth < maxDepth) {
result.push(
buildEntryList<T>({
depth: depth + 1,
entries: entry,
getEntryLabel,
hasPassword,
listKey: itemKey,
maxDepth,
renderEntry,
renderEntryValue,
skip,
}),
);
}
});
const listId = `form-summary-list-${listKey ?? 'root'}`;
return (
<MUIList
dense
disablePadding
key={listId}
{...getListProps?.call(null, { depth, entries, key: listKey })}
>
{result}
</MUIList>
);
};
const FormSummary = <T extends FormEntries>({
entries,
getEntryLabel = ({ cap, key }) => cap(key),
getListProps,
getListItemProps,
hasPassword = false,
maxDepth = 3,
renderEntry = renderEntryBase,
renderEntryValue = (base, ...args) => base(...args),
skip = (base, ...args) => base(...args),
}: FormSummaryProps<T>): ReturnType<FC<FormSummaryProps<T>>> =>
buildEntryList<T>({
entries,
getEntryLabel,
getListProps,
getListItemProps,
hasPassword,
maxDepth,
renderEntry,
renderEntryValue,
skip,
});
export default FormSummary;