Fixed the following SonarQube code smells:

1) Do not use the Array index in keys.
2) Import from the same module should be merged.
3) Mutable variables should not be exported.
4) Variables should not be initialized to undefined.
5) startswith or endswith method should be used.
6) Unwrap this unnecessarily grouped subpattern.

Additionally, addressed many other SonarQube rules.
pull/7575/head
Akshay Joshi 2024-06-12 18:09:06 +05:30
parent 288fd7ed12
commit dea5335ce5
29 changed files with 51 additions and 57 deletions

View File

@ -70,7 +70,7 @@ FROM alpine:latest AS env-builder
# Install dependencies # Install dependencies
COPY requirements.txt / COPY requirements.txt /
RUN apk add --no-cache \ RUN apk add --no-cache \
make \ make \
python3 \ python3 \
py3-pip && \ py3-pip && \
@ -187,7 +187,7 @@ COPY LICENSE /pgadmin4/LICENSE
COPY DEPENDENCIES /pgadmin4/DEPENDENCIES COPY DEPENDENCIES /pgadmin4/DEPENDENCIES
# Install runtime dependencies and configure everything in one RUN step # Install runtime dependencies and configure everything in one RUN step
RUN apk add \ RUN apk add --no-cache \
python3 \ python3 \
py3-pip \ py3-pip \
postfix \ postfix \

View File

@ -14,12 +14,12 @@
{% trans copyright=copyright|e %}<li class="left" style="margin-left: 10px">&#169; Copyright {{ copyright }}.</li>{% endtrans %} {% trans copyright=copyright|e %}<li class="left" style="margin-left: 10px">&#169; Copyright {{ copyright }}.</li>{% endtrans %}
{%- endif %} {%- endif %}
{%- endif %} {%- endif %}
<li class="right" style="margin-right: 10px"><a href="genindex.html" title="General Index" accesskey="I">index</a></li> <li class="right" style="margin-right: 10px"><a href="genindex.html" title="General Index">index</a></li>
{%- if next %} {%- if next %}
<li class="right" ><a href="{{ next.link|e }}" title="{{ next.title|striptags|e }}" accesskey="N">next</a> |</li> <li class="right" ><a href="{{ next.link|e }}" title="{{ next.title|striptags|e }}">next</a> |</li>
{%- endif %} {%- endif %}
{%- if prev %} {%- if prev %}
<li class="right" ><a href="{{ prev.link|e }}" title="{{ prev.title|striptags|e }}" accesskey="P">previous</a> |</li> <li class="right" ><a href="{{ prev.link|e }}" title="{{ prev.title|striptags|e }}">previous</a> |</li>
{%- endif %} {%- endif %}
</ul> </ul>
</div> </div>

View File

