mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-02-25 18:55:31 -06:00
Fixed following issues for query tool after react porting:
1) Add New Server Connection > Server options keep loading(For empty Server group). 2) After clicking indent/Unindent(for all operations) for large query option left as it is till operation completes 3) Check sign beside options in Execute Option/Copy Header is little bit big 4) In explain > Analysis tab does not show ROWS column 5) In explain > Explain > analysis previous explain output is NOT cleared. New rows are appended. Same applies to the statistics tab. 6) Update new query tool connection tool tip. Fixes #7289 7) Explain-Analyze > Loops column is empty. 8) Explain-Analyze with Verbose & Costs > in ROW X columns upward arrows are missing. 9) Explain-Analyze with all option checked > background colors are missing for timing. 10) Explain-Analyze > Additional bullet is added before Hash Cond. 11) Browser Tree > Filtered rows icon is not working. 12) Create table with timestamp and default value as function now() > Add new row > Enter mandatory columns except column where default value is function(now()) > Click Save > New row added but column with default value has value [default]. not updated to actual value. / Default values are not considered for any column while adding a new entry. 13) Disable execute options in View/Edit data. 14) The Boolean column always shows null. 15) In Query history Remove & Remove all buttons are stuck to each other. 16) On Remove all, the right panel is empty. 17) Create a column with boolean[]/ text[], Try to add a new entry from data grid, enter “” quotes > Click Ok > Now try edit cell > You can not change value. 18) In query history - Select queries are suffixed by ’Save Data’ icon 19) Edit any table with PK > Try to insert duplicate PK > Error thrown > Correct pK value > Still old error shown > Not able to add new entry (This works when focus is moved from edited cell) 20) Clicking arrows after opening dropdown options, does not collapse dropdown. refs #6131
This commit is contained in:
committed by
Akshay Joshi
parent
74e3f976c1
commit
9c30d983bd
@@ -24,16 +24,19 @@ const useStyles = makeStyles((theme)=>({
|
||||
borderBottom: '2px dashed '+theme.palette.primary.main,
|
||||
},
|
||||
level2: {
|
||||
backgroundColor: '#fff',
|
||||
color: '#000',
|
||||
backgroundColor: theme.otherVars.explain.sev2.bg,
|
||||
color: theme.otherVars.explain.sev2.color,
|
||||
},
|
||||
level3: {
|
||||
backgroundColor: '#fff',
|
||||
color: '#000',
|
||||
backgroundColor: theme.otherVars.explain.sev3.bg,
|
||||
color: theme.otherVars.explain.sev3.color,
|
||||
},
|
||||
level4: {
|
||||
backgroundColor: '#fff',
|
||||
color: '#000',
|
||||
backgroundColor: theme.otherVars.explain.sev4.bg,
|
||||
color: theme.otherVars.explain.sev4.color,
|
||||
},
|
||||
textRight: {
|
||||
textAlign: 'right',
|
||||
},
|
||||
}));
|
||||
|
||||
@@ -43,15 +46,6 @@ function getRowClassname(data, collapseParent) {
|
||||
if(data['Plans']?.length > 0) {
|
||||
className.push(classes.collapsible);
|
||||
}
|
||||
if(!_.isEmpty(data['exclusive_flag'])) {
|
||||
className.push(classes['level'+data['exclusive_flag']]);
|
||||
}
|
||||
if(!_.isEmpty(data['inclusive_flag'])) {
|
||||
className.push(classes['level'+data['inclusive_flag']]);
|
||||
}
|
||||
if(!_.isEmpty(data['rowsx_flag'])) {
|
||||
className.push(classes['level'+data['rowsx_flag']]);
|
||||
}
|
||||
if(collapseParent) {
|
||||
className.push(classes.collapseParent);
|
||||
}
|
||||
@@ -61,10 +55,10 @@ function getRowClassname(data, collapseParent) {
|
||||
function NodeText({displayText, extraInfo}) {
|
||||
return (
|
||||
<>
|
||||
<ArrowRightAltIcon fontSize="small" /> {displayText}
|
||||
{extraInfo?.length > 0 && <ul>
|
||||
<ArrowRightAltIcon fontSize="small" style={{marginLeft: '-24px'}} /> {displayText}
|
||||
{extraInfo?.length > 0 && <ul style={{fontSize: '13px'}}>
|
||||
{extraInfo.map((item, i)=>{
|
||||
return <li key={i}>{HTMLReactParse(item)}</li>;
|
||||
return <li key={i} style={{opacity: '0.8'}}>{HTMLReactParse(item)}</li>;
|
||||
})}
|
||||
</ul>}
|
||||
</>);
|
||||
@@ -76,6 +70,7 @@ NodeText.propTypes = {
|
||||
|
||||
function ExplainRow({row, show, activeExId, setActiveExId, collapsedExId, toggleCollapseExId}) {
|
||||
let data = row['data'];
|
||||
const classes = useStyles();
|
||||
const exId = `pga_ex_${data['level'].join('_')}`;
|
||||
const parentExId = `pga_ex_${data['parent_node']}`;
|
||||
const collapsed = collapsedExId.findIndex((v)=>parentExId.startsWith(v)) > -1;
|
||||
@@ -94,29 +89,28 @@ function ExplainRow({row, show, activeExId, setActiveExId, collapsedExId, toggle
|
||||
<td>
|
||||
<FiberManualRecordIcon fontSize="small" style={{visibility: activeExId==parentExId ? 'visible' : 'hidden'}} />
|
||||
</td>
|
||||
<td>{data['_serial']}.</td>
|
||||
<td className={classes.textRight}>{data['_serial']}.</td>
|
||||
<td style={{paddingLeft: data['level'].length*30+'px'}} title={row['tooltip_text']}>
|
||||
<NodeText displayText={row['display_text']} extraInfo={row['node_extra_info']} />
|
||||
</td>
|
||||
<td style={show.show_timings ? {} : {display: 'none'}}>
|
||||
<td className={clsx(classes.textRight, classes['level'+data['exclusive_flag']])} style={show.show_timings ? {} : {display: 'none'}}>
|
||||
{data['exclusive'] && (data['exclusive']+' ms')}
|
||||
</td>
|
||||
<td style={show.show_timings ? {} : {display: 'none'}}>
|
||||
<td className={clsx(classes.textRight, classes['level'+data['inclusive_flag']])} style={show.show_timings ? {} : {display: 'none'}}>
|
||||
{data['inclusive'] && (data['inclusive']+' ms')}
|
||||
</td>
|
||||
<td style={{display: 'none'}}>{!_.isUndefined(data['rowsx_flag'])
|
||||
&& (data['rowsx_direction'] == 'positive' ? '↑' : '↓')
|
||||
}</td>
|
||||
<td style={show.show_rowsx ? {} : {display: 'none'}}>
|
||||
{data['rowsx']}
|
||||
<td className={clsx(classes.textRight, classes['level'+data['rowsx_flag']])} style={show.show_rowsx ? {} : {display: 'none'}}>
|
||||
{!_.isUndefined(data['rowsx_flag'])
|
||||
&& (data['rowsx_direction'] == 'positive' ? <>↑</> : <>↓</>)
|
||||
} {data['rowsx']}
|
||||
</td>
|
||||
<td style={(show.show_rowsx || show.show_rows) ? {} : {display: 'none'}}>
|
||||
<td className={classes.textRight} style={(show.show_rowsx || show.show_rows) ? {} : {display: 'none'}}>
|
||||
{data['Actual Rows']}
|
||||
</td>
|
||||
<td style={(show.show_rowsx || show.show_plan_rows) ? {} : {display: 'none'}}>
|
||||
<td className={classes.textRight} style={(show.show_rowsx || show.show_plan_rows) ? {} : {display: 'none'}}>
|
||||
{data['Plan Rows']}
|
||||
</td>
|
||||
<td style={(show.show_rowsx || show.show_rows) ? {} : {display: 'none'}}>
|
||||
<td className={classes.textRight} style={(show.show_rowsx || show.show_rows) ? {} : {display: 'none'}}>
|
||||
{data['Actual Loops']}
|
||||
</td>
|
||||
</tr>
|
||||
@@ -130,7 +124,9 @@ ExplainRow.propTypes = {
|
||||
_serial: PropTypes.number,
|
||||
parent_node: PropTypes.number,
|
||||
exclusive: PropTypes.number,
|
||||
exclusive_flag: PropTypes.string,
|
||||
inclusive: PropTypes.number,
|
||||
inclusive_flag: PropTypes.string,
|
||||
rowsx_direction: PropTypes.string,
|
||||
rowsx: PropTypes.number,
|
||||
rowsx_flag: PropTypes.number,
|
||||
@@ -178,7 +174,8 @@ export default function Analysis({explainTable}) {
|
||||
<th colSpan="2" style={explainTable.show_timings ? {} : {display: 'none'}}>
|
||||
<button disabled="">Timings</button>
|
||||
</th>
|
||||
<th style={(explainTable.show_rowsx || explainTable.show_rows) ? {} : {display: 'none'}} colSpan="3">
|
||||
<th style={(explainTable.show_rowsx || explainTable.show_rows) ? {} : {display: 'none'}}
|
||||
colSpan={(explainTable.show_rowsx) ? '3' : '1'}>
|
||||
<button disabled="">Rows</button>
|
||||
</th>
|
||||
<th style={(explainTable.show_rowsx || explainTable.show_rows) ? {} : {display: 'none'}} rowSpan="2">
|
||||
|
||||
@@ -250,6 +250,7 @@ function PlanContent({plan, pXpos, pYpos, ...props}) {
|
||||
strokeWidth={1.2}
|
||||
fill="gray"
|
||||
fillOpacity={0.2}
|
||||
pointerEvents="none"
|
||||
/>
|
||||
<tspan x={currentXpos + pWIDTH - (plan.width / 2) - xMargin}
|
||||
y={currentYpos + pHEIGHT - (plan.height / 2) - yMargin}
|
||||
|
||||
@@ -23,7 +23,7 @@ const useStyles = makeStyles((theme)=>({
|
||||
tabPanel: {
|
||||
padding: 0,
|
||||
backgroundColor: theme.palette.background.default,
|
||||
}
|
||||
},
|
||||
}));
|
||||
|
||||
// Some predefined constants used to calculate image location and its border
|
||||
@@ -261,7 +261,11 @@ function parsePlan(data, ctx) {
|
||||
totalCost = data['Total Cost'];
|
||||
if (startCost != undefined && totalCost != undefined) {
|
||||
arrowSize = Math.round(Math.log((startCost + totalCost) / 2 + startCost));
|
||||
arrowSize = arrowSize < 1 ? 1 : arrowSize > 10 ? 10 : arrowSize;
|
||||
if (arrowSize < 1) {
|
||||
arrowSize = 1;
|
||||
} else if (arrowSize > 10) {
|
||||
arrowSize = 10;
|
||||
}
|
||||
}
|
||||
data['arr_id'] = _.uniqueId('arr');
|
||||
ctx.arrows[data['arr_id']] = arrowSize;
|
||||
@@ -292,15 +296,21 @@ function parsePlan(data, ctx) {
|
||||
|
||||
if ('Actual Total Time' in data && 'Actual Loops' in data) {
|
||||
data['inclusive'] = Math.ceil10(
|
||||
data['Actual Total Time'] * data['Actual Loops'], -3
|
||||
data['Actual Total Time'], -3
|
||||
);
|
||||
data['exclusive'] = data['inclusive'];
|
||||
data['inclusive_factor'] = data['inclusive'] / (
|
||||
data['total_time'] || data['Actual Total Time']
|
||||
);
|
||||
data['inclusive_flag'] = data['inclusive_factor'] <= 0.1 ? '1' :
|
||||
data['inclusive_factor'] < 0.5 ? '2' :
|
||||
data['inclusive_factor'] <= 0.9 ? '3' : '4';
|
||||
if (data['inclusive_factor'] <= 0.1) {
|
||||
data['inclusive_flag'] = '1';
|
||||
} else if (data['inclusive_factor'] < 0.5) {
|
||||
data['inclusive_flag'] = '2';
|
||||
} else if (data['inclusive_factor'] <= 0.9) {
|
||||
data['inclusive_flag'] = '3';
|
||||
} else {
|
||||
data['inclusive_flag'] = '4';
|
||||
}
|
||||
}
|
||||
|
||||
if ('Actual Rows' in data && 'Plan Rows' in data) {
|
||||
@@ -316,10 +326,20 @@ function parsePlan(data, ctx) {
|
||||
);
|
||||
data['rowsx_direction'] = 'positive';
|
||||
}
|
||||
data['rowsx_flag'] = data['rowsx'] <= 10 ? '1' : (
|
||||
data['rowsx'] <= 100 ? '2' : (data['rowsx'] <= 1000 ? '3' : '4')
|
||||
);
|
||||
data['rowsx'] = Math.ceil10(data['rowsx'], -2);
|
||||
if (data['rowsx'] <= 10) {
|
||||
data['rowsx_flag'] = '1';
|
||||
} else if (data['rowsx'] <= 100 ) {
|
||||
data['rowsx_flag'] = '2';
|
||||
} else if (data['rowsx'] <= 1000 ) {
|
||||
data['rowsx_flag'] = '3';
|
||||
} else {
|
||||
data['rowsx_flag'] = '4';
|
||||
}
|
||||
if('loops' in data) {
|
||||
data['rowsx'] = Math.ceil10(data['rowsx'] / data['loops'] || 1, -2);
|
||||
} else {
|
||||
data['rowsx'] = Math.ceil10(data['rowsx'], -2);
|
||||
}
|
||||
}
|
||||
|
||||
// Start calculating xpos, ypos, width and height for child plans if any
|
||||
@@ -337,6 +357,7 @@ function parsePlan(data, ctx) {
|
||||
ypos: ypos,
|
||||
total_time: data['total_time'] || data['Actual Total Time'],
|
||||
parent_node: lvl.join('_'),
|
||||
loops: data['Actual Loops']
|
||||
}, ctx);
|
||||
|
||||
if (maxChildWidth < plan.width) {
|
||||
@@ -344,7 +365,7 @@ function parsePlan(data, ctx) {
|
||||
}
|
||||
|
||||
if ('exclusive' in data) {
|
||||
if (plan.inclusive) {
|
||||
if (plan.inclusive < data['exclusive']) {
|
||||
data['exclusive'] -= plan.inclusive;
|
||||
}
|
||||
}
|
||||
@@ -361,6 +382,11 @@ function parsePlan(data, ctx) {
|
||||
plans.push(plan);
|
||||
idx++;
|
||||
});
|
||||
} else{
|
||||
if('loops' in data && 'exclusive' in data) {
|
||||
data['inclusive'] = Math.ceil10(data['Actual Total Time'] / data['loops'] || 1, -3);
|
||||
data['exclusive'] = data['inclusive'];
|
||||
}
|
||||
}
|
||||
|
||||
if ('exclusive' in data) {
|
||||
@@ -368,9 +394,15 @@ function parsePlan(data, ctx) {
|
||||
data['exclusive_factor'] = (
|
||||
data['exclusive'] / (data['total_time'] || data['Actual Total Time'])
|
||||
);
|
||||
data['exclusive_flag'] = data['exclusive_factor'] <= 0.1 ? '1' :
|
||||
data['exclusive_factor'] < 0.5 ? '2' :
|
||||
data['exclusive_factor'] <= 0.9 ? '3' : '4';
|
||||
if (data['exclusive_factor'] <= 0.1) {
|
||||
data['exclusive_flag'] = '1';
|
||||
} else if (data['exclusive_factor'] < 0.5) {
|
||||
data['exclusive_flag'] = '2';
|
||||
} else if (data['exclusive_factor'] <= 0.9) {
|
||||
data['exclusive_flag'] = '3';
|
||||
} else {
|
||||
data['exclusive_flag'] = '4';
|
||||
}
|
||||
}
|
||||
|
||||
// Final Width and Height of current node
|
||||
@@ -389,6 +421,7 @@ function parsePlanData(data, ctx) {
|
||||
...data['Plan'],
|
||||
xpos: 0,
|
||||
ypos: 0,
|
||||
loops: 1,
|
||||
}, ctx);
|
||||
retPlan['Plan'] = plan;
|
||||
retPlan['xpos'] = 0;
|
||||
@@ -431,20 +464,23 @@ export default function Explain({plans=[]}) {
|
||||
const classes = useStyles();
|
||||
const [tabValue, setTabValue] = React.useState(0);
|
||||
|
||||
let ctx = React.useRef({
|
||||
totalNodes: 0,
|
||||
totalDownloadedNodes: 0,
|
||||
isDownloaded: 0,
|
||||
explainTable: {
|
||||
rows: [],
|
||||
statistics: {
|
||||
tables: {},
|
||||
nodes: {},
|
||||
let ctx = React.useRef({});
|
||||
let planData = React.useMemo(()=>{
|
||||
ctx.current = {
|
||||
totalNodes: 0,
|
||||
totalDownloadedNodes: 0,
|
||||
isDownloaded: 0,
|
||||
explainTable: {
|
||||
rows: [],
|
||||
statistics: {
|
||||
tables: {},
|
||||
nodes: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
arrows: {},
|
||||
});
|
||||
let planData = React.useMemo(()=>(plans && parsePlanData(plans[0], ctx.current)), [plans]);
|
||||
arrows: {},
|
||||
};
|
||||
return plans && parsePlanData(plans[0], ctx.current);
|
||||
}, [plans]);
|
||||
|
||||
if(_.isEmpty(plans)) {
|
||||
return <Box height="100%" display="flex" flexDirection="column">
|
||||
|
||||
@@ -19,6 +19,7 @@ import CustomPropTypes from '../custom_prop_types';
|
||||
import getStandardTheme from './standard';
|
||||
import getDarkTheme from './dark';
|
||||
import getHightContrastTheme from './high_contrast';
|
||||
import { CssBaseline } from '@material-ui/core';
|
||||
|
||||
/* Common settings across all themes */
|
||||
let basicSettings = createMuiTheme();
|
||||
@@ -278,6 +279,19 @@ function getFinalTheme(baseTheme) {
|
||||
return createMuiTheme({
|
||||
mixins: mixins,
|
||||
overrides: {
|
||||
MuiCssBaseline: {
|
||||
'@global': {
|
||||
ul: {
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
},
|
||||
li: {
|
||||
listStyle: 'none',
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
}
|
||||
},
|
||||
},
|
||||
MuiOutlinedInput: {
|
||||
root: {
|
||||
'&.Mui-disabled .MuiOutlinedInput-notchedOutline': {
|
||||
@@ -535,6 +549,7 @@ export default function Theme(props) {
|
||||
}, []);
|
||||
return (
|
||||
<ThemeProvider theme={theme}>
|
||||
<CssBaseline />
|
||||
{props.children}
|
||||
</ThemeProvider>
|
||||
);
|
||||
@@ -561,6 +576,7 @@ export const commonTableStyles = makeStyles((theme)=>({
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap',
|
||||
userSelect: 'text',
|
||||
maxWidth: '250px',
|
||||
'&:first-of-type':{
|
||||
borderLeft: 'none',
|
||||
},
|
||||
|
||||
@@ -105,6 +105,20 @@ export default function(basicSettings) {
|
||||
qtDatagridSelectFg: '#222',
|
||||
cardHeaderBg: '#fff',
|
||||
emptySpaceBg: '#ebeef3',
|
||||
explain: {
|
||||
sev2: {
|
||||
color: '#222222',
|
||||
bg: '#FFEE88',
|
||||
},
|
||||
sev3: {
|
||||
color: '#FFFFFF',
|
||||
bg: '#EE8800'
|
||||
},
|
||||
sev4: {
|
||||
color: '#FFFFFF',
|
||||
bg: '#880000'
|
||||
},
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -405,6 +405,22 @@ export default function CodeMirror({currEditor, name, value, options, events, re
|
||||
}
|
||||
|
||||
Object.keys(events||{}).forEach((eventName)=>{
|
||||
if(eventName === 'change') {
|
||||
let timeoutId;
|
||||
const change = (...args)=>{
|
||||
/* In case of indent, change is triggered for each line */
|
||||
/* This can be avoided and taking only the latest */
|
||||
if(timeoutId) {
|
||||
clearTimeout(timeoutId);
|
||||
}
|
||||
timeoutId = setTimeout(()=>{
|
||||
events[eventName](...args);
|
||||
timeoutId = null;
|
||||
}, 0);
|
||||
};
|
||||
editor.current.on(eventName, change);
|
||||
return;
|
||||
}
|
||||
editor.current.on(eventName, events[eventName]);
|
||||
});
|
||||
editor.current.on('drop', handleDrop);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React from 'react';
|
||||
import QueryToolSvg from '../../img/fonticon/query_tool.svg?svgr';
|
||||
import ViewDataSvg from '../../img/fonticon/view_data.svg?svgr';
|
||||
import SaveDataSvg from '../../img/fonticon/save_data_changes.svg?svgr';
|
||||
import PasteSvg from '../../img/content_paste.svg?svgr';
|
||||
import FilterSvg from '../../img/filter_alt_black.svg?svgr';
|
||||
@@ -22,16 +23,44 @@ ExternalIcon.propTypes = {
|
||||
Icon: PropTypes.elementType.isRequired,
|
||||
};
|
||||
|
||||
export const QueryToolIcon = ()=><ExternalIcon Icon={QueryToolSvg} style={{height: '1rem'}} />;
|
||||
export const SaveDataIcon = ()=><ExternalIcon Icon={SaveDataSvg} style={{height: '1rem'}} />;
|
||||
export const PasteIcon = ()=><ExternalIcon Icon={PasteSvg} />;
|
||||
export const FilterIcon = ()=><ExternalIcon Icon={FilterSvg} />;
|
||||
export const CommitIcon = ()=><ExternalIcon Icon={CommitSvg} />;
|
||||
export const RollbackIcon = ()=><ExternalIcon Icon={RollbackSvg} />;
|
||||
export const ClearIcon = ()=><ExternalIcon Icon={ClearSvg} />;
|
||||
export const ConnectedIcon = ()=><ExternalIcon Icon={ConnectedSvg} style={{height: '1rem'}} />;
|
||||
export const DisonnectedIcon = ()=><ExternalIcon Icon={DisconnectedSvg} style={{height: '1rem'}} />;
|
||||
export const RegexIcon = ()=><ExternalIcon Icon={RegexSvg} />;
|
||||
export const FormatCaseIcon = ()=><ExternalIcon Icon={FormatCaseSvg} />;
|
||||
export const ExpandDialogIcon = ()=><ExternalIcon Icon={Expand} style={{height: '1.2rem'}} />;
|
||||
export const MinimizeDialogIcon = ()=><ExternalIcon Icon={Collapse} style={{height: '1.4rem'}} />;
|
||||
export const QueryToolIcon = ({style})=><ExternalIcon Icon={QueryToolSvg} style={{height: '1rem', ...style}} />;
|
||||
QueryToolIcon.propTypes = {style: PropTypes.object};
|
||||
|
||||
export const ViewDataIcon = ({style})=><ExternalIcon Icon={ViewDataSvg} style={{height: '0.8rem', ...style}} />;
|
||||
ViewDataIcon.propTypes = {style: PropTypes.object};
|
||||
|
||||
export const SaveDataIcon = ({style})=><ExternalIcon Icon={SaveDataSvg} style={{height: '1rem', ...style}} />;
|
||||
SaveDataIcon.propTypes = {style: PropTypes.object};
|
||||
|
||||
export const PasteIcon = ({style})=><ExternalIcon Icon={PasteSvg} style={style} />;
|
||||
PasteIcon.propTypes = {style: PropTypes.object};
|
||||
|
||||
export const FilterIcon = ({style})=><ExternalIcon Icon={FilterSvg} style={style} />;
|
||||
FilterIcon.propTypes = {style: PropTypes.object};
|
||||
|
||||
export const CommitIcon = ({style})=><ExternalIcon Icon={CommitSvg} style={style} />;
|
||||
CommitIcon.propTypes = {style: PropTypes.object};
|
||||
|
||||
export const RollbackIcon = ({style})=><ExternalIcon Icon={RollbackSvg} style={style} />;
|
||||
RollbackIcon.propTypes = {style: PropTypes.object};
|
||||
|
||||
export const ClearIcon = ({style})=><ExternalIcon Icon={ClearSvg} style={style} />;
|
||||
ClearIcon.propTypes = {style: PropTypes.object};
|
||||
|
||||
export const ConnectedIcon = ({style})=><ExternalIcon Icon={ConnectedSvg} style={{height: '1rem', ...style}} />;
|
||||
ConnectedIcon.propTypes = {style: PropTypes.object};
|
||||
|
||||
export const DisonnectedIcon = ({style})=><ExternalIcon Icon={DisconnectedSvg} style={{height: '1rem', ...style}} />;
|
||||
DisonnectedIcon.propTypes = {style: PropTypes.object};
|
||||
|
||||
export const RegexIcon = ({style})=><ExternalIcon Icon={RegexSvg} style={style} />;
|
||||
RegexIcon.propTypes = {style: PropTypes.object};
|
||||
|
||||
export const FormatCaseIcon = ({style})=><ExternalIcon Icon={FormatCaseSvg} style={style} />;
|
||||
FormatCaseIcon.propTypes = {style: PropTypes.object};
|
||||
|
||||
export const ExpandDialogIcon = ({style})=><ExternalIcon Icon={Expand} style={{height: '1.2rem', ...style}} />;QueryToolIcon.propTypes = {style: PropTypes.object};
|
||||
ExpandDialogIcon.propTypes = {style: PropTypes.object};
|
||||
|
||||
export const MinimizeDialogIcon = ({style})=><ExternalIcon Icon={Collapse} style={{height: '1.4rem', ...style}} />;
|
||||
MinimizeDialogIcon.propTypes = {style: PropTypes.object};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { makeStyles } from '@material-ui/styles';
|
||||
import React from 'react';
|
||||
import React, { useRef } from 'react';
|
||||
import CheckIcon from '@material-ui/icons/Check';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
@@ -34,6 +34,9 @@ const useStyles = makeStyles((theme)=>({
|
||||
color: theme.palette.primary.contrastText,
|
||||
}
|
||||
},
|
||||
checkIcon: {
|
||||
width: '1.3rem',
|
||||
},
|
||||
hideCheck: {
|
||||
visibility: 'hidden',
|
||||
},
|
||||
@@ -70,7 +73,7 @@ export const PgMenuItem = applyStatics(MenuItem)(({hasCheck=false, checked=false
|
||||
};
|
||||
}
|
||||
return <MenuItem {...props} onClick={onClick} className={classes.menuItem}>
|
||||
{hasCheck && <CheckIcon style={checked ? {} : {visibility: 'hidden'}}/>}
|
||||
{hasCheck && <CheckIcon className={classes.checkIcon} style={checked ? {} : {visibility: 'hidden'}} />}
|
||||
{children}
|
||||
{(shortcut || accesskey) && <div className={classes.shortcut}>({shortcutToString(shortcut, accesskey)})</div>}
|
||||
</MenuItem>;
|
||||
@@ -84,3 +87,32 @@ PgMenuItem.propTypes = {
|
||||
children: CustomPropTypes.children,
|
||||
onClick: PropTypes.func,
|
||||
};
|
||||
|
||||
export function usePgMenuGroup() {
|
||||
const [openMenuName, setOpenMenuName] = React.useState(null);
|
||||
const prevMenuOpenIdRef = useRef(null);
|
||||
|
||||
const toggleMenu = React.useCallback((e)=>{
|
||||
setOpenMenuName(()=>{
|
||||
return prevMenuOpenIdRef.current == e.currentTarget?.name ? null : e.currentTarget?.name;
|
||||
});
|
||||
prevMenuOpenIdRef.current = null;
|
||||
}, []);
|
||||
|
||||
const handleMenuClose = React.useCallback(()=>{
|
||||
/* We have no way here to know if the menu was closed using menu button or not
|
||||
We will keep the last menu name ref for sometime so that the menu does not
|
||||
open again if menu button is clicked to close the menu */
|
||||
prevMenuOpenIdRef.current = openMenuName;
|
||||
setTimeout(()=>{
|
||||
prevMenuOpenIdRef.current = null;
|
||||
}, 300);
|
||||
setOpenMenuName(null);
|
||||
}, [openMenuName]);
|
||||
|
||||
return {
|
||||
openMenuName: openMenuName,
|
||||
toggleMenu: toggleMenu,
|
||||
onMenuClose: handleMenuClose,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ export default class EventBus {
|
||||
if(e.event === event) {
|
||||
return e.callback.toString()!=callback.toString();
|
||||
}
|
||||
return e.event!=event && e.callback.toString()!=callback.toString();
|
||||
return true;
|
||||
});
|
||||
} else {
|
||||
this._eventListeners = this._eventListeners.filter((e)=>e.event!=event);
|
||||
|
||||
Reference in New Issue
Block a user