Fixed SonarQube code smells.

This commit is contained in:
Akshay Joshi 2024-06-13 18:48:02 +05:30
parent ad34ee2699
commit 5866da8194
45 changed files with 130 additions and 164 deletions

View File

@ -4,7 +4,7 @@ Version 8.9
Release date: 2024-06-27 Release date: 2024-06-27
This release contains a number of bug fixes and new features since the release of pgAdmin 4 v8.7. This release contains a number of bug fixes and new features since the release of pgAdmin 4 v8.8.
Supported Database Servers Supported Database Servers
************************** **************************
@ -19,8 +19,8 @@ Bundled PostgreSQL Utilities
New features New features
************ ************
| `Issue #5932 <https://github.com/pgadmin-org/pgadmin4/issues/5932>`_ - Provide option to set theme based on OS theme preference.
| `Issue #5932 <https://github.com/pgadmin-org/pgadmin4/issues/5932>`_ - Provide option to set theme based on OS theme preference.
Housekeeping Housekeeping
************ ************
@ -31,6 +31,11 @@ Bug fixes
********* *********
| `Issue #6357 <https://github.com/pgadmin-org/pgadmin4/issues/6357>`_ - Disable the query tool editor input if any SQL is being loaded to prevent users from typing. | `Issue #6357 <https://github.com/pgadmin-org/pgadmin4/issues/6357>`_ - Disable the query tool editor input if any SQL is being loaded to prevent users from typing.
| `Issue #7241 <https://github.com/pgadmin-org/pgadmin4/issues/7241>`_ - Fixed an issue where resizable data editors in query tool should not be allowed to resize beyond the app window bounds.
| `Issue #7295 <https://github.com/pgadmin-org/pgadmin4/issues/7295>`_ - Fixed new line indentation in query editor and add a user preference to disable it.
| `Issue #7306 <https://github.com/pgadmin-org/pgadmin4/issues/7306>`_ - Ensure that a user can connect to a server using SSL certificates and identity files from a shared storage. | `Issue #7306 <https://github.com/pgadmin-org/pgadmin4/issues/7306>`_ - Ensure that a user can connect to a server using SSL certificates and identity files from a shared storage.
| `Issue #7414 <https://github.com/pgadmin-org/pgadmin4/issues/7414>`_ - Add support for comments on RLS policy object.
| `Issue #7481 <https://github.com/pgadmin-org/pgadmin4/issues/7481>`_ - Fixed an issue where dark theme shows white background when all tabs are closed. | `Issue #7481 <https://github.com/pgadmin-org/pgadmin4/issues/7481>`_ - Fixed an issue where dark theme shows white background when all tabs are closed.
| `Issue #7516 <https://github.com/pgadmin-org/pgadmin4/issues/7516>`_ - Ensure preferences can be loaded using preferences.json. | `Issue #7516 <https://github.com/pgadmin-org/pgadmin4/issues/7516>`_ - Ensure preferences can be loaded using preferences.json.
| `Issue #7536 <https://github.com/pgadmin-org/pgadmin4/issues/7536>`_ - Search Objects dialog should focus on search input on open.
| `Issue #7555 <https://github.com/pgadmin-org/pgadmin4/issues/7555>`_ - Fixed an issue where query tool shortcuts for find/replace are not working.

View File

@ -165,9 +165,8 @@ export default class CollationSchema extends BaseUISchema {
else { else {
if (actionObj.oldState.is_deterministic) { if (actionObj.oldState.is_deterministic) {
return { is_deterministic: false }; return { is_deterministic: false };
} else {
return { is_deterministic: true };
} }
return { is_deterministic: true };
} }
}, },
}, },

View File

@ -825,7 +825,7 @@ class PackageView(PGChildNodeView, SchemaDiffObjectCompare):
if sql is None: if sql is None:
return None return None
start = 0 start = 0
start_position = re.search("\\s+[is|as]+\\s+", sql, flags=re.I) start_position = re.search("\\s+(is|as)+\\s+", sql, flags=re.I)
if start_position: if start_position:
start = start_position.start() + 4 start = start_position.start() + 4

View File

@ -582,7 +582,7 @@ class EdbFuncView(PGChildNodeView, DataTypeReader):
if sql is None: if sql is None:
return None return None
start = 0 start = 0
start_position = re.search(r"\s+[is|as]+\s+", sql, flags=re.I) start_position = re.search(r"\s+(is|as)+\s+", sql, flags=re.I)
if start_position: if start_position:
start = start_position.start() + 4 start = start_position.start() + 4

View File

@ -128,10 +128,7 @@ export default class CompoundTriggerSchema extends BaseUISchema {
} }
// Enable column only if update event is set true // Enable column only if update event is set true
let isUpdate = state.evnt_update; let isUpdate = state.evnt_update;
if(!_.isUndefined(isUpdate) && isUpdate) { return !(!_.isUndefined(isUpdate) && isUpdate);
return false;
}
return true;
}, },
readonly: function(state) { return !obj.isNew(state); }, readonly: function(state) { return !obj.isNew(state); },
},{ },{

View File

@ -402,7 +402,7 @@ define('pgadmin.node.table', [
handle_cache: function() { handle_cache: function() {
// Clear Table's cache as column's type is dependent on two node // Clear Table's cache as column's type is dependent on two node
// 1) Type node 2) Domain node // 1) Type node 2) Domain node
this.clear_cache.apply(this, null); this.clear_cache(...null);
}, },
}); });
} }

View File

@ -521,13 +521,13 @@ def parse_rule_definition(res):
# Parse data for condition # Parse data for condition
condition = '' condition = ''
condition_part_match = re.search( condition_part_match = re.search(
r"((?:ON)\s+(?:[\s\S]+?)" r"(ON\s+[\s\S]+?"
r"(?:TO)\s+(?:[\s\S]+?)(?:DO))", data_def) r"TO\s+[\s\S]+?DO)", data_def)
if condition_part_match is not None: if condition_part_match is not None:
condition_part = condition_part_match.group(1) condition_part = condition_part_match.group(1)
condition_match = re.search( condition_match = re.search(
r"(?:WHERE)\s+(\([\s\S]*\))\s+(?:DO)", condition_part) r"WHERE\s+(\([\s\S]*\))\s+DO", condition_part)
if condition_match is not None: if condition_match is not None:
condition = condition_match.group(1) condition = condition_match.group(1)
@ -537,7 +537,7 @@ def parse_rule_definition(res):
# Parse data for statements # Parse data for statements
statement_match = re.search( statement_match = re.search(
r"(?:DO\s+)(?:INSTEAD\s+)?([\s\S]*)(?:;)", data_def) r"DO\s+(?:INSTEAD\s+)?([\s\S]*);", data_def)
statement = '' statement = ''
if statement_match is not None: if statement_match is not None:

View File

