mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-02-25 18:55:31 -06:00
- Add feature to allow collection header form using CustomControl. - Framework stability and bug fixes.
This commit is contained in:
parent
08f2121544
commit
9bfef1f6e5
@ -78,6 +78,8 @@ const useStyles = makeStyles((theme)=>({
|
|||||||
...theme.mixins.panelBorder.bottom,
|
...theme.mixins.panelBorder.bottom,
|
||||||
...theme.mixins.panelBorder.right,
|
...theme.mixins.panelBorder.right,
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
|
overflow: 'hidden',
|
||||||
|
textOverflow: 'ellipsis',
|
||||||
},
|
},
|
||||||
tableCellHeader: {
|
tableCellHeader: {
|
||||||
fontWeight: theme.typography.fontWeightBold,
|
fontWeight: theme.typography.fontWeightBold,
|
||||||
@ -159,6 +161,20 @@ function DataTableRow({row, totalRows, isResizing, schema, schemaRef, accessPath
|
|||||||
let retVal = [];
|
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)=>{
|
||||||
|
(evalFunc(null, field.deps) || []).forEach((dep)=>{
|
||||||
|
let source = accessPath.concat(dep);
|
||||||
|
if(_.isArray(dep)) {
|
||||||
|
source = dep;
|
||||||
|
/* If its an array, then dep is from the top schema and external */
|
||||||
|
retVal.push(source);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return retVal;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(()=>{
|
||||||
schema.fields.forEach((field)=>{
|
schema.fields.forEach((field)=>{
|
||||||
/* Self change is also dep change */
|
/* Self change is also dep change */
|
||||||
if(field.depChange) {
|
if(field.depChange) {
|
||||||
@ -168,13 +184,14 @@ 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;
|
||||||
/* 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;
|
return ()=>{
|
||||||
|
/* Cleanup the listeners when unmounting */
|
||||||
|
depListener.removeDepListener(accessPath);
|
||||||
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
/* External deps values are from top schema sess data */
|
/* External deps values are from top schema sess data */
|
||||||
@ -201,12 +218,28 @@ function DataTableRow({row, totalRows, isResizing, schema, schemaRef, accessPath
|
|||||||
</div>, depsMap);
|
</div>, depsMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function DataGridHeader({label, canAdd, onAddClick}) {
|
||||||
|
const classes = useStyles();
|
||||||
|
return (
|
||||||
|
<Box className={classes.gridHeader}>
|
||||||
|
<Box className={classes.gridHeaderText}>{label}</Box>
|
||||||
|
<Box className={classes.gridControls}>
|
||||||
|
{canAdd && <PgIconButton data-test="add-row" title={gettext('Add row')} onClick={onAddClick} icon={<AddIcon />} className={classes.gridControlsButton} />}
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
DataGridHeader.propTypes = {
|
||||||
|
label: PropTypes.string,
|
||||||
|
canAdd: PropTypes.bool,
|
||||||
|
onAddClick: PropTypes.func,
|
||||||
|
};
|
||||||
|
|
||||||
export default function DataGridView({
|
export default function DataGridView({
|
||||||
value, viewHelperProps, formErr, schema, accessPath, dataDispatch, containerClassName,
|
value, viewHelperProps, formErr, schema, accessPath, dataDispatch, containerClassName,
|
||||||
fixedRows, ...props}) {
|
fixedRows, ...props}) {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const stateUtils = useContext(StateUtilsContext);
|
const stateUtils = useContext(StateUtilsContext);
|
||||||
const depListener = useContext(DepListenerContext);
|
|
||||||
|
|
||||||
/* Using ref so that schema variable is not frozen in columns closure */
|
/* Using ref so that schema variable is not frozen in columns closure */
|
||||||
const schemaRef = useRef(schema);
|
const schemaRef = useRef(schema);
|
||||||
@ -268,7 +301,6 @@ export default function DataGridView({
|
|||||||
value: row.index,
|
value: row.index,
|
||||||
});
|
});
|
||||||
|
|
||||||
depListener.removeDepListener(accessPath.concat(row.index));
|
|
||||||
}, ()=>{}, props.customDeleteTitle, props.customDeleteMsg);
|
}, ()=>{}, props.customDeleteTitle, props.customDeleteMsg);
|
||||||
}} className={classes.gridRowButton} disabled={!canDeleteRow} />
|
}} className={classes.gridRowButton} disabled={!canDeleteRow} />
|
||||||
);
|
);
|
||||||
@ -349,22 +381,30 @@ export default function DataGridView({
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
return cols;
|
return cols;
|
||||||
},[]
|
},[props.canEdit, props.canDelete]
|
||||||
);
|
);
|
||||||
|
|
||||||
const onAddClick = useCallback(()=>{
|
const onAddClick = useCallback(()=>{
|
||||||
|
if(props.canAddRow) {
|
||||||
|
let state = schemaRef.current.top ? schemaRef.current.top.sessData : schemaRef.current.sessData;
|
||||||
|
let canAddRow = evalFunc(schemaRef.current, props.canAddRow, state || {});
|
||||||
|
if(!canAddRow) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let newRow = schemaRef.current.getNewData();
|
let newRow = schemaRef.current.getNewData();
|
||||||
dataDispatch({
|
dataDispatch({
|
||||||
type: SCHEMA_STATE_ACTIONS.ADD_ROW,
|
type: SCHEMA_STATE_ACTIONS.ADD_ROW,
|
||||||
path: accessPath,
|
path: accessPath,
|
||||||
value: newRow,
|
value: newRow,
|
||||||
});
|
});
|
||||||
});
|
}, []);
|
||||||
|
|
||||||
const defaultColumn = useMemo(()=>({
|
const defaultColumn = useMemo(()=>({
|
||||||
minWidth: 175,
|
minWidth: 175,
|
||||||
width: 0,
|
width: 0,
|
||||||
}));
|
}), []);
|
||||||
|
|
||||||
let tablePlugins = [
|
let tablePlugins = [
|
||||||
useBlockLayout,
|
useBlockLayout,
|
||||||
@ -393,6 +433,8 @@ export default function DataGridView({
|
|||||||
|
|
||||||
useEffect(()=>{
|
useEffect(()=>{
|
||||||
let rowsPromise = fixedRows, umounted=false;
|
let rowsPromise = fixedRows, umounted=false;
|
||||||
|
|
||||||
|
/* If fixedRows is defined, fetch the details */
|
||||||
if(typeof rowsPromise === 'function') {
|
if(typeof rowsPromise === 'function') {
|
||||||
rowsPromise = rowsPromise();
|
rowsPromise = rowsPromise();
|
||||||
}
|
}
|
||||||
@ -417,12 +459,7 @@ export default function DataGridView({
|
|||||||
return (
|
return (
|
||||||
<Box className={containerClassName}>
|
<Box className={containerClassName}>
|
||||||
<Box className={classes.grid}>
|
<Box className={classes.grid}>
|
||||||
{(props.label || props.canAdd) && <Box className={classes.gridHeader}>
|
{(props.label || props.canAdd) && <DataGridHeader label={props.label} canAdd={props.canAdd} onAddClick={onAddClick} />}
|
||||||
<Box className={classes.gridHeaderText}>{props.label}</Box>
|
|
||||||
<Box className={classes.gridControls}>
|
|
||||||
{props.canAdd && <PgIconButton data-test="add-row" title={gettext('Add row')} onClick={onAddClick} icon={<AddIcon />} className={classes.gridControlsButton} />}
|
|
||||||
</Box>
|
|
||||||
</Box>}
|
|
||||||
<div {...getTableProps()} className={classes.table}>
|
<div {...getTableProps()} className={classes.table}>
|
||||||
<DataTableHeader headerGroups={headerGroups} />
|
<DataTableHeader headerGroups={headerGroups} />
|
||||||
<div {...getTableBodyProps()}>
|
<div {...getTableBodyProps()}>
|
||||||
@ -460,6 +497,9 @@ DataGridView.propTypes = {
|
|||||||
canAdd: PropTypes.bool,
|
canAdd: PropTypes.bool,
|
||||||
canDelete: PropTypes.bool,
|
canDelete: PropTypes.bool,
|
||||||
visible: PropTypes.bool,
|
visible: PropTypes.bool,
|
||||||
|
canAddRow: PropTypes.oneOfType([
|
||||||
|
PropTypes.bool, PropTypes.func,
|
||||||
|
]),
|
||||||
canEditRow: PropTypes.oneOfType([
|
canEditRow: PropTypes.oneOfType([
|
||||||
PropTypes.bool, PropTypes.func,
|
PropTypes.bool, PropTypes.func,
|
||||||
]),
|
]),
|
||||||
|
@ -25,7 +25,7 @@ export default function FieldSetView({
|
|||||||
|
|
||||||
useEffect(()=>{
|
useEffect(()=>{
|
||||||
/* Calculate the fields which depends on the current field */
|
/* Calculate the fields which depends on the current field */
|
||||||
if(!isDataGridForm) {
|
if(!isDataGridForm && depListener) {
|
||||||
schema.fields.forEach((field)=>{
|
schema.fields.forEach((field)=>{
|
||||||
/* Self change is also dep change */
|
/* Self change is also dep change */
|
||||||
if(field.depChange || field.deferredDepChange) {
|
if(field.depChange || field.deferredDepChange) {
|
||||||
|
@ -122,7 +122,7 @@ export function getFieldMetaData(field, schema, value, viewHelperProps) {
|
|||||||
/* The first component of schema view form */
|
/* The first component of schema view form */
|
||||||
export default function FormView({
|
export default function FormView({
|
||||||
value, formErr, schema={}, viewHelperProps, isNested=false, accessPath, dataDispatch, hasSQLTab,
|
value, formErr, schema={}, viewHelperProps, isNested=false, accessPath, dataDispatch, hasSQLTab,
|
||||||
getSQLValue, onTabChange, firstEleRef, className, isDataGridForm=false, visible}) {
|
getSQLValue, onTabChange, firstEleRef, className, isDataGridForm=false, isTabView=true, visible}) {
|
||||||
let defaultTab = 'General';
|
let defaultTab = 'General';
|
||||||
let tabs = {};
|
let tabs = {};
|
||||||
let tabsClassname = {};
|
let tabsClassname = {};
|
||||||
@ -164,6 +164,10 @@ export default function FormView({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
return ()=>{
|
||||||
|
/* Cleanup the listeners when unmounting */
|
||||||
|
depListener.removeDepListener(accessPath);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@ -175,7 +179,7 @@ export default function FormView({
|
|||||||
getFieldMetaData(field, schema, value, viewHelperProps);
|
getFieldMetaData(field, schema, value, viewHelperProps);
|
||||||
|
|
||||||
if(modeSupported) {
|
if(modeSupported) {
|
||||||
let {group} = field;
|
let {group, CustomControl} = field;
|
||||||
group = groupLabels[group] || group || defaultTab;
|
group = groupLabels[group] || group || defaultTab;
|
||||||
|
|
||||||
if(!tabs[group]) tabs[group] = [];
|
if(!tabs[group]) tabs[group] = [];
|
||||||
@ -223,11 +227,18 @@ export default function FormView({
|
|||||||
canDelete = false;
|
canDelete = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
tabs[group].push(
|
const props = {
|
||||||
<DataGridView key={field.id} value={value[field.id]} viewHelperProps={viewHelperProps} formErr={formErr}
|
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,
|
||||||
{...field} canAdd={canAdd} canEdit={canEdit} canDelete={canDelete} visible={visible}/>
|
containerClassName: classes.controlRow, ...field, canAdd: canAdd, canEdit: canEdit, canDelete: canDelete,
|
||||||
);
|
visible: visible,
|
||||||
|
};
|
||||||
|
|
||||||
|
if(CustomControl) {
|
||||||
|
tabs[group].push(<CustomControl {...props}/>);
|
||||||
|
} else {
|
||||||
|
tabs[group].push(<DataGridView {...props}/>);
|
||||||
|
}
|
||||||
} else if(field.type === 'group') {
|
} else if(field.type === 'group') {
|
||||||
groupLabels[field.id] = field.label;
|
groupLabels[field.id] = field.label;
|
||||||
if(!visible) {
|
if(!visible) {
|
||||||
@ -311,6 +322,7 @@ export default function FormView({
|
|||||||
return <></>;
|
return <></>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(isTabView) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Box height="100%" display="flex" flexDirection="column" className={className} ref={formRef}>
|
<Box height="100%" display="flex" flexDirection="column" className={className} ref={formRef}>
|
||||||
@ -340,6 +352,18 @@ export default function FormView({
|
|||||||
})}
|
})}
|
||||||
</Box>
|
</Box>
|
||||||
</>);
|
</>);
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Box height="100%" display="flex" flexDirection="column" className={className} ref={formRef}>
|
||||||
|
{Object.keys(tabs).map((tabName)=>{
|
||||||
|
return (
|
||||||
|
<>{tabs[tabName]}</>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Box>
|
||||||
|
</>);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FormView.propTypes = {
|
FormView.propTypes = {
|
||||||
|
@ -126,4 +126,9 @@ export default class BaseUISchema {
|
|||||||
});
|
});
|
||||||
return newRow;
|
return newRow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Used in header schema */
|
||||||
|
addDisabled() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ import { minMaxValidator, numberValidator, integerValidator, emptyValidator, che
|
|||||||
import { MappedFormControl } from './MappedControl';
|
import { MappedFormControl } from './MappedControl';
|
||||||
import gettext from 'sources/gettext';
|
import gettext from 'sources/gettext';
|
||||||
import BaseUISchema from 'sources/SchemaView/base_schema.ui';
|
import BaseUISchema from 'sources/SchemaView/base_schema.ui';
|
||||||
import FormView from './FormView';
|
import FormView, { getFieldMetaData } from './FormView';
|
||||||
import { pgAlertify } from '../helpers/legacyConnector';
|
import { pgAlertify } from '../helpers/legacyConnector';
|
||||||
import { evalFunc } from 'sources/utils';
|
import { evalFunc } from 'sources/utils';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
@ -113,9 +113,9 @@ const diffArrayOptions = {
|
|||||||
compareFunction: objectComparator,
|
compareFunction: objectComparator,
|
||||||
};
|
};
|
||||||
|
|
||||||
function getChangedData(topSchema, mode, sessData, stringify=false) {
|
function getChangedData(topSchema, viewHelperProps, sessData, stringify=false) {
|
||||||
let changedData = {};
|
let changedData = {};
|
||||||
let isEdit = mode === 'edit';
|
let isEdit = viewHelperProps.mode === 'edit';
|
||||||
|
|
||||||
/* The comparator and setter */
|
/* The comparator and setter */
|
||||||
const attrChanged = (currPath, change, force=false)=>{
|
const attrChanged = (currPath, change, force=false)=>{
|
||||||
@ -136,6 +136,10 @@ function getChangedData(topSchema, mode, sessData, stringify=false) {
|
|||||||
/* Will be called recursively as data can be nested */
|
/* Will be called recursively as data can be nested */
|
||||||
const parseChanges = (schema, accessPath, changedData)=>{
|
const parseChanges = (schema, accessPath, changedData)=>{
|
||||||
schema.fields.forEach((field)=>{
|
schema.fields.forEach((field)=>{
|
||||||
|
let {modeSupported} = getFieldMetaData(field, schema, {}, viewHelperProps);
|
||||||
|
if(!modeSupported) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if(typeof(field.type) == 'string' && field.type.startsWith('nested-')) {
|
if(typeof(field.type) == 'string' && field.type.startsWith('nested-')) {
|
||||||
/* its nested */
|
/* its nested */
|
||||||
parseChanges(field.schema, accessPath, changedData);
|
parseChanges(field.schema, accessPath, changedData);
|
||||||
@ -324,7 +328,6 @@ const sessDataReducer = (state, action)=>{
|
|||||||
/* If there is any dep listeners get the changes */
|
/* If there is any dep listeners get the changes */
|
||||||
data = getDepChange(action.path, data, state, action);
|
data = getDepChange(action.path, data, state, action);
|
||||||
deferredList = getDeferredDepChange(action.path, data, state, action);
|
deferredList = getDeferredDepChange(action.path, data, state, action);
|
||||||
// let deferredInfo = getDeferredDepChange(action.path, data, state, action);
|
|
||||||
data.__deferred__ = deferredList || [];
|
data.__deferred__ = deferredList || [];
|
||||||
break;
|
break;
|
||||||
case SCHEMA_STATE_ACTIONS.ADD_ROW:
|
case SCHEMA_STATE_ACTIONS.ADD_ROW:
|
||||||
@ -387,7 +390,7 @@ function prepareData(val) {
|
|||||||
|
|
||||||
/* If its the dialog */
|
/* If its the dialog */
|
||||||
function SchemaDialogView({
|
function SchemaDialogView({
|
||||||
getInitData, viewHelperProps, schema={}, ...props}) {
|
getInitData, viewHelperProps, schema={}, showFooter=true, isTabView=true, ...props}) {
|
||||||
const classes = useDialogStyles();
|
const classes = useDialogStyles();
|
||||||
/* Some useful states */
|
/* Some useful states */
|
||||||
const [dirty, setDirty] = useState(false);
|
const [dirty, setDirty] = useState(false);
|
||||||
@ -421,11 +424,12 @@ function SchemaDialogView({
|
|||||||
if(!isNotValid) setFormErr({});
|
if(!isNotValid) setFormErr({});
|
||||||
|
|
||||||
/* check if anything changed */
|
/* check if anything changed */
|
||||||
let dataChanged = Object.keys(getChangedData(schema, viewHelperProps.mode, sessData)).length > 0;
|
let changedData = getChangedData(schema, viewHelperProps, sessData);
|
||||||
setDirty(dataChanged);
|
let isDataChanged = Object.keys(changedData).length > 0;
|
||||||
|
setDirty(isDataChanged);
|
||||||
|
|
||||||
/* tell the callbacks the data has changed */
|
/* tell the callbacks the data has changed */
|
||||||
props.onDataChange && props.onDataChange(dataChanged);
|
props.onDataChange && props.onDataChange(isDataChanged, changedData);
|
||||||
}, [sessData]);
|
}, [sessData]);
|
||||||
|
|
||||||
useEffect(()=>{
|
useEffect(()=>{
|
||||||
@ -518,7 +522,7 @@ function SchemaDialogView({
|
|||||||
setSaving(true);
|
setSaving(true);
|
||||||
setLoaderText('Saving...');
|
setLoaderText('Saving...');
|
||||||
/* Get the changed data */
|
/* Get the changed data */
|
||||||
let changeData = getChangedData(schema, viewHelperProps.mode, sessData);
|
let changeData = getChangedData(schema, viewHelperProps, sessData);
|
||||||
|
|
||||||
/* Add the id when in edit mode */
|
/* Add the id when in edit mode */
|
||||||
if(viewHelperProps.mode !== 'edit') {
|
if(viewHelperProps.mode !== 'edit') {
|
||||||
@ -577,7 +581,7 @@ function SchemaDialogView({
|
|||||||
/* Called when SQL tab is active */
|
/* Called when SQL tab is active */
|
||||||
if(dirty) {
|
if(dirty) {
|
||||||
if(!formErr.name) {
|
if(!formErr.name) {
|
||||||
let changeData = getChangedData(schema, viewHelperProps.mode, sessData);
|
let changeData = getChangedData(schema, viewHelperProps, sessData);
|
||||||
if(viewHelperProps.mode !== 'edit') {
|
if(viewHelperProps.mode !== 'edit') {
|
||||||
/* If new then merge the changed data with origData */
|
/* If new then merge the changed data with origData */
|
||||||
changeData = _.assign({}, schema.origData, changeData);
|
changeData = _.assign({}, schema.origData, changeData);
|
||||||
@ -626,11 +630,11 @@ function SchemaDialogView({
|
|||||||
<Loader message={loaderText}/>
|
<Loader message={loaderText}/>
|
||||||
<FormView value={sessData} viewHelperProps={viewHelperProps} formErr={formErr}
|
<FormView value={sessData} viewHelperProps={viewHelperProps} formErr={formErr}
|
||||||
schema={schema} accessPath={[]} dataDispatch={sessDispatchWithListener}
|
schema={schema} accessPath={[]} dataDispatch={sessDispatchWithListener}
|
||||||
hasSQLTab={props.hasSQL} getSQLValue={getSQLValue} firstEleRef={firstEleRef} />
|
hasSQLTab={props.hasSQL} getSQLValue={getSQLValue} firstEleRef={firstEleRef} isTabView={isTabView} />
|
||||||
<FormFooterMessage type={MESSAGE_TYPE.ERROR} message={formErr.message}
|
<FormFooterMessage type={MESSAGE_TYPE.ERROR} message={formErr.message}
|
||||||
onClose={onErrClose} />
|
onClose={onErrClose} />
|
||||||
</Box>
|
</Box>
|
||||||
<Box className={classes.footer}>
|
{showFooter && <Box className={classes.footer}>
|
||||||
{useMemo(()=><Box>
|
{useMemo(()=><Box>
|
||||||
<PgIconButton data-test="sql-help" onClick={()=>props.onHelp(true, isNew)} icon={<InfoIcon />}
|
<PgIconButton data-test="sql-help" onClick={()=>props.onHelp(true, isNew)} icon={<InfoIcon />}
|
||||||
disabled={props.disableSqlHelp} className={classes.buttonMargin} title="SQL help for this object type."/>
|
disabled={props.disableSqlHelp} className={classes.buttonMargin} title="SQL help for this object type."/>
|
||||||
@ -648,7 +652,7 @@ function SchemaDialogView({
|
|||||||
{gettext('Save')}
|
{gettext('Save')}
|
||||||
</PrimaryButton>
|
</PrimaryButton>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>}
|
||||||
</Box>
|
</Box>
|
||||||
</DepListenerContext.Provider>
|
</DepListenerContext.Provider>
|
||||||
</StateUtilsContext.Provider>
|
</StateUtilsContext.Provider>
|
||||||
@ -671,10 +675,12 @@ SchemaDialogView.propTypes = {
|
|||||||
onHelp: PropTypes.func,
|
onHelp: PropTypes.func,
|
||||||
onDataChange: PropTypes.func,
|
onDataChange: PropTypes.func,
|
||||||
confirmOnCloseReset: PropTypes.bool,
|
confirmOnCloseReset: PropTypes.bool,
|
||||||
|
isTabView: PropTypes.bool,
|
||||||
hasSQL: PropTypes.bool,
|
hasSQL: PropTypes.bool,
|
||||||
getSQLValue: PropTypes.func,
|
getSQLValue: PropTypes.func,
|
||||||
disableSqlHelp: PropTypes.bool,
|
disableSqlHelp: PropTypes.bool,
|
||||||
disableDialogHelp: PropTypes.bool,
|
disableDialogHelp: PropTypes.bool,
|
||||||
|
showFooter: PropTypes.bool,
|
||||||
};
|
};
|
||||||
|
|
||||||
const usePropsStyles = makeStyles((theme)=>({
|
const usePropsStyles = makeStyles((theme)=>({
|
||||||
|
92
web/pgadmin/static/js/helpers/DataGridViewWithHeaderForm.jsx
Normal file
92
web/pgadmin/static/js/helpers/DataGridViewWithHeaderForm.jsx
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||||
|
import { Box, makeStyles } from '@material-ui/core';
|
||||||
|
import DataGridView, { DataGridHeader } from '../SchemaView/DataGridView';
|
||||||
|
import SchemaView, { SCHEMA_STATE_ACTIONS } from '../SchemaView';
|
||||||
|
import { DefaultButton } from '../components/Buttons';
|
||||||
|
import { evalFunc } from '../utils';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import CustomPropTypes from '../custom_prop_types';
|
||||||
|
|
||||||
|
const useStyles = makeStyles((theme)=>({
|
||||||
|
formBorder: {
|
||||||
|
...theme.mixins.panelBorder,
|
||||||
|
borderBottom: 0,
|
||||||
|
},
|
||||||
|
form: {
|
||||||
|
padding: '0.25rem',
|
||||||
|
},
|
||||||
|
addBtn: {
|
||||||
|
marginLeft: 'auto',
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
export default function DataGridViewWithHeaderForm(props) {
|
||||||
|
let {containerClassName, headerSchema, headerVisible, ...otherProps} = props;
|
||||||
|
const classes = useStyles();
|
||||||
|
const headerFormData = useRef({});
|
||||||
|
const schemaRef = useRef(otherProps.schema);
|
||||||
|
const [isAddDisabled, setAddDisabled] = useState(true);
|
||||||
|
|
||||||
|
const onAddClick = useCallback(()=>{
|
||||||
|
if(otherProps.canAddRow) {
|
||||||
|
let state = schemaRef.current.top ? schemaRef.current.top.sessData : schemaRef.current.sessData;
|
||||||
|
let canAddRow = evalFunc(schemaRef.current, otherProps.canAddRow, state || {});
|
||||||
|
if(!canAddRow) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let newRow = headerSchema.getNewData(headerFormData.current);
|
||||||
|
otherProps.dataDispatch({
|
||||||
|
type: SCHEMA_STATE_ACTIONS.ADD_ROW,
|
||||||
|
path: otherProps.accessPath,
|
||||||
|
value: newRow,
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(()=>{
|
||||||
|
headerSchema.top = schemaRef.current.top;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
let state = schemaRef.current.top ? schemaRef.current.top.origData : schemaRef.current.origData;
|
||||||
|
headerVisible = headerVisible && evalFunc(null, headerVisible, state);
|
||||||
|
return (
|
||||||
|
<Box className={containerClassName}>
|
||||||
|
<Box className={classes.formBorder}>
|
||||||
|
<DataGridHeader label={props.label} />
|
||||||
|
{headerVisible && <Box className={classes.form}>
|
||||||
|
<SchemaView
|
||||||
|
formType={'dialog'}
|
||||||
|
getInitData={()=>Promise.resolve({})}
|
||||||
|
schema={headerSchema}
|
||||||
|
viewHelperProps={props.viewHelperProps}
|
||||||
|
showFooter={false}
|
||||||
|
onDataChange={(isDataChanged, dataChanged)=>{
|
||||||
|
headerFormData.current = dataChanged;
|
||||||
|
setAddDisabled(headerSchema.addDisabled(headerFormData.current));
|
||||||
|
}}
|
||||||
|
hasSQL={false}
|
||||||
|
isTabView={false}
|
||||||
|
/>
|
||||||
|
<Box display="flex">
|
||||||
|
<DefaultButton className={classes.addBtn} onClick={onAddClick} disabled={isAddDisabled}>Add</DefaultButton>
|
||||||
|
</Box>
|
||||||
|
</Box>}
|
||||||
|
</Box>
|
||||||
|
<DataGridView {...otherProps} canAdd={false}/>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
DataGridViewWithHeaderForm.propTypes = {
|
||||||
|
label: PropTypes.string,
|
||||||
|
value: PropTypes.array,
|
||||||
|
viewHelperProps: PropTypes.object,
|
||||||
|
formErr: PropTypes.object,
|
||||||
|
headerSchema: CustomPropTypes.schemaUI.isRequired,
|
||||||
|
headerVisible: PropTypes.func,
|
||||||
|
schema: CustomPropTypes.schemaUI,
|
||||||
|
accessPath: PropTypes.array.isRequired,
|
||||||
|
dataDispatch: PropTypes.func.isRequired,
|
||||||
|
containerClassName: PropTypes.oneOfType([PropTypes.object, PropTypes.string]),
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user