mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-02-25 18:55:31 -06:00
1. Unable to change shared server switch. 2. DB restriction and schema restriction have an empty option. 3. File select input control does not allow manual text input. 4. In the Parameters tab if the value is a switch control, then an empty value error should not come. 5. Values for parameters should be reset on changing parameters. 6. Added a new key - helpMessageMode which can have a value similar to mode. It will show the help message if the mode is supported. Fixes #6814
211 lines
7.8 KiB
JavaScript
211 lines
7.8 KiB
JavaScript
/////////////////////////////////////////////////////////////
|
|
//
|
|
// pgAdmin 4 - PostgreSQL Tools
|
|
//
|
|
// Copyright (C) 2013 - 2021, The pgAdmin Development Team
|
|
// This software is released under the PostgreSQL Licence
|
|
//
|
|
//////////////////////////////////////////////////////////////
|
|
|
|
import React, { useCallback } from 'react';
|
|
import _ from 'lodash';
|
|
|
|
import { FormInputText, FormInputSelect, FormInputSwitch, FormInputCheckbox, FormInputColor,
|
|
FormInputFileSelect, FormInputToggle, InputSwitch, FormInputSQL, FormNote, FormInputDateTimePicker, PlainString } from '../components/FormComponents';
|
|
import { InputSelect, InputText, InputCheckbox, InputDateTimePicker } from '../components/FormComponents';
|
|
import Privilege from '../components/Privilege';
|
|
import { evalFunc } from 'sources/utils';
|
|
import PropTypes from 'prop-types';
|
|
import CustomPropTypes from '../custom_prop_types';
|
|
import { SelectRefresh} from '../components/SelectRefresh';
|
|
|
|
/* Control mapping for form view */
|
|
function MappedFormControlBase({type, value, id, onChange, className, visible, inputRef, noLabel, ...props}) {
|
|
const name = id;
|
|
const onTextChange = useCallback((e) => {
|
|
let value = e;
|
|
if(e && e.target) {
|
|
value = e.target.value;
|
|
}
|
|
onChange && onChange(value);
|
|
}, []);
|
|
|
|
const onSqlChange = useCallback((value) => {
|
|
onChange && onChange(value);
|
|
}, []);
|
|
|
|
if(!visible) {
|
|
return <></>;
|
|
}
|
|
|
|
/* The mapping uses Form* components as it comes with labels */
|
|
switch (type) {
|
|
case 'int':
|
|
return <FormInputText name={name} value={value} onChange={onTextChange} className={className} inputRef={inputRef} {...props} type='int'/>;
|
|
case 'numeric':
|
|
return <FormInputText name={name} value={value} onChange={onTextChange} className={className} inputRef={inputRef} {...props} type='numeric'/>;
|
|
case 'text':
|
|
return <FormInputText name={name} value={value} onChange={onTextChange} className={className} inputRef={inputRef} {...props}/>;
|
|
case 'multiline':
|
|
return <FormInputText name={name} value={value} onChange={onTextChange} className={className}
|
|
inputRef={inputRef} controlProps={{multiline: true}} {...props}/>;
|
|
case 'password':
|
|
return <FormInputText name={name} value={value} onChange={onTextChange} className={className} type='password' inputRef={inputRef} {...props}/>;
|
|
case 'select':
|
|
return <FormInputSelect name={name} value={value} onChange={onTextChange} className={className} inputRef={inputRef} {...props} />;
|
|
case 'select-refresh':
|
|
return <SelectRefresh name={name} value={value} onChange={onTextChange} className={className} {...props} />;
|
|
case 'switch':
|
|
return <FormInputSwitch name={name} value={value}
|
|
onChange={(e)=>onTextChange(e.target.checked, e.target.name)} className={className}
|
|
{...props} />;
|
|
case 'checkbox':
|
|
return <FormInputCheckbox name={name} value={value}
|
|
onChange={(e)=>onTextChange(e.target.checked, e.target.name)} className={className}
|
|
{...props} />;
|
|
case 'toggle':
|
|
return <FormInputToggle name={name} value={value}
|
|
onChange={onTextChange} className={className}
|
|
{...props} />;
|
|
case 'color':
|
|
return <FormInputColor name={name} value={value} onChange={onTextChange} className={className} {...props} />;
|
|
case 'file':
|
|
return <FormInputFileSelect name={name} value={value} onChange={onTextChange} className={className} {...props} />;
|
|
case 'sql':
|
|
return <FormInputSQL name={name} value={value} onChange={onSqlChange} className={className} noLabel={noLabel} {...props} />;
|
|
case 'note':
|
|
return <FormNote className={className} {...props}/>;
|
|
case 'datetimepicker':
|
|
return <FormInputDateTimePicker name={name} value={value} onChange={onTextChange} className={className} {...props} />;
|
|
default:
|
|
return <PlainString value={value} {...props} />;
|
|
}
|
|
}
|
|
|
|
MappedFormControlBase.propTypes = {
|
|
type: PropTypes.oneOfType([
|
|
PropTypes.string, PropTypes.func,
|
|
]).isRequired,
|
|
value: PropTypes.any,
|
|
id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
|
|
onChange: PropTypes.func,
|
|
className: PropTypes.oneOfType([
|
|
PropTypes.string, PropTypes.object,
|
|
]),
|
|
visible: PropTypes.bool,
|
|
inputRef: CustomPropTypes.ref,
|
|
noLabel: PropTypes.bool
|
|
};
|
|
|
|
/* Control mapping for grid cell view */
|
|
function MappedCellControlBase({cell, value, id, optionsLoaded, onCellChange, visible, reRenderRow,...props}) {
|
|
const name = id;
|
|
const onTextChange = useCallback((e) => {
|
|
let value = e;
|
|
if(e && e.target) {
|
|
value = e.target.value;
|
|
}
|
|
|
|
onCellChange && onCellChange(value);
|
|
}, []);
|
|
|
|
/* Some grid cells are based on options selected in other cells.
|
|
* lets trigger a re-render for the row if optionsLoaded
|
|
*/
|
|
const optionsLoadedRerender = useCallback((res)=>{
|
|
/* optionsLoaded is called when select options are fetched */
|
|
optionsLoaded && optionsLoaded(res);
|
|
reRenderRow && reRenderRow();
|
|
}, []);
|
|
|
|
if(!visible) {
|
|
return <></>;
|
|
}
|
|
|
|
/* The mapping does not need Form* components as labels are not needed for grid cells */
|
|
switch(cell) {
|
|
case 'int':
|
|
return <InputText name={name} value={value} onChange={onTextChange} {...props} type='int'/>;
|
|
case 'numeric':
|
|
return <InputText name={name} value={value} onChange={onTextChange} {...props} type='numeric'/>;
|
|
case 'text':
|
|
return <InputText name={name} value={value} onChange={onTextChange} {...props}/>;
|
|
case 'password':
|
|
return <InputText name={name} value={value} onChange={onTextChange} {...props}/>;
|
|
case 'select':
|
|
return <InputSelect name={name} value={value} onChange={onTextChange} optionsLoaded={optionsLoadedRerender} {...props}/>;
|
|
case 'switch':
|
|
return <InputSwitch name={name} value={value}
|
|
onChange={(e)=>onTextChange(e.target.checked, e.target.name)} {...props} />;
|
|
case 'checkbox':
|
|
return <InputCheckbox name={name} value={value}
|
|
onChange={(e)=>onTextChange(e.target.checked, e.target.name)} {...props} />;
|
|
case 'privilege':
|
|
return <Privilege name={name} value={value} onChange={onTextChange} {...props}/>;
|
|
case 'datetimepicker':
|
|
return <InputDateTimePicker name={name} value={value} onChange={onTextChange} {...props}/>;
|
|
default:
|
|
return <PlainString value={value} {...props} />;
|
|
}
|
|
}
|
|
|
|
MappedCellControlBase.propTypes = {
|
|
cell: PropTypes.oneOfType([
|
|
PropTypes.string, PropTypes.func,
|
|
]).isRequired,
|
|
value: PropTypes.any,
|
|
id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
|
|
onChange: PropTypes.func,
|
|
reRenderRow: PropTypes.func,
|
|
optionsLoaded: PropTypes.func,
|
|
onCellChange: PropTypes.func,
|
|
visible: PropTypes.bool
|
|
};
|
|
|
|
const ALLOWED_PROPS_FIELD_COMMON = [
|
|
'mode', 'value', 'readonly', 'disabled', 'hasError', 'id',
|
|
'label', 'options', 'optionsLoaded', 'controlProps', 'schema', 'inputRef',
|
|
'visible', 'autoFocus', 'helpMessage', 'className', 'optionsReloadBasis'
|
|
];
|
|
|
|
const ALLOWED_PROPS_FIELD_FORM = [
|
|
'type', 'onChange', 'state', 'noLabel', 'text',
|
|
];
|
|
|
|
const ALLOWED_PROPS_FIELD_CELL = [
|
|
'cell', 'onCellChange', 'row', 'reRenderRow',
|
|
];
|
|
|
|
|
|
export const MappedFormControl = (props)=>{
|
|
let newProps = {...props};
|
|
let typeProps = evalFunc(null, newProps.type, newProps.state);
|
|
if(typeof(typeProps) === 'object') {
|
|
newProps = {
|
|
...newProps,
|
|
...typeProps,
|
|
};
|
|
} else {
|
|
newProps.type = typeProps;
|
|
}
|
|
|
|
/* Filter out garbage props if any using ALLOWED_PROPS_FIELD */
|
|
return <MappedFormControlBase {..._.pick(newProps, _.union(ALLOWED_PROPS_FIELD_COMMON, ALLOWED_PROPS_FIELD_FORM))}/>;
|
|
};
|
|
|
|
export const MappedCellControl = (props)=>{
|
|
let newProps = {...props};
|
|
let cellProps = evalFunc(null, newProps.cell, newProps.row);
|
|
if(typeof(cellProps) === 'object') {
|
|
newProps = {
|
|
...newProps,
|
|
...cellProps,
|
|
};
|
|
} else {
|
|
newProps.cell = cellProps;
|
|
}
|
|
|
|
/* Filter out garbage props if any using ALLOWED_PROPS_FIELD */
|
|
return <MappedCellControlBase {..._.pick(newProps, _.union(ALLOWED_PROPS_FIELD_COMMON, ALLOWED_PROPS_FIELD_CELL))}/>;
|
|
};
|