@ -212,7 +212,7 @@ function launchPgAdminWindow() {
// https://github.com/nwjs/nw.js/issues/7973 // https://github.com/nwjs/nw.js/issues/7973
pgadminWindow.on('close', function () { pgadminWindow.on('close', function () {
// Resize Window // Resize Window
resizeHeightBy = pgadminWindow.window.outerHeight - pgadminWindow.window.innerHeight; let resizeHeightBy = pgadminWindow.window.outerHeight - pgadminWindow.window.innerHeight;
pgadminWindow.resizeBy(0, -resizeHeightBy); pgadminWindow.resizeBy(0, -resizeHeightBy);
// Remove 'close' event handler, and then close window // Remove 'close' event handler, and then close window
pgadminWindow.removeAllListeners('close'); pgadminWindow.removeAllListeners('close');
@ -554,7 +554,7 @@ function getSubMenu(menuItem) {
if (sub.submenu?.items?.length) { if (sub.submenu?.items?.length) {
sub.submenu.items.forEach((m) => { sub.submenu.items.forEach((m) => {
if (m.type == 'checkbox') { if (m.type == 'checkbox') {
m.label == item.label ? m.checked = true : m.checked = false; m.checked = m.label == item.label;
} }
}); });
} }

View File

@ -10,7 +10,7 @@
import * as Node from 'pgbrowser/node'; import * as Node from 'pgbrowser/node';
import * as SchemaTreeNode from './schema_child_tree_node'; import * as SchemaTreeNode from './schema_child_tree_node';
let SchemaChildNode = Node.extend({ const SchemaChildNode = Node.extend({
parent_type: ['schema', 'catalog'], parent_type: ['schema', 'catalog'],
canDrop: SchemaTreeNode.isTreeItemOfChildOfSchema, canDrop: SchemaTreeNode.isTreeItemOfChildOfSchema,
canDropCascade: SchemaTreeNode.isTreeItemOfChildOfSchema, canDropCascade: SchemaTreeNode.isTreeItemOfChildOfSchema,

View File

@ -587,7 +587,7 @@ export default class ColumnSchema extends BaseUISchema {
} }
validate(state, setError) { validate(state, setError) {
let msg = undefined; let msg;
if (!_.isUndefined(state.cltype) && !isEmptyString(state.attlen)) { if (!_.isUndefined(state.cltype) && !isEmptyString(state.attlen)) {
// Validation for Length field // Validation for Length field

View File

@ -527,7 +527,7 @@ def parse_rule_definition(res):
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

@ -106,14 +106,14 @@ const DiskStatsTable = (props) => {
<Table classNameRoot='Storage-tableWhiteSpace'> <Table classNameRoot='Storage-tableWhiteSpace'>
<thead> <thead>
<tr> <tr>
{tableHeader.map((item, index) => ( {tableHeader.map((item) => (
<th key={index}>{item.header}</th> <th key={item.header}>{item.header}</th>
))} ))}
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{data.map((item, index) => ( {data.map((item) => (
<tr key={index}> <tr key={item.file_system_type + item.mount_point}>
{tableHeader.map((header, id) => ( {tableHeader.map((header, id) => (
<td key={header.accessorKey+'-'+id}>{item[header.accessorKey]}</td> <td key={header.accessorKey+'-'+id}>{item[header.accessorKey]}</td>
))} ))}

View File

@ -54,8 +54,8 @@ const SummaryTable = (props) => {
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{data.map((item, index) => ( {data.map((item) => (
<tr key={index}> <tr key={item.name}>
<td>{item.name}</td> <td>{item.name}</td>
<td>{item.value}</td> <td>{item.value}</td>
</tr> </tr>

View File

@ -248,8 +248,7 @@ export function getAWSSummary(cloud, cloudInstanceDetails, cloudDBDetails) {
} }
const getStorageType = (cloudInstanceDetails) => { const getStorageType = (cloudInstanceDetails) => {
let _storage_type = 'General Purpose SSD (gp2)', let _storage_type = 'General Purpose SSD (gp2)', _io1;
_io1 = undefined;
if(cloudInstanceDetails.storage_type == 'gp2'){ _storage_type = 'General Purpose SSD (gp2)';} if(cloudInstanceDetails.storage_type == 'gp2'){ _storage_type = 'General Purpose SSD (gp2)';}
else if (cloudInstanceDetails.storage_type == 'gp3'){ _storage_type = 'General Purpose SSD (gp3)';} else if (cloudInstanceDetails.storage_type == 'gp3'){ _storage_type = 'General Purpose SSD (gp3)';}

View File

@ -273,7 +273,7 @@ export function checkClusternameAvailbility(clusterName){
resolve(res.data); resolve(res.data);
} }
}).catch((error) => { }).catch((error) => {
reject(gettext(`Error while checking server name availability with Microsoft Azure: ${error.response.data.errormsg}`)); reject(new Error(gettext(`Error while checking server name availability with Microsoft Azure: ${error.response.data.errormsg}`)));
}); });
}); });
} }

View File

@ -717,7 +717,7 @@ class AzureClusterSchema extends BaseUISchema {
} }
validate(data, setErr) { validate(data, setErr) {
if ( !isEmptyString(data.name) && (!/^[a-z0-9\-]*$/.test(data.name) || data.name.length < 3)) { if ( !isEmptyString(data.name) && (!/^[a-z0-9-]*$/.test(data.name) || data.name.length < 3)) {
setErr('name',gettext('Name must be more than 2 characters and must only contain lowercase letters, numbers, and hyphens')); setErr('name',gettext('Name must be more than 2 characters and must only contain lowercase letters, numbers, and hyphens'));
return true; return true;
} }

View File

@ -8,14 +8,13 @@
////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////
import React from 'react'; import React from 'react';
import { ToggleButton, ToggleButtonGroup } from '@mui/material'; import { ToggleButton, ToggleButtonGroup, TableBody, TableCell, TableHead, TableRow } from '@mui/material';
import CheckRoundedIcon from '@mui/icons-material/CheckRounded'; import CheckRoundedIcon from '@mui/icons-material/CheckRounded';
import { DefaultButton, PrimaryButton } from '../../../../static/js/components/Buttons'; import { DefaultButton, PrimaryButton } from '../../../../static/js/components/Buttons';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { getAWSSummary } from './aws'; import { getAWSSummary } from './aws';
import {getAzureSummary} from './azure'; import {getAzureSummary} from './azure';
import { getBigAnimalSummary } from './biganimal'; import { getBigAnimalSummary } from './biganimal';
import { TableBody, TableCell, TableHead, TableRow } from '@mui/material';
import gettext from 'sources/gettext'; import gettext from 'sources/gettext';
import { getGoogleSummary } from './google'; import { getGoogleSummary } from './google';
import { CLOUD_PROVIDERS_LABELS } from './cloud_constants'; import { CLOUD_PROVIDERS_LABELS } from './cloud_constants';

View File

@ -158,9 +158,9 @@ function Multitext({currentXpos, currentYpos, label, maxWidth}) {
return res; return res;
}; };
for (let i = 0; i < words.length; i++) { for (let word in words) {
let tmpArr = splitTextInMultiLine( let tmpArr = splitTextInMultiLine(
currLine, widthSoFar, words[i] currLine, widthSoFar, word
); );
if (currLine) { if (currLine) {

View File

@ -601,7 +601,7 @@ export default function DataGridView({
<PgReactTableBody> <PgReactTableBody>
{rows.map((row, i) => { {rows.map((row, i) => {
return <PgReactTableRow key={row.index}> return <PgReactTableRow key={row.index}>
<DataTableRow index={i} key={i} row={row} totalRows={rows.length} isResizing={isResizing} <DataTableRow index={i} row={row} totalRows={rows.length} isResizing={isResizing}
schema={schemaRef.current} schemaRef={schemaRef} accessPath={accessPath.concat([row.index])} schema={schemaRef.current} schemaRef={schemaRef} accessPath={accessPath.concat([row.index])}
moveRow={moveRow} isHovered={i == hoverIndex} setHoverIndex={setHoverIndex} viewHelperProps={viewHelperProps} moveRow={moveRow} isHovered={i == hoverIndex} setHoverIndex={setHoverIndex} viewHelperProps={viewHelperProps}
/> />

View File

@ -103,14 +103,11 @@ function isValueEqual(val1, val2) {
/* If the orig value was null and new one is empty string, then its a "no change" */ /* If the orig value was null and new one is empty string, then its a "no change" */
/* If the orig value and new value are of different datatype but of same value(numeric) "no change" */ /* If the orig value and new value are of different datatype but of same value(numeric) "no change" */
/* If the orig value is undefined or null and new value is boolean false "no change" */ /* If the orig value is undefined or null and new value is boolean false "no change" */
if (_.isEqual(val1, val2) return (_.isEqual(val1, val2)
|| ((val1 === null || _.isUndefined(val1)) && val2 === '') || ((val1 === null || _.isUndefined(val1)) && val2 === '')
|| ((val1 === null || _.isUndefined(val1)) && typeof(val2) === 'boolean' && !val2) || ((val1 === null || _.isUndefined(val1)) && typeof(val2) === 'boolean' && !val2)
|| (attrDefined ? (!_.isObject(val1) && _.isEqual(val1.toString(), val2.toString())) : false) || (attrDefined ? (!_.isObject(val1) && _.isEqual(val1.toString(), val2.toString())) : false)
) { );
return true;
}
return false;
} }
/* Compare two objects */ /* Compare two objects */
@ -144,7 +141,7 @@ function getChangedData(topSchema, viewHelperProps, sessData, stringify=false, i
if(_.isNull(change) && parseChanges.depth === 0) { if(_.isNull(change) && parseChanges.depth === 0) {
change = ''; change = '';
} }
return levelChanges[id] = change; levelChanges[id] = change;
} }
}; };

View File

@ -171,7 +171,7 @@ export const PgReactTableCell = forwardRef(({row, cell, children, className}, re
flex: `var(--col-${cell.column.id.replace(/\W/g, '_')}-size) 0 auto`, flex: `var(--col-${cell.column.id.replace(/\W/g, '_')}-size) 0 auto`,
width: `calc(var(--col-${cell.column.id.replace(/\W/g, '_')}-size)*1px)`, width: `calc(var(--col-${cell.column.id.replace(/\W/g, '_')}-size)*1px)`,
...(cell.column.columnDef.maxSize ? { maxWidth: `${cell.column.columnDef.maxSize}px` } : {}) ...(cell.column.columnDef.maxSize ? { maxWidth: `${cell.column.columnDef.maxSize}px` } : {})
}} role='cell' }}
className={classNames.join(' ')} className={classNames.join(' ')}
title={String(cell.getValue() ?? '')}> title={String(cell.getValue() ?? '')}>
<div className='pgrd-row-cell-content'>{children}</div> <div className='pgrd-row-cell-content'>{children}</div>
@ -189,7 +189,7 @@ PgReactTableCell.propTypes = {
export const PgReactTableRow = forwardRef(({ children, className, ...props }, ref)=>{ export const PgReactTableRow = forwardRef(({ children, className, ...props }, ref)=>{
return ( return (
<div className={['pgrt-row', className].join(' ')} ref={ref} role="row" {...props}> <div className={['pgrt-row', className].join(' ')} ref={ref} {...props}>
{children} {children}
</div> </div>
); );
@ -232,8 +232,8 @@ PgReactTableRowExpandContent.propTypes = {
export function PgReactTableHeader({table}) { export function PgReactTableHeader({table}) {
return ( return (
<div className='pgrt-header'> <div className='pgrt-header'>
{table.getHeaderGroups().map((headerGroup, idx) => ( {table.getHeaderGroups().map((headerGroup) => (
<div key={idx} className='pgrt-header-row' style={{ }}> <div key={headerGroup.id} className='pgrt-header-row' style={{ }}>
{headerGroup.headers.map((header) => ( {headerGroup.headers.map((header) => (
<div <div
key={header.id} key={header.id}

View File

@ -11,7 +11,7 @@ let getWindowOpener = (opener) => {
return opener.opener?.pgAdmin ? getWindowOpener(opener.opener) : opener; return opener.opener?.pgAdmin ? getWindowOpener(opener.opener) : opener;
}; };
let pgWindow = function() { const pgWindow = function() {
let localPgWindow = null; let localPgWindow = null;
try { try {
if(window.opener?.pgAdmin) { if(window.opener?.pgAdmin) {

View File

@ -103,7 +103,7 @@ class BackupMessage(IProcessDesc):
return '' return ''
for arg in _args: for arg in _args:
if arg and len(arg) >= 2 and arg[:2] == '--': if arg and len(arg) >= 2 and arg.startswith('--'):
self.cmd += ' ' + arg self.cmd += ' ' + arg
else: else:
self.cmd += cmd_arg(arg) self.cmd += cmd_arg(arg)

View File

@ -269,7 +269,7 @@ export default class DebuggerModule {
} }
getUrl(_d, newTreeInfo, trans_id) { getUrl(_d, newTreeInfo, trans_id) {
let baseUrl = undefined; let baseUrl;
if (_d._type == 'function' || _d._type == 'edbfunc') { if (_d._type == 'function' || _d._type == 'edbfunc') {
baseUrl = url_for( baseUrl = url_for(
'debugger.initialize_target_for_function', { 'debugger.initialize_target_for_function', {

View File

@ -24,7 +24,7 @@ class EmptySchema extends BaseUISchema {
} }
export function getTableDialogSchema(attributes, isNew, tableNodesDict, colTypes, schemas) { export function getTableDialogSchema(attributes, isNew, tableNodesDict, colTypes, schemas) {
let treeNodeInfo = undefined; let treeNodeInfo;
let columnSchema = new ColumnSchema( let columnSchema = new ColumnSchema(
()=>{/*This is intentional (SonarQube)*/}, ()=>{/*This is intentional (SonarQube)*/},

View File

@ -80,7 +80,7 @@ class IEMessage(IProcessDesc):
replace_next = False replace_next = False
for arg in _args: for arg in _args:
if arg and len(arg) >= 2 and arg[:2] == '--': if arg and len(arg) >= 2 and arg.startswith('--'):
if arg == '--command': if arg == '--command':
replace_next = True replace_next = True
self._cmd += ' ' + arg self._cmd += ' ' + arg

View File

@ -72,7 +72,7 @@ class RestoreMessage(IProcessDesc):
return '' return ''
for arg in _args: for arg in _args:
if arg and len(arg) >= 2 and arg[:2] == '--': if arg and len(arg) >= 2 and arg.startswith('--'):
self.cmd += ' ' + arg self.cmd += ' ' + arg
else: else:
self.cmd += cmd_arg(arg) self.cmd += cmd_arg(arg)

View File

@ -758,7 +758,7 @@ export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedN
); );
}); });
if(existIdx > -1) { if(existIdx > -1) {
reject(gettext('Connection with this configuration already present.')); reject(new Error(gettext('Connection with this configuration already present.')));
return; return;
} }
updateQueryToolConnection(connectionData, true) updateQueryToolConnection(connectionData, true)

View File

@ -189,7 +189,7 @@ export default function MacrosDialog({onClose, onSave}) {
formType={'dialog'} formType={'dialog'}
getInitData={()=>{ getInitData={()=>{
if(macrosErr) { if(macrosErr) {
return Promise.reject(macrosErr); return Promise.reject(new Error(macrosErr));
} }
return Promise.resolve({macro: userMacrosData.filter((m)=>Boolean(m.name))}); return Promise.resolve({macro: userMacrosData.filter((m)=>Boolean(m.name))});
}} }}

View File

@ -14,7 +14,7 @@ import gettext from 'sources/gettext';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import url_for from 'sources/url_for'; import url_for from 'sources/url_for';
import Loader from 'sources/components/Loader'; import Loader from 'sources/components/Loader';
import { Box } from '@mui/material'; import { Box, useTheme } from '@mui/material';
import ShowChartRoundedIcon from '@mui/icons-material/ShowChartRounded'; import ShowChartRoundedIcon from '@mui/icons-material/ShowChartRounded';
import ZoomOutMapIcon from '@mui/icons-material/ZoomOutMap'; import ZoomOutMapIcon from '@mui/icons-material/ZoomOutMap';
import SaveAltIcon from '@mui/icons-material/SaveAlt'; import SaveAltIcon from '@mui/icons-material/SaveAlt';
@ -26,7 +26,6 @@ import { LineChart, BarChart, PieChart, DATA_POINT_STYLE, DATA_POINT_SIZE,
LightenDarkenColor} from 'sources/chartjs'; LightenDarkenColor} from 'sources/chartjs';
import { QueryToolEventsContext, QueryToolContext } from '../QueryToolComponent'; import { QueryToolEventsContext, QueryToolContext } from '../QueryToolComponent';
import { QUERY_TOOL_EVENTS, PANELS } from '../QueryToolConstants'; import { QUERY_TOOL_EVENTS, PANELS } from '../QueryToolConstants';
import { useTheme } from '@mui/material';
import { getChartColor } from '../../../../../../static/js/utils'; import { getChartColor } from '../../../../../../static/js/utils';
const StyledBox = styled(Box)(({theme}) => ({ const StyledBox = styled(Box)(({theme}) => ({

View File

@ -166,10 +166,10 @@ class UserManagementCollection extends BaseUISchema {
if (state.auth_source != AUTH_METHODS['INTERNAL']) { if (state.auth_source != AUTH_METHODS['INTERNAL']) {
if (obj.isNew(state) && obj.top?._sessData?.userManagement) { if (obj.isNew(state) && obj.top?._sessData?.userManagement) {
for (let i=0; i < obj.top._sessData.userManagement.length; i++) { for (let user in obj.top._sessData.userManagement) {
if (obj.top._sessData.userManagement[i]?.id && if (user?.id &&
obj.top._sessData.userManagement[i].username.toLowerCase() == state.username.toLowerCase() && user.username.toLowerCase() == state.username.toLowerCase() &&
obj.top._sessData.userManagement[i].auth_source == state.auth_source) { user.auth_source == state.auth_source) {
msg = gettext('User name \'%s\' already exists', state.username); msg = gettext('User name \'%s\' already exists', state.username);
setError('username', msg); setError('username', msg);
return true; return true;
@ -179,7 +179,7 @@ class UserManagementCollection extends BaseUISchema {
} }
if (state.auth_source == AUTH_METHODS['INTERNAL']) { if (state.auth_source == AUTH_METHODS['INTERNAL']) {
let email_filter = /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/; let email_filter = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
if (isEmptyString(state.email)) { if (isEmptyString(state.email)) {
msg = gettext('Email cannot be empty'); msg = gettext('Email cannot be empty');
setError('email', msg); setError('email', msg);
@ -193,9 +193,9 @@ class UserManagementCollection extends BaseUISchema {
} }
if (obj.isNew(state) && obj.top?._sessData?.userManagement) { if (obj.isNew(state) && obj.top?._sessData?.userManagement) {
for (let i=0; i < obj.top._sessData.userManagement.length; i++) { for (let user in obj.top._sessData.userManagement) {
if (obj.top._sessData.userManagement[i]?.id && if (user?.id &&
obj.top._sessData.userManagement[i].email?.toLowerCase() == state.email?.toLowerCase()) { user.email?.toLowerCase() == state.email?.toLowerCase()) {
msg = gettext('Email address \'%s\' already exists', state.email); msg = gettext('Email address \'%s\' already exists', state.email);
setError('email', msg); setError('email', msg);
return true; return true;

View File

@ -336,7 +336,7 @@ class Driver(BaseDriver):
return True return True
# certain types should not be quoted even though it contains a space. # certain types should not be quoted even though it contains a space.
# Evilness. # Evilness.
elif for_types and value[-2:] == "[]": elif for_types and value.endswith('[]'):
val_noarray = value[:-2] val_noarray = value[:-2]
if for_types and val_noarray.lower() in [ if for_types and val_noarray.lower() in [

View File

@ -7,6 +7,6 @@
// //
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
let treeMenu = null; const treeMenu = null;
export {treeMenu}; export {treeMenu};

View File

@ -95,6 +95,6 @@ export const addNewDatagridRow = async (user, ctrl)=>{
await user.click(ctrl.container.querySelector('[data-test="add-row"] button')); await user.click(ctrl.container.querySelector('[data-test="add-row"] button'));
}; };
export let genericBeforeEach = ()=> { export const genericBeforeEach = ()=> {
pgWindow.pgAdmin = pgAdmin; pgWindow.pgAdmin = pgAdmin;
}; };