From b51eef12b7b2a167277c599336afe11e657dfbea Mon Sep 17 00:00:00 2001 From: Pravesh Sharma Date: Wed, 6 Nov 2024 15:52:31 +0530 Subject: [PATCH] Add an object menu option to disconnect all server and database connections. #1984 --- .../servers/databases/static/js/database.js | 126 +++++++++---- .../server_groups/servers/static/js/server.js | 167 +++++++++++------- .../overrides/pgadmin.classes.override.js | 3 + web/pgadmin/static/js/tree/tree.js | 2 +- 4 files changed, 203 insertions(+), 95 deletions(-) diff --git a/web/pgadmin/browser/server_groups/servers/databases/static/js/database.js b/web/pgadmin/browser/server_groups/servers/databases/static/js/database.js index d4c1ce592..2f5b4b739 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/static/js/database.js +++ b/web/pgadmin/browser/server_groups/servers/databases/static/js/database.js @@ -109,6 +109,13 @@ define('pgadmin.node.database', [ enable : 'is_connected',data: { data_disabled: gettext('Selected database is already disconnected.'), }, + },{ + name: 'disconnect_all_databases', node: 'coll-database', module: this, + applies: ['object', 'context'], callback: 'disconnect_all_databases', + category: 'disconnect', priority: 5, label: gettext('Disconnect from all databases'), + enable: 'can_disconnect',data: { + data_disabled: gettext('All the databases are already disconnected.'), + }, },{ name: 'generate_erd', node: 'database', module: this, applies: ['object', 'context'], callback: 'generate_erd', @@ -207,6 +214,14 @@ define('pgadmin.node.database', [ } } }, + can_disconnect: function(node, item) { + return _.some(item.children, (child) => { + let data = pgAdmin.Browser.tree.getData(child), + {connected, canDisconn} = data; + return connected && canDisconn; + } + ); + }, callbacks: { /* Connect the database */ connect_database: function(args){ @@ -230,45 +245,31 @@ define('pgadmin.node.database', [ d = i ? t.itemData(i) : undefined; if (d) { + disconnect_from_database(obj, d, t, i, true); + } + + return false; + }, + + disconnect_all_databases: function(args, item) { + let children = item.children ?? [], + obj = this, + t = pgBrowser.tree; + + if (children) { pgAdmin.Browser.notifier.confirm( - gettext('Disconnect from database'), - gettext('Are you sure you want to disconnect from database - %s?', d.label), + gettext('Disconnect from all databases'), + gettext('Are you sure you want to disconnect from all databases?'), function() { - let data = d; - getApiInstance().delete( - obj.generate_url(i, 'connect', d, true), - ).then(({data: res})=> { - if (res.success == 1) { - let prv_i = t.parent(i); - if(res.data.info_prefix) { - res.info = `${_.escape(res.data.info_prefix)} - ${res.info}`; - } - pgAdmin.Browser.notifier.success(res.info); - t.removeIcon(i); - data.connected = false; - data.icon = data.isTemplate ? 'icon-database-template-not-connected':'icon-database-not-connected'; - - t.addIcon(i, {icon: data.icon}); - t.unload(i); - pgBrowser.Events.trigger('pgadmin:browser:tree:update-tree-state', i); - setTimeout(function() { - t.select(prv_i); - }, 10); - - } else { - try { - pgAdmin.Browser.notifier.error(res.errormsg); - } catch (e) { - console.warn(e.stack || e); - } - t.unload(i); + _.forEach(children, function(child) { + let data = pgAdmin.Browser.tree.getData(child); + if (data.connected && data.canDisconn) { + disconnect_from_database(obj, data, t, child, false); } - }).catch(function(error) { - pgAdmin.Browser.notifier.pgRespErrorNotify(error); - t.unload(i); }); + t.deselect(item); }, - function() { return true; } + function() { return true;}, ); } @@ -502,6 +503,63 @@ define('pgadmin.node.database', [ error, obj, data, tree, item, wasConnected ); }); + }, + disconnect_from_database = function(obj, data, tree, item, notify=false) { + let d = data, + t = tree, + i = item, + label = data.label; + let disconnect = function() { + d.label = `[Disconnecting...] ${label}`; + t.setLabel(i,{label:d.label}); + t.close(i); + let data = d; + getApiInstance().delete( + obj.generate_url(i, 'connect', d, true), + ).then(({data: res})=> { + if (res.success == 1) { + let prv_i = t.parent(i); + if(res.data.info_prefix) { + res.info = `${_.escape(res.data.info_prefix)} - ${res.info}`; + } + pgAdmin.Browser.notifier.success(res.info); + t.removeIcon(i); + data.connected = false; + data.icon = data.isTemplate ? 'icon-database-template-not-connected':'icon-database-not-connected'; + d.label = label; + t.setLabel(i, {label}); + t.addIcon(i, {icon: data.icon}); + t.unload(i); + pgBrowser.Events.trigger('pgadmin:browser:tree:update-tree-state', i); + setTimeout(function() { + t.select(prv_i); + }, 10); + + } else { + try { + pgAdmin.Browser.notifier.error(res.errormsg); + } catch (e) { + console.warn(e.stack || e); + } + t.unload(i); + } + }).catch(function(error) { + pgAdmin.Browser.notifier.pgRespErrorNotify(error); + t.unload(i); + }); + }; + if (notify) { + pgAdmin.Browser.notifier.confirm( + gettext('Disconnect from database'), + gettext('Are you sure you want to disconnect from database - %s?', d.label), + function() { + disconnect(); + }, + function() { return true; } + ); + } else { + disconnect(); + } }; } diff --git a/web/pgadmin/browser/server_groups/servers/static/js/server.js b/web/pgadmin/browser/server_groups/servers/static/js/server.js index 0c7f5748a..b100965cf 100644 --- a/web/pgadmin/browser/server_groups/servers/static/js/server.js +++ b/web/pgadmin/browser/server_groups/servers/static/js/server.js @@ -78,6 +78,11 @@ define('pgadmin.node.server', [ applies: ['object', 'context'], callback: 'show_obj_properties', category: 'register', priority: 1, label: gettext('Server...'), data: {action: 'create'}, enable: 'canCreate', + },{ + name: 'disconnect_all_servers', node: 'server_group', module: this, + applies: ['object','context'], callback: 'disconnect_all_servers', + priority: 5, label: gettext('Disconnect from all servers'), + data:{action: 'disconnect_all'}, enable: 'can_disconnect_all' },{ name: 'create_server', node: 'server', module: this, applies: ['object', 'context'], callback: 'show_obj_properties', @@ -200,6 +205,9 @@ define('pgadmin.node.server', [ node?.connected && node?.user?.is_superuser && node?.in_recovery && node?.wal_pause); }, + can_disconnect_all: function(node, item) { + return _.some(item.children, (child) => pgAdmin.Browser.tree.getData(child).connected); + }, callbacks: { /* Connect the server */ connect_server: function(args){ @@ -215,73 +223,40 @@ define('pgadmin.node.server', [ return false; }, /* Disconnect the server */ - disconnect_server: function(args, notify) { + disconnect_server: function(args) { let input = args || {}, obj = this, t = pgBrowser.tree, i = 'item' in input ? input.item : t.selected(), d = i ? t.itemData(i) : undefined; - if (d) { - notify = notify || _.isUndefined(notify) || _.isNull(notify); - - let disconnect = function() { - getApiInstance().delete( - obj.generate_url(i, 'connect', d, true), - ).then(({data: res})=> { - if (res.success == 1) { - pgAdmin.Browser.notifier.success(res.info); - d = t.itemData(i); - t.removeIcon(i); - d.connected = false; - // Update server tree node data after server diconnected. - t.update(i,d); - - // Generate the event that server is disconnected - pgBrowser.Events.trigger( - 'pgadmin:server:disconnect', - {item: i, data: d}, false - ); - if (d.shared && pgAdmin.server_mode == 'True'){ - d.icon = 'icon-shared-server-not-connected'; - }else{ - d.icon = 'icon-server-not-connected'; - } - t.addIcon(i, {icon: d.icon}); - obj.callbacks.refresh.apply(obj, [null, i]); - setTimeout(() => { - t.close(i); - }, 10); - if (pgBrowser.serverInfo && d._id in pgBrowser.serverInfo) { - delete pgBrowser.serverInfo[d._id]; - } - else { - try { - pgAdmin.Browser.notifier.error(res.errormsg); - } catch (e) { - console.warn(e.stack || e); - } - t.unload(i); - } - } - }).catch(function(error) { - pgAdmin.Browser.notifier.pgRespErrorNotify(error); - t.unload(i); - }); - }; - - if (notify) { - pgAdmin.Browser.notifier.confirm( - gettext('Disconnect from server'), - gettext('Are you sure you want to disconnect from the server %s?', d.label), - function() { disconnect(); }, - function() { return true;}, - ); - } else { - disconnect(); - } + disconnect_from_server(obj, d, t, i, true); + } + return false; + }, + disconnect_all_servers: function(args, item) { + let children = item.children ?? [], + obj = this, + t = pgBrowser.tree; + if (children) { + pgAdmin.Browser.notifier.confirm( + gettext('Disconnect from all servers'), + gettext('Are you sure you want to disconnect from all servers?'), + function() { + _.forEach(children, function(child) { + let data = pgAdmin.Browser.tree.getData(child); + if (data.connected) { + disconnect_from_server(obj, data, t, child, false); + } + }); + t.deselect(item); + setTimeout(() => { + t.select(item); + }, 100); + }, + function() { return true;}, + ); } - return false; }, /* Connect the server (if not connected), before opening this node */ @@ -819,6 +794,78 @@ define('pgadmin.node.server', [ pgAdmin.Browser.notifier.pgRespErrorNotify(error); }); }; + let disconnect_from_server = async function(obj, data, tree, item, notify=false) { + let d = data, + i = item, + t = tree, + label = data.label; + + let disconnect = function() { + d.label = `[Disconnecting...] ${label}`; + t.setLabel(i,{label:d.label}); + t.close(i); + getApiInstance().delete( + obj.generate_url(i, 'connect', d, true), + ).then(({data: res})=> { + if (res.success == 1) { + if (notify) { + pgAdmin.Browser.notifier.success(res.info); + } else { + pgAdmin.Browser.notifier.success(`${label} - ${res.info}`); + } + d = t.itemData(i); + t.removeIcon(i); + d.connected = false; + d.label = label; + t.setLabel(i, {label}); + // Update server tree node data after server diconnected. + t.update(i,d); + // Generate the event that server is disconnected + pgBrowser.Events.trigger( + 'pgadmin:server:disconnect', + {item: i, data: d}, false + ); + if (d.shared && pgAdmin.server_mode == 'True'){ + d.icon = 'icon-shared-server-not-connected'; + }else{ + d.icon = 'icon-server-not-connected'; + } + t.addIcon(i, {icon: d.icon}); + obj.callbacks.refresh.apply(obj, [null, i]); + setTimeout(() => { + t.close(i); + }, 10); + if (pgBrowser.serverInfo && d._id in pgBrowser.serverInfo) { + delete pgBrowser.serverInfo[d._id]; + } + else { + try { + pgAdmin.Browser.notifier.error(res.errormsg); + } catch (e) { + console.warn(e.stack || e); + } + t.setLabel(i, {label}); + t.unload(i); + } + } + }).catch(function(error) { + pgAdmin.Browser.notifier.pgRespErrorNotify(error); + t.setLabel(i, {label}); + t.unload(i); + }); + }; + + if (notify) { + pgAdmin.Browser.notifier.confirm( + gettext('Disconnect from server'), + gettext('Are you sure you want to disconnect from the server %s?', label), + function() { disconnect(); }, + function() { return true;}, + ); + } else { + disconnect(); + } + }; } return pgBrowser.Nodes['server']; diff --git a/web/pgadmin/static/js/Theme/overrides/pgadmin.classes.override.js b/web/pgadmin/static/js/Theme/overrides/pgadmin.classes.override.js index 8e8278525..52980017d 100644 --- a/web/pgadmin/static/js/Theme/overrides/pgadmin.classes.override.js +++ b/web/pgadmin/static/js/Theme/overrides/pgadmin.classes.override.js @@ -24,5 +24,8 @@ export default function pgadminOverride(theme) { '&.icon-terminal': { fontSize: '1.3rem !important', } + }, + '.text-muted': { + color: theme.otherVars.textMuted } };} diff --git a/web/pgadmin/static/js/tree/tree.js b/web/pgadmin/static/js/tree/tree.js index bb13b7450..82dee8f0c 100644 --- a/web/pgadmin/static/js/tree/tree.js +++ b/web/pgadmin/static/js/tree/tree.js @@ -475,7 +475,7 @@ export class Tree { let idx = 0; let node_cnt = 0; let result = {}; - if (identifier === undefined) return; + if (!identifier) return; let item = TreeNode.prototype.isPrototypeOf(identifier) ? identifier : this.findNode(identifier.path); if (!item) return; do {