Allow two controls to be inline in SchemaView.

pull/6551/head
Aditya Toshniwal 2023-07-10 17:42:20 +05:30 committed by GitHub
parent 7686280cb2
commit a08714cd65
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 162 additions and 80 deletions

View File

@ -18,6 +18,7 @@ import CustomPropTypes from '../custom_prop_types';
import { DepListenerContext } from './DepListener'; import { DepListenerContext } from './DepListener';
import { getFieldMetaData } from './FormView'; import { getFieldMetaData } from './FormView';
import FieldSet from '../components/FieldSet'; import FieldSet from '../components/FieldSet';
import { Box } from '@material-ui/core';
export default function FieldSetView({ export default function FieldSetView({
value, schema={}, viewHelperProps, accessPath, dataDispatch, controlClassName, isDataGridForm=false, label, visible}) { value, schema={}, viewHelperProps, accessPath, dataDispatch, controlClassName, isDataGridForm=false, label, visible}) {
@ -46,6 +47,8 @@ export default function FieldSetView({
}, []); }, []);
let viewFields = []; let viewFields = [];
let inlineComponents = [];
/* Prepare the array of components based on the types */ /* Prepare the array of components based on the types */
for(const field of schema.fields) { for(const field of schema.fields) {
let {visible, disabled, readonly, modeSupported} = let {visible, disabled, readonly, modeSupported} =
@ -58,40 +61,63 @@ export default function FieldSetView({
* lets pass the new changes to dependent and get the new values * lets pass the new changes to dependent and get the new values
* from there as well. * from there as well.
*/ */
viewFields.push( const currentControl = <MappedFormControl
<MappedFormControl state={value}
state={value} key={field.id}
key={field.id} viewHelperProps={viewHelperProps}
viewHelperProps={viewHelperProps} name={field.id}
name={field.id} value={value[field.id]}
value={value[field.id]} {...field}
{...field} readonly={readonly}
readonly={readonly} disabled={disabled}
disabled={disabled} visible={visible}
visible={visible} onChange={(changeValue)=>{
onChange={(changeValue)=>{ /* Get the changes on dependent fields as well */
/* Get the changes on dependent fields as well */ dataDispatch({
dataDispatch({ type: SCHEMA_STATE_ACTIONS.SET_VALUE,
type: SCHEMA_STATE_ACTIONS.SET_VALUE, path: accessPath.concat(field.id),
path: accessPath.concat(field.id), value: changeValue,
value: changeValue, });
}); }}
}} hasError={hasError}
hasError={hasError} className={controlClassName}
className={controlClassName} memoDeps={[
memoDeps={[ value[field.id],
value[field.id], readonly,
readonly, disabled,
disabled, visible,
visible, hasError,
hasError, controlClassName,
controlClassName, ...(evalFunc(null, field.deps) || []).map((dep)=>value[dep]),
...(evalFunc(null, field.deps) || []).map((dep)=>value[dep]), ]}
]} />;
/>
); if(field.inlineNext) {
inlineComponents.push(React.cloneElement(currentControl, {
withContainer: false, controlGridBasis: 3
}));
} else if(inlineComponents?.length > 0) {
inlineComponents.push(React.cloneElement(currentControl, {
withContainer: false, controlGridBasis: 3
}));
viewFields.push(
<Box key={`ic-${inlineComponents[0].key}`} display="flex" className={controlClassName} gridRowGap="8px" flexWrap="wrap">
{inlineComponents}
</Box>
);
inlineComponents = [];
} else {
viewFields.push(currentControl);
}
} }
} }
if(inlineComponents?.length > 0) {
viewFields.push(
<Box key={`ic-${inlineComponents[0].key}`} display="flex" className={controlClassName} gridRowGap="8px" flexWrap="wrap">
{inlineComponents}
</Box>
);
}
if(!visible) { if(!visible) {
return <></>; return <></>;

View File

@ -212,6 +212,8 @@ export default function FormView({
}, [stateUtils.formResetKey]); }, [stateUtils.formResetKey]);
let fullTabs = []; let fullTabs = [];
let inlineComponents = [];
let inlineCompGroup = null;
/* Prepare the array of components based on the types */ /* Prepare the array of components based on the types */
for(const field of schemaRef.current.fields) { for(const field of schemaRef.current.fields) {
@ -304,49 +306,75 @@ export default function FormView({
firstEleID.current = field.id; firstEleID.current = field.id;
} }
tabs[group].push( const currentControl = <MappedFormControl
<MappedFormControl inputRef={(ele)=>{
inputRef={(ele)=>{ if(firstEleRef && firstEleID.current === field.id) {
if(firstEleRef && firstEleID.current === field.id) { firstEleRef.current = ele;
firstEleRef.current = ele; }
} }}
}} state={value}
state={value} key={id}
key={id} viewHelperProps={viewHelperProps}
viewHelperProps={viewHelperProps} name={id}
name={id} value={value[id]}
value={value[id]} {...field}
{...field} id={id}
id={id} readonly={readonly}
readonly={readonly} disabled={disabled}
disabled={disabled} visible={visible}
visible={visible} onChange={(changeValue)=>{
onChange={(changeValue)=>{ /* Get the changes on dependent fields as well */
/* Get the changes on dependent fields as well */ dataDispatch({
dataDispatch({ type: SCHEMA_STATE_ACTIONS.SET_VALUE,
type: SCHEMA_STATE_ACTIONS.SET_VALUE, path: accessPath.concat(id),
path: accessPath.concat(id), value: changeValue,
value: changeValue, });
}); }}
}} hasError={hasError}
hasError={hasError} className={classes.controlRow}
className={classes.controlRow} noLabel={field.isFullTab}
noLabel={field.isFullTab} memoDeps={[
memoDeps={[ value[id],
value[id], readonly,
readonly, disabled,
disabled, visible,
visible, hasError,
hasError, classes.controlRow,
classes.controlRow, ...(evalFunc(null, field.deps) || []).map((dep)=>value[dep]),
...(evalFunc(null, field.deps) || []).map((dep)=>value[dep]), ]}
]} />;
/>
); if(field.inlineNext) {
inlineComponents.push(React.cloneElement(currentControl, {
withContainer: false, controlGridBasis: 3
}));
inlineCompGroup = group;
} else if(inlineComponents?.length > 0) {
inlineComponents.push(React.cloneElement(currentControl, {
withContainer: false, controlGridBasis: 3
}));
tabs[group].push(
<Box key={`ic-${inlineComponents[0].key}`} display="flex" className={classes.controlRow} gridRowGap="8px" flexWrap="wrap">
{inlineComponents}
</Box>
);
inlineComponents = [];
inlineCompGroup = null;
} else {
tabs[group].push(currentControl);
}
} }
} }
} }
if(inlineComponents?.length > 0) {
tabs[inlineCompGroup].push(
<Box key={`ic-${inlineComponents[0].key}`} display="flex" className={classes.controlRow} gridRowGap="8px" flexWrap="wrap">
{inlineComponents}
</Box>
);
}
let finalTabs = _.pickBy(tabs, (v, tabName)=>schemaRef.current.filterGroups.indexOf(tabName) <= -1); let finalTabs = _.pickBy(tabs, (v, tabName)=>schemaRef.current.filterGroups.indexOf(tabName) <= -1);
/* Add the SQL tab if required */ /* Add the SQL tab if required */