@ -62,7 +62,6 @@
.wizard { .wizard {
width: 100%; width: 100%;
/*height: 550px;*/
} }
.step { .step {

View File

@ -25,7 +25,7 @@ export function AzureCredentials(props) {
let _eventBus = React.useContext(CloudWizardEventsContext); let _eventBus = React.useContext(CloudWizardEventsContext);
React.useMemo(() => { React.useMemo(() => {
const azureCloudDBCredSchema = new AzureCredSchema({ const azureCloudDBCredSchema = new AzureCredSchema(_eventBus, {
authenticateAzure:(auth_type, azure_tenant_id) => { authenticateAzure:(auth_type, azure_tenant_id) => {
let loading_icon_url = url_for( let loading_icon_url = url_for(
'static', { 'filename': 'img/loading.gif'} 'static', { 'filename': 'img/loading.gif'}
@ -77,7 +77,7 @@ export function AzureCredentials(props) {
}, 1000); }, 1000);
}); });
} }
}, {}, _eventBus); }, {});
setCloudDBCredInstance(azureCloudDBCredSchema); setCloudDBCredInstance(azureCloudDBCredSchema);
}, [props.cloudProvider]); }, [props.cloudProvider]);

View File

@ -13,7 +13,7 @@ import { isEmptyString } from 'sources/validators';
import pgAdmin from 'sources/pgadmin'; import pgAdmin from 'sources/pgadmin';
class AzureCredSchema extends BaseUISchema { class AzureCredSchema extends BaseUISchema {
constructor(fieldOptions = {}, initValues = {}, eventBus) { constructor(eventBus, fieldOptions = {}, initValues = {}) {
super({ super({
oid: null, oid: null,
auth_type: 'interactive_browser_credential', auth_type: 'interactive_browser_credential',

View File

@ -8,12 +8,13 @@
////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////
import { Box } from '@mui/material'; import { Box } from '@mui/material';
import { styled } from '@mui/material/styles'; import { styled } from '@mui/material/styles';
import React, { useState, useEffect } from 'react'; import React, { useEffect } from 'react';
import { PrimaryButton } from './components/Buttons'; import { PrimaryButton } from './components/Buttons';
import { PgMenu, PgMenuDivider, PgMenuItem, PgSubMenu } from './components/Menu'; import { PgMenu, PgMenuDivider, PgMenuItem, PgSubMenu } from './components/Menu';
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown'; import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
import AccountCircleRoundedIcon from '@mui/icons-material/AccountCircleRounded'; import AccountCircleRoundedIcon from '@mui/icons-material/AccountCircleRounded';
import { usePgAdmin } from '../../static/js/BrowserComponent'; import { usePgAdmin } from '../../static/js/BrowserComponent';
import { useForceUpdate } from './custom_hooks';
const StyledBox = styled(Box)(({theme}) => ({ const StyledBox = styled(Box)(({theme}) => ({
@ -39,7 +40,7 @@ const StyledBox = styled(Box)(({theme}) => ({
alignItems: 'center', alignItems: 'center',
gap: '2px', gap: '2px',
marginLeft: '16px', marginLeft: '16px',
'& .MuiButton-containedPrimary': { '& .MuiButton-containedPrimary': {
padding: '1px 8px', padding: '1px 8px',
} }
@ -59,17 +60,15 @@ const StyledBox = styled(Box)(({theme}) => ({
export default function AppMenuBar() { export default function AppMenuBar() {
const [,setRefresh] = useState(false); const forceUpdate = useForceUpdate();
const pgAdmin = usePgAdmin(); const pgAdmin = usePgAdmin();
const reRenderMenus = ()=>setRefresh((prev)=>!prev);
useEffect(()=>{ useEffect(()=>{
pgAdmin.Browser.Events.on('pgadmin:nw-enable-disable-menu-items', _.debounce(()=>{ pgAdmin.Browser.Events.on('pgadmin:nw-enable-disable-menu-items', _.debounce(()=>{
reRenderMenus(); forceUpdate();
}, 100)); }, 100));
pgAdmin.Browser.Events.on('pgadmin:nw-refresh-menu-item', _.debounce(()=>{ pgAdmin.Browser.Events.on('pgadmin:nw-refresh-menu-item', _.debounce(()=>{
reRenderMenus(); forceUpdate();
}, 100)); }, 100));
}, []); }, []);
@ -85,7 +84,7 @@ export default function AppMenuBar() {
onClick={()=>{ onClick={()=>{
menuItem.callback(); menuItem.callback();
if(hasCheck) { if(hasCheck) {
reRenderMenus(); forceUpdate();
} }
}} }}
hasCheck={hasCheck} hasCheck={hasCheck}

View File

@ -23,7 +23,7 @@ export default function UrlDialogContent({ url, helpFile, onClose }) {
return ( return (
<ModalContent> <ModalContent>
<Box flexGrow="1"> <Box flexGrow="1">
<iframe src={url} width="100%" height="100%" onLoad={(e)=>{ <iframe src={url} title=" " width="100%" height="100%" onLoad={(e)=>{
e.target?.contentWindow?.focus(); e.target?.contentWindow?.focus();
}}/> }}/>
</Box> </Box>

View File

@ -17,6 +17,7 @@ export default function HiddenIframe({id, srcURL, onLoad}) {
<iframe <iframe
id={id} id={id}
src={srcURL} src={srcURL}
title=" "
onLoad={onLoad} onLoad={onLoad}
width={'20'} width={'20'}
height={'20'} height={'20'}

View File

@ -430,12 +430,14 @@ const sessDataReducer = (state, action)=>{
data = getDepChange(action.path, data, state, action); data = getDepChange(action.path, data, state, action);
break; break;
case SCHEMA_STATE_ACTIONS.MOVE_ROW: case SCHEMA_STATE_ACTIONS.MOVE_ROW:
{
rows = _.get(data, action.path)||[]; rows = _.get(data, action.path)||[];
var row = rows[action.oldIndex]; let row = rows[action.oldIndex];
rows.splice(action.oldIndex, 1); rows.splice(action.oldIndex, 1);
rows.splice(action.newIndex, 0, row); rows.splice(action.newIndex, 0, row);
_.set(data, action.path, rows); _.set(data, action.path, rows);
break; break;
}
case SCHEMA_STATE_ACTIONS.CLEAR_DEFERRED_QUEUE: case SCHEMA_STATE_ACTIONS.CLEAR_DEFERRED_QUEUE:
data.__deferred__ = []; data.__deferred__ = [];
break; break;

View File

@ -818,7 +818,7 @@ function OptionView({ image, imageUrl, label }) {
return ( return (
<Root> <Root>
{image && <span className={'Form-optionIcon ' + image}></span>} {image && <span className={'Form-optionIcon ' + image}></span>}
{imageUrl && <img style={{height: '20px', marginRight: '4px'}} src={imageUrl} />} {imageUrl && <img style={{height: '20px', marginRight: '4px'}} src={imageUrl} alt="" />}
<span>{label}</span> <span>{label}</span>
</Root> </Root>
); );

View File

@ -84,7 +84,7 @@ export default function KeyboardShortcuts({ value, onChange, fields, name }) {
{hasKeys && {hasKeys &&
<> <>
<ToggleButtonGroup value={value?.shift ? ['shift'] : []} onChange={(e, val)=>{ <ToggleButtonGroup value={value?.shift ? ['shift'] : []} onChange={(e, val)=>{
onChangeButton('shift', val.length == 0 ? false : true); onChangeButton('shift', val.length != 0 );
}}> }}>
<ToggleCheckButton value="shift" label={gettext('Shift')} selected={value?.shift} /> <ToggleCheckButton value="shift" label={gettext('Shift')} selected={value?.shift} />
</ToggleButtonGroup> </ToggleButtonGroup>
@ -93,7 +93,7 @@ export default function KeyboardShortcuts({ value, onChange, fields, name }) {
{isMac() && <ToggleCheckButton value="ctrl_is_meta" label={gettext('Cmd')} selected={ctrlValue == 'ctrl_is_meta'} />} {isMac() && <ToggleCheckButton value="ctrl_is_meta" label={gettext('Cmd')} selected={ctrlValue == 'ctrl_is_meta'} />}
</ToggleButtonGroup> </ToggleButtonGroup>
<ToggleButtonGroup value={value?.alt ? ['alt'] : []} onChange={(e, val)=>{ <ToggleButtonGroup value={value?.alt ? ['alt'] : []} onChange={(e, val)=>{
onChangeButton('alt', val.length == 0 ? false : true); onChangeButton('alt', val.length != 0);
}}> }}>
<ToggleCheckButton value="alt" label={isMac() ? gettext('Option') : gettext('Alt')} selected={value?.alt} /> <ToggleCheckButton value="alt" label={isMac() ? gettext('Option') : gettext('Alt')} selected={value?.alt} />
</ToggleButtonGroup> </ToggleButtonGroup>
@ -112,4 +112,4 @@ KeyboardShortcuts.propTypes = {
onChange: PropTypes.func, onChange: PropTypes.func,
fields: PropTypes.array, fields: PropTypes.array,
name: PropTypes.string, name: PropTypes.string,
}; };

View File

@ -6,7 +6,7 @@
// This software is released under the PostgreSQL Licence // This software is released under the PostgreSQL Licence
// //
////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////
import React, { useContext, useEffect } from 'react'; import React, { useContext, useEffect, useMemo } from 'react';
import ReactDataGrid, { Row } from 'react-data-grid'; import ReactDataGrid, { Row } from 'react-data-grid';
import { Box } from '@mui/material'; import { Box } from '@mui/material';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
@ -108,7 +108,7 @@ export function CustomRow({inTest=false, ...props}) {
} }
}, [props.selectedCellIdx]); }, [props.selectedCellIdx]);
if(inTest) { if(inTest) {
return <div data-test='test-div' tabIndex={0} onKeyDown={handleKeyDown}></div>; return <div data-test='test-div' tabIndex={-1} onKeyDown={handleKeyDown}></div>;
} }
const onRowClick = (...args)=>{ const onRowClick = (...args)=>{
gridUtils.onItemClick?.(props.rowIdx); gridUtils.onItemClick?.(props.rowIdx);
@ -135,8 +135,9 @@ export default function PgReactDataGrid({gridRef, className, hasSelectColumn=tru
hasSelectColumn && finalClassName.push('ReactGrid-hasSelectColumn'); hasSelectColumn && finalClassName.push('ReactGrid-hasSelectColumn');
props.enableCellSelect && finalClassName.push('ReactGrid-cellSelection'); props.enableCellSelect && finalClassName.push('ReactGrid-cellSelection');
finalClassName.push(className); finalClassName.push(className);
const valObj = useMemo(() => ({onItemEnter, onItemSelect, onItemClick}), [onItemEnter, onItemSelect, onItemClick]);
return ( return (
<GridContextUtils.Provider value={{onItemEnter, onItemSelect, onItemClick}}> <GridContextUtils.Provider value={valObj}>
<StyledReactDataGrid <StyledReactDataGrid
ref={gridRef} ref={gridRef}
className={finalClassName.join(' ')} className={finalClassName.join(' ')}

View File

@ -120,7 +120,7 @@ export default function Privilege({value, onChange, controlProps}) {
return ( return (
<Root> <Root>
<InputText value={textValue} readOnly/> <InputText value={textValue} readOnly/>
<table className={'Privilege-table priv-table'} tabIndex="0"> <table className={'Privilege-table priv-table'} tabIndex="-1">
{(realVal.length > 1) && <thead> {(realVal.length > 1) && <thead>
<tr> <tr>
<td className='Privilege-tableCell'> <td className='Privilege-tableCell'>

View File

@ -6,7 +6,7 @@
// This software is released under the PostgreSQL Licence // This software is released under the PostgreSQL Licence
// //
////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////
import {useRef, useEffect, useState, useCallback, useLayoutEffect} from 'react'; import React, {useRef, useEffect, useState, useCallback, useLayoutEffect} from 'react';
import moment from 'moment'; import moment from 'moment';
import { isMac } from './keyboard_shortcuts'; import { isMac } from './keyboard_shortcuts';
@ -205,3 +205,7 @@ export function useWindowSize() {
}, []); }, []);
return size; return size;
} }
export function useForceUpdate() {
return React.useReducer(() => ({}), {})[1];
}

View File

@ -61,7 +61,7 @@ export default function LayoutIframeTab({target, src, children}) {
if(r) setIframeTarget(r.querySelector('#'+target)); if(r) setIframeTarget(r.querySelector('#'+target));
}} container={document.querySelector('#layout-portal')}> }} container={document.querySelector('#layout-portal')}>
{src ? {src ?
<iframe src={src} id={target} style={{position: 'fixed', border: 0}} />: <iframe src={src} title=" " id={target} style={{position: 'fixed', border: 0}} />:
<Frame src={src} id={target} style={{position: 'fixed', border: 0}}> <Frame src={src} id={target} style={{position: 'fixed', border: 0}}>
{children} {children}
</Frame> </Frame>

View File

@ -592,7 +592,7 @@ export function pgHandleItemError(error, args) {
export function fullHexColor(shortHex) { export function fullHexColor(shortHex) {
if(shortHex?.length == 4) { if(shortHex?.length == 4) {
return shortHex.replace(RegExp('#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])'), '#$1$1$2$2$3$3').toUpperCase(); return shortHex.replace(/#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])/, '#$1$1$2$2$3$3').toUpperCase();
} }
return shortHex; return shortHex;
} }

View File

@ -315,16 +315,7 @@ export default function DebuggerArgumentComponent({ debuggerInfo, restartDebug,
let myObj = []; let myObj = [];
for (let i = 0; i < argType.length; i++) { for (let i = 0; i < argType.length; i++) {
let useDefValue = checkIsDefault(defValList[i]); let useDefValue = checkIsDefault(defValList[i]);
if (debuggerInfo['proargmodes'] == null) { if (debuggerInfo['proargmodes'] == null || (argMode?.[i] == 'i' || argMode?.[i] == 'b' || (isEdbProc && argMode?.[i] == 'o'))) {
myObj.push({
'name': myargname[i],
'type': argType[i],
'use_default': useDefValue,
'default_value': defValList[i],
'disable_use_default': defValList[i] == DEBUGGER_ARGS.NO_DEFAULT_VALUE,
});
} else if (argMode && (argMode[i] == 'i' || argMode[i] == 'b' ||
(isEdbProc && argMode[i] == 'o'))) {
myObj.push({ myObj.push({
'name': myargname[i], 'name': myargname[i],
'type': argType[i], 'type': argType[i],

View File

@ -141,10 +141,10 @@ export default class ERDTool extends React.Component {
this.eventBus = new EventBus(); this.eventBus = new EventBus();
_.bindAll(this, ['onLoadDiagram', 'onSaveDiagram', 'onSaveAsDiagram', 'onSQLClick', _.bindAll(this, ['onLoadDiagram', 'onSaveDiagram', 'onSQLClick',
'onImageClick', 'onAddNewNode', 'onEditTable', 'onCloneNode', 'onDeleteNode', 'onNoteClick', 'onImageClick', 'onAddNewNode', 'onEditTable', 'onCloneNode', 'onDeleteNode', 'onNoteClick',
'onNoteClose', 'onOneToManyClick', 'onManyToManyClick', 'onAutoDistribute', 'onDetailsToggle', 'onNoteClose', 'onOneToManyClick', 'onManyToManyClick', 'onAutoDistribute', 'onDetailsToggle',
'onChangeColors', 'onHelpClick', 'onDropNode', 'onBeforeUnload', 'onNotationChange', 'onChangeColors', 'onDropNode', 'onBeforeUnload', 'onNotationChange',
]); ]);
this.diagram.zoomToFit = this.diagram.zoomToFit.bind(this.diagram); this.diagram.zoomToFit = this.diagram.zoomToFit.bind(this.diagram);
@ -568,16 +568,6 @@ export default class ERDTool extends React.Component {
this.setState({cardinality_notation: e.value}); this.setState({cardinality_notation: e.value});
} }
onHelpClick() {
let url = url_for('help.static', {'filename': 'erd_tool.html'});
if (this.props.pgWindow) {
this.props.pgWindow.open(url, 'pgadmin_help');
}
else {
window.open(url, 'pgadmin_help');
}
}
onLoadDiagram() { onLoadDiagram() {
const params = { const params = {
'supported_types': ['*','pgerd'], // file types allowed 'supported_types': ['*','pgerd'], // file types allowed
@ -622,10 +612,6 @@ export default class ERDTool extends React.Component {
} }
} }
onSaveAsDiagram() {
this.onSaveDiagram(true);
}
saveFile(fileName) { saveFile(fileName) {
this.setLoading(gettext('Saving...')); this.setLoading(gettext('Saving...'));
this.apiObj.post(url_for('sqleditor.save_file'), { this.apiObj.post(url_for('sqleditor.save_file'), {
@ -945,8 +931,6 @@ export default class ERDTool extends React.Component {
} }
} }
//export default withStyles(styles)(ERDTool);
ERDTool.propTypes = { ERDTool.propTypes = {
params:PropTypes.shape({ params:PropTypes.shape({
trans_id: PropTypes.number.isRequired, trans_id: PropTypes.number.isRequired,
@ -965,7 +949,6 @@ ERDTool.propTypes = {
pgAdmin: PropTypes.object.isRequired, pgAdmin: PropTypes.object.isRequired,
panelId: PropTypes.string, panelId: PropTypes.string,
panelDocker: PropTypes.object, panelDocker: PropTypes.object,
classes: PropTypes.object,
isTest: PropTypes.bool, isTest: PropTypes.bool,
}; };

View File

@ -169,7 +169,7 @@ export class TableNodeModel extends DefaultNodeModel {
function RowIcon({icon}) { function RowIcon({icon}) {
return ( return (
<div style={{padding: '0rem 0.125rem'}}> <div style={{padding: '0rem 0.125rem'}}>
<img src={icon} crossOrigin="anonymous"/> <img src={icon} alt="" crossOrigin="anonymous"/>
</div> </div>
); );
} }
@ -275,7 +275,7 @@ export class TableNodeWidget extends React.Component {
if(col.attlen) { if(col.attlen) {
cltype += '('+ col.attlen + (col.attprecision ? ',' + col.attprecision : '') +')'; cltype += '('+ col.attlen + (col.attprecision ? ',' + col.attprecision : '') +')';
} }
return ( return (
<Box className='TableNode-columnSection' key={col.attnum} data-test="column-row"> <Box className='TableNode-columnSection' key={col.attnum} data-test="column-row">
<Box marginRight="auto" padding="0" minHeight="0" display="flex" alignItems="center"> <Box marginRight="auto" padding="0" minHeight="0" display="flex" alignItems="center">
@ -364,8 +364,7 @@ export class TableNodeWidget extends React.Component {
TableNodeWidget.propTypes = { TableNodeWidget.propTypes = {
node: PropTypes.instanceOf(TableNodeModel), node: PropTypes.instanceOf(TableNodeModel),
engine: PropTypes.instanceOf(DiagramEngine), engine: PropTypes.instanceOf(DiagramEngine)
classes: PropTypes.object,
}; };
export class TableNodeFactory extends AbstractReactFactory { export class TableNodeFactory extends AbstractReactFactory {

View File

@ -55,7 +55,8 @@ class ERDTableView(BaseTableView, DataTypeReader):
@BaseTableView.check_precondition @BaseTableView.check_precondition
def traverse_related_tables(self, did=None, sid=None, scid=None, def traverse_related_tables(self, did=None, sid=None, scid=None,
tid=None, related={}, maxdepth=0, currdepth=0): tid=None, related=None, maxdepth=0,
currdepth=0):
status, res = \ status, res = \
BaseTableView.fetch_tables(self, sid, did, scid, tid=tid, BaseTableView.fetch_tables(self, sid, did, scid, tid=tid,
@ -64,6 +65,9 @@ class ERDTableView(BaseTableView, DataTypeReader):
if not status: if not status:
return status, res return status, res
if related is None:
related = list()
related[tid] = res related[tid] = res
# Max depth limit reached # Max depth limit reached
if currdepth == maxdepth: if currdepth == maxdepth:

View File

@ -35,7 +35,7 @@ const StyledBox = styled(Box)(({theme}) => ({
fontSize: '13px', fontSize: '13px',
'--rdg-background-color': theme.palette.default.main, '--rdg-background-color': theme.palette.default.main,
'--rdg-selection-color': theme.palette.primary.main, '--rdg-selection-color': theme.palette.primary.main,
'& .ResultGridComponent-gridPanel': { '& .ResultGridComponent-gridPanel': {
'--rdg-background-color': theme.palette.default.main + ' !important', '--rdg-background-color': theme.palette.default.main + ' !important',
'&.ResultGridComponent-grid': { '&.ResultGridComponent-grid': {
fontSize: '13px', fontSize: '13px',
@ -256,8 +256,7 @@ CellExpanderFormatter.propTypes = {
isCellSelected: PropTypes.bool, isCellSelected: PropTypes.bool,
expanded: PropTypes.bool, expanded: PropTypes.bool,
onCellExpand: PropTypes.func, onCellExpand: PropTypes.func,
filterParams: PropTypes.array, filterParams: PropTypes.array
classes: PropTypes.object
}; };

View File

@ -78,9 +78,7 @@ export function SchemaDiffButtonComponent({ sourceData, targetData, selectedRowI
useEffect(() => { useEffect(() => {
let isDisableComp = true; let isDisableComp = true;
if (sourceData.sid != null && sourceData.did != null && targetData.sid != null && targetData.did != null) { if (sourceData.sid != null && sourceData.did != null && targetData.sid != null && targetData.did != null) {
if ((sourceData.scid != null && targetData.scid == null) || (sourceData.scid == null && targetData.scid != null)) { if (!((sourceData.scid != null && targetData.scid == null) || (sourceData.scid == null && targetData.scid != null))) {
isDisableComp = true;
} else {
isDisableComp = false; isDisableComp = false;
} }
} }

View File

@ -169,7 +169,7 @@ const FIXED_PREF = {
export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedNodeInfo, qtPanelDocker, qtPanelId, eventBusObj}) { export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedNodeInfo, qtPanelDocker, qtPanelId, eventBusObj}) {
const containerRef = React.useRef(null); const containerRef = React.useRef(null);
const preferencesStore = usePreferences(); const preferencesStore = usePreferences();
const [qtState, _setQtState] = useState({ const [qtState, setQtState] = useState({
preferences: { preferences: {
browser: preferencesStore.getPreferencesForModule('browser'), browser: preferencesStore.getPreferencesForModule('browser'),
sqleditor: {...preferencesStore.getPreferencesForModule('sqleditor'), ...FIXED_PREF}, sqleditor: {...preferencesStore.getPreferencesForModule('sqleditor'), ...FIXED_PREF},
@ -211,8 +211,8 @@ export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedN
}); });
const [selectedText, setSelectedText] = useState(''); const [selectedText, setSelectedText] = useState('');
const setQtState = (state)=>{ const setQtStatePartial = (state)=>{
_setQtState((prev)=>({...prev,...evalFunc(null, state, prev)})); setQtState((prev)=>({...prev,...evalFunc(null, state, prev)}));
}; };
const isDirtyRef = useRef(false); // usefull when conn change. const isDirtyRef = useRef(false); // usefull when conn change.
const eventBus = useRef(eventBusObj || (new EventBus())); const eventBus = useRef(eventBusObj || (new EventBus()));
@ -233,12 +233,12 @@ export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedN
try { try {
let {data: respData} = await fetchConnectionStatus(api, qtState.params.trans_id); let {data: respData} = await fetchConnectionStatus(api, qtState.params.trans_id);
if(respData.data) { if(respData.data) {
setQtState({ setQtStatePartial({
connected: true, connected: true,
connection_status: respData.data.status, connection_status: respData.data.status,
}); });
} else { } else {
setQtState({ setQtStatePartial({
connected: false, connected: false,
connection_status: null, connection_status: null,
connection_status_msg: gettext('An unexpected error occurred - ensure you are logged into the application.') connection_status_msg: gettext('An unexpected error occurred - ensure you are logged into the application.')
@ -249,7 +249,7 @@ export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedN
} }
} catch (error) { } catch (error) {
console.error(error); console.error(error);
setQtState({ setQtStatePartial({
connected: false, connected: false,
connection_status: null, connection_status: null,
connection_status_msg: parseApiError(error), connection_status_msg: parseApiError(error),
@ -320,11 +320,11 @@ export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedN
api.get(qtState.params.query_url) api.get(qtState.params.query_url)
.then((res) => { .then((res) => {
eventBus.current.fireEvent(QUERY_TOOL_EVENTS.EDITOR_SET_SQL, res.data); eventBus.current.fireEvent(QUERY_TOOL_EVENTS.EDITOR_SET_SQL, res.data);
setQtState({ editor_disabled: false }); setQtStatePartial({ editor_disabled: false });
}) })
.catch((err) => { .catch((err) => {
eventBus.current.fireEvent(QUERY_TOOL_EVENTS.HANDLE_API_ERROR, err); eventBus.current.fireEvent(QUERY_TOOL_EVENTS.HANDLE_API_ERROR, err);
setQtState({ editor_disabled: true }); setQtStatePartial({ editor_disabled: true });
}); });
} else if (qtState.params.sql_id) { } else if (qtState.params.sql_id) {
let sqlValue = localStorage.getItem(qtState.params.sql_id); let sqlValue = localStorage.getItem(qtState.params.sql_id);
@ -332,9 +332,9 @@ export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedN
if (sqlValue) { if (sqlValue) {
eventBus.current.fireEvent(QUERY_TOOL_EVENTS.EDITOR_SET_SQL, sqlValue); eventBus.current.fireEvent(QUERY_TOOL_EVENTS.EDITOR_SET_SQL, sqlValue);
} }
setQtState({ editor_disabled: false }); setQtStatePartial({ editor_disabled: false });
} else { } else {
setQtState({ editor_disabled: false }); setQtStatePartial({ editor_disabled: false });
} }
}; };
@ -363,7 +363,7 @@ export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedN
dbname: selectedConn.database_name dbname: selectedConn.database_name
} : JSON.stringify(qtState.params.sql_filter)) } : JSON.stringify(qtState.params.sql_filter))
.then(()=>{ .then(()=>{
setQtState({ setQtStatePartial({
connected: true, connected: true,
connected_once: true, connected_once: true,
obtaining_conn: false, obtaining_conn: false,
@ -379,7 +379,7 @@ export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedN
initializeQueryTool(); initializeQueryTool();
}) })
.catch((kberr)=>{ .catch((kberr)=>{
setQtState({ setQtStatePartial({
connected: false, connected: false,
obtaining_conn: false, obtaining_conn: false,
}); });
@ -389,14 +389,14 @@ export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedN
connectServerModal(error.response?.data?.result, (passwordData)=>{ connectServerModal(error.response?.data?.result, (passwordData)=>{
initializeQueryTool(passwordData.password); initializeQueryTool(passwordData.password);
}, ()=>{ }, ()=>{
setQtState({ setQtStatePartial({
connected: false, connected: false,
obtaining_conn: false, obtaining_conn: false,
connection_status_msg: gettext('Not Connected'), connection_status_msg: gettext('Not Connected'),
}); });
}); });
} else { } else {
setQtState({ setQtStatePartial({
connected: false, connected: false,
obtaining_conn: false, obtaining_conn: false,
}); });
@ -414,7 +414,7 @@ export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedN
}); });
eventBus.current.registerListener(QUERY_TOOL_EVENTS.SET_CONNECTION_STATUS, (status)=>{ eventBus.current.registerListener(QUERY_TOOL_EVENTS.SET_CONNECTION_STATUS, (status)=>{
setQtState({connection_status: status}); setQtStatePartial({connection_status: status});
}); });
eventBus.current.registerListener(QUERY_TOOL_EVENTS.FORCE_CLOSE_PANEL, ()=>{ eventBus.current.registerListener(QUERY_TOOL_EVENTS.FORCE_CLOSE_PANEL, ()=>{
@ -431,7 +431,7 @@ export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedN
qtPanelDocker.eventBus.registerListener(LAYOUT_EVENTS.ACTIVE, _.debounce((currentTabId)=>{ qtPanelDocker.eventBus.registerListener(LAYOUT_EVENTS.ACTIVE, _.debounce((currentTabId)=>{
/* Focus the appropriate panel on visible */ /* Focus the appropriate panel on visible */
if(qtPanelId == currentTabId) { if(qtPanelId == currentTabId) {
setQtState({is_visible: true}); setQtStatePartial({is_visible: true});
if(docker.current.isTabVisible(PANELS.QUERY)) { if(docker.current.isTabVisible(PANELS.QUERY)) {
docker.current.focus(PANELS.QUERY); docker.current.focus(PANELS.QUERY);
@ -441,23 +441,23 @@ export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedN
eventBus.current.fireEvent(QUERY_TOOL_EVENTS.GOTO_LAST_SCROLL); eventBus.current.fireEvent(QUERY_TOOL_EVENTS.GOTO_LAST_SCROLL);
} else { } else {
setQtState({is_visible: false}); setQtStatePartial({is_visible: false});
} }
}, 100)); }, 100));
/* If the tab or window is not visible, applicable for open in new tab */ /* If the tab or window is not visible, applicable for open in new tab */
document.addEventListener('visibilitychange', function() { document.addEventListener('visibilitychange', function() {
if(document.hidden) { if(document.hidden) {
setQtState({is_visible: false}); setQtStatePartial({is_visible: false});
} else { } else {
setQtState({is_visible: true}); setQtStatePartial({is_visible: true});
} }
}); });
}, []); }, []);
useEffect(() => usePreferences.subscribe( useEffect(() => usePreferences.subscribe(
state => { state => {
setQtState({preferences: { setQtStatePartial({preferences: {
browser: state.getPreferencesForModule('browser'), browser: state.getPreferencesForModule('browser'),
sqleditor: {...state.getPreferencesForModule('sqleditor'), ...FIXED_PREF}, sqleditor: {...state.getPreferencesForModule('sqleditor'), ...FIXED_PREF},
graphs: state.getPreferencesForModule('graphs'), graphs: state.getPreferencesForModule('graphs'),
@ -550,7 +550,7 @@ export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedN
useEffect(()=>{ useEffect(()=>{
const fileDone = (fileName, success=true)=>{ const fileDone = (fileName, success=true)=>{
if(success) { if(success) {
setQtState({ setQtStatePartial({
current_file: fileName, current_file: fileName,
}); });
isDirtyRef.current = false; isDirtyRef.current = false;
@ -648,7 +648,7 @@ export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedN
let currConnected = qtState.connected; let currConnected = qtState.connected;
const selectConn = (newConnData, connected=false, obtainingConn=true)=>{ const selectConn = (newConnData, connected=false, obtainingConn=true)=>{
setQtState((prevQtState)=>{ setQtStatePartial((prevQtState)=>{
let newConnList = [...prevQtState.connection_list]; let newConnList = [...prevQtState.connection_list];
/* If new, add to the list */ /* If new, add to the list */
if(isNew) { if(isNew) {
@ -687,7 +687,7 @@ export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedN
if(isNew) { if(isNew) {
selectConn(connectionData); selectConn(connectionData);
} }
setQtState((prev)=>{ setQtStatePartial((prev)=>{
return { return {
params: { params: {
...prev.params, ...prev.params,
@ -807,7 +807,7 @@ export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedN
id: 'manage-macros', id: 'manage-macros',
title: gettext('Manage Macros'), title: gettext('Manage Macros'),
content: <MacrosDialog onSave={(newMacros)=>{ content: <MacrosDialog onSave={(newMacros)=>{
setQtState((prev)=>{ setQtStatePartial((prev)=>{
return { return {
params: { params: {
...prev.params, ...prev.params,
@ -835,7 +835,7 @@ export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedN
) )
.then(({ data: respData }) => { .then(({ data: respData }) => {
const filteredData = respData.filter(m => Boolean(m.name)); const filteredData = respData.filter(m => Boolean(m.name));
setQtState(prev => ({ setQtStatePartial(prev => ({
...prev, ...prev,
params: { params: {
...prev.params, ...prev.params,
@ -877,7 +877,7 @@ export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedN
preferences: qtState.preferences, preferences: qtState.preferences,
mainContainerRef: containerRef, mainContainerRef: containerRef,
editor_disabled: qtState.editor_disabled, editor_disabled: qtState.editor_disabled,
toggleQueryTool: () => setQtState((prev)=>{ toggleQueryTool: () => setQtStatePartial((prev)=>{
return { return {
...prev, ...prev,
params: { params: {
@ -888,7 +888,7 @@ export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedN
}), }),
updateTitle: (title) => { updateTitle: (title) => {
setPanelTitle(qtPanelDocker, qtPanelId, title, qtState, isDirtyRef.current); setPanelTitle(qtPanelDocker, qtPanelId, title, qtState, isDirtyRef.current);
setQtState((prev) => { setQtStatePartial((prev) => {
// Update connection Title // Update connection Title
let newConnList = [...prev.connection_list]; let newConnList = [...prev.connection_list];
newConnList.forEach((conn) => { newConnList.forEach((conn) => {

View File

@ -132,7 +132,7 @@ function SelectAllHeaderRenderer({onAllRowsSelectionChange, isCellSelected}) {
}, [isCellSelected]); }, [isCellSelected]);
return <div ref={cellRef} style={{width: '100%', height: '100%'}} onClick={onClick} return <div ref={cellRef} style={{width: '100%', height: '100%'}} onClick={onClick}
tabIndex="0" onKeyDown={getCopyShortcutHandler(dataGridExtras.handleCopy)}></div>; tabIndex="-1" onKeyDown={getCopyShortcutHandler(dataGridExtras.handleCopy)}></div>;
} }
SelectAllHeaderRenderer.propTypes = { SelectAllHeaderRenderer.propTypes = {
onAllRowsSelectionChange: PropTypes.func, onAllRowsSelectionChange: PropTypes.func,

View File

@ -89,7 +89,7 @@ export function MainToolBar({containerRef, onFilterClick, onManageMacros, onAddT
if(!queryToolCtx.preferences.sqleditor.underline_query_cursor && queryToolCtx.preferences.sqleditor.underlined_query_execute_warning){ if(!queryToolCtx.preferences.sqleditor.underline_query_cursor && queryToolCtx.preferences.sqleditor.underlined_query_execute_warning){
eventBus.fireEvent(QUERY_TOOL_EVENTS.EXECUTE_CURSOR_WARNING); eventBus.fireEvent(QUERY_TOOL_EVENTS.EXECUTE_CURSOR_WARNING);
} else { } else {
eventBus.fireEvent(QUERY_TOOL_EVENTS.TRIGGER_EXECUTION,true); eventBus.fireEvent(QUERY_TOOL_EVENTS.TRIGGER_EXECUTION, null, '', true);
} }
}, [queryToolCtx.preferences.sqleditor]); }, [queryToolCtx.preferences.sqleditor]);
const executeScript = useCallback(()=>{ const executeScript = useCallback(()=>{
@ -100,7 +100,7 @@ export function MainToolBar({containerRef, onFilterClick, onManageMacros, onAddT
}, []); }, []);
const explain = useCallback((analyze=false)=>{ const explain = useCallback((analyze=false)=>{
eventBus.fireEvent(QUERY_TOOL_EVENTS.TRIGGER_EXECUTION, false, { eventBus.fireEvent(QUERY_TOOL_EVENTS.TRIGGER_EXECUTION, {
format: 'json', format: 'json',
analyze: analyze, analyze: analyze,
verbose: Boolean(checkedMenuItems['explain_verbose']), verbose: Boolean(checkedMenuItems['explain_verbose']),
@ -282,7 +282,7 @@ export function MainToolBar({containerRef, onFilterClick, onManageMacros, onAddT
eventBus.fireEvent(QUERY_TOOL_EVENTS.EXECUTION_START, 'ROLLBACK;', null, true); eventBus.fireEvent(QUERY_TOOL_EVENTS.EXECUTION_START, 'ROLLBACK;', null, true);
}; };
const executeMacro = (m)=>{ const executeMacro = (m)=>{
eventBus.fireEvent(QUERY_TOOL_EVENTS.TRIGGER_EXECUTION,false, null, m.sql); eventBus.fireEvent(QUERY_TOOL_EVENTS.TRIGGER_EXECUTION, null, m.sql);
}; };
const onLimitChange=(e)=>{ const onLimitChange=(e)=>{
setLimit(e.target.value); setLimit(e.target.value);

View File

@ -136,11 +136,11 @@ export default function Query({onTextSelect}) {
} }
}; };
const triggerExecution = (executeCursor=false, explainObject, macroSQL)=>{ const triggerExecution = (explainObject, macroSQL, executeCursor=false)=>{
if(queryToolCtx.params.is_query_tool) { if(queryToolCtx.params.is_query_tool) {
let external = null; let external = null;
let query = editor.current?.getSelection(); let query = editor.current?.getSelection();
if(!_.isUndefined(macroSQL)) { if(!_.isEmpty(macroSQL)) {
const regex = /\$SELECTION\$/gi; const regex = /\$SELECTION\$/gi;
query = macroSQL.replace(regex, query); query = macroSQL.replace(regex, query);
external = true; external = true;
@ -445,7 +445,7 @@ export default function Query({onTextSelect}) {
text={query} text={query}
onContinue={(formData)=>{ onContinue={(formData)=>{
preferencesStore.setPreference(formData); preferencesStore.setPreference(formData);
eventBus.fireEvent(QUERY_TOOL_EVENTS.TRIGGER_EXECUTION,true); eventBus.fireEvent(QUERY_TOOL_EVENTS.TRIGGER_EXECUTION, null, '', true);
}} }}
onClose={()=>{ onClose={()=>{
closeModal?.(); closeModal?.();

View File

@ -15,7 +15,7 @@ import { SaveDataIcon, CommitIcon, RollbackIcon, ViewDataIcon } from '../../../.
import { InputSwitch } from '../../../../../../static/js/components/FormComponents'; import { InputSwitch } from '../../../../../../static/js/components/FormComponents';
import CodeMirror from '../../../../../../static/js/components/ReactCodeMirror'; import CodeMirror from '../../../../../../static/js/components/ReactCodeMirror';
import { DefaultButton } from '../../../../../../static/js/components/Buttons'; import { DefaultButton } from '../../../../../../static/js/components/Buttons';
import { useDelayedCaller } from '../../../../../../static/js/custom_hooks'; import { useDelayedCaller, useForceUpdate } from '../../../../../../static/js/custom_hooks';
import Loader from 'sources/components/Loader'; import Loader from 'sources/components/Loader';
import { LayoutDockerContext, LAYOUT_EVENTS } from '../../../../../../static/js/helpers/Layout'; import { LayoutDockerContext, LAYOUT_EVENTS } from '../../../../../../static/js/helpers/Layout';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
@ -377,7 +377,7 @@ export function QueryHistory() {
const eventBus = React.useContext(QueryToolEventsContext); const eventBus = React.useContext(QueryToolEventsContext);
const [selectedItemKey, setSelectedItemKey] = React.useState(1); const [selectedItemKey, setSelectedItemKey] = React.useState(1);
const [showInternal, setShowInternal] = React.useState(true); const [showInternal, setShowInternal] = React.useState(true);
const [, setRefresh] = React.useState(false); const forceUpdate = useForceUpdate();
const [loaderText, setLoaderText] = React.useState(''); const [loaderText, setLoaderText] = React.useState('');
const selectedEntry = qhu.current.getEntry(selectedItemKey); const selectedEntry = qhu.current.getEntry(selectedItemKey);
const layoutDocker = useContext(LayoutDockerContext); const layoutDocker = useContext(LayoutDockerContext);
@ -425,7 +425,7 @@ export function QueryHistory() {
}; };
} }
qhu.current.addEntry(h); qhu.current.addEntry(h);
setRefresh((prev)=>!prev); forceUpdate();
}; };
listRef.current?.focus(); listRef.current?.focus();

View File

@ -87,13 +87,12 @@ def get_user_macros():
data = [] data = []
for m in macros: for m in macros:
key_label = ( key_label = ''
'Ctrl + ' + str(m[5]) if m[4] is True:
if m[4] is True key_label = 'Ctrl + ' + str(m[5])
else 'Alt + ' + str(m[5]) elif m[5] is not None:
if m[5] is not None key_label = 'Alt + ' + str(m[5])
else ''
)
data.append({'id': m[0], 'name': m[1], 'mid': m[2], 'key': m[5], data.append({'id': m[0], 'name': m[1], 'mid': m[2], 'key': m[5],
'key_label': key_label, 'alt': 1 if m[3] else 0, 'key_label': key_label, 'alt': 1 if m[3] else 0,
'control': 1 if m[4] else 0, 'key_code': m[6], 'control': 1 if m[4] else 0, 'key_code': m[6],

View File

@ -54,7 +54,6 @@ class StartRunningQuery:
can_edit = False can_edit = False
can_filter = False can_filter = False
notifies = None notifies = None
trans_status = None
status = -1 status = -1
result = None result = None
if transaction_object is not None and session_obj is not None: if transaction_object is not None and session_obj is not None:
@ -103,8 +102,6 @@ class StartRunningQuery:
# Get the notifies # Get the notifies
notifies = conn.get_notifies() notifies = conn.get_notifies()
trans_status = conn.transaction_status()
else: else:
status = False status = False
result = gettext( result = gettext(
@ -161,10 +158,10 @@ class StartRunningQuery:
self.logger.error(e) self.logger.error(e)
return internal_server_error(errormsg=str(e)) return internal_server_error(errormsg=str(e))
_thread = pgAdminThread(target=asyn_exec_query, _thread = QueryThread(target=asyn_exec_query,
args=(conn, sql, trans_obj, is_rollback_req, args=(conn, sql, trans_obj, is_rollback_req,
current_app._get_current_object()) current_app._get_current_object())
) )
_thread.start() _thread.start()
_native_id = _thread.native_id if hasattr(_thread, 'native_id' _native_id = _thread.native_id if hasattr(_thread, 'native_id'
) else _thread.ident ) else _thread.ident
@ -215,7 +212,7 @@ class StartRunningQuery:
return grid_data[str(transaction_id)] return grid_data[str(transaction_id)]
class pgAdminThread(Thread): class QueryThread(Thread):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.app = current_app._get_current_object() self.app = current_app._get_current_object()

View File

@ -174,10 +174,10 @@ def register_binary_typecasters(connection):
# The new classes can be registered globally, on a connection, on a cursor # The new classes can be registered globally, on a connection, on a cursor
connection.adapters.register_loader(17, connection.adapters.register_loader(17,
pgAdminByteaLoader) ByteaLoader)
connection.adapters.register_loader(1001, connection.adapters.register_loader(1001,
pgAdminByteaLoader) ByteaLoader)
def register_array_to_string_typecasters(connection=None): def register_array_to_string_typecasters(connection=None):
@ -194,7 +194,7 @@ def register_array_to_string_typecasters(connection=None):
TextLoaderpgAdmin) TextLoaderpgAdmin)
class pgAdminInetLoader(InetLoader): class InetLoader(InetLoader):
def load(self, data): def load(self, data):
if isinstance(data, memoryview): if isinstance(data, memoryview):
data = bytes(data) data = bytes(data)
@ -206,11 +206,11 @@ class pgAdminInetLoader(InetLoader):
# The new classes can be registered globally, on a connection, on a cursor # The new classes can be registered globally, on a connection, on a cursor
psycopg.adapters.register_loader("inet", pgAdminInetLoader) psycopg.adapters.register_loader("inet", InetLoader)
psycopg.adapters.register_loader("cidr", pgAdminInetLoader) psycopg.adapters.register_loader("cidr", InetLoader)
class pgAdminByteaLoader(Loader): class ByteaLoader(Loader):
def load(self, data): def load(self, data):
return 'binary data' if data is not None else None return 'binary data' if data is not None else None

View File

@ -148,7 +148,7 @@ def suggest_type(full_text, text_before_cursor):
return suggest_based_on_last_token(stmt.last_token, stmt) return suggest_based_on_last_token(stmt.last_token, stmt)
named_query_regex = re.compile(r"^\s*\\ns\s+[A-z0-9\-_]+\s+") named_query_regex = re.compile(r"^\s*\\ns\s+[A-z0-9\-]+\s+")
def _strip_named_query(txt): def _strip_named_query(txt):
@ -163,7 +163,7 @@ def _strip_named_query(txt):
return txt return txt
function_body_pattern = re.compile(r"(\$.*?\$)([\s\S]*?)\1", re.M) function_body_pattern = re.compile(r"(\$[^$]*\$)([\s\S]*?)\1", re.M)
def _find_function_body(text): def _find_function_body(text):

View File

@ -77,8 +77,6 @@ class KeyboardShortcutFeatureTest(BaseFeatureTest):
) )
) )
assert True, "Keyboard shortcut change is unsuccessful."
print("OK", file=sys.stderr) print("OK", file=sys.stderr)
def _update_preferences(self): def _update_preferences(self):

View File

@ -60,7 +60,7 @@ class PGUtilitiesBackupFeatureTest(BaseFeatureTest):
self._update_preferences() self._update_preferences()
db_id = test_utils.create_database(self.server, self.database_name) db_id = test_utils.create_database(self.server, self.database_name)
if not db_id: if not db_id:
self.assertTrue(False, "Database {} is not " self.assertEqual(0, 1, "Database {} is not "
"created".format(self.database_name)) "created".format(self.database_name))
self.page.add_server(self.server) self.page.add_server(self.server)

View File

@ -132,9 +132,10 @@ CREATE TABLE public.nonintpkey
self._perform_test_for_table('nonintpkey', data_local) self._perform_test_for_table('nonintpkey', data_local)
except Exception: except Exception:
traceback.print_exc() traceback.print_exc()
self.assertTrue(False, 'Exception occurred in run test ' self.assertEqual(0, 1,
'Validate Insert, Update operations in ' 'Exception occurred in run test Validate '
'View/Edit data with given test data') 'Insert, Update operations in View/Edit data with'
' given test data')
def after(self): def after(self):
self.page.remove_server(self.server) self.page.remove_server(self.server)

View File

@ -7,7 +7,7 @@
// //
////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////
import React, { useRef } from 'react'; import React, { useRef, useMemo } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import {DebuggerContext, DebuggerEventsContext} from '../../../pgadmin/tools/debugger/static/js/components/DebuggerComponent'; import {DebuggerContext, DebuggerEventsContext} from '../../../pgadmin/tools/debugger/static/js/components/DebuggerComponent';
@ -15,8 +15,9 @@ import { withBrowser } from '../genericFunctions';
function MockDebuggerComponent({value, eventsvalue, children}) { function MockDebuggerComponent({value, eventsvalue, children}) {
const containerRef = useRef(); const containerRef = useRef();
const valObj = useMemo(() => ({...value, containerRef: containerRef}), [value]);
return ( return (
<DebuggerContext.Provider value={{...value, containerRef: containerRef}}> <DebuggerContext.Provider value={valObj}>
<DebuggerEventsContext.Provider value={eventsvalue}> <DebuggerEventsContext.Provider value={eventsvalue}>
<div ref={containerRef} style={{width: '100%', height: '100%'}}> <div ref={containerRef} style={{width: '100%', height: '100%'}}>
{children} {children}

View File

@ -190,8 +190,8 @@ describe('ERDCore', ()=>{
it('serialize', ()=>{ it('serialize', ()=>{
let retVal = erdCoreObj.serialize(); let retVal = erdCoreObj.serialize();
expect(Object.prototype.hasOwnProperty.call(retVal,'version')).toBeTruthy(); expect(Object.hasOwn(retVal,'version')).toBeTruthy();
expect(Object.prototype.hasOwnProperty.call(retVal,'data')).toBeTruthy(); expect(Object.hasOwn(retVal,'data')).toBeTruthy();
expect(erdEngine.getModel().serialize).toHaveBeenCalled(); expect(erdEngine.getModel().serialize).toHaveBeenCalled();
}); });

View File

@ -7,13 +7,6 @@
// //
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
// define(function () {
// return {
// 'id': 'pgadmin4@pgadmin.org',
// 'current_auth_source': 'internal'
// };
// });
module.exports = { module.exports = {
'id': 'pgadmin4@pgadmin.org', 'id': 'pgadmin4@pgadmin.org',
'current_auth_source': 'internal' 'current_auth_source': 'internal'

View File

@ -25,6 +25,6 @@ export class FakeModel {
} }
toJSON() { toJSON() {
return Object.assign({}, this.values); return {...this.values};
} }
} }

View File

@ -54,8 +54,7 @@ def open_process_details(tester):
time.sleep(3) time.sleep(3)
tester.page.find_by_css_selector( tester.page.find_by_css_selector(
"div[data-test='processes'] " "div[data-test='processes'] "
"div[role='row']:nth-child(1) " "button[data-label='View details']:nth-child(1)").click()
"div[role='cell']:nth-child(3) button").click()
tester.page.wait_for_element_to_disappear( tester.page.wait_for_element_to_disappear(
lambda driver: driver.find_element( lambda driver: driver.find_element(

View File

@ -193,10 +193,7 @@ let webpackShimConfig = {
}, },
isBrowserNode: function(module) { isBrowserNode: function(module) {
if (module.rawRequest === undefined) { return false; } if (module.rawRequest === undefined) { return false; }
if(module.rawRequest.startsWith('pgadmin.node')) { return module.rawRequest.startsWith('pgadmin.node');
return true;
}
return false;
}, },
matchModules: function(module, match_modules) { matchModules: function(module, match_modules) {
if (module.rawRequest === undefined) { return false; } if (module.rawRequest === undefined) { return false; }