- Some UI changes based on review comments. - Fix the numeric type.

This commit is contained in:
Aditya Toshniwal
2021-07-20 18:26:20 +05:30
committed by Akshay Joshi
parent 453f26817a
commit 5db72a6916
4 changed files with 63 additions and 18 deletions

View File

@@ -9,7 +9,7 @@
/* The DataGridView component is based on react-table component */ /* The DataGridView component is based on react-table component */
import React, { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react'; import React, { useCallback, useContext, useMemo, useRef, useState } from 'react';
import { Box } from '@material-ui/core'; import { Box } from '@material-ui/core';
import { makeStyles } from '@material-ui/core/styles'; import { makeStyles } from '@material-ui/core/styles';
import { PgIconButton } from '../components/Buttons'; import { PgIconButton } from '../components/Buttons';
@@ -85,6 +85,9 @@ const useStyles = makeStyles((theme)=>({
padding: theme.spacing(1, 0.5), padding: theme.spacing(1, 0.5),
textAlign: 'left', textAlign: 'left',
}, },
btnCell: {
padding: theme.spacing(0.5, 0),
},
resizer: { resizer: {
display: 'inline-block', display: 'inline-block',
width: '5px', width: '5px',
@@ -146,13 +149,14 @@ function DataTableRow({row, totalRows, isResizing, schema, schemaRef, accessPath
const classes = useStyles(); const classes = useStyles();
const [key, setKey] = useState(false); const [key, setKey] = useState(false);
const depListener = useContext(DepListenerContext); const depListener = useContext(DepListenerContext);
/* Memoize the row to avoid unnecessary re-render. /* Memoize the row to avoid unnecessary re-render.
* If table data changes, then react-table re-renders the complete tables * If table data changes, then react-table re-renders the complete tables
* We can avoid re-render by if row data is not changed * We can avoid re-render by if row data is not changed
*/ */
let depsMap = _.values(row.values, Object.keys(row.values).filter((k)=>!k.startsWith('btn'))); let depsMap = _.values(row.values, Object.keys(row.values).filter((k)=>!k.startsWith('btn')));
useEffect(()=>{ const externalDeps = useMemo(()=>{
let retVal = [];
/* Calculate the fields which depends on the current field /* Calculate the fields which depends on the current field
deps has info on fields which the current field depends on. */ deps has info on fields which the current field depends on. */
schema.fields.forEach((field)=>{ schema.fields.forEach((field)=>{
@@ -164,18 +168,25 @@ function DataTableRow({row, totalRows, isResizing, schema, schemaRef, accessPath
let source = accessPath.concat(dep); let source = accessPath.concat(dep);
if(_.isArray(dep)) { if(_.isArray(dep)) {
source = dep; source = dep;
depsMap.push(_.get(schemaRef.current.sessData, source)); /* If its an array, then dep is from the top schema */
retVal.push(source);
} }
depListener.addDepListener(source, accessPath.concat(field.id), field.depChange); depListener.addDepListener(source, accessPath.concat(field.id), field.depChange);
}); });
}); });
return retVal;
}, []); }, []);
/* External deps values are from top schema sess data */
depsMap = depsMap.concat(externalDeps.map((source)=>_.get(schemaRef.current.top?.sessData, source)));
depsMap = depsMap.concat([totalRows, row.isExpanded, key, isResizing]); depsMap = depsMap.concat([totalRows, row.isExpanded, key, isResizing]);
return useMemo(()=> return useMemo(()=>
<div {...row.getRowProps()} className="tr"> <div {...row.getRowProps()} className="tr">
{row.cells.map((cell, ci) => { {row.cells.map((cell, ci) => {
let classNames = [classes.tableCell]; let classNames = [classes.tableCell];
if(typeof(cell.column.id) == 'string' && cell.column.id.startsWith('btn-')) {
classNames.push(classes.btnCell);
}
if(cell.column.id == 'btn-edit' && row.isExpanded) { if(cell.column.id == 'btn-edit' && row.isExpanded) {
classNames.push(classes.expandedIconCell); classNames.push(classes.expandedIconCell);
} }
@@ -207,14 +218,14 @@ export default function DataGridView({
resizable: false, resizable: false,
sortable: false, sortable: false,
dataType: 'edit', dataType: 'edit',
width: 30, width: 26,
minWidth: '0', minWidth: '0',
Cell: ({row})=>{ Cell: ({row})=>{
let canEditRow = true; let canEditRow = true;
if(props.canEditRow) { if(props.canEditRow) {
canEditRow = evalFunc(schemaRef.current, props.canEditRow, row.original || {}); canEditRow = evalFunc(schemaRef.current, props.canEditRow, row.original || {});
} }
return <PgIconButton data-test="expand-row" title={gettext('Edit row')} icon={<EditRoundedIcon />} className={classes.gridRowButton} return <PgIconButton data-test="expand-row" title={gettext('Edit row')} icon={<EditRoundedIcon fontSize="small" />} className={classes.gridRowButton}
onClick={()=>{ onClick={()=>{
row.toggleRowExpanded(!row.isExpanded); row.toggleRowExpanded(!row.isExpanded);
}} disabled={!canEditRow} }} disabled={!canEditRow}
@@ -235,7 +246,7 @@ export default function DataGridView({
resizable: false, resizable: false,
sortable: false, sortable: false,
dataType: 'delete', dataType: 'delete',
width: 30, width: 26,
minWidth: '0', minWidth: '0',
Cell: ({row}) => { Cell: ({row}) => {
let canDeleteRow = true; let canDeleteRow = true;
@@ -244,7 +255,7 @@ export default function DataGridView({
} }
return ( return (
<PgIconButton data-test="delete-row" title={gettext('Delete row')} icon={<DeleteRoundedIcon />} <PgIconButton data-test="delete-row" title={gettext('Delete row')} icon={<DeleteRoundedIcon fontSize="small" />}
onClick={()=>{ onClick={()=>{
confirmDeleteRow(()=>{ confirmDeleteRow(()=>{
/* Get the changes on dependent fields as well */ /* Get the changes on dependent fields as well */

View File

@@ -77,7 +77,7 @@ export function getFieldMetaData(field, schema, value, viewHelperProps) {
disabled: false, disabled: false,
visible: true, visible: true,
canAdd: true, canAdd: true,
canEdit: true, canEdit: false,
canDelete: true, canDelete: true,
modeSupported: true, modeSupported: true,
}; };
@@ -112,9 +112,9 @@ export function getFieldMetaData(field, schema, value, viewHelperProps) {
retData.disabled = Boolean(evalFunc(schema, disabled, value)); retData.disabled = Boolean(evalFunc(schema, disabled, value));
let {canAdd, canEdit, canDelete } = field; let {canAdd, canEdit, canDelete } = field;
retData.canAdd = _.isUndefined(canAdd) ? true : evalFunc(schema, canAdd, value); retData.canAdd = _.isUndefined(canAdd) ? retData.canAdd : evalFunc(schema, canAdd, value);
retData.canEdit = _.isUndefined(canEdit) ? true : evalFunc(schema, canEdit, value); retData.canEdit = _.isUndefined(canEdit) ? retData.canEdit : evalFunc(schema, canEdit, value);
retData.canDelete = _.isUndefined(canDelete) ? true : evalFunc(schema, canDelete, value); retData.canDelete = _.isUndefined(canDelete) ? retData.canDelete : evalFunc(schema, canDelete, value);
return retData; return retData;
} }
@@ -216,9 +216,9 @@ export default function FormView({
depsMap.push(canAdd, canEdit, canDelete, visible); depsMap.push(canAdd, canEdit, canDelete, visible);
tabs[group].push( tabs[group].push(
useMemo(()=><DataGridView key={field.id} value={value[field.id]} viewHelperProps={viewHelperProps} formErr={formErr} <DataGridView key={field.id} value={value[field.id]} viewHelperProps={viewHelperProps} formErr={formErr}
schema={field.schema} accessPath={accessPath.concat(field.id)} dataDispatch={dataDispatch} containerClassName={classes.controlRow} schema={field.schema} accessPath={accessPath.concat(field.id)} dataDispatch={dataDispatch} containerClassName={classes.controlRow}
{...field} canAdd={canAdd} canEdit={canEdit} canDelete={canDelete} visible={visible}/>, depsMap) {...field} canAdd={canAdd} canEdit={canEdit} canDelete={canDelete} visible={visible}/>
); );
} else if(field.type === 'group') { } else if(field.type === 'group') {
groupLabels[field.id] = field.label; groupLabels[field.id] = field.label;

View File

@@ -43,6 +43,17 @@ function MappedFormControlBase({type, value, id, onChange, className, visible, i
onChange && onChange(value); onChange && onChange(value);
}, []); }, []);
const onNumChange = useCallback((e) => {
let value = e;
if(e && e.target) {
value = e.target.value;
}
if(!isNaN(parseFloat(value))) {
value = parseFloat(value);
}
onChange && onChange(value);
}, []);
if(!visible) { if(!visible) {
return <></>; return <></>;
} }
@@ -51,6 +62,8 @@ function MappedFormControlBase({type, value, id, onChange, className, visible, i
switch (type) { switch (type) {
case 'int': case 'int':
return <FormInputText name={name} value={value} onChange={onIntChange} className={className} inputRef={inputRef} {...props}/>; return <FormInputText name={name} value={value} onChange={onIntChange} className={className} inputRef={inputRef} {...props}/>;
case 'numeric':
return <FormInputText name={name} value={value} onChange={onNumChange} className={className} inputRef={inputRef} {...props}/>;
case 'text': case 'text':
return <FormInputText name={name} value={value} onChange={onTextChange} className={className} inputRef={inputRef} {...props}/>; return <FormInputText name={name} value={value} onChange={onTextChange} className={className} inputRef={inputRef} {...props}/>;
case 'multiline': case 'multiline':
@@ -109,6 +122,28 @@ function MappedCellControlBase({cell, value, id, optionsLoaded, onCellChange, vi
onCellChange(value); onCellChange(value);
}, []); }, []);
const onIntChange = useCallback((e) => {
let value = e;
if(e && e.target) {
value = e.target.value;
}
if(!isNaN(parseInt(value))) {
value = parseInt(value);
}
onChange && onChange(value);
}, []);
const onNumChange = useCallback((e) => {
let value = e;
if(e && e.target) {
value = e.target.value;
}
if(!isNaN(parseFloat(value))) {
value = parseFloat(value);
}
onChange && onChange(value);
}, []);
/* Some grid cells are based on options selected in other cells. /* Some grid cells are based on options selected in other cells.
* lets trigger a re-render for the row if optionsLoaded * lets trigger a re-render for the row if optionsLoaded
*/ */
@@ -125,7 +160,9 @@ function MappedCellControlBase({cell, value, id, optionsLoaded, onCellChange, vi
/* The mapping does not need Form* components as labels are not needed for grid cells */ /* The mapping does not need Form* components as labels are not needed for grid cells */
switch(cell) { switch(cell) {
case 'int': case 'int':
case 'number': return <InputText name={name} value={value} onChange={onIntChange} {...props}/>;
case 'numeric':
return <InputText name={name} value={value} onChange={onNumChange} {...props}/>;
case 'text': case 'text':
return <InputText name={name} value={value} onChange={onTextChange} {...props}/>; return <InputText name={name} value={value} onChange={onTextChange} {...props}/>;
case 'password': case 'password':

View File

@@ -781,9 +781,6 @@ export function InputColor({value, controlProps, disabled, onChange, currObj}) {
let btnStyles = {backgroundColor: value}; let btnStyles = {backgroundColor: value};
return ( return (
// <Button variant="contained" ref={eleRef} className={classes.colorBtn} style={btnStyles} disabled={pickrOptions.disabled}>
// {(_.isUndefined(value) || _.isNull(value) || value === '') && <CloseIcon />}
// </Button>
<PgIconButton ref={eleRef} title={gettext('Select the color')} className={classes.colorBtn} style={btnStyles} disabled={pickrOptions.disabled} <PgIconButton ref={eleRef} title={gettext('Select the color')} className={classes.colorBtn} style={btnStyles} disabled={pickrOptions.disabled}
icon={(_.isUndefined(value) || _.isNull(value) || value === '') && <CloseIcon />} icon={(_.isUndefined(value) || _.isNull(value) || value === '') && <CloseIcon />}
/> />