Fixed the following code smells:

1) useState call is not destructured into value + setter pair.
2) A fragment with only one child is redundant.
3) Unnecessary '.apply()' and '.call()'.
4) Expected the Promise rejection reason to be an Error.
This commit is contained in:
Akshay Joshi
2024-04-09 19:18:56 +05:30
parent ed2a73f7ff
commit 30d2d1b23e
51 changed files with 486 additions and 511 deletions

View File

@@ -43,7 +43,7 @@ function fetch_ticket_lifetime () {
if (ticket_lifetime > 0) { if (ticket_lifetime > 0) {
return Promise.resolve(ticket_lifetime); return Promise.resolve(ticket_lifetime);
} else { } else {
return Promise.reject(); return Promise.reject(new Error(null));
} }
}); });

View File

@@ -76,11 +76,10 @@ define('pgadmin.node.cast', [
return new Promise((resolve, reject)=>{ return new Promise((resolve, reject)=>{
const api = getApiInstance(); const api = getApiInstance();
let _url = pgBrowser.Nodes['cast'].generate_url.apply( let _url = pgBrowser.Nodes['cast'].generate_url(
pgBrowser.Nodes['cast'], [ null, 'get_functions', itemNodeData, false,
null, 'get_functions', itemNodeData, false, treeNodeInfo,
treeNodeInfo, );
]);
let data = {'srctyp' : srcTyp, 'trgtyp' : trgtyp}; let data = {'srctyp' : srcTyp, 'trgtyp' : trgtyp};
if(srcTyp != undefined && srcTyp != '' && if(srcTyp != undefined && srcTyp != '' &&

View File

@@ -191,7 +191,7 @@ define('pgadmin.node.compound_trigger', [
} }
return itemData.icon === 'icon-compound_trigger-bad' && return itemData.icon === 'icon-compound_trigger-bad' &&
this.canCreate.apply(this, [itemData, item, data]); this.canCreate(itemData, item, data);
}, },
// Check to whether trigger is enable ? // Check to whether trigger is enable ?
canCreate_with_compound_trigger_disable: function(itemData, item, data) { canCreate_with_compound_trigger_disable: function(itemData, item, data) {
@@ -201,7 +201,7 @@ define('pgadmin.node.compound_trigger', [
} }
return itemData.icon === 'icon-compound_trigger' && return itemData.icon === 'icon-compound_trigger' &&
this.canCreate.apply(this, [itemData, item, data]); this.canCreate(itemData, item, data);
}, },
}); });
} }

View File

@@ -322,14 +322,14 @@ function(
canCreate: SchemaChildTreeNode.isTreeItemOfChildOfSchema, canCreate: SchemaChildTreeNode.isTreeItemOfChildOfSchema,
// Check to whether table has disable trigger(s) // Check to whether table has disable trigger(s)
canCreate_with_trigger_enable: function(itemData, item, data) { canCreate_with_trigger_enable: function(itemData, item, data) {
if(this.canCreate.apply(this, [itemData, item, data])) { if(this.canCreate(itemData, item, data)) {
// We are here means we can create menu, now let's check condition // We are here means we can create menu, now let's check condition
return (itemData.tigger_count > 0); return (itemData.tigger_count > 0);
} }
}, },
// Check to whether table has enable trigger(s) // Check to whether table has enable trigger(s)
canCreate_with_trigger_disable: function(itemData, item, data) { canCreate_with_trigger_disable: function(itemData, item, data) {
if(this.canCreate.apply(this, [itemData, item, data])) { if(this.canCreate(itemData, item, data)) {
// We are here means we can create menu, now let's check condition // We are here means we can create menu, now let's check condition
return (itemData.tigger_count > 0 && itemData.has_enable_triggers > 0); return (itemData.tigger_count > 0 && itemData.has_enable_triggers > 0);
} }

View File

@@ -234,7 +234,7 @@ define('pgadmin.node.rule', [
} }
return itemData.icon === 'icon-rule-bad' && return itemData.icon === 'icon-rule-bad' &&
this.canCreate.apply(this,[itemData, item, data]); this.canCreate(itemData, item, data);
}, },
// Check to whether rule is enable ? // Check to whether rule is enable ?
canCreate_with_rule_disable: function(itemData, item, data) { canCreate_with_rule_disable: function(itemData, item, data) {

View File

@@ -183,7 +183,7 @@ define('pgadmin.node.trigger', [
} }
return itemData.icon === 'icon-trigger-bad' && return itemData.icon === 'icon-trigger-bad' &&
this.canCreate.apply(this, [itemData, item, data]); this.canCreate(itemData, item, data);
}, },
// Check to whether trigger is enable ? // Check to whether trigger is enable ?
canCreate_with_trigger_disable: function(itemData, item, data) { canCreate_with_trigger_disable: function(itemData, item, data) {
@@ -193,7 +193,7 @@ define('pgadmin.node.trigger', [
} }
return itemData.icon === 'icon-trigger' && return itemData.icon === 'icon-trigger' &&
this.canCreate.apply(this, [itemData, item, data]); this.canCreate(itemData, item, data);
}, },
}); });
} }

View File