View File

@ -201,7 +201,8 @@ const ALLOWED_PROPS_FIELD_COMMON = [
'mode', 'value', 'readonly', 'disabled', 'hasError', 'id', 'mode', 'value', 'readonly', 'disabled', 'hasError', 'id',
'label', 'options', 'optionsLoaded', 'controlProps', 'schema', 'inputRef', 'label', 'options', 'optionsLoaded', 'controlProps', 'schema', 'inputRef',
'visible', 'autoFocus', 'helpMessage', 'className', 'optionsReloadBasis', 'visible', 'autoFocus', 'helpMessage', 'className', 'optionsReloadBasis',
'orientation', 'isvalidate', 'fields', 'radioType', 'hideBrowseButton', 'btnName', 'hidden' 'orientation', 'isvalidate', 'fields', 'radioType', 'hideBrowseButton', 'btnName', 'hidden',
'withContainer', 'controlGridBasis',
]; ];
const ALLOWED_PROPS_FIELD_FORM = [ const ALLOWED_PROPS_FIELD_FORM = [

View File

@ -125,19 +125,37 @@ FormIcon.propTypes = {
}; };
/* Wrapper on any form component to add label, error indicator and help message */ /* Wrapper on any form component to add label, error indicator and help message */
export function FormInput({ children, error, className, label, helpMessage, required, testcid }) { export function FormInput({ children, error, className, label, helpMessage, required, testcid, withContainer=true, labelGridBasis=3, controlGridBasis=9 }) {
const classes = useStyles(); const classes = useStyles();
const cid = testcid || _.uniqueId('c'); const cid = testcid || _.uniqueId('c');
const helpid = `h${cid}`; const helpid = `h${cid}`;
if(!withContainer) {
return (
<>
<Grid item lg={labelGridBasis} md={labelGridBasis} sm={12} xs={12}>
<InputLabel htmlFor={cid} className={clsx(classes.formLabel, error ? classes.formLabelError : null)} required={required}>
{label}
<FormIcon type={MESSAGE_TYPE.ERROR} style={{ marginLeft: 'auto', visibility: error ? 'unset' : 'hidden' }} />
</InputLabel>
</Grid>
<Grid item lg={controlGridBasis} md={controlGridBasis} sm={12} xs={12}>
<FormControl error={Boolean(error)} fullWidth>
{React.cloneElement(children, { cid, helpid })}
</FormControl>
<FormHelperText id={helpid} variant="outlined">{HTMLReactParse(helpMessage || '')}</FormHelperText>
</Grid>
</>
);
}
return ( return (
<Grid container spacing={0} className={className}> <Grid container spacing={0} className={className}>
<Grid item lg={3} md={3} sm={3} xs={12}> <Grid item lg={labelGridBasis} md={labelGridBasis} sm={12} xs={12}>
<InputLabel htmlFor={cid} className={clsx(classes.formLabel, error ? classes.formLabelError : null)} required={required}> <InputLabel htmlFor={cid} className={clsx(classes.formLabel, error ? classes.formLabelError : null)} required={required}>
{label} {label}
<FormIcon type={MESSAGE_TYPE.ERROR} style={{ marginLeft: 'auto', visibility: error ? 'unset' : 'hidden' }} /> <FormIcon type={MESSAGE_TYPE.ERROR} style={{ marginLeft: 'auto', visibility: error ? 'unset' : 'hidden' }} />
</InputLabel> </InputLabel>
</Grid> </Grid>
<Grid item lg={9} md={9} sm={9} xs={12}> <Grid item lg={controlGridBasis} md={controlGridBasis} sm={12} xs={12}>
<FormControl error={Boolean(error)} fullWidth> <FormControl error={Boolean(error)} fullWidth>
{React.cloneElement(children, { cid, helpid })} {React.cloneElement(children, { cid, helpid })}
</FormControl> </FormControl>
@ -154,6 +172,9 @@ FormInput.propTypes = {
helpMessage: PropTypes.string, helpMessage: PropTypes.string,
required: PropTypes.bool, required: PropTypes.bool,
testcid: PropTypes.any, testcid: PropTypes.any,
withContainer: PropTypes.bool,
labelGridBasis: PropTypes.number,
controlGridBasis: PropTypes.number,
}; };
export function InputSQL({ value, options, onChange, className, controlProps, inputRef, ...props }) { export function InputSQL({ value, options, onChange, className, controlProps, inputRef, ...props }) {
@ -512,10 +533,10 @@ InputSwitch.propTypes = {
controlProps: PropTypes.object, controlProps: PropTypes.object,
}; };
export function FormInputSwitch({ hasError, required, label, className, helpMessage, testcid, ...props }) { export function FormInputSwitch({ hasError, required, label, className, helpMessage, testcid, withContainer, controlGridBasis, ...props }) {
return ( return (
<FormInput required={required} label={label} error={hasError} className={className} helpMessage={helpMessage} testcid={testcid}> <FormInput required={required} label={label} error={hasError} className={className}
helpMessage={helpMessage} testcid={testcid} withContainer={withContainer} controlGridBasis={controlGridBasis}>
<InputSwitch {...props} /> <InputSwitch {...props} />
</FormInput> </FormInput>
); );
@ -527,6 +548,8 @@ FormInputSwitch.propTypes = {
className: CustomPropTypes.className, className: CustomPropTypes.className,
helpMessage: PropTypes.string, helpMessage: PropTypes.string,
testcid: PropTypes.string, testcid: PropTypes.string,
withContainer: PropTypes.bool,
controlGridBasis: PropTypes.number,
}; };
export function InputCheckbox({ cid, helpid, value, onChange, controlProps, readonly, ...props }) { export function InputCheckbox({ cid, helpid, value, onChange, controlProps, readonly, ...props }) {
@ -1019,10 +1042,11 @@ InputColor.propTypes = {
}; };
export function FormInputColor({ export function FormInputColor({
hasError, required, className, label, helpMessage, testcid, ...props }) { hasError, required, className, label, helpMessage, testcid, withContainer, controlGridBasis, ...props }) {
return ( return (
<FormInput required={required} label={label} error={hasError} className={className} helpMessage={helpMessage} testcid={testcid}> <FormInput required={required} label={label} error={hasError} className={className} helpMessage={helpMessage} testcid={testcid}
withContainer={withContainer} controlGridBasis={controlGridBasis}>
<InputColor {...props} /> <InputColor {...props} />
</FormInput> </FormInput>
); );
@ -1034,6 +1058,8 @@ FormInputColor.propTypes = {
label: PropTypes.string, label: PropTypes.string,
helpMessage: PropTypes.string, helpMessage: PropTypes.string,
testcid: PropTypes.string, testcid: PropTypes.string,
withContainer: PropTypes.bool,
controlGridBasis: PropTypes.number,
}; };
export function PlainString({ controlProps, value }) { export function PlainString({ controlProps, value }) {

View File

@ -40,6 +40,7 @@ export class SectionSchema extends BaseUISchema {
state.only_tablespaces || state.only_tablespaces ||
state.only_roles; state.only_roles;
}, },
inlineNext: true,
}, { }, {
id: 'data', id: 'data',
label: gettext('Data'), label: gettext('Data'),