mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-02-25 18:55:31 -06:00
Fixed following: - Dropdown selected menu color - CodeMirror render on properties tab - Placeholders on select control - Codemirror borders
This commit is contained in:
committed by
Akshay Joshi
parent
c35c72c551
commit
27e446a0b0
@@ -349,7 +349,7 @@ export default class ColumnSchema extends BaseUISchema {
|
|||||||
},{
|
},{
|
||||||
id: 'attstorage', label: gettext('Storage'), group: gettext('Definition'),
|
id: 'attstorage', label: gettext('Storage'), group: gettext('Definition'),
|
||||||
type: 'select', mode: ['properties', 'edit'],
|
type: 'select', mode: ['properties', 'edit'],
|
||||||
cell: 'select', disabled: obj.inSchemaWithColumnCheck, first_empty: true,
|
cell: 'select', disabled: obj.inSchemaWithColumnCheck,
|
||||||
controlProps: { placeholder: gettext('Select storage'),
|
controlProps: { placeholder: gettext('Select storage'),
|
||||||
allowClear: false,
|
allowClear: false,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ const useStyles = makeStyles((theme)=>({
|
|||||||
height: '100%'
|
height: '100%'
|
||||||
},
|
},
|
||||||
controlRow: {
|
controlRow: {
|
||||||
paddingBottom: theme.spacing(1),
|
marginBottom: theme.spacing(1),
|
||||||
},
|
},
|
||||||
nestedTabPanel: {
|
nestedTabPanel: {
|
||||||
backgroundColor: theme.otherVars.headerBg,
|
backgroundColor: theme.otherVars.headerBg,
|
||||||
@@ -62,7 +62,6 @@ function SQLTab({active, getSQLValue}) {
|
|||||||
options={{
|
options={{
|
||||||
readOnly: true,
|
readOnly: true,
|
||||||
}}
|
}}
|
||||||
isAsync={true}
|
|
||||||
readonly={true}
|
readonly={true}
|
||||||
/>;
|
/>;
|
||||||
}
|
}
|
||||||
@@ -314,7 +313,7 @@ export default function FormView({
|
|||||||
sqlTabActive = (Object.keys(tabs).length === tabValue);
|
sqlTabActive = (Object.keys(tabs).length === tabValue);
|
||||||
/* Re-render and fetch the SQL tab when it is active */
|
/* Re-render and fetch the SQL tab when it is active */
|
||||||
tabs[sqlTabName] = [
|
tabs[sqlTabName] = [
|
||||||
useMemo(()=><SQLTab key="sqltab" active={sqlTabActive} getSQLValue={getSQLValue} />, [sqlTabActive]),
|
useMemo(()=><SQLTab key="sqltab" active={sqlTabActive} getSQLValue={getSQLValue} />, [sqlTabActive, value]),
|
||||||
];
|
];
|
||||||
tabsClassname[sqlTabName] = classes.fullSpace;
|
tabsClassname[sqlTabName] = classes.fullSpace;
|
||||||
fullTabs.push(sqlTabName);
|
fullTabs.push(sqlTabName);
|
||||||
|
|||||||
@@ -30,8 +30,8 @@ function MappedFormControlBase({type, value, id, onChange, className, visible, i
|
|||||||
onChange && onChange(value);
|
onChange && onChange(value);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const onSqlChange = useCallback((e, cm) => {
|
const onSqlChange = useCallback((value) => {
|
||||||
onChange && onChange(cm.getValue());
|
onChange && onChange(value);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const onIntChange = useCallback((e) => {
|
const onIntChange = useCallback((e) => {
|
||||||
|
|||||||
@@ -711,7 +711,7 @@ const usePropsStyles = makeStyles((theme)=>({
|
|||||||
flexDirection: 'column'
|
flexDirection: 'column'
|
||||||
},
|
},
|
||||||
controlRow: {
|
controlRow: {
|
||||||
paddingBottom: theme.spacing(1),
|
marginBottom: theme.spacing(1),
|
||||||
},
|
},
|
||||||
form: {
|
form: {
|
||||||
padding: theme.spacing(1),
|
padding: theme.spacing(1),
|
||||||
@@ -726,6 +726,9 @@ const usePropsStyles = makeStyles((theme)=>({
|
|||||||
buttonMargin: {
|
buttonMargin: {
|
||||||
marginRight: '0.5rem',
|
marginRight: '0.5rem',
|
||||||
},
|
},
|
||||||
|
noPadding: {
|
||||||
|
padding: 0,
|
||||||
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
/* If its the properties tab */
|
/* If its the properties tab */
|
||||||
@@ -757,7 +760,7 @@ function SchemaPropertiesView({
|
|||||||
group = group || defaultTab;
|
group = group || defaultTab;
|
||||||
|
|
||||||
if(field.isFullTab) {
|
if(field.isFullTab) {
|
||||||
tabsClassname[group] = classes.fullSpace;
|
tabsClassname[group] = classes.noPadding;
|
||||||
fullTabs.push(group);
|
fullTabs.push(group);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -814,7 +817,7 @@ function SchemaPropertiesView({
|
|||||||
readonly={readonly}
|
readonly={readonly}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
visible={visible}
|
visible={visible}
|
||||||
className={classes.controlRow}
|
className={field.isFullTab ? null : classes.controlRow}
|
||||||
noLabel={field.isFullTab}
|
noLabel={field.isFullTab}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@@ -846,7 +849,7 @@ function SchemaPropertiesView({
|
|||||||
>
|
>
|
||||||
{tabName}
|
{tabName}
|
||||||
</AccordionSummary>
|
</AccordionSummary>
|
||||||
<AccordionDetails>
|
<AccordionDetails className={tabsClassname[tabName]}>
|
||||||
<Box style={{width: '100%'}}>
|
<Box style={{width: '100%'}}>
|
||||||
{finalTabs[tabName]}
|
{finalTabs[tabName]}
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -7,71 +7,64 @@
|
|||||||
//
|
//
|
||||||
//////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
import React, { useEffect, useRef } from 'react';
|
import React, { useEffect, useMemo, useRef } from 'react';
|
||||||
import {default as OrigCodeMirror} from 'bundled_codemirror';
|
import {default as OrigCodeMirror} from 'bundled_codemirror';
|
||||||
import {useOnScreen} from 'sources/custom_hooks';
|
import {useOnScreen} from 'sources/custom_hooks';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
import CustomPropTypes from '../custom_prop_types';
|
||||||
|
|
||||||
/* React wrapper for CodeMirror */
|
/* React wrapper for CodeMirror */
|
||||||
export default function CodeMirror({currObj, name, value, options, events, ...props}) {
|
export default function CodeMirror({currEditor, name, value, options, events, className}) {
|
||||||
const taRef = useRef();
|
const taRef = useRef();
|
||||||
const cmObj = useRef();
|
const editor = useRef();
|
||||||
const cmWrapper = useRef();
|
const cmWrapper = useRef();
|
||||||
const isVisibleTrack = useRef();
|
const isVisibleTrack = useRef();
|
||||||
|
|
||||||
useEffect(()=>{
|
useEffect(()=>{
|
||||||
/* Create the object only once on mount */
|
/* Create the object only once on mount */
|
||||||
cmObj.current = new OrigCodeMirror.fromTextArea(
|
editor.current = new OrigCodeMirror.fromTextArea(
|
||||||
taRef.current, options);
|
taRef.current, options);
|
||||||
|
|
||||||
currObj && currObj(cmObj.current);
|
editor.current.setValue(value);
|
||||||
|
currEditor && currEditor(editor.current);
|
||||||
if(cmObj.current) {
|
if(editor.current) {
|
||||||
try {
|
try {
|
||||||
cmWrapper.current = cmObj.current.getWrapperElement();
|
cmWrapper.current = editor.current.getWrapperElement();
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
cmWrapper.current = null;
|
cmWrapper.current = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.keys(events||{}).forEach((eventName)=>{
|
Object.keys(events||{}).forEach((eventName)=>{
|
||||||
cmObj.current.on(eventName, events[eventName]);
|
editor.current.on(eventName, events[eventName]);
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(()=>{
|
useMemo(() => {
|
||||||
/* Refresh when value changes async */
|
if(editor.current) {
|
||||||
if(props.isAsync) {
|
editor.current.setValue(value);
|
||||||
if(cmObj.current) {
|
|
||||||
cmObj.current.setValue(value);
|
|
||||||
cmObj.current.refresh();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}, [value]);
|
}, [value]);
|
||||||
|
|
||||||
const onScreenVisible = useOnScreen(cmWrapper);
|
const onScreenVisible = useOnScreen(cmWrapper);
|
||||||
if(!isVisibleTrack.current && onScreenVisible) {
|
if(!isVisibleTrack.current && onScreenVisible) {
|
||||||
isVisibleTrack.current = true;
|
isVisibleTrack.current = true;
|
||||||
|
editor.current?.refresh();
|
||||||
/* Refresh when value changes */
|
|
||||||
if(cmObj.current) {
|
|
||||||
cmObj.current.setValue(value);
|
|
||||||
cmObj.current.refresh();
|
|
||||||
}
|
|
||||||
cmObj.current.refresh();
|
|
||||||
} else if(!onScreenVisible) {
|
} else if(!onScreenVisible) {
|
||||||
isVisibleTrack.current = false;
|
isVisibleTrack.current = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return <textarea ref={taRef} name={name} />;
|
return (
|
||||||
|
<div className={className}><textarea ref={taRef} name={name} /></div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
CodeMirror.propTypes = {
|
CodeMirror.propTypes = {
|
||||||
currObj: PropTypes.func,
|
currEditor: PropTypes.func,
|
||||||
name: PropTypes.string,
|
name: PropTypes.string,
|
||||||
value: PropTypes.string,
|
value: PropTypes.string,
|
||||||
options: PropTypes.object,
|
options: PropTypes.object,
|
||||||
change: PropTypes.func,
|
change: PropTypes.func,
|
||||||
events: PropTypes.object,
|
events: PropTypes.object,
|
||||||
isAsync: PropTypes.bool
|
className: CustomPropTypes.className,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
//////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////
|
||||||
/* Common form components used in pgAdmin */
|
/* Common form components used in pgAdmin */
|
||||||
|
|
||||||
import React, { forwardRef, useCallback, useEffect, useRef, useState } from 'react';
|
import React, { forwardRef, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { makeStyles } from '@material-ui/core/styles';
|
import { makeStyles } from '@material-ui/core/styles';
|
||||||
import { Box, FormControl, OutlinedInput, FormHelperText,
|
import { Box, FormControl, OutlinedInput, FormHelperText,
|
||||||
Grid, IconButton, FormControlLabel, Switch, Checkbox, useTheme, InputLabel, Paper } from '@material-ui/core';
|
Grid, IconButton, FormControlLabel, Switch, Checkbox, useTheme, InputLabel, Paper } from '@material-ui/core';
|
||||||
@@ -59,7 +59,8 @@ const useStyles = makeStyles((theme) => ({
|
|||||||
color: theme.palette.error.main,
|
color: theme.palette.error.main,
|
||||||
},
|
},
|
||||||
sql: {
|
sql: {
|
||||||
height: '100%',
|
border: '1px solid ' + theme.otherVars.inputBorderColor,
|
||||||
|
borderRadius: theme.shape.borderRadius,
|
||||||
},
|
},
|
||||||
optionIcon: {
|
optionIcon: {
|
||||||
...theme.mixins.nodeIcon,
|
...theme.mixins.nodeIcon,
|
||||||
@@ -139,17 +140,17 @@ FormInput.propTypes = {
|
|||||||
|
|
||||||
export function InputSQL({value, options, onChange, readonly, ...props}) {
|
export function InputSQL({value, options, onChange, readonly, ...props}) {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const cmObj = useRef();
|
const editor = useRef();
|
||||||
|
|
||||||
useEffect(()=>{
|
useEffect(()=>{
|
||||||
if(cmObj.current) {
|
if(editor.current) {
|
||||||
cmObj.current.setOption('readOnly', readonly);
|
editor.current.setOption('readOnly', readonly);
|
||||||
}
|
}
|
||||||
}, [readonly]);
|
}, [readonly]);
|
||||||
|
|
||||||
return (
|
return useMemo(()=>(
|
||||||
<CodeMirror
|
<CodeMirror
|
||||||
currObj={(obj)=>cmObj.current=obj}
|
currEditor={(obj)=>editor.current=obj}
|
||||||
value={value||''}
|
value={value||''}
|
||||||
options={{
|
options={{
|
||||||
lineNumbers: true,
|
lineNumbers: true,
|
||||||
@@ -159,12 +160,12 @@ export function InputSQL({value, options, onChange, readonly, ...props}) {
|
|||||||
className={classes.sql}
|
className={classes.sql}
|
||||||
events={{
|
events={{
|
||||||
change: (cm)=>{
|
change: (cm)=>{
|
||||||
onChange && onChange(cm.getValue(), cm);
|
onChange && onChange(cm.getValue());
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
);
|
), [value]);
|
||||||
}
|
}
|
||||||
InputSQL.propTypes = {
|
InputSQL.propTypes = {
|
||||||
value: PropTypes.string,
|
value: PropTypes.string,
|
||||||
@@ -581,18 +582,23 @@ const customReactSelectStyles = (theme, readonly)=>({
|
|||||||
color: theme.palette.text.primary,
|
color: theme.palette.text.primary,
|
||||||
boxShadow: 'none',
|
boxShadow: 'none',
|
||||||
border: '1px solid ' + theme.otherVars.inputBorderColor,
|
border: '1px solid ' + theme.otherVars.inputBorderColor,
|
||||||
|
marginTop: '2px',
|
||||||
}),
|
}),
|
||||||
menuPortal: (provided)=>({
|
menuPortal: (provided)=>({
|
||||||
...provided, zIndex: 9999,
|
...provided, zIndex: 9999,
|
||||||
backgroundColor: 'inherit',
|
backgroundColor: 'inherit',
|
||||||
color: 'inherit',
|
color: 'inherit',
|
||||||
}),
|
}),
|
||||||
option: (provided, state)=>({
|
option: (provided, state)=>{
|
||||||
...provided,
|
return {
|
||||||
padding: '0.5rem',
|
...provided,
|
||||||
backgroundColor: state.isFocused ? theme.palette.grey[200] :
|
padding: '0.5rem',
|
||||||
(state.isSelected ? theme.palette.primary.main : 'inherit'),
|
color: 'inherit',
|
||||||
}),
|
backgroundColor: state.isFocused ?
|
||||||
|
theme.palette.grey[400] : (state.isSelected ?
|
||||||
|
theme.palette.primary.light : 'inherit'),
|
||||||
|
};
|
||||||
|
},
|
||||||
multiValue: (provided)=>({
|
multiValue: (provided)=>({
|
||||||
...provided,
|
...provided,
|
||||||
backgroundColor: theme.palette.grey[400],
|
backgroundColor: theme.palette.grey[400],
|
||||||
@@ -736,11 +742,12 @@ export function InputSelect({
|
|||||||
openMenuOnClick: !readonly,
|
openMenuOnClick: !readonly,
|
||||||
onChange: onChangeOption,
|
onChange: onChangeOption,
|
||||||
isLoading: isLoading,
|
isLoading: isLoading,
|
||||||
options: controlProps.allowSelectAll ? [{ label: 'Select All', value: '*' }, ...filteredOptions] : filteredOptions,
|
options: controlProps.allowSelectAll ? [{ label: gettext('Select All'), value: '*' }, ...filteredOptions] : filteredOptions,
|
||||||
value: realValue,
|
value: realValue,
|
||||||
menuPortalTarget: document.body,
|
menuPortalTarget: document.body,
|
||||||
styles: styles,
|
styles: styles,
|
||||||
inputId: cid,
|
inputId: cid,
|
||||||
|
placeholder: controlProps.placeholder || gettext('Select...'),
|
||||||
...otherProps,
|
...otherProps,
|
||||||
...props
|
...props
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ export function useOnScreen(ref) {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (ref.current) {
|
if(ref?.current) {
|
||||||
observer.observe(ref.current);
|
observer.observe(ref.current);
|
||||||
}
|
}
|
||||||
// Remove the observer as soon as the component is unmounted
|
// Remove the observer as soon as the component is unmounted
|
||||||
|
|||||||
@@ -19,14 +19,13 @@ describe('CodeMirror', ()=>{
|
|||||||
let cmInstance, options={
|
let cmInstance, options={
|
||||||
lineNumbers: true,
|
lineNumbers: true,
|
||||||
mode: 'text/x-pgsql',
|
mode: 'text/x-pgsql',
|
||||||
}, cmObj = jasmine.createSpyObj('cmObj', {'setValue': ()=>{}, 'refresh': ()=>{}});
|
}, cmObj = jasmine.createSpyObj('cmObj', {'getValue':()=>'', 'setValue': ()=>{}, 'refresh': ()=>{}});
|
||||||
beforeEach(()=>{
|
beforeEach(()=>{
|
||||||
jasmineEnzyme();
|
jasmineEnzyme();
|
||||||
spyOn(OrigCodeMirror, 'fromTextArea').and.returnValue(cmObj);
|
spyOn(OrigCodeMirror, 'fromTextArea').and.returnValue(cmObj);
|
||||||
cmInstance = mount(
|
cmInstance = mount(
|
||||||
<CodeMirror
|
<CodeMirror
|
||||||
value={'Init text'}
|
value={'Init text'}
|
||||||
isAsync={true}
|
|
||||||
options={options}
|
options={options}
|
||||||
className="testClass"
|
className="testClass"
|
||||||
/>);
|
/>);
|
||||||
@@ -34,14 +33,12 @@ describe('CodeMirror', ()=>{
|
|||||||
|
|
||||||
it('init', ()=>{
|
it('init', ()=>{
|
||||||
/* textarea ref passed to fromTextArea */
|
/* textarea ref passed to fromTextArea */
|
||||||
expect(OrigCodeMirror.fromTextArea).toHaveBeenCalledWith(cmInstance.getDOMNode(), options);
|
expect(OrigCodeMirror.fromTextArea).toHaveBeenCalledWith(cmInstance.find('textarea').getDOMNode(), options);
|
||||||
expect(cmObj.setValue).toHaveBeenCalledWith('Init text');
|
expect(cmObj.setValue).toHaveBeenCalledWith('Init text');
|
||||||
expect(cmObj.refresh).toHaveBeenCalled();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('change value', ()=>{
|
it('change value', ()=>{
|
||||||
cmInstance.setProps({value: 'the new text'});
|
cmInstance.setProps({value: 'the new text'});
|
||||||
expect(cmObj.setValue).toHaveBeenCalledWith('the new text');
|
expect(cmObj.setValue).toHaveBeenCalledWith('the new text');
|
||||||
expect(cmObj.refresh).toHaveBeenCalled();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -9,15 +9,15 @@
|
|||||||
|
|
||||||
/* eslint-disable no-console */
|
/* eslint-disable no-console */
|
||||||
|
|
||||||
// beforeAll(function () {
|
beforeAll(function () {
|
||||||
// spyOn(console, 'warn').and.callThrough();
|
spyOn(console, 'warn').and.callThrough();
|
||||||
// spyOn(console, 'error').and.callThrough();
|
spyOn(console, 'error').and.callThrough();
|
||||||
// });
|
});
|
||||||
|
|
||||||
// afterEach(function (done) {
|
afterEach(function (done) {
|
||||||
// setTimeout(function () {
|
setTimeout(function () {
|
||||||
// expect(console.warn).not.toHaveBeenCalled();
|
expect(console.warn).not.toHaveBeenCalled();
|
||||||
// expect(console.error).not.toHaveBeenCalled();
|
expect(console.error).not.toHaveBeenCalled();
|
||||||
// done();
|
done();
|
||||||
// }, 0);
|
}, 0);
|
||||||
// });
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user