@@ -85,11 +85,10 @@ function getRangeSchema(nodeObj, treeNodeInfo, itemNodeData) {
return new Promise((resolve, reject)=>{ return new Promise((resolve, reject)=>{
const api = getApiInstance(); const api = getApiInstance();
let _url = nodeObj.generate_url.apply( let _url = nodeObj.generate_url(
nodeObj, [ null, 'get_subopclass', itemNodeData, false,
null, 'get_subopclass', itemNodeData, false, treeNodeInfo,
treeNodeInfo, );
]);
let data; let data;
if(!_.isUndefined(typname) && typname != ''){ if(!_.isUndefined(typname) && typname != ''){
@@ -113,11 +112,10 @@ function getRangeSchema(nodeObj, treeNodeInfo, itemNodeData) {
return new Promise((resolve, reject)=>{ return new Promise((resolve, reject)=>{
const api = getApiInstance(); const api = getApiInstance();
let _url = nodeObj.generate_url.apply( let _url = nodeObj.generate_url(
nodeObj, [ null, 'get_canonical', itemNodeData, false,
null, 'get_canonical', itemNodeData, false, treeNodeInfo,
treeNodeInfo, );
]);
let data = []; let data = [];
if(!_.isUndefined(name) && name != '' && name != null){ if(!_.isUndefined(name) && name != '' && name != null){
@@ -140,11 +138,10 @@ function getRangeSchema(nodeObj, treeNodeInfo, itemNodeData) {
return new Promise((resolve, reject)=>{ return new Promise((resolve, reject)=>{
const api = getApiInstance(); const api = getApiInstance();
let _url = nodeObj.generate_url.apply( let _url = nodeObj.generate_url(
nodeObj, [ null, 'get_stypediff', itemNodeData, false,
null, 'get_stypediff', itemNodeData, false, treeNodeInfo,
treeNodeInfo, );
]);
let data; let data;
if(!_.isUndefined(typname) && typname != '' && if(!_.isUndefined(typname) && typname != '' &&

View File

@@ -462,7 +462,7 @@ define('pgadmin.node.database', [
); );
/* Call enable/disable menu function after database is connected. /* Call enable/disable menu function after database is connected.
To make sure all the menus for database is in the right state */ To make sure all the menus for database is in the right state */
pgBrowser.enable_disable_menus.apply(pgBrowser, [_item]); pgBrowser.enable_disable_menus(_item);
pgBrowser.Nodes['database'].callbacks.selected(_item, _data); pgBrowser.Nodes['database'].callbacks.selected(_item, _data);
if (!_connected) { if (!_connected) {

View File

@@ -713,7 +713,7 @@ define('pgadmin.node.server', [
/* Call enable/disable menu function after database is connected. /* Call enable/disable menu function after database is connected.
To make sure all the menus for database is in the right state */ To make sure all the menus for database is in the right state */
pgBrowser.enable_disable_menus.apply(pgBrowser, [_item]); pgBrowser.enable_disable_menus(_item);
// We're not reconnecting // We're not reconnecting
if (!_wasConnected) { if (!_wasConnected) {

View File

@@ -87,7 +87,7 @@ export default class MainMenuFactory {
if (options.module && 'callbacks' in options.module && options.module.callbacks[options.callback]) { if (options.module && 'callbacks' in options.module && options.module.callbacks[options.callback]) {
options.module.callbacks[options.callback].apply(options.module, [options.data, pgAdmin.Browser.tree?.selected()]); options.module.callbacks[options.callback].apply(options.module, [options.data, pgAdmin.Browser.tree?.selected()]);
} else if (options?.module?.[options.callback]) { } else if (options?.module?.[options.callback]) {
options.module[options.callback].apply(options.module, [options.data, pgAdmin.Browser.tree?.selected()]); options.module[options.callback](options.data, pgAdmin.Browser.tree?.selected());
} else if (options?.callback) { } else if (options?.callback) {
options.callback(options); options.callback(options);
} else if (options.url != '#') { } else if (options.url != '#') {
@@ -117,7 +117,7 @@ export default class MainMenuFactory {
let selectedNode=pgAdmin.Browser.tree.selected(); let selectedNode=pgAdmin.Browser.tree.selected();
let flag=!_.isUndefined(selectedNodeFromNodes.showMenu); let flag=!_.isUndefined(selectedNodeFromNodes.showMenu);
if(flag){ if(flag){
var showMenu = selectedNodeFromNodes.showMenu(d, selectedNode); let showMenu = selectedNodeFromNodes.showMenu(d, selectedNode);
return {flag:showMenu?false:flag,showMenu}; return {flag:showMenu?false:flag,showMenu};
} else{ } else{
return {flag,showMenu:undefined}; return {flag,showMenu:undefined};

View File

@@ -1697,7 +1697,7 @@ define('pgadmin.browser', [
load: true, load: true,
}; };
ctx.success = function() { ctx.success = function() {
this.b._refreshNode.call(this.b, this, this.d); this.b._refreshNode(this, this.d);
}.bind(ctx); }.bind(ctx);
findNode(__ctx.i, d, ctx); findNode(__ctx.i, d, ctx);
} }

View File

@@ -139,7 +139,7 @@ define('pgadmin.browser.node', [
}, },
enable: _.isFunction(self.canEdit) ? enable: _.isFunction(self.canEdit) ?
function() { function() {
return !!(self.canEdit.apply(self, arguments)); return !!(self.canEdit(arguments));
} : (!!self.canEdit), } : (!!self.canEdit),
}]); }]);
} }
@@ -159,7 +159,7 @@ define('pgadmin.browser.node', [
}, },
enable: _.isFunction(self.canDrop) ? enable: _.isFunction(self.canDrop) ?
function() { function() {
return !!(self.canDrop.apply(self, arguments)); return !!(self.canDrop(arguments));
} : (!!self.canDrop), } : (!!self.canDrop),
}]); }]);
@@ -177,7 +177,7 @@ define('pgadmin.browser.node', [
}, },
enable: _.isFunction(self.canDropCascade) ? enable: _.isFunction(self.canDropCascade) ?
function() { function() {
return self.canDropCascade.apply(self, arguments); return self.canDropCascade(arguments);
} : (!!self.canDropCascade), } : (!!self.canDropCascade),
}]); }]);
} }
@@ -386,7 +386,7 @@ define('pgadmin.browser.node', [
const onSave = (newNodeData)=>{ const onSave = (newNodeData)=>{
// Clear the cache for this node now. // Clear the cache for this node now.
setTimeout(()=>{ setTimeout(()=>{
this.clear_cache.apply(this, item); this.clear_cache(item);
}, 0); }, 0);
try { try {
pgBrowser.Events.trigger( pgBrowser.Events.trigger(
@@ -416,7 +416,7 @@ define('pgadmin.browser.node', [
const onSave = (newNodeData)=>{ const onSave = (newNodeData)=>{
// Clear the cache for this node now. // Clear the cache for this node now.
setTimeout(()=>{ setTimeout(()=>{
this.clear_cache.apply(this, item); this.clear_cache(item);
}, 0); }, 0);
try { try {
pgBrowser.Events.trigger( pgBrowser.Events.trigger(
@@ -446,7 +446,7 @@ define('pgadmin.browser.node', [
// Clear the cache for this node now. // Clear the cache for this node now.
setTimeout(()=>{ setTimeout(()=>{
this.clear_cache.apply(this, item); this.clear_cache(item);
}, 0); }, 0);
pgBrowser.Events.trigger( pgBrowser.Events.trigger(
@@ -530,7 +530,7 @@ define('pgadmin.browser.node', [
title = gettext('Delete CASCADE %s?', obj.label); title = gettext('Delete CASCADE %s?', obj.label);
if (!(_.isFunction(obj.canDropCascade) ? if (!(_.isFunction(obj.canDropCascade) ?
obj.canDropCascade.apply(obj, [d, i]) : obj.canDropCascade)) { obj.canDropCascade(d, i) : obj.canDropCascade)) {
pgAdmin.Browser.notifier.error( pgAdmin.Browser.notifier.error(
gettext('The %s "%s" cannot be dropped.', obj.label, d.label), gettext('The %s "%s" cannot be dropped.', obj.label, d.label),
10000 10000
@@ -547,7 +547,7 @@ define('pgadmin.browser.node', [
} }
if (!(_.isFunction(obj.canDrop) ? if (!(_.isFunction(obj.canDrop) ?
obj.canDrop.apply(obj, [d, i]) : obj.canDrop)) { obj.canDrop(d, i) : obj.canDrop)) {
pgAdmin.Browser.notifier.error( pgAdmin.Browser.notifier.error(
gettext('The %s "%s" cannot be dropped/removed.', obj.label, d.label), gettext('The %s "%s" cannot be dropped/removed.', obj.label, d.label),
10000 10000
@@ -745,7 +745,7 @@ define('pgadmin.browser.node', [
removed: function(item) { removed: function(item) {
let self = this; let self = this;
setTimeout(function() { setTimeout(function() {
self.clear_cache.apply(self, item); self.clear_cache(item);
}, 0); }, 0);
}, },
refresh: function(cmd, _item) { refresh: function(cmd, _item) {

View File

@@ -144,10 +144,10 @@ export function getNodeListById(nodeObj, treeNodeInfo, itemNodeData, params={},
_.each(rows, function(r) { _.each(rows, function(r) {
if (filter(r)) { if (filter(r)) {
let l = (_.isFunction(nodeObj['node_label']) ? let l = (_.isFunction(nodeObj['node_label']) ?
(nodeObj['node_label']).apply(nodeObj, [r]) : nodeObj['node_label'](r) :
r.label), r.label),
image = (_.isFunction(nodeObj['node_image']) ? image = (_.isFunction(nodeObj['node_image']) ?
(nodeObj['node_image']).apply(nodeObj, [r]) : nodeObj['node_image'](r) :
(nodeObj['node_image'] || ('icon-' + nodeObj.type))); (nodeObj['node_image'] || ('icon-' + nodeObj.type)));
res.push({ res.push({
@@ -175,10 +175,10 @@ export function getNodeListByName(node, treeNodeInfo, itemNodeData, params={}, f
_.each(rows, function(r) { _.each(rows, function(r) {
if (filter(r)) { if (filter(r)) {
let l = (_.isFunction(nodeObj['node_label']) ? let l = (_.isFunction(nodeObj['node_label']) ?
(nodeObj['node_label']).apply(nodeObj, [r]) : nodeObj['node_label'](r) :
r.label), r.label),
image = (_.isFunction(nodeObj['node_image']) ? image = (_.isFunction(nodeObj['node_image']) ?
(nodeObj['node_image']).apply(nodeObj, [r]) : nodeObj['node_image'](r) :
(nodeObj['node_image'] || ('icon-' + nodeObj.type))); (nodeObj['node_image'] || ('icon-' + nodeObj.type)));
res.push({ res.push({

View File

@@ -143,7 +143,7 @@ function Dashboard({
mainTabs.push(gettext('Replication')); mainTabs.push(gettext('Replication'));
} }
let systemStatsTabs = [gettext('Summary'), gettext('CPU'), gettext('Memory'), gettext('Storage')]; let systemStatsTabs = [gettext('Summary'), gettext('CPU'), gettext('Memory'), gettext('Storage')];
const [dashData, setdashData] = useState([]); const [dashData, setDashData] = useState([]);
const [msg, setMsg] = useState(''); const [msg, setMsg] = useState('');
const [ssMsg, setSsMsg] = useState(''); const [ssMsg, setSsMsg] = useState('');
const [tabVal, setTabVal] = useState(0); const [tabVal, setTabVal] = useState(0);
@@ -751,7 +751,7 @@ function Dashboard({
type: 'GET', type: 'GET',
}) })
.then((res) => { .then((res) => {
setdashData(parseData(res.data)); setDashData(parseData(res.data));
}) })
.catch((error) => { .catch((error) => {
pgAdmin.Browser.notifier.alert( pgAdmin.Browser.notifier.alert(
@@ -769,7 +769,7 @@ function Dashboard({
}) })
.then((res) => { .then((res) => {
const data = res.data; const data = res.data;
if(data['ss_present'] == false){ if(!data['ss_present']){
setSsMsg(gettext('The system_stats extension is not installed. You can install the extension in a database using the "CREATE EXTENSION system_stats;" SQL command. Reload pgAdmin once it is installed.')); setSsMsg(gettext('The system_stats extension is not installed. You can install the extension in a database using the "CREATE EXTENSION system_stats;" SQL command. Reload pgAdmin once it is installed.'));
setLdid(0); setLdid(0);
} else { } else {

View File

@@ -70,8 +70,6 @@ export default function CPU({preferences, sid, did, pageVisible, enablePoll=true
const [loadAvgInfo, loadAvgInfoReduce] = useReducer(statsReducer, chartsDefault['la_stats']); const [loadAvgInfo, loadAvgInfoReduce] = useReducer(statsReducer, chartsDefault['la_stats']);
const [processCpuUsageStats, setProcessCpuUsageStats] = useState([]); const [processCpuUsageStats, setProcessCpuUsageStats] = useState([]);
const [, setCounterData] = useState({});
const [pollDelay, setPollDelay] = useState(5000); const [pollDelay, setPollDelay] = useState(5000);
const [errorMsg, setErrorMsg] = useState(null); const [errorMsg, setErrorMsg] = useState(null);
@@ -196,20 +194,12 @@ export default function CPU({preferences, sid, did, pageVisible, enablePoll=true
setProcessCpuUsageStats(pcu_info_list); setProcessCpuUsageStats(pcu_info_list);
} }
setCounterData((prevCounterData)=>{
return {
...prevCounterData,
...data,
};
});
}) })
.catch((error)=>{ .catch((error)=>{
if(!errorMsg) { if(!errorMsg) {
cpuUsageInfoReduce({reset:chartsDefault['cpu_stats']}); cpuUsageInfoReduce({reset:chartsDefault['cpu_stats']});
loadAvgInfoReduce({reset:chartsDefault['la_stats']}); loadAvgInfoReduce({reset:chartsDefault['la_stats']});
setProcessCpuUsageStats([]); setProcessCpuUsageStats([]);
setCounterData({});
if(error.response) { if(error.response) {
if (error.response.status === 428) { if (error.response.status === 428) {
setErrorMsg(gettext('Please connect to the selected server to view the graph.')); setErrorMsg(gettext('Please connect to the selected server to view the graph.'));

View File

@@ -69,8 +69,6 @@ export default function Memory({preferences, sid, did, pageVisible, enablePoll=t
const [swapMemoryUsageInfo, swapMemoryUsageInfoReduce] = useReducer(statsReducer, chartsDefault['sm_stats']); const [swapMemoryUsageInfo, swapMemoryUsageInfoReduce] = useReducer(statsReducer, chartsDefault['sm_stats']);
const [processMemoryUsageStats, setProcessMemoryUsageStats] = useState([]); const [processMemoryUsageStats, setProcessMemoryUsageStats] = useState([]);
const [, setCounterData] = useState({});
const [pollDelay, setPollDelay] = useState(5000); const [pollDelay, setPollDelay] = useState(5000);
const [errorMsg, setErrorMsg] = useState(null); const [errorMsg, setErrorMsg] = useState(null);
const [chartDrawnOnce, setChartDrawnOnce] = useState(false); const [chartDrawnOnce, setChartDrawnOnce] = useState(false);
@@ -199,20 +197,12 @@ export default function Memory({preferences, sid, did, pageVisible, enablePoll=t
setProcessMemoryUsageStats(pmu_info_list); setProcessMemoryUsageStats(pmu_info_list);
} }
setCounterData((prevCounterData)=>{
return {
...prevCounterData,
...data,
};
});
}) })
.catch((error)=>{ .catch((error)=>{
if(!errorMsg) { if(!errorMsg) {
memoryUsageInfoReduce({reset:chartsDefault['m_stats']}); memoryUsageInfoReduce({reset:chartsDefault['m_stats']});
swapMemoryUsageInfoReduce({reset:chartsDefault['sm_stats']}); swapMemoryUsageInfoReduce({reset:chartsDefault['sm_stats']});
setProcessMemoryUsageStats([]); setProcessMemoryUsageStats([]);
setCounterData({});
if(error.response) { if(error.response) {
if (error.response.status === 428) { if (error.response.status === 428) {
setErrorMsg(gettext('Please connect to the selected server to view the graph.')); setErrorMsg(gettext('Please connect to the selected server to view the graph.'));

View File

@@ -172,8 +172,6 @@ export default function Storage({preferences, sid, did, pageVisible, enablePoll=
const [diskStats, setDiskStats] = useState([]); const [diskStats, setDiskStats] = useState([]);
const [ioInfo, ioInfoReduce] = useReducer(ioStatsReducer, chartsDefault['io_stats']); const [ioInfo, ioInfoReduce] = useReducer(ioStatsReducer, chartsDefault['io_stats']);
const [, setCounterData] = useState({});
const [pollDelay, setPollDelay] = useState(5000); const [pollDelay, setPollDelay] = useState(5000);
const [errorMsg, setErrorMsg] = useState(null); const [errorMsg, setErrorMsg] = useState(null);
const [chartDrawnOnce, setChartDrawnOnce] = useState(false); const [chartDrawnOnce, setChartDrawnOnce] = useState(false);
@@ -351,18 +349,10 @@ export default function Storage({preferences, sid, did, pageVisible, enablePoll=
} }
ioInfoReduce({incoming: new_io_stats}); ioInfoReduce({incoming: new_io_stats});
} }
setCounterData((prevCounterData)=>{
return {
...prevCounterData,
...data,
};
});
}) })
.catch((error)=>{ .catch((error)=>{
if(!errorMsg) { if(!errorMsg) {
ioInfoReduce({reset:chartsDefault['io_stats']}); ioInfoReduce({reset:chartsDefault['io_stats']});
setCounterData({});
if(error.response) { if(error.response) {
if (error.response.status === 428) { if (error.response.status === 428) {
setErrorMsg(gettext('Please connect to the selected server to view the graph.')); setErrorMsg(gettext('Please connect to the selected server to view the graph.'));

View File

@@ -87,7 +87,6 @@ export default function Summary({preferences, sid, did, pageVisible, enablePoll=
const [osStats, setOsStats] = useState([]); const [osStats, setOsStats] = useState([]);
const [cpuStats, setCpuStats] = useState([]); const [cpuStats, setCpuStats] = useState([]);
const [, setCounterData] = useState({});
const [pollDelay, setPollDelay] = useState(5000); const [pollDelay, setPollDelay] = useState(5000);
const [errorMsg, setErrorMsg] = useState(null); const [errorMsg, setErrorMsg] = useState(null);
const [chartDrawnOnce, setChartDrawnOnce] = useState(false); const [chartDrawnOnce, setChartDrawnOnce] = useState(false);
@@ -204,17 +203,10 @@ export default function Summary({preferences, sid, did, pageVisible, enablePoll=
setErrorMsg(null); setErrorMsg(null);
processHandleCountReduce({incoming: data['hpc_stats']}); processHandleCountReduce({incoming: data['hpc_stats']});
setCounterData((prevCounterData)=>{
return {
...prevCounterData,
...data,
};
});
}) })
.catch((error)=>{ .catch((error)=>{
if(!errorMsg) { if(!errorMsg) {
processHandleCountReduce({reset:chartsDefault['hpc_stats']}); processHandleCountReduce({reset:chartsDefault['hpc_stats']});
setCounterData({});
if(error.response) { if(error.response) {
if (error.response.status === 428) { if (error.response.status === 428) {
setErrorMsg(gettext('Please connect to the selected server to view the graph.')); setErrorMsg(gettext('Please connect to the selected server to view the graph.'));

View File

@@ -275,49 +275,47 @@ export default function Processes() {
}, []); }, []);
return ( return (
<> <PgTable
<PgTable data-test="processes"
data-test="processes" className={classes.autoResizer}
className={classes.autoResizer} columns={columns}
columns={columns} data={tableData}
data={tableData} sortOptions={[{id: 'stime', desc: true}]}
sortOptions={[{id: 'stime', desc: true}]} getSelectedRows={(rows)=>{setSelectedRows(rows);}}
getSelectedRows={(rows)=>{setSelectedRows(rows);}} isSelectRow={true}
isSelectRow={true} tableProps={{
tableProps={{ autoResetSelectedRows: false,
autoResetSelectedRows: false, getRowId: (row)=>{
getRowId: (row)=>{ return row.id;
return row.id; }
} }}
}} CustomHeader={()=>{
CustomHeader={()=>{ return (
return ( <Box>
<Box> <PgButtonGroup>
<PgButtonGroup> <PgIconButton
<PgIconButton icon={<DeleteIcon style={{height: '1.4rem'}}/>}
icon={<DeleteIcon style={{height: '1.4rem'}}/>} aria-label="Acknowledge and Remove"
aria-label="Acknowledge and Remove" title={gettext('Acknowledge and Remove')}
title={gettext('Acknowledge and Remove')} onClick={() => {
onClick={() => { pgAdmin.Browser.notifier.confirm(gettext('Remove Processes'), gettext('Are you sure you want to remove the selected processes?'), ()=>{
pgAdmin.Browser.notifier.confirm(gettext('Remove Processes'), gettext('Are you sure you want to remove the selected processes?'), ()=>{ pgAdmin.Browser.BgProcessManager.acknowledge(selectedRows.map((p)=>p.original.id));
pgAdmin.Browser.BgProcessManager.acknowledge(selectedRows.map((p)=>p.original.id)); });
}); }}
}} disabled={selectedRows.length <= 0}
disabled={selectedRows.length <= 0} ></PgIconButton>
></PgIconButton> <PgIconButton
<PgIconButton icon={<HelpIcon style={{height: '1.4rem'}}/>}
icon={<HelpIcon style={{height: '1.4rem'}}/>} aria-label="Help"
aria-label="Help" title={gettext('Help')}
title={gettext('Help')} onClick={() => {
onClick={() => { window.open(url_for('help.static', {'filename': 'processes.html'}));
window.open(url_for('help.static', {'filename': 'processes.html'})); }}
}} ></PgIconButton>
></PgIconButton> </PgButtonGroup>
</PgButtonGroup> </Box>
</Box> );
); }}
}} ></PgTable>
></PgTable>
</>
); );
} }

View File

@@ -71,7 +71,7 @@ export default function CloudWizard({ nodeInfo, nodeData, onClose, cloudPanelId}
let steps = [gettext('Cloud Provider'), gettext('Credentials'), gettext('Cluster Type'), let steps = [gettext('Cloud Provider'), gettext('Credentials'), gettext('Cluster Type'),
gettext('Instance Specification'), gettext('Database Details'), gettext('Review')]; gettext('Instance Specification'), gettext('Database Details'), gettext('Review')];
const [currentStep, setCurrentStep] = React.useState(''); const [currentStep, setCurrentStep] = React.useState('');
const [selectionVal, setCloudSelection] = React.useState(''); const [cloudSelection, setCloudSelection] = React.useState('');
const [errMsg, setErrMsg] = React.useState(''); const [errMsg, setErrMsg] = React.useState('');
const [cloudInstanceDetails, setCloudInstanceDetails] = React.useState({}); const [cloudInstanceDetails, setCloudInstanceDetails] = React.useState({});
const [cloudDBCred, setCloudDBCred] = React.useState({}); const [cloudDBCred, setCloudDBCred] = React.useState({});
@@ -295,14 +295,14 @@ export default function CloudWizard({ nodeInfo, nodeData, onClose, cloudPanelId}
setErrMsg([MESSAGE_TYPE.INFO, gettext('Validating credentials...')]); setErrMsg([MESSAGE_TYPE.INFO, gettext('Validating credentials...')]);
let _url = url_for('rds.verify_credentials'); let _url = url_for('rds.verify_credentials');
const post_data = { const post_data = {
cloud: selectionVal, cloud: cloudSelection,
secret: cloudDBCred, secret: cloudDBCred,
}; };
axiosApi.post(_url, post_data) axiosApi.post(_url, post_data)
.then((res) => { .then((res) => {
if(!res.data.success) { if(!res.data.success) {
setErrMsg([MESSAGE_TYPE.ERROR, res.data.info]); setErrMsg([MESSAGE_TYPE.ERROR, res.data.info]);
reject(); reject(new Error(res.data.info));
} else { } else {
setErrMsg(['', '']); setErrMsg(['', '']);
if (activeStep == 1) { if (activeStep == 1) {
@@ -314,7 +314,7 @@ export default function CloudWizard({ nodeInfo, nodeData, onClose, cloudPanelId}
}) })
.catch(() => { .catch(() => {
setErrMsg([MESSAGE_TYPE.ERROR, gettext('Error while checking cloud credentials')]); setErrMsg([MESSAGE_TYPE.ERROR, gettext('Error while checking cloud credentials')]);
reject(); reject(new Error(gettext('Error while checking cloud credentials')));
}); });
} else if(activeStep == 0 && cloudProvider == CLOUD_PROVIDERS.BIGANIMAL) { } else if(activeStep == 0 && cloudProvider == CLOUD_PROVIDERS.BIGANIMAL) {
if (!isEmptyString(verificationURI)) { resolve(); return; } if (!isEmptyString(verificationURI)) { resolve(); return; }
@@ -328,7 +328,7 @@ export default function CloudWizard({ nodeInfo, nodeData, onClose, cloudPanelId}
}) })
.catch((error) => { .catch((error) => {
setErrMsg([MESSAGE_TYPE.ERROR, gettext(error)]); setErrMsg([MESSAGE_TYPE.ERROR, gettext(error)]);
reject(); reject(new Error(gettext(error)));
}); });
} else if (cloudProvider == CLOUD_PROVIDERS.AZURE) { } else if (cloudProvider == CLOUD_PROVIDERS.AZURE) {
if (activeStep == 1) { if (activeStep == 1) {
@@ -347,7 +347,7 @@ export default function CloudWizard({ nodeInfo, nodeData, onClose, cloudPanelId}
resolve(); resolve();
}).catch((error)=>{ }).catch((error)=>{
setErrMsg([MESSAGE_TYPE.ERROR, gettext(error)]); setErrMsg([MESSAGE_TYPE.ERROR, gettext(error)]);
reject(); reject(new Error(gettext(error)));
}); });
} else { } else {
resolve(); resolve();
@@ -423,157 +423,155 @@ export default function CloudWizard({ nodeInfo, nodeData, onClose, cloudPanelId}
return ( return (
<CloudWizardEventsContext.Provider value={eventBus.current}> <CloudWizardEventsContext.Provider value={eventBus.current}>
<> <Wizard
<Wizard title={gettext('Deploy Cloud Instance')}
title={gettext('Deploy Cloud Instance')} stepList={steps}
stepList={steps} disableNextStep={disableNextCheck}
disableNextStep={disableNextCheck} onStepChange={wizardStepChange}
onStepChange={wizardStepChange} onSave={onSave}
onSave={onSave} onHelp={onDialogHelp}
onHelp={onDialogHelp} beforeNext={onBeforeNext}
beforeNext={onBeforeNext} beforeBack={onBeforeBack}>
beforeBack={onBeforeBack}> <WizardStep stepId={0}>
<WizardStep stepId={0}> <Box className={classes.messageBox}>
<Box className={classes.messageBox}> <Box className={classes.messagePadding}>{gettext('Select a cloud provider for PostgreSQL database.')}</Box>
<Box className={classes.messagePadding}>{gettext('Select a cloud provider for PostgreSQL database.')}</Box> </Box>
</Box> <Box className={classes.messageBox}>
<Box className={classes.messageBox}> <ToggleButtons cloudProvider={cloudProvider} setCloudProvider={setCloudProvider}
<ToggleButtons cloudProvider={cloudProvider} setCloudProvider={setCloudProvider} options={cloud_providers}
options={cloud_providers} ></ToggleButtons>
></ToggleButtons> </Box>
</Box> <FormFooterMessage type={errMsg[0]} message={errMsg[1]} onClose={onErrClose} />
<FormFooterMessage type={errMsg[0]} message={errMsg[1]} onClose={onErrClose} /> </WizardStep>
</WizardStep> <WizardStep stepId={1} >
<WizardStep stepId={1} > <Box className={classes.buttonMarginEDB}>
<Box className={classes.buttonMarginEDB}> {cloudProvider == CLOUD_PROVIDERS.BIGANIMAL && <Box className={classes.messageBox}>
{cloudProvider == CLOUD_PROVIDERS.BIGANIMAL && <Box className={classes.messageBox}> <Box>{gettext('The verification code to authenticate the pgAdmin to EDB BigAnimal is: ')} <strong>{verificationCode}</strong>
<Box>{gettext('The verification code to authenticate the pgAdmin to EDB BigAnimal is: ')} <strong>{verificationCode}</strong> <br/>{gettext('By clicking the below button, you will be redirected to the EDB BigAnimal authentication page in a new tab.')}
<br/>{gettext('By clicking the below button, you will be redirected to the EDB BigAnimal authentication page in a new tab.')} </Box>
</Box> </Box>}
</Box>} {cloudProvider == CLOUD_PROVIDERS.BIGANIMAL && <PrimaryButton onClick={authenticateBigAnimal} disabled={verificationIntiated}>
{cloudProvider == CLOUD_PROVIDERS.BIGANIMAL && <PrimaryButton onClick={authenticateBigAnimal} disabled={verificationIntiated}> {gettext('Click here to authenticate yourself to EDB BigAnimal')}
{gettext('Click here to authenticate yourself to EDB BigAnimal')} </PrimaryButton>}
</PrimaryButton>} {cloudProvider == CLOUD_PROVIDERS.BIGANIMAL && <Box className={classes.messageBox}>
{cloudProvider == CLOUD_PROVIDERS.BIGANIMAL && <Box className={classes.messageBox}> <Box ></Box>
<Box ></Box> </Box>}
</Box>} </Box>
</Box> {cloudProvider == CLOUD_PROVIDERS.AWS && <AwsCredentials cloudProvider={cloudProvider} nodeInfo={nodeInfo} nodeData={nodeData} setCloudDBCred={setCloudDBCred}/>}
{cloudProvider == CLOUD_PROVIDERS.AWS && <AwsCredentials cloudProvider={cloudProvider} nodeInfo={nodeInfo} nodeData={nodeData} setCloudDBCred={setCloudDBCred}/>} { cloudProvider == CLOUD_PROVIDERS.AZURE &&
{ cloudProvider == CLOUD_PROVIDERS.AZURE &&
<Box flexGrow={1}> <Box flexGrow={1}>
<AzureCredentials cloudProvider={cloudProvider} setAzureCredData={setAzureCredData}/> <AzureCredentials cloudProvider={cloudProvider} setAzureCredData={setAzureCredData}/>
</Box>} </Box>}
<Box flexGrow={1}> <Box flexGrow={1}>
{cloudProvider == CLOUD_PROVIDERS.GOOGLE && <GoogleCredentials cloudProvider={cloudProvider} setGoogleCredData={setGoogleCredData}/>} {cloudProvider == CLOUD_PROVIDERS.GOOGLE && <GoogleCredentials cloudProvider={cloudProvider} setGoogleCredData={setGoogleCredData}/>}
</Box> </Box>
<FormFooterMessage type={errMsg[0]} message={errMsg[1]} onClose={onErrClose} /> <FormFooterMessage type={errMsg[0]} message={errMsg[1]} onClose={onErrClose} />
</WizardStep> </WizardStep>
<WizardStep stepId={2} > <WizardStep stepId={2} >
{cloudProvider == CLOUD_PROVIDERS.BIGANIMAL && callRDSAPI == 2 && <BigAnimalClusterType {cloudProvider == CLOUD_PROVIDERS.BIGANIMAL && callRDSAPI == 2 && <BigAnimalClusterType
cloudProvider={cloudProvider}
nodeInfo={nodeInfo}
nodeData={nodeData}
setBigAnimalClusterTypeData={setBigAnimalClusterTypeData}
hostIP={hostIP}
/> }
<FormFooterMessage type={errMsg[0]} message={errMsg[1]} onClose={onErrClose} />
</WizardStep>
<WizardStep stepId={3} >
{cloudProvider == CLOUD_PROVIDERS.AWS && callRDSAPI == 3 && <AwsInstanceDetails
cloudProvider={cloudProvider}
nodeInfo={nodeInfo}
nodeData={nodeData}
setCloudInstanceDetails={setCloudInstanceDetails}
hostIP={hostIP} /> }
{cloudProvider == CLOUD_PROVIDERS.BIGANIMAL && callRDSAPI == 3 && <BigAnimalInstance
cloudProvider={cloudProvider}
nodeInfo={nodeInfo}
nodeData={nodeData}
setBigAnimalInstanceData={setBigAnimalInstanceData}
hostIP={hostIP}
bigAnimalClusterTypeData={bigAnimalClusterTypeData}
/> }
{cloudProvider == CLOUD_PROVIDERS.AZURE && callRDSAPI == 3 && <AzureInstanceDetails
cloudProvider={cloudProvider}
nodeInfo={nodeInfo}
nodeData={nodeData}
setAzureInstanceData={setAzureInstanceData}
hostIP={hostIP}
azureInstanceData = {azureInstanceData}
/> }
{cloudProvider == CLOUD_PROVIDERS.GOOGLE && callRDSAPI == 3 && <GoogleInstanceDetails
cloudProvider={cloudProvider}
nodeInfo={nodeInfo}
nodeData={nodeData}
setGoogleInstanceData={setGoogleInstanceData}
hostIP={hostIP}
googleInstanceData = {googleInstanceData}
/> }
<FormFooterMessage type={errMsg[0]} message={errMsg[1]} onClose={onErrClose} />
</WizardStep>
<WizardStep stepId={4} >
{cloudProvider == CLOUD_PROVIDERS.AWS && <AwsDatabaseDetails
cloudProvider={cloudProvider}
nodeInfo={nodeInfo}
nodeData={nodeData}
setCloudDBDetails={setCloudDBDetails}
/>
}
{cloudProvider == CLOUD_PROVIDERS.BIGANIMAL && callRDSAPI == 4 && <BigAnimalDatabase
cloudProvider={cloudProvider}
nodeInfo={nodeInfo}
nodeData={nodeData}
setBigAnimalDatabaseData={setBigAnimalDatabaseData}
bigAnimalClusterTypeData={bigAnimalClusterTypeData}
/>
}
{cloudProvider == CLOUD_PROVIDERS.AZURE && <AzureDatabaseDetails
cloudProvider={cloudProvider}
nodeInfo={nodeInfo}
nodeData={nodeData}
setAzureDatabaseData={setAzureDatabaseData}
/>
}
{cloudProvider == CLOUD_PROVIDERS.GOOGLE && <GoogleDatabaseDetails
cloudProvider={cloudProvider}
nodeInfo={nodeInfo}
nodeData={nodeData}
setGoogleDatabaseData={setGoogleDatabaseData}
/>
}
</WizardStep>
<WizardStep stepId={5} >
<Box className={classes.boxText}>{gettext('Please review the details before creating the cloud instance.')}</Box>
<Paper variant="outlined" elevation={0} className={classes.summaryContainer}>
{cloudProvider == CLOUD_PROVIDERS.AWS && callRDSAPI == 5 && <FinalSummary
cloudProvider={cloudProvider} cloudProvider={cloudProvider}
nodeInfo={nodeInfo} instanceData={cloudInstanceDetails}
nodeData={nodeData} databaseData={cloudDBDetails}
setBigAnimalClusterTypeData={setBigAnimalClusterTypeData}
hostIP={hostIP}
/> }
<FormFooterMessage type={errMsg[0]} message={errMsg[1]} onClose={onErrClose} />
</WizardStep>
<WizardStep stepId={3} >
{cloudProvider == CLOUD_PROVIDERS.AWS && callRDSAPI == 3 && <AwsInstanceDetails
cloudProvider={cloudProvider}
nodeInfo={nodeInfo}
nodeData={nodeData}
setCloudInstanceDetails={setCloudInstanceDetails}
hostIP={hostIP} /> }
{cloudProvider == CLOUD_PROVIDERS.BIGANIMAL && callRDSAPI == 3 && <BigAnimalInstance
cloudProvider={cloudProvider}
nodeInfo={nodeInfo}
nodeData={nodeData}
setBigAnimalInstanceData={setBigAnimalInstanceData}
hostIP={hostIP}
bigAnimalClusterTypeData={bigAnimalClusterTypeData}
/> }
{cloudProvider == CLOUD_PROVIDERS.AZURE && callRDSAPI == 3 && <AzureInstanceDetails
cloudProvider={cloudProvider}
nodeInfo={nodeInfo}
nodeData={nodeData}
setAzureInstanceData={setAzureInstanceData}
hostIP={hostIP}
azureInstanceData = {azureInstanceData}
/> }
{cloudProvider == CLOUD_PROVIDERS.GOOGLE && callRDSAPI == 3 && <GoogleInstanceDetails
cloudProvider={cloudProvider}
nodeInfo={nodeInfo}
nodeData={nodeData}
setGoogleInstanceData={setGoogleInstanceData}
hostIP={hostIP}
googleInstanceData = {googleInstanceData}
/> }
<FormFooterMessage type={errMsg[0]} message={errMsg[1]} onClose={onErrClose} />
</WizardStep>
<WizardStep stepId={4} >
{cloudProvider == CLOUD_PROVIDERS.AWS && <AwsDatabaseDetails
cloudProvider={cloudProvider}
nodeInfo={nodeInfo}
nodeData={nodeData}
setCloudDBDetails={setCloudDBDetails}
/> />
} }
{cloudProvider == CLOUD_PROVIDERS.BIGANIMAL && callRDSAPI == 4 && <BigAnimalDatabase {cloudProvider == CLOUD_PROVIDERS.BIGANIMAL && callRDSAPI == 5 && <FinalSummary
cloudProvider={cloudProvider} cloudProvider={cloudProvider}
nodeInfo={nodeInfo} instanceData={bigAnimalInstanceData}
nodeData={nodeData} databaseData={bigAnimalDatabaseData}
setBigAnimalDatabaseData={setBigAnimalDatabaseData} clusterTypeData={bigAnimalClusterTypeData}
bigAnimalClusterTypeData={bigAnimalClusterTypeData}
/> />
} }
{cloudProvider == CLOUD_PROVIDERS.AZURE && <AzureDatabaseDetails {cloudProvider == CLOUD_PROVIDERS.AZURE && callRDSAPI == 5 && <FinalSummary
cloudProvider={cloudProvider} cloudProvider={cloudProvider}
nodeInfo={nodeInfo} instanceData={azureInstanceData}
nodeData={nodeData} databaseData={azureDatabaseData}
setAzureDatabaseData={setAzureDatabaseData}
/> />
} }
{cloudProvider == CLOUD_PROVIDERS.GOOGLE && <GoogleDatabaseDetails {cloudProvider == CLOUD_PROVIDERS.GOOGLE && callRDSAPI == 5 && <FinalSummary
cloudProvider={cloudProvider} cloudProvider={cloudProvider}
nodeInfo={nodeInfo} instanceData={googleInstanceData}
nodeData={nodeData} databaseData={googleDatabaseData}
setGoogleDatabaseData={setGoogleDatabaseData}
/> />
} }
</WizardStep> </Paper>
<WizardStep stepId={5} > </WizardStep>
<Box className={classes.boxText}>{gettext('Please review the details before creating the cloud instance.')}</Box> </Wizard>
<Paper variant="outlined" elevation={0} className={classes.summaryContainer}>
{cloudProvider == CLOUD_PROVIDERS.AWS && callRDSAPI == 5 && <FinalSummary
cloudProvider={cloudProvider}
instanceData={cloudInstanceDetails}
databaseData={cloudDBDetails}
/>
}
{cloudProvider == CLOUD_PROVIDERS.BIGANIMAL && callRDSAPI == 5 && <FinalSummary
cloudProvider={cloudProvider}
instanceData={bigAnimalInstanceData}
databaseData={bigAnimalDatabaseData}
clusterTypeData={bigAnimalClusterTypeData}
/>
}
{cloudProvider == CLOUD_PROVIDERS.AZURE && callRDSAPI == 5 && <FinalSummary
cloudProvider={cloudProvider}
instanceData={azureInstanceData}
databaseData={azureDatabaseData}
/>
}
{cloudProvider == CLOUD_PROVIDERS.GOOGLE && callRDSAPI == 5 && <FinalSummary
cloudProvider={cloudProvider}
instanceData={googleInstanceData}
databaseData={googleDatabaseData}
/>
}
</Paper>
</WizardStep>
</Wizard>
</>
</CloudWizardEventsContext.Provider> </CloudWizardEventsContext.Provider>
); );
} }

View File

@@ -61,7 +61,7 @@ export function AzureCredentials(props) {
}) })
.catch((error) => { .catch((error) => {
_eventBus.fireEvent('SET_ERROR_MESSAGE_FOR_CLOUD_WIZARD',[MESSAGE_TYPE.ERROR, gettext(`Error while verifying Microsoft Azure: ${error}`)]); _eventBus.fireEvent('SET_ERROR_MESSAGE_FOR_CLOUD_WIZARD',[MESSAGE_TYPE.ERROR, gettext(`Error while verifying Microsoft Azure: ${error}`)]);
reject(false); reject(new Error(gettext(error)));
}); });
}); });
}, },

View File

@@ -205,7 +205,7 @@ export function validateBigAnimal() {
} }
}) })
.catch((error) => { .catch((error) => {
reject(`Error while fetching EDB BigAnimal verification URI: ${error.response.data.errormsg}`); reject(new Error(`Error while fetching EDB BigAnimal verification URI: ${error.response.data.errormsg}`));
}); });
}); });
} }

View File

@@ -62,7 +62,7 @@ export function GoogleCredentials(props) {
}) })
.catch((error) => { .catch((error) => {
_eventBus.fireEvent('SET_ERROR_MESSAGE_FOR_CLOUD_WIZARD',[MESSAGE_TYPE.ERROR, gettext(`Error while authentication: ${error}`)]); _eventBus.fireEvent('SET_ERROR_MESSAGE_FOR_CLOUD_WIZARD',[MESSAGE_TYPE.ERROR, gettext(`Error while authentication: ${error}`)]);
reject(false); reject(new Error(gettext(`Error while authentication: ${error}`)));
}); });
}); });
}, },
@@ -201,7 +201,7 @@ GoogleInstanceDetails.propTypes = {
// Google Database Details // Google Database Details
export function GoogleDatabaseDetails(props) { export function GoogleDatabaseDetails(props) {
const [gooeleDBInstance, setGoogleDBInstance] = React.useState(); const [googleDBInstance, setGoogleDBInstance] = React.useState();
const classes = useStyles(); const classes = useStyles();
React.useMemo(() => { React.useMemo(() => {
@@ -220,7 +220,7 @@ export function GoogleDatabaseDetails(props) {
formType={'dialog'} formType={'dialog'}
getInitData={() => { /*This is intentional (SonarQube)*/ }} getInitData={() => { /*This is intentional (SonarQube)*/ }}
viewHelperProps={{ mode: 'create' }} viewHelperProps={{ mode: 'create' }}
schema={gooeleDBInstance} schema={googleDBInstance}
showFooter={false} showFooter={false}
isTabView={false} isTabView={false}
onDataChange={(isChanged, changedData) => { onDataChange={(isChanged, changedData) => {

View File

@@ -59,7 +59,7 @@ function parseData(data, node) {
if (element.icon == null || element.icon == '') { if (element.icon == null || element.icon == '') {
if (node) { if (node) {
element.icon = _.isFunction(node['node_image']) element.icon = _.isFunction(node['node_image'])
? node['node_image'].apply(node, [null, null]) ? node['node_image'](null, null)
: node['node_image'] || 'icon-' + element.type; : node['node_image'] || 'icon-' + element.type;
} else { } else {
element.icon = 'icon-' + element.type; element.icon = 'icon-' + element.type;

View File

@@ -59,7 +59,7 @@ function parseData(data, node) {
if (element.icon == null || element.icon == '') { if (element.icon == null || element.icon == '') {
if (node) { if (node) {
element.icon = _.isFunction(node['node_image']) element.icon = _.isFunction(node['node_image'])
? node['node_image'].apply(node, [null, null]) ? node['node_image'](null, null)
: node['node_image'] || 'icon-' + element.type; : node['node_image'] || 'icon-' + element.type;
} else { } else {
element.icon = 'icon-' + element.type; element.icon = 'icon-' + element.type;

View File

@@ -112,9 +112,7 @@ export default function CollectionNodeProperties({
selItem = pgAdmin.Browser.tree.selected(), selItem = pgAdmin.Browser.tree.selected(),
selectedItemData = selItem ? pgAdmin.Browser.tree.itemData(selItem) : null, selectedItemData = selItem ? pgAdmin.Browser.tree.itemData(selItem) : null,
selNode = selectedItemData && pgAdmin.Browser.Nodes[selectedItemData._type], selNode = selectedItemData && pgAdmin.Browser.Nodes[selectedItemData._type],
url = undefined, url, msg, title;
msg = undefined,
title = undefined;
if (selNode?.type == 'coll-constraints') { if (selNode?.type == 'coll-constraints') {
// In order to identify the constraint type, the type should be passed to the server // In order to identify the constraint type, the type should be passed to the server
@@ -206,7 +204,7 @@ export default function CollectionNodeProperties({
setLoaderText(gettext('Loading...')); setLoaderText(gettext('Loading...'));
if (!_.isUndefined(nodeObj.getSchema)) { if (!_.isUndefined(nodeObj.getSchema)) {
schemaRef.current = nodeObj.getSchema?.call(nodeObj, treeNodeInfo, nodeData); schemaRef.current = nodeObj.getSchema?.(treeNodeInfo, nodeData);
schemaRef.current?.fields.forEach((field) => { schemaRef.current?.fields.forEach((field) => {
if (node.columns.indexOf(field.id) > -1) { if (node.columns.indexOf(field.id) > -1) {
if (field.label.indexOf('?') > -1) { if (field.label.indexOf('?') > -1) {

View File

@@ -42,7 +42,7 @@ export default function ObjectNodeProperties({panelId, node, treeNodeInfo, nodeD
let warnOnCloseFlag = true; let warnOnCloseFlag = true;
const confirmOnCloseReset = usePreferences().getPreferencesForModule('browser').confirm_on_properties_close; const confirmOnCloseReset = usePreferences().getPreferencesForModule('browser').confirm_on_properties_close;
let updatedData = ['table', 'partition'].includes(nodeType) && !_.isEmpty(nodeData.rows_cnt) ? {rows_cnt: nodeData.rows_cnt} : undefined; let updatedData = ['table', 'partition'].includes(nodeType) && !_.isEmpty(nodeData.rows_cnt) ? {rows_cnt: nodeData.rows_cnt} : undefined;
let schema = node.getSchema.call(node, treeNodeInfo, nodeData); let schema = node.getSchema(treeNodeInfo, nodeData);
// We only have two actionTypes, 'create' and 'edit' to initiate the dialog, // We only have two actionTypes, 'create' and 'edit' to initiate the dialog,
// so if isActionTypeCopy is true, we should revert back to "create" since // so if isActionTypeCopy is true, we should revert back to "create" since

View File

@@ -1,3 +1,11 @@
/////////////////////////////////////////////////////////////
//
// pgAdmin 4 - PostgreSQL Tools
//
// Copyright (C) 2013 - 2024, The pgAdmin Development Team
// This software is released under the PostgreSQL Licence
//
//////////////////////////////////////////////////////////////
import { Box } from '@mui/material'; import { Box } from '@mui/material';
import { makeStyles } from '@mui/styles'; import { makeStyles } from '@mui/styles';
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
@@ -90,33 +98,32 @@ export default function AppMenuBar() {
const userMenuInfo = pgAdmin.Browser.utils.userMenuInfo; const userMenuInfo = pgAdmin.Browser.utils.userMenuInfo;
return( return(
<> <Box className={classes.root} data-test="app-menu-bar">
<Box className={classes.root} data-test="app-menu-bar"> <div className={classes.logo} />
<div className={classes.logo} /> <div className={classes.menus}>
<div className={classes.menus}> {pgAdmin.Browser.MainMenus?.map((menu)=>{
{pgAdmin.Browser.MainMenus?.map((menu)=>{ return (
return ( <PgMenu
<PgMenu menuButton={<PrimaryButton key={menu.label} data-label={menu.label}>{menu.label}<KeyboardArrowDownIcon fontSize="small" /></PrimaryButton>}
menuButton={<PrimaryButton key={menu.label} data-label={menu.label}>{menu.label}<KeyboardArrowDownIcon fontSize="small" /></PrimaryButton>} label={menu.label}
label={menu.label} key={menu.name}
key={menu.name} >
> {menu.getMenuItems().map((menuItem, i)=>{
{menu.getMenuItems().map((menuItem, i)=>{ const submenus = menuItem.getMenuItems();
const submenus = menuItem.getMenuItems(); if(submenus) {
if(submenus) { return <PgSubMenu key={menuItem.label} label={menuItem.label}>
return <PgSubMenu key={menuItem.label} label={menuItem.label}> {submenus.map((submenuItem, si)=>{
{submenus.map((submenuItem, si)=>{ return getPgMenuItem(submenuItem, si);
return getPgMenuItem(submenuItem, si); })}
})} </PgSubMenu>;
</PgSubMenu>; }
} return getPgMenuItem(menuItem, i);
return getPgMenuItem(menuItem, i); })}
})} </PgMenu>
</PgMenu> );
); })}
})} </div>
</div> {userMenuInfo &&
{userMenuInfo &&
<div className={classes.userMenu}> <div className={classes.userMenu}>
<PgMenu <PgMenu
menuButton={ menuButton={
@@ -124,7 +131,7 @@ export default function AppMenuBar() {
<div className={classes.gravatar}> <div className={classes.gravatar}>
{userMenuInfo.gravatar && {userMenuInfo.gravatar &&
<img src={userMenuInfo.gravatar} width = "18" height = "18" <img src={userMenuInfo.gravatar} width = "18" height = "18"
alt ={`Gravatar image for ${ userMenuInfo.username }`} />} alt ={`Gravatar for ${ userMenuInfo.username }`} />}
{!userMenuInfo.gravatar && <AccountCircleRoundedIcon />} {!userMenuInfo.gravatar && <AccountCircleRoundedIcon />}
</div> </div>
{ userMenuInfo.username } ({userMenuInfo.auth_source}) { userMenuInfo.username } ({userMenuInfo.auth_source})
@@ -139,7 +146,6 @@ export default function AppMenuBar() {
})} })}
</PgMenu> </PgMenu>
</div>} </div>}
</Box> </Box>
</>
); );
} }

View File

@@ -15,7 +15,7 @@ function convertImageURLtoDataURI(api, image) {
image.setAttribute('href', 'data:image/svg+xml;base64,'+window.btoa(data)); image.setAttribute('href', 'data:image/svg+xml;base64,'+window.btoa(data));
resolve(); resolve();
}).catch(()=>{ }).catch(()=>{
reject(); reject(new Error(null));
}); });
}); });
} }

View File

@@ -290,33 +290,31 @@ function DataTableRow({index, row, totalRows, isResizing, isHovered, schema, sch
drop(rowRef); drop(rowRef);
return useMemo(()=> return useMemo(()=>
<> <div {...row.getRowProps()} ref={rowRef} data-handler-id={handlerId}
<div {...row.getRowProps()} ref={rowRef} data-handler-id={handlerId} className={isHovered ? classes.tableRowHovered : null}
className={isHovered ? classes.tableRowHovered : null} data-test='data-table-row'
data-test='data-table-row' >
> {row.cells.map((cell, ci) => {
{row.cells.map((cell, ci) => { let classNames = [classes.tableCell];
let classNames = [classes.tableCell];
let {modeSupported} = cell.column.field? getFieldMetaData(cell.column.field, schemaRef.current, {}, viewHelperProps) : {modeSupported: true}; let {modeSupported} = cell.column.field? getFieldMetaData(cell.column.field, schemaRef.current, {}, viewHelperProps) : {modeSupported: true};
if(typeof(cell.column.id) == 'string' && cell.column.id.startsWith('btn-')) { if(typeof(cell.column.id) == 'string' && cell.column.id.startsWith('btn-')) {
classNames.push(classes.btnCell); classNames.push(classes.btnCell);
} }
if(cell.column.id == 'btn-edit' && row.isExpanded) { if(cell.column.id == 'btn-edit' && row.isExpanded) {
classNames.push(classes.expandedIconCell); classNames.push(classes.expandedIconCell);
} }
return (modeSupported && return (modeSupported &&
<div ref={cell.column.id == 'btn-reorder' ? dragHandleRef : null} key={ci} {...cell.getCellProps()} className={clsx(classNames)}> <div ref={cell.column.id == 'btn-reorder' ? dragHandleRef : null} key={ci} {...cell.getCellProps()} className={clsx(classNames)}>
{cell.render('Cell', { {cell.render('Cell', {
reRenderRow: ()=>{setKey((currKey)=>!currKey);} reRenderRow: ()=>{setKey((currKey)=>!currKey);}
})} })}
</div> </div>
); );
})} })}
<div className='hover-overlay'></div> <div className='hover-overlay'></div>
</div> </div>, depsMap);
</>, depsMap);
} }
export function DataGridHeader({label, canAdd, onAddClick, canSearch, onSearchTextChange}) { export function DataGridHeader({label, canAdd, onAddClick, canSearch, onSearchTextChange}) {

View File

@@ -428,54 +428,50 @@ export default function FormView({
if(isTabView) { if(isTabView) {
return ( return (
<> <Box height="100%" display="flex" flexDirection="column" className={className} ref={formRef} data-test="form-view">
<Box height="100%" display="flex" flexDirection="column" className={className} ref={formRef} data-test="form-view"> <Box>
<Box> <Tabs
<Tabs value={tabValue}
value={tabValue} onChange={(event, selTabValue) => {
onChange={(event, selTabValue) => { setTabValue(selTabValue);
setTabValue(selTabValue); }}
}} variant="scrollable"
variant="scrollable" scrollButtons="auto"
scrollButtons="auto" action={(ref)=>ref?.updateIndicator()}
action={(ref)=>ref?.updateIndicator()} >
> {Object.keys(finalTabs).map((tabName)=>{
{Object.keys(finalTabs).map((tabName)=>{ return <Tab key={tabName} label={tabName} data-test={tabName}/>;
return <Tab key={tabName} label={tabName} data-test={tabName}/>; })}
})} </Tabs>
</Tabs>
</Box>
{Object.keys(finalTabs).map((tabName, i)=>{
let contentClassName = [stateUtils.formErr.message ? classes.errorMargin : null];
if(fullTabs.indexOf(tabName) == -1) {
contentClassName.push(classes.nestedControl);
} else {
contentClassName.push(classes.fullControl);
}
return (
<TabPanel key={tabName} value={tabValue} index={i} classNameRoot={clsx(tabsClassname[tabName], isNested ? classes.nestedTabPanel : null)}
className={clsx(contentClassName)} data-testid={tabName}>
{finalTabs[tabName]}
</TabPanel>
);
})}
</Box> </Box>
</>); {Object.keys(finalTabs).map((tabName, i)=>{
let contentClassName = [stateUtils.formErr.message ? classes.errorMargin : null];
if(fullTabs.indexOf(tabName) == -1) {
contentClassName.push(classes.nestedControl);
} else {
contentClassName.push(classes.fullControl);
}
return (
<TabPanel key={tabName} value={tabValue} index={i} classNameRoot={clsx(tabsClassname[tabName], isNested ? classes.nestedTabPanel : null)}
className={clsx(contentClassName)} data-testid={tabName}>
{finalTabs[tabName]}
</TabPanel>
);
})}
</Box>);
} else { } else {
let contentClassName = [classes.nonTabPanelContent, stateUtils.formErr.message ? classes.errorMargin : null]; let contentClassName = [classes.nonTabPanelContent, stateUtils.formErr.message ? classes.errorMargin : null];
return ( return (
<> <Box height="100%" display="flex" flexDirection="column" className={clsx(className)} ref={formRef} data-test="form-view">
<Box height="100%" display="flex" flexDirection="column" className={clsx(className)} ref={formRef} data-test="form-view"> <TabPanel value={tabValue} index={0} classNameRoot={classes.nonTabPanel}
<TabPanel value={tabValue} index={0} classNameRoot={classes.nonTabPanel} className={clsx(contentClassName)}>
className={clsx(contentClassName)}> {Object.keys(finalTabs).map((tabName)=>{
{Object.keys(finalTabs).map((tabName)=>{ return (
return ( <React.Fragment key={tabName}>{finalTabs[tabName]}</React.Fragment>
<React.Fragment key={tabName}>{finalTabs[tabName]}</React.Fragment> );
); })}
})} </TabPanel>
</TabPanel> </Box>);
</Box>
</>);
} }
} }

View File

@@ -1,3 +1,11 @@
/////////////////////////////////////////////////////////////
//
// pgAdmin 4 - PostgreSQL Tools
//
// Copyright (C) 2013 - 2024, The pgAdmin Development Team
// This software is released under the PostgreSQL Licence
//
//////////////////////////////////////////////////////////////
import { Box } from '@mui/material'; import { Box } from '@mui/material';
import React, { useState } from 'react'; import React, { useState } from 'react';
import LoginImage from '../../img/login.svg?svgr'; import LoginImage from '../../img/login.svg?svgr';
@@ -68,39 +76,37 @@ AuthenticatorRegisterView.propTypes = {
export default function MfaRegisterPage({actionUrl, mfaList, nextUrl, mfaView, ...props}) { export default function MfaRegisterPage({actionUrl, mfaList, nextUrl, mfaView, ...props}) {
return ( return (
<> <BasePage title={gettext('Authentication Registration')} pageImage={<LoginImage style={{height: '100%', width: '100%'}} />} {...props}>
<BasePage title={gettext('Authentication Registration')} pageImage={<LoginImage style={{height: '100%', width: '100%'}} />} {...props}> <form style={{display:'flex', gap:'15px', flexDirection:'column', minHeight: 0}} action={actionUrl} method="POST">
<form style={{display:'flex', gap:'15px', flexDirection:'column', minHeight: 0}} action={actionUrl} method="POST"> {mfaView ? <>
{mfaView ? <> {mfaView.auth_method == 'email' && <EmailRegisterView mfaView={mfaView} />}
{mfaView.auth_method == 'email' && <EmailRegisterView mfaView={mfaView} />} {mfaView.auth_method == 'authenticator' && <AuthenticatorRegisterView mfaView={mfaView} />}
{mfaView.auth_method == 'authenticator' && <AuthenticatorRegisterView mfaView={mfaView} />} <Box display="flex" gap="15px">
<Box display="flex" gap="15px"> <SecurityButton name="continue" value="Continue">{gettext('Continue')}</SecurityButton>
<SecurityButton name="continue" value="Continue">{gettext('Continue')}</SecurityButton> <DefaultButton type="submit" name="cancel" value="Cancel" style={{width: '100%'}}>{gettext('Cancel')}</DefaultButton>
<DefaultButton type="submit" name="cancel" value="Cancel" style={{width: '100%'}}>{gettext('Cancel')}</DefaultButton> </Box>
</Box> </>:<>
</>:<> {mfaList?.map((m)=>{
{mfaList?.map((m)=>{ return (
return ( <Box display="flex" width="100%" key={m.label}>
<Box display="flex" width="100%" key={m.label}> <div style={{
<div style={{ width: '10%', mask: `url(${m.icon})`, maskRepeat: 'no-repeat',
width: '10%', mask: `url(${m.icon})`, maskRepeat: 'no-repeat', WebkitMask: `url(${m.icon})`, WebkitMaskRepeat: 'no-repeat',
WebkitMask: `url(${m.icon})`, WebkitMaskRepeat: 'no-repeat', backgroundColor: '#fff'
backgroundColor: '#fff' }}>
}}> </div>
</div> <div style={{width: '70%'}}>{m.label}</div>
<div style={{width: '70%'}}>{m.label}</div> <div style={{width: '20%'}}>
<div style={{width: '20%'}}> <SecurityButton name={m.id} value={m.registered ? 'DELETE' : 'SETUP'}>{m.registered ? gettext('Delete') : gettext('Setup')}</SecurityButton>
<SecurityButton name={m.id} value={m.registered ? 'DELETE' : 'SETUP'}>{m.registered ? gettext('Delete') : gettext('Setup')}</SecurityButton> </div>
</div> </Box>
</Box> );
); })}
})} {nextUrl != 'internal' && <SecurityButton value="Continue">{gettext('Continue')}</SecurityButton>}
{nextUrl != 'internal' && <SecurityButton value="Continue">{gettext('Continue')}</SecurityButton>} </>}
</>} <div><input type="hidden" name="next" value={nextUrl}/></div>
<div><input type="hidden" name="next" value={nextUrl}/></div> </form>
</form> </BasePage>
</BasePage>
</>
); );
} }

View File

@@ -1,3 +1,11 @@
/////////////////////////////////////////////////////////////
//
// pgAdmin 4 - PostgreSQL Tools
//
// Copyright (C) 2013 - 2024, The pgAdmin Development Team
// This software is released under the PostgreSQL Licence
//
//////////////////////////////////////////////////////////////
import React, { useState } from 'react'; import React, { useState } from 'react';
import LoginImage from '../../img/login.svg?svgr'; import LoginImage from '../../img/login.svg?svgr';
import { InputSelect, InputText, MESSAGE_TYPE, NotifierMessage } from '../components/FormComponents'; import { InputSelect, InputText, MESSAGE_TYPE, NotifierMessage } from '../components/FormComponents';
@@ -93,25 +101,23 @@ AuthenticatorValidateView.propTypes = {
export default function MfaValidatePage({actionUrl, views, logoutUrl, sendEmailUrl, csrfHeader, csrfToken, ...props}) { export default function MfaValidatePage({actionUrl, views, logoutUrl, sendEmailUrl, csrfHeader, csrfToken, ...props}) {
const [method, setMethod] = useState(Object.values(views).find((v)=>v.selected)?.id); const [method, setMethod] = useState(Object.values(views).find((v)=>v.selected)?.id);
return ( return (
<> <BasePage title={gettext('Authentication')} pageImage={<LoginImage style={{height: '100%', width: '100%'}} />} {...props}>
<BasePage title={gettext('Authentication')} pageImage={<LoginImage style={{height: '100%', width: '100%'}} />} {...props}> <form style={{display:'flex', gap:'15px', flexDirection:'column', minHeight: 0}} action={actionUrl} method="POST">
<form style={{display:'flex', gap:'15px', flexDirection:'column', minHeight: 0}} action={actionUrl} method="POST"> <InputSelect value={method} options={Object.keys(views).map((k)=>({
<InputSelect value={method} options={Object.keys(views).map((k)=>({ label: views[k].label,
label: views[k].label, value: views[k].id,
value: views[k].id, imageUrl: views[k].icon
imageUrl: views[k].icon }))} onChange={setMethod} controlProps={{
}))} onChange={setMethod} controlProps={{ allowClear: false,
allowClear: false, }} />
}} /> <div><input type='hidden' name='mfa_method' defaultValue={method} /></div>
<div><input type='hidden' name='mfa_method' defaultValue={method} /></div> {method == 'email' && <EmailValidateView mfaView={views[method].view} sendEmailUrl={sendEmailUrl} csrfHeader={csrfHeader} csrfToken={csrfToken} />}
{method == 'email' && <EmailValidateView mfaView={views[method].view} sendEmailUrl={sendEmailUrl} csrfHeader={csrfHeader} csrfToken={csrfToken} />} {method == 'authenticator' && <AuthenticatorValidateView mfaView={views[method].view} />}
{method == 'authenticator' && <AuthenticatorValidateView mfaView={views[method].view} />} <div style={{textAlign: 'right'}}>
<div style={{textAlign: 'right'}}> <a style={{color:'inherit'}} href={logoutUrl}>{gettext('Logout')}</a>
<a style={{color:'inherit'}} href={logoutUrl}>{gettext('Logout')}</a> </div>
</div> </form>
</form> </BasePage>
</BasePage>
</>
); );
} }

View File

@@ -1,3 +1,11 @@
/////////////////////////////////////////////////////////////
//
// pgAdmin 4 - PostgreSQL Tools
//
// Copyright (C) 2013 - 2024, The pgAdmin Development Team
// This software is released under the PostgreSQL Licence
//
//////////////////////////////////////////////////////////////
import { Box } from '@mui/material'; import { Box } from '@mui/material';
import { makeStyles } from '@mui/styles'; import { makeStyles } from '@mui/styles';
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
@@ -68,24 +76,22 @@ export default function ObjectBreadcrumbs() {
} }
return( return(
<> <Box className={classes.root} data-testid="object-breadcrumbs">
<Box className={classes.root} data-testid="object-breadcrumbs"> <div className={classes.row}>
<div className={classes.row}> <AccountTreeIcon style={{height: '1rem', marginRight: '0.125rem'}} data-label="AccountTreeIcon"/>
<AccountTreeIcon style={{height: '1rem', marginRight: '0.125rem'}} data-label="AccountTreeIcon"/> <div className={classes.overflow}>
<div className={classes.overflow}> {
{ objectData.path?.reduce((res, item)=>(
objectData.path?.reduce((res, item)=>( res.concat(<span key={item}>{item}</span>, <ArrowForwardIosRoundedIcon key={item+'-arrow'} style={{height: '0.8rem', width: '1.25rem'}} />)
res.concat(<span key={item}>{item}</span>, <ArrowForwardIosRoundedIcon key={item+'-arrow'} style={{height: '0.8rem', width: '1.25rem'}} />) ), []).slice(0, -1)
), []).slice(0, -1) }
}
</div>
</div> </div>
{preferences.breadcrumbs_show_comment && objectData.description && </div>
{preferences.breadcrumbs_show_comment && objectData.description &&
<div className={classes.row}> <div className={classes.row}>
<CommentIcon style={{height: '1rem', marginRight: '0.125rem'}} data-label="CommentIcon"/> <CommentIcon style={{height: '1rem', marginRight: '0.125rem'}} data-label="CommentIcon"/>
<div className={classes.overflow}>{objectData.description}</div> <div className={classes.overflow}>{objectData.description}</div>
</div>} </div>}
</Box> </Box>
</>
); );
} }

View File

@@ -207,13 +207,11 @@ const IndeterminateCheckbox = React.forwardRef(
resolvedRef.current.indeterminate = indeterminate; resolvedRef.current.indeterminate = indeterminate;
}, [resolvedRef, indeterminate]); }, [resolvedRef, indeterminate]);
return ( return (
<> <Checkbox
<Checkbox color="primary"
color="primary" ref={resolvedRef} {...rest}
ref={resolvedRef} {...rest} inputProps={{'aria-label': label}}
inputProps={{'aria-label': label}} />
/>
</>
); );
}, },
); );

View File

@@ -1,3 +1,11 @@
/////////////////////////////////////////////////////////////
//
// pgAdmin 4 - PostgreSQL Tools
//
// Copyright (C) 2013 - 2024, The pgAdmin Development Team
// This software is released under the PostgreSQL Licence
//
//////////////////////////////////////////////////////////////
import {useRef, useEffect, useState, useCallback, useLayoutEffect} from 'react'; import {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';
@@ -53,10 +61,10 @@ export function useDelayDebounce(callback, args, delay) {
} }
export function useOnScreen(ref) { export function useOnScreen(ref) {
const [isIntersecting, setIntersecting] = useState(false); const [intersecting, setIntersecting] = useState(false);
const observer = new IntersectionObserver( const observer = new IntersectionObserver(
([entry]) => { ([entry]) => {
setIntersecting(entry.isIntersecting); setIntersecting(entry.intersecting);
} }
); );
useEffect(() => { useEffect(() => {
@@ -67,7 +75,7 @@ export function useOnScreen(ref) {
return () => { observer.disconnect(); }; return () => { observer.disconnect(); };
}, []); }, []);
return isIntersecting; return intersecting;
} }
export function useIsMounted() { export function useIsMounted() {

View File

@@ -36,7 +36,7 @@ export default function DataGridViewWithHeaderForm(props) {
const classes = useStyles(); const classes = useStyles();
const headerFormData = useRef({}); const headerFormData = useRef({});
const schemaRef = useRef(otherProps.schema); const schemaRef = useRef(otherProps.schema);
const [isAddDisabled, setAddDisabled] = useState(true); const [addDisabled, setAddDisabled] = useState(true);
const [headerFormResetKey, setHeaderFormResetKey] = useState(0); const [headerFormResetKey, setHeaderFormResetKey] = useState(0);
const onAddClick = useCallback(()=>{ const onAddClick = useCallback(()=>{
if(!otherProps.canAddRow) { if(!otherProps.canAddRow) {
@@ -80,7 +80,7 @@ export default function DataGridViewWithHeaderForm(props) {
resetKey={headerFormResetKey} resetKey={headerFormResetKey}
/> />
<Box display="flex"> <Box display="flex">
<DefaultButton className={classes.addBtn} onClick={onAddClick} disabled={isAddDisabled}>Add</DefaultButton> <DefaultButton className={classes.addBtn} onClick={onAddClick} disabled={addDisabled}>Add</DefaultButton>
</Box> </Box>
</Box>} </Box>}
</Box> </Box>

View File

@@ -1,3 +1,11 @@
/////////////////////////////////////////////////////////////
//
// pgAdmin 4 - PostgreSQL Tools
//
// Copyright (C) 2013 - 2024, The pgAdmin Development Team
// This software is released under the PostgreSQL Licence
//
//////////////////////////////////////////////////////////////
import { Portal } from '@mui/material'; import { Portal } from '@mui/material';
import React, { useEffect, useRef, useState } from 'react'; import React, { useEffect, useRef, useState } from 'react';
import Frame from 'react-frame-component'; import Frame from 'react-frame-component';
@@ -47,7 +55,7 @@ export default function LayoutIframeTab({target, src, children}) {
}; };
}, [iframeTarget]); }, [iframeTarget]);
return <> return (
<div ref={selfRef} data-target={target} style={{width: '100%', height: '100%'}}> <div ref={selfRef} data-target={target} style={{width: '100%', height: '100%'}}>
<Portal ref={(r)=>{ <Portal ref={(r)=>{
if(r) setIframeTarget(r.querySelector('#'+target)); if(r) setIframeTarget(r.querySelector('#'+target));
@@ -59,8 +67,7 @@ export default function LayoutIframeTab({target, src, children}) {
</Frame> </Frame>
} }
</Portal> </Portal>
</div> </div>);
</>;
} }
LayoutIframeTab.propTypes = { LayoutIframeTab.propTypes = {

View File

@@ -15,7 +15,7 @@ export default class Menu {
this.name = name; this.name = name;
this.id = id; this.id = id;
this.index = index || 1; this.index = index || 1;
this.menuItems = [], this.menuItems = [];
this.addSepratior = addSepratior || false; this.addSepratior = addSepratior || false;
} }
@@ -202,7 +202,7 @@ export class MenuItem {
return true; return true;
} }
if (this.module && _.isFunction(this.module[this.enable])) { if (this.module && _.isFunction(this.module[this.enable])) {
return !(this.module[this.enable]).apply(this.module, [node, item, this.data]); return !(this.module[this.enable])(node, item, this.data);
} }
return false; return false;

View File

@@ -276,35 +276,34 @@ function ModalContainer({ id, title, content, dialogHeight, dialogWidth, onClose
onClose?.(); onClose?.();
} }
}; };
const [isfullScreen, setIsFullScreen] = useState(fullScreen); const [isFullScreen, setIsFullScreen] = useState(fullScreen);
return ( return (
<Dialog <Dialog
open={true} open={true}
onClose={closeModal} onClose={closeModal}
PaperComponent={PaperComponent} PaperComponent={PaperComponent}
PaperProps={{ 'isfullscreen': isfullScreen.toString(), 'isresizeable': isResizeable.toString(), width: dialogWidth, height: dialogHeight, minHeight: minHeight, minWidth: minWidth }} PaperProps={{ 'isfullscreen': isFullScreen.toString(), 'isresizeable': isResizeable.toString(), width: dialogWidth, height: dialogHeight, minHeight: minHeight, minWidth: minWidth }}
fullScreen={isfullScreen} fullScreen={isFullScreen}
fullWidth={isFullWidth} fullWidth={isFullWidth}
disablePortal disablePortal
> >
{ showTitle && <> { showTitle &&
<DialogTitle className='modal-drag-area'> <DialogTitle className='modal-drag-area'>
<Box className={classes.titleBar}> <Box className={classes.titleBar}>
<Box className={classes.title} marginRight="0.25rem" >{title}</Box> <Box className={classes.title} marginRight="0.25rem" >{title}</Box>
{ {
showFullScreen && !isfullScreen && showFullScreen && !isFullScreen &&
<Box className={classes.iconButtonStyle}><PgIconButton title={gettext('Maximize')} icon={<ExpandDialogIcon className={classes.icon} />} size="xs" noBorder onClick={() => { setIsFullScreen(!isfullScreen); }} /></Box> <Box className={classes.iconButtonStyle}><PgIconButton title={gettext('Maximize')} icon={<ExpandDialogIcon className={classes.icon} />} size="xs" noBorder onClick={() => { setIsFullScreen(!isFullScreen); }} /></Box>
} }
{ {
showFullScreen && isfullScreen && showFullScreen && isFullScreen &&
<Box className={classes.iconButtonStyle}><PgIconButton title={gettext('Minimize')} icon={<MinimizeDialogIcon className={classes.icon} />} size="xs" noBorder onClick={() => { setIsFullScreen(!isfullScreen); }} /></Box> <Box className={classes.iconButtonStyle}><PgIconButton title={gettext('Minimize')} icon={<MinimizeDialogIcon className={classes.icon} />} size="xs" noBorder onClick={() => { setIsFullScreen(!isFullScreen); }} /></Box>
} }
<Box marginLeft="auto"><PgIconButton title={gettext('Close')} icon={<CloseIcon />} size="xs" noBorder onClick={closeModal} /></Box> <Box marginLeft="auto"><PgIconButton title={gettext('Close')} icon={<CloseIcon />} size="xs" noBorder onClick={closeModal} /></Box>
</Box> </Box>
</DialogTitle> </DialogTitle>
</>
} }
<DialogContent height="100%"> <DialogContent height="100%">
{useMemo(()=>{ return content(closeModal); }, [])} {useMemo(()=>{ return content(closeModal); }, [])}

View File

@@ -136,7 +136,7 @@ function Wizard({ stepList, onStepChange, onSave, className, ...props }) {
const classes = useStyles(); const classes = useStyles();
const [activeStep, setActiveStep] = React.useState(0); const [activeStep, setActiveStep] = React.useState(0);
const steps = stepList && stepList.length > 0 ? stepList : []; const steps = stepList && stepList.length > 0 ? stepList : [];
const [disableNext, setdisableNext] = React.useState(false); const [disableNext, setDisableNext] = React.useState(false);
const handleNext = () => { const handleNext = () => {
@@ -177,7 +177,7 @@ function Wizard({ stepList, onStepChange, onSave, className, ...props }) {
React.useEffect(() => { React.useEffect(() => {
if (props.disableNextStep) { if (props.disableNextStep) {
setdisableNext(props.disableNextStep(activeStep)); setDisableNext(props.disableNextStep(activeStep));
} }
}); });

View File

@@ -347,7 +347,7 @@ export class Tree {
let tree = this; let tree = this;
if (path == null || !Array.isArray(path)) { if (path == null || !Array.isArray(path)) {
return Promise.reject(); return Promise.reject(new Error(null));
} }
const basepath = '/browser/' + path.slice(0, path.length-1).join('/') + '/'; const basepath = '/browser/' + path.slice(0, path.length-1).join('/') + '/';
path = '/browser/' + path.join('/'); path = '/browser/' + path.join('/');
@@ -366,7 +366,7 @@ export class Tree {
* the path for currentNode itself is not matching * the path for currentNode itself is not matching
*/ */
if (currentNode.path !== undefined && !onCorrectPath(currentNode.path)) { if (currentNode.path !== undefined && !onCorrectPath(currentNode.path)) {
reject(null); reject(new Error(null));
} else if (currentNode.path === path) { } else if (currentNode.path === path) {
resolve(currentNode); resolve(currentNode);
} else { } else {
@@ -380,10 +380,10 @@ export class Tree {
return; return;
} }
} }
reject(null); reject(new Error(null));
}) })
.catch(() => { .catch(() => {
reject(null); reject(new Error(null));
}); });
} }
}); });
@@ -403,7 +403,7 @@ export class Tree {
currItem = currItem.parent; currItem = currItem.parent;
} }
retStack = retStack.reverse(); retStack = retStack.reverse();
if(separator == false) return retStack; if(!separator) return retStack;
return retStack.join(separator); return retStack.join(separator);
} }
@@ -621,6 +621,6 @@ export function findInTree(rootNode, path) {
})(rootNode); })(rootNode);
} }
let isValidTreeNodeData = (data) => (!_.isEmpty(data)); const isValidTreeNodeData = (data) => (!_.isEmpty(data));
export { isValidTreeNodeData }; export { isValidTreeNodeData };

View File

@@ -128,12 +128,10 @@ class ERDTool extends React.Component {
this.diagram = new ERDCore(); this.diagram = new ERDCore();
/* Flag for checking if user has opted for save before close */ /* Flag for checking if user has opted for save before close */
this.closeOnSave = React.createRef(); this.closeOnSave = React.createRef();
this.fileInputRef = React.createRef();
this.containerRef = React.createRef(); this.containerRef = React.createRef();
this.diagramContainerRef = React.createRef(); this.diagramContainerRef = React.createRef();
this.canvasEle = props.isTest ? document.createElement('div') : null; this.canvasEle = props.isTest ? document.createElement('div') : null;
this.noteRefEle = null; this.noteRefEle = null;
this.noteNode = null;
this.keyboardActionObj = null; this.keyboardActionObj = null;
this.erdDialogs = new ERDDialogs(this.context); this.erdDialogs = new ERDDialogs(this.context);
this.apiObj = getApiInstance(); this.apiObj = getApiInstance();
@@ -486,7 +484,7 @@ class ERDTool extends React.Component {
}) })
.catch((err)=>{ .catch((err)=>{
console.error(err); console.error(err);
reject(); reject(new Error(err));
}); });
}); });
const {x, y} = this.diagram.getEngine().getRelativeMousePoint(e); const {x, y} = this.diagram.getEngine().getRelativeMousePoint(e);
@@ -641,7 +639,7 @@ class ERDTool extends React.Component {
this.setTitle(fileName); this.setTitle(fileName);
this.setLoading(null); this.setLoading(null);
if(this.closeOnSave) { if(this.closeOnSave) {
this.closePanel.call(this); this.closePanel();
} }
}).catch((err)=>{ }).catch((err)=>{
this.setLoading(null); this.setLoading(null);

View File

@@ -343,12 +343,11 @@ class TableNodeWidgetRaw extends React.Component {
}} }}
/>} />}
</div> </div>
{tableMetaData.is_promise && <> {tableMetaData.is_promise &&
<div className={classes.tableSection}> <div className={classes.tableSection}>
{!tableMetaData.data_failed && <div className={classes.tableNameText}>{gettext('Fetching...')}</div>} {!tableMetaData.data_failed && <div className={classes.tableNameText}>{gettext('Fetching...')}</div>}
{tableMetaData.data_failed && <div className={clsx(classes.tableNameText, classes.error)}>{gettext('Failed to get data. Please delete this table.')}</div>} {tableMetaData.data_failed && <div className={clsx(classes.tableNameText, classes.error)}>{gettext('Failed to get data. Please delete this table.')}</div>}
</div> </div>}
</>}
{!tableMetaData.is_promise && <> {!tableMetaData.is_promise && <>
<div className={classes.tableSection}> <div className={classes.tableSection}>
<RowIcon icon={SchemaIcon}/> <RowIcon icon={SchemaIcon}/>

View File

@@ -115,9 +115,9 @@ export default function GrantWizard({ sid, did, nodeInfo, nodeData, onClose }) {
let steps = [gettext('Object Selection'), gettext('Privilege Selection'), gettext('Review')]; let steps = [gettext('Object Selection'), gettext('Privilege Selection'), gettext('Review')];
const [selectedObject, setSelectedObject] = React.useState([]); const [selectedObject, setSelectedObject] = React.useState([]);
const [selectedAcl, setSelectedAcl] = React.useState({}); const [selectedAcl, setSelectedAcl] = React.useState({});
const [msqlData, setSQL] = React.useState(''); const [msqlData, setMSQLData] = React.useState('');
const [loaderText, setLoaderText] = React.useState(''); const [loaderText, setLoaderText] = React.useState('');
const [tablebData, setTableData] = React.useState([]); const [tableData, setTableData] = React.useState([]);
const [privOptions, setPrivOptions] = React.useState({}); const [privOptions, setPrivOptions] = React.useState({});
const [privileges, setPrivileges] = React.useState([]); const [privileges, setPrivileges] = React.useState([]);
const [privSchemaInstance, setPrivSchemaInstance] = React.useState(); const [privSchemaInstance, setPrivSchemaInstance] = React.useState();
@@ -201,7 +201,7 @@ export default function GrantWizard({ sid, did, nodeInfo, nodeData, onClose }) {
}; };
api.post(msql_url, post_data) api.post(msql_url, post_data)
.then(res => { .then(res => {
setSQL(res.data.data); setMSQLData(res.data.data);
setLoaderText(''); setLoaderText('');
}) })
.catch(() => { .catch(() => {
@@ -319,7 +319,7 @@ export default function GrantWizard({ sid, did, nodeInfo, nodeData, onClose }) {
className={classes.table} className={classes.table}
height={window.innerHeight - 450} height={window.innerHeight - 450}
columns={columns} columns={columns}
data={tablebData} data={tableData}
isSelectRow={true} isSelectRow={true}
getSelectedRows={getTableSelectedRows}> getSelectedRows={getTableSelectedRows}>
</PgTable> </PgTable>

View File

@@ -175,7 +175,7 @@ export default function ImportExportServers({onClose}) {
.catch(() => { .catch(() => {
setLoaderText(''); setLoaderText('');
setErrMsg(gettext('Error while fetching Server Groups and Servers.')); setErrMsg(gettext('Error while fetching Server Groups and Servers.'));
reject(); reject(new Error(gettext('Error while fetching Server Groups and Servers.')));
}); });
} else if (selectionFormData.imp_exp == 'i') { } else if (selectionFormData.imp_exp == 'i') {
let load_servers_url = url_for('import_export_servers.load_servers'); let load_servers_url = url_for('import_export_servers.load_servers');
@@ -192,7 +192,7 @@ export default function ImportExportServers({onClose}) {
.catch((err) => { .catch((err) => {
setLoaderText(''); setLoaderText('');
setErrMsg(err.response.data.errormsg); setErrMsg(err.response.data.errormsg);
reject(); reject(new Error(err.response.data.errormsg));
}); });
} }
} else { } else {

View File

@@ -212,11 +212,10 @@ export function TextEditor({row, column, onRowChange, onClose}) {
{gettext('Cancel')} {gettext('Cancel')}
</DefaultButton> </DefaultButton>
{column.can_edit && {column.can_edit &&
<>
<PrimaryButton startIcon={<CheckRoundedIcon />} onClick={onOK} size="small" className={classes.buttonMargin}> <PrimaryButton startIcon={<CheckRoundedIcon />} onClick={onOK} size="small" className={classes.buttonMargin}>
{gettext('OK')} {gettext('OK')}
</PrimaryButton> </PrimaryButton>
</>} }
</Box> </Box>
</Box> </Box>
</Portal> </Portal>
@@ -390,11 +389,10 @@ export function JsonTextEditor({row, column, onRowChange, onClose}) {
{gettext('Cancel')} {gettext('Cancel')}
</DefaultButton> </DefaultButton>
{column.can_edit && {column.can_edit &&
<>
<PrimaryButton startIcon={<CheckRoundedIcon />} onClick={onOK} size="small" className={classes.buttonMargin}> <PrimaryButton startIcon={<CheckRoundedIcon />} onClick={onOK} size="small" className={classes.buttonMargin}>
{gettext('OK')} {gettext('OK')}
</PrimaryButton> </PrimaryButton>
</>} }
</Box> </Box>
</Box> </Box>
</Portal> </Portal>

View File

@@ -130,7 +130,7 @@ export default function FilterDialog({onClose, onSave}) {
}); });
}; };
return (<> return (
<SchemaView <SchemaView
formType={'dialog'} formType={'dialog'}
getInitData={getInitData} getInitData={getInitData}
@@ -147,7 +147,7 @@ export default function FilterDialog({onClose, onSave}) {
formClassName={classes.root} formClassName={classes.root}
checkDirtyOnEnableSave={true} checkDirtyOnEnableSave={true}
/> />
</>); );
} }
FilterDialog.propTypes = { FilterDialog.propTypes = {

View File

@@ -159,7 +159,7 @@ export default function MacrosDialog({onClose, onSave}) {
if(keyOptions.length <= 0) { if(keyOptions.length <= 0) {
return <></>; return <></>;
} }
return (<> return (
<SchemaView <SchemaView
formType={'dialog'} formType={'dialog'}
getInitData={()=>{ getInitData={()=>{
@@ -180,7 +180,7 @@ export default function MacrosDialog({onClose, onSave}) {
isTabView={false} isTabView={false}
formClassName={classes.root} formClassName={classes.root}
/> />
</>); );
} }
MacrosDialog.propTypes = { MacrosDialog.propTypes = {

View File

@@ -255,8 +255,8 @@ export function GraphVisualiser({initColumns}) {
const eventBus = useContext(QueryToolEventsContext); const eventBus = useContext(QueryToolEventsContext);
const queryToolCtx = useContext(QueryToolContext); const queryToolCtx = useContext(QueryToolContext);
const [graphType, setGraphType] = useState('L'); const [graphType, setGraphType] = useState('L');
const [xaxis, setXAxis] = useState(null); const [xAxis, setXAxis] = useState(null);
const [yaxis, setYAxis] = useState([]); const [yAxis, setYAxis] = useState([]);
const [[graphData, graphDataKey], setGraphData] = useState([{'datasets': []}, 0]); const [[graphData, graphDataKey], setGraphData] = useState([{'datasets': []}, 0]);
const [loaderText, setLoaderText] = useState(''); const [loaderText, setLoaderText] = useState('');
const [columns, setColumns] = useState(initColumns); const [columns, setColumns] = useState(initColumns);
@@ -359,7 +359,7 @@ export function GraphVisualiser({initColumns}) {
setLoaderText(gettext('Rendering data points...')); setLoaderText(gettext('Rendering data points...'));
// Set the Graph Data // Set the Graph Data
setGraphData( setGraphData(
(prev)=> [getGraphDataSet(graphType, res.data.data.result, columns, xaxis, _.isArray(yaxis) ? yaxis : [yaxis] , queryToolCtx), prev[1] + 1] (prev)=> [getGraphDataSet(graphType, res.data.data.result, columns, xAxis, _.isArray(yAxis) ? yAxis : [yAxis] , queryToolCtx), prev[1] + 1]
); );
setLoaderText(''); setLoaderText('');
@@ -411,7 +411,7 @@ export function GraphVisualiser({initColumns}) {
} }
}} value={graphType} /> }} value={graphType} />
<DefaultButton style={{marginLeft: 'auto'}} onClick={onGenerate} startIcon={<ShowChartRoundedIcon />} <DefaultButton style={{marginLeft: 'auto'}} onClick={onGenerate} startIcon={<ShowChartRoundedIcon />}
disabled={ _.isEmpty(xaxis) || yaxis.length <= 0 }> disabled={ _.isEmpty(xAxis) || yAxis.length <= 0 }>
{gettext('Generate')} {gettext('Generate')}
</DefaultButton> </DefaultButton>
<PgIconButton title={expandedState ? gettext('Collapse') : gettext('Expand')} <PgIconButton title={expandedState ? gettext('Collapse') : gettext('Expand')}
@@ -422,12 +422,12 @@ export function GraphVisualiser({initColumns}) {
<Box className={classes.displayFlex}> <Box className={classes.displayFlex}>
<span className={classes.spanLabel}>{graphType != 'P' ? gettext('X Axis') : gettext('Label')}</span> <span className={classes.spanLabel}>{graphType != 'P' ? gettext('X Axis') : gettext('Label')}</span>
<InputSelect className={classes.axisSelectCtrl} options={xAxisOptions} <InputSelect className={classes.axisSelectCtrl} options={xAxisOptions}
onChange={(v)=>setXAxis(v)} value={xaxis} optionsReloadBasis={optionsReload}/> onChange={(v)=>setXAxis(v)} value={xAxis} optionsReloadBasis={optionsReload}/>
</Box> </Box>
<Box className={classes.displayFlex}> <Box className={classes.displayFlex}>
<span className={classes.spanLabel}>{graphType != 'P' ? gettext('Y Axis') : gettext('Value')}</span> <span className={classes.spanLabel}>{graphType != 'P' ? gettext('Y Axis') : gettext('Value')}</span>
<InputSelect className={classes.axisSelectCtrl} controlProps={{'multiple': graphType != 'P', allowSelectAll: graphType != 'P'}} <InputSelect className={classes.axisSelectCtrl} controlProps={{'multiple': graphType != 'P', allowSelectAll: graphType != 'P'}}
options={yAxisOptions} onChange={(v)=>setYAxis(v)} value={yaxis} optionsReloadBasis={optionsReload}/> options={yAxisOptions} onChange={(v)=>setYAxis(v)} value={yAxis} optionsReloadBasis={optionsReload}/>
</Box> </Box>
</> </>
} }

View File

@@ -378,7 +378,6 @@ export function QueryHistory() {
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 [loaderText, setLoaderText] = React.useState(''); const [loaderText, setLoaderText] = React.useState('');
const [,refresh] = React.useState({});
const selectedEntry = qhu.current.getEntry(selectedItemKey); const selectedEntry = qhu.current.getEntry(selectedItemKey);
const layoutDocker = useContext(LayoutDockerContext); const layoutDocker = useContext(LayoutDockerContext);
const listRef = React.useRef(); const listRef = React.useRef();
@@ -425,7 +424,6 @@ export function QueryHistory() {
}; };
} }
qhu.current.addEntry(h); qhu.current.addEntry(h);
refresh({});
}; };
listRef.current?.focus(); listRef.current?.focus();