2019-01-02 15:54:12 +05:30
/////////////////////////////////////////////////////////////
//
// pgAdmin 4 - PostgreSQL Tools
//
2023-01-02 11:53:55 +05:30
// Copyright (C) 2013 - 2023, The pgAdmin Development Team
2019-01-02 15:54:12 +05:30
// This software is released under the PostgreSQL Licence
//
//////////////////////////////////////////////////////////////
2021-06-29 14:33:36 +05:30
import { getNodeView , removeNodeView } from './node_view' ;
2021-12-02 16:05:52 +05:30
import Notify from '../../../static/js/helpers/Notifier' ;
2022-09-08 15:16:48 +05:30
import _ from 'lodash' ;
2021-06-29 14:33:36 +05:30
2018-01-12 12:59:51 +05:30
define ( 'pgadmin.browser.node' , [
2022-09-08 15:16:48 +05:30
'sources/gettext' , 'jquery' , 'sources/pgadmin' ,
2022-11-21 10:54:15 +05:30
'sources/browser/generate_url' , 'sources/utils' ,
'pgadmin.browser.utils' , 'pgadmin.browser.events' ,
2018-06-05 16:06:19 +05:30
] , function (
2022-11-21 10:54:15 +05:30
gettext , $ , pgAdmin , generateUrl , commonUtils
2018-06-05 16:06:19 +05:30
) {
2015-06-30 11:21:55 +05:30
2022-11-21 10:54:15 +05:30
let wcDocker = window . wcDocker ;
const pgBrowser = pgAdmin . Browser = pgAdmin . Browser || { } ;
2015-06-30 11:21:55 +05:30
// It has already been defined.
// Avoid running this script again.
if ( pgBrowser . Node )
return pgBrowser . Node ;
pgBrowser . Nodes = pgBrowser . Nodes || { } ;
// A helper (base) class for all the nodes, this has basic
// operations/callbacks defined for basic operation.
2022-01-12 18:59:21 +05:30
pgBrowser . Node = function ( ) { /*This is intentional (SonarQube)*/ } ;
2015-06-30 11:21:55 +05:30
// Helper function to correctly set up the property chain, for subclasses.
// Uses a hash of class properties to be extended.
//
// It is unlikely - we will instantiate an object for this class.
2018-06-05 16:06:19 +05:30
pgBrowser . Node . extend = function ( props , initialize ) {
2022-09-09 15:23:18 +05:30
let parent = this ;
let child ;
2015-06-30 11:21:55 +05:30
// The constructor function for the new subclass is defined to simply call
// the parent's constructor.
2018-01-12 12:59:51 +05:30
child = function ( ) {
return parent . apply ( this , arguments ) ;
} ;
2015-06-30 11:21:55 +05:30
// Add static properties to the constructor function, if supplied.
_ . extend ( child , parent , _ . omit ( props , 'callbacks' ) ) ;
// Make sure - a child have all the callbacks of the parent.
child . callbacks = _ . extend ( { } , parent . callbacks , props . callbacks ) ;
2018-06-05 16:06:19 +05:30
// Let's not bind the callbacks, or initialize the child.
2022-09-09 11:42:32 +05:30
if ( ! ( initialize ? ? true ) )
2018-06-05 16:06:19 +05:30
return child ;
2022-09-09 15:23:18 +05:30
let bindToChild = function ( cb ) {
2018-01-12 12:59:51 +05:30
if ( typeof ( child . callbacks [ cb ] ) == 'function' ) {
child . callbacks [ cb ] = child . callbacks [ cb ] . bind ( child ) ;
}
} ,
callbacks = _ . keys ( child . callbacks ) ;
2022-01-18 14:49:54 +05:30
for ( let cb _val of callbacks ) bindToChild ( cb _val ) ;
2016-08-29 11:52:50 +05:30
2015-06-30 11:21:55 +05:30
// Registering the node by calling child.Init(...) function
child . Init . apply ( child ) ;
// Initialize the parent
this . Init . apply ( child ) ;
return child ;
} ;
2022-11-21 10:54:15 +05:30
_ . extend ( pgAdmin . Browser . Node , {
2015-06-30 11:21:55 +05:30
// Node type
type : undefined ,
// Label
label : '' ,
2016-05-16 11:25:51 -04:00
// Help pages
2016-04-12 13:35:47 +01:00
sqlAlterHelp : '' ,
sqlCreateHelp : '' ,
2016-05-16 11:25:51 -04:00
dialogHelp : '' ,
2021-10-06 14:49:56 +05:30
epasHelp : false ,
2016-04-12 13:35:47 +01:00
2017-07-18 15:13:16 +01:00
title : function ( o , d ) {
2016-01-11 21:30:42 +05:30
return o . label + ( d ? ( ' - ' + d . label ) : '' ) ;
2015-06-30 11:21:55 +05:30
} ,
2015-11-19 23:15:48 +05:30
hasId : true ,
2015-06-30 11:21:55 +05:30
///////
// Initialization function
// Generally - used to register the menus for this type of node.
//
// Also, look at pgAdmin.Browser.add_menus(...) function.
//
// NOTE: Override this for each node for initialization purpose
Init : function ( ) {
2022-09-09 15:23:18 +05:30
let self = this ;
2016-01-04 21:57:18 +05:30
if ( self . node _initialized )
2015-06-30 11:21:55 +05:30
return ;
2016-01-04 21:57:18 +05:30
self . node _initialized = true ;
2015-06-30 11:21:55 +05:30
pgAdmin . Browser . add _menus ( [ {
2018-01-12 12:59:51 +05:30
name : 'refresh' ,
node : self . type ,
module : self ,
applies : [ 'object' , 'context' ] ,
callback : 'refresh' ,
2022-02-14 12:13:48 +05:30
priority : 2 ,
label : gettext ( 'Refresh...' ) ,
2022-12-06 18:16:36 +05:30
enable : true ,
2015-06-30 11:21:55 +05:30
} ] ) ;
2016-01-04 21:57:18 +05:30
2016-08-22 12:30:16 +01:00
if ( self . canEdit ) {
pgAdmin . Browser . add _menus ( [ {
2018-01-12 12:59:51 +05:30
name : 'show_obj_properties' ,
node : self . type ,
module : self ,
applies : [ 'object' , 'context' ] ,
callback : 'show_obj_properties' ,
priority : 999 ,
label : gettext ( 'Properties...' ) ,
data : {
'action' : 'edit' ,
} ,
2020-10-12 13:49:54 +05:30
enable : _ . isFunction ( self . canEdit ) ?
function ( ) {
return ! ! ( self . canEdit . apply ( self , arguments ) ) ;
} : ( ! ! self . canEdit ) ,
2018-01-12 12:59:51 +05:30
} ] ) ;
2016-08-22 12:30:16 +01:00
}
2016-01-04 21:57:18 +05:30
if ( self . canDrop ) {
pgAdmin . Browser . add _menus ( [ {
2018-01-12 12:59:51 +05:30
name : 'delete_object' ,
node : self . type ,
module : self ,
applies : [ 'object' , 'context' ] ,
callback : 'delete_obj' ,
2019-12-03 11:52:02 +05:30
priority : self . dropPriority ,
label : ( self . dropAsRemove ) ? gettext ( 'Remove %s' , self . label ) : gettext ( 'Delete/Drop' ) ,
2018-01-12 12:59:51 +05:30
data : {
'url' : 'drop' ,
2021-02-03 12:15:37 +05:30
data _disabled : gettext ( 'The selected tree node does not support this option.' ) ,
2018-01-12 12:59:51 +05:30
} ,
2016-05-14 01:09:59 +05:30
enable : _ . isFunction ( self . canDrop ) ?
function ( ) {
return ! ! ( self . canDrop . apply ( self , arguments ) ) ;
2018-01-12 12:59:51 +05:30
} : ( ! ! self . canDrop ) ,
2016-01-04 21:57:18 +05:30
} ] ) ;
2018-01-12 12:59:51 +05:30
2016-01-04 21:57:18 +05:30
if ( self . canDropCascade ) {
pgAdmin . Browser . add _menus ( [ {
2018-01-12 12:59:51 +05:30
name : 'delete_object_cascade' ,
node : self . type ,
module : self ,
applies : [ 'object' , 'context' ] ,
callback : 'delete_obj' ,
priority : 3 ,
label : gettext ( 'Drop Cascade' ) ,
data : {
'url' : 'delete' ,
} ,
2016-05-06 15:47:21 +01:00
enable : _ . isFunction ( self . canDropCascade ) ?
2018-01-12 12:59:51 +05:30
function ( ) {
return self . canDropCascade . apply ( self , arguments ) ;
} : ( ! ! self . canDropCascade ) ,
2016-01-04 21:57:18 +05:30
} ] ) ;
}
}
2016-06-08 13:18:59 +01:00
2018-01-12 12:59:51 +05:30
// Show query tool only in context menu of supported nodes.
if ( _ . indexOf ( pgAdmin . unsupported _nodes , self . type ) == - 1 ) {
2020-04-06 17:33:07 +05:30
let enable = function ( itemData ) {
if ( itemData . _type == 'database' && itemData . allowConn )
return true ;
else if ( itemData . _type != 'database' )
return true ;
else
return false ;
} ;
2018-01-12 12:59:51 +05:30
pgAdmin . Browser . add _menus ( [ {
name : 'show_query_tool' ,
node : self . type ,
module : self ,
applies : [ 'context' ] ,
callback : 'show_query_tool' ,
priority : 998 ,
2021-01-20 15:52:34 +00:00
label : gettext ( 'Query Tool' ) ,
2020-04-06 17:33:07 +05:30
enable : enable ,
} ] ) ;
// show search objects same as query tool
pgAdmin . Browser . add _menus ( [ {
2022-08-30 17:08:12 +05:30
name : 'search_objects' , node : self . type , module : pgAdmin . Tools . SearchObjects ,
2020-04-06 17:33:07 +05:30
applies : [ 'context' ] , callback : 'show_search_objects' ,
priority : 997 , label : gettext ( 'Search Objects...' ) ,
icon : 'fa fa-search' , enable : enable ,
2018-01-12 12:59:51 +05:30
} ] ) ;
2021-05-25 20:12:57 +05:30
2021-06-08 14:58:43 +05:30
if ( pgAdmin [ 'enable_psql' ] ) {
2021-05-25 20:12:57 +05:30
// show psql tool same as query tool.
pgAdmin . Browser . add _menus ( [ {
name : 'show_psql_tool' , node : this . type , module : this ,
applies : [ 'context' ] , callback : 'show_psql_tool' ,
2021-09-23 16:17:39 +05:30
priority : 998 , label : gettext ( 'PSQL Tool' ) ,
2021-05-25 20:12:57 +05:30
} ] ) ;
}
2016-06-08 13:18:59 +01:00
}
2016-05-16 00:25:31 +05:30
// This will add options of scripts eg:'CREATE Script'
2018-01-12 12:59:51 +05:30
if ( self . hasScriptTypes && _ . isArray ( self . hasScriptTypes ) &&
self . hasScriptTypes . length > 0 ) {
// For each script type create menu
_ . each ( self . hasScriptTypes , function ( stype ) {
2022-09-09 15:23:18 +05:30
let type _label = gettext ( '%s Script' , stype . toUpperCase ( ) ) ;
2018-01-12 12:59:51 +05:30
stype = stype . toLowerCase ( ) ;
// Adding menu for each script type
pgAdmin . Browser . add _menus ( [ {
name : 'show_script_' + stype ,
node : self . type ,
module : self ,
applies : [ 'object' , 'context' ] ,
callback : 'show_script' ,
priority : 4 ,
label : type _label ,
2020-03-24 11:14:05 +05:30
category : gettext ( 'Scripts' ) ,
2018-01-12 12:59:51 +05:30
data : {
'script' : stype ,
2021-02-03 12:15:37 +05:30
data _disabled : gettext ( 'The selected tree node does not support this option.' ) ,
2018-01-12 12:59:51 +05:30
} ,
enable : self . check _user _permission ,
} ] ) ;
} ) ;
2016-05-16 00:25:31 +05:30
}
} ,
///////
// Checks if Script Type is allowed to user
// First check if role node & create role allowed
// Otherwise test rest of database objects
// if no permission matched then do not allow create script
///////
check _user _permission : function ( itemData , item , data ) {
2016-09-23 10:06:50 +01:00
// Do not display CREATE script on server group and server node
2017-07-27 17:25:07 +05:30
if ( itemData . _type == 'server_group' || itemData . _type == 'server' ) {
2016-09-23 10:06:50 +01:00
return false ;
}
2016-12-09 11:59:13 +00:00
// Do not display the menu if the database connection is not allowed
if ( itemData . _type == 'database' && ! itemData . allowConn )
return false ;
2022-09-09 15:23:18 +05:30
let parentData = pgBrowser . tree . getTreeNodeHierarchy ( item ) ;
2018-01-12 12:59:51 +05:30
if ( _ . indexOf ( [ 'create' , 'insert' , 'update' , 'delete' ] , data . script ) != - 1 ) {
2016-05-16 00:25:31 +05:30
if ( itemData . type == 'role' &&
parentData . server . user . can _create _role ) {
return true ;
2016-10-18 12:37:44 +01:00
} else if (
2018-01-12 12:59:51 +05:30
(
2016-10-18 12:37:44 +01:00
parentData . server && (
2018-01-12 12:59:51 +05:30
parentData . server . user . is _superuser ||
parentData . server . user . can _create _db )
) ||
(
2016-10-18 12:37:44 +01:00
parentData . schema && parentData . schema . can _create
2018-01-12 12:59:51 +05:30
)
) {
return true ;
2016-05-16 00:25:31 +05:30
} else {
2018-01-12 12:59:51 +05:30
return false ;
2016-05-16 00:25:31 +05:30
}
} else {
return true ;
}
2015-06-30 11:21:55 +05:30
} ,
2022-05-16 16:21:14 +05:30
addUtilityPanel : function ( width , height , docker ) {
2022-09-09 15:23:18 +05:30
let body = window . document . body ,
2022-05-16 16:21:14 +05:30
el = document . createElement ( 'div' ) ,
dockerObject = docker || pgBrowser . docker ;
2021-11-22 11:20:44 +05:30
body . insertBefore ( el , body . firstChild ) ;
2022-09-09 15:23:18 +05:30
let new _width = screen . width < 700 ? screen . width * 0.95 : screen . width * 0.5 ,
2022-01-18 14:49:54 +05:30
new _height = screen . height < 500 ? screen . height * 0.95 : screen . height * 0.4 ;
if ( ! _ . isUndefined ( width ) && ! _ . isNull ( width ) ) {
new _width = width ;
}
if ( ! _ . isUndefined ( height ) && ! _ . isNull ( height ) ) {
new _height = height ;
}
2022-07-05 18:46:49 +05:30
let x = ( body . offsetWidth - new _width ) / 2 ;
let y = ( body . offsetHeight - new _height ) / 4 ;
2022-09-09 15:23:18 +05:30
let new _panel = dockerObject . addPanel (
2021-11-22 11:20:44 +05:30
'utility_props' , window . wcDocker . DOCK . FLOAT , undefined , {
2022-01-18 14:49:54 +05:30
w : new _width ,
h : new _height ,
2022-07-05 18:46:49 +05:30
x : ( x ) ,
y : ( y ) ,
2021-11-22 11:20:44 +05:30
}
) ;
/ * s e t m o v a b l e f a l s e t o p r e v e n t d i a l o g f r o m d o c k i n g ,
by setting this we can able to move the dialog but can ' t dock it
in to the frame . e . g : can ' t dock it in to properties and other tabs . * /
setTimeout ( function ( ) {
new _panel . moveable ( false ) ;
} , 0 ) ;
body . removeChild ( el ) ;
return new _panel ;
} ,
2022-01-25 20:10:31 +05:30
2022-07-19 15:27:47 +05:30
registerDockerPanel : function ( docker , name , params ) {
2022-09-09 15:23:18 +05:30
let w = docker || pgBrowser . docker ,
2022-07-19 15:27:47 +05:30
p = w . findPanels ( name ) ;
if ( p && p . length == 1 )
return ;
2022-01-25 20:10:31 +05:30
2022-07-19 15:27:47 +05:30
p = new pgBrowser . Panel ( {
name : name ,
showTitle : true ,
isCloseable : true ,
isPrivate : true ,
isLayoutMember : false ,
canMaximise : true ,
content : '<div class="obj_properties container-fluid h-100"></div>' ,
... params ,
} ) ;
p . load ( w ) ;
} ,
2022-05-16 16:21:14 +05:30
registerUtilityPanel : function ( docker ) {
2022-09-09 15:23:18 +05:30
let w = docker || pgBrowser . docker ,
2021-11-22 11:20:44 +05:30
p = w . findPanels ( 'utility_props' ) ;
if ( p && p . length == 1 )
return ;
2022-09-09 15:23:18 +05:30
let events = { } ;
2021-11-22 11:20:44 +05:30
p = new pgBrowser . Panel ( {
name : 'utility_props' ,
showTitle : true ,
isCloseable : true ,
isPrivate : true ,
isLayoutMember : false ,
canMaximise : true ,
elContainer : true ,
content : '<div class="obj_properties container-fluid h-100"><div role="status" class="pg-panel-message">' + gettext ( 'Please wait while we fetch information ...' ) + '</div></div>' ,
onCreate : function ( myPanel , $container ) {
$container . addClass ( 'pg-no-overflow' ) ;
} ,
events : events ,
} ) ;
2022-05-16 16:21:14 +05:30
p . load ( w ) ;
2021-11-22 11:20:44 +05:30
} ,
2015-06-30 11:21:55 +05:30
register _node _panel : function ( ) {
2022-09-09 15:23:18 +05:30
let w = pgBrowser . docker ,
2015-06-30 11:21:55 +05:30
p = w . findPanels ( 'node_props' ) ;
if ( p && p . length == 1 )
return ;
2022-09-09 15:23:18 +05:30
let events = { } ;
2016-09-26 10:04:49 +01:00
2015-06-30 11:21:55 +05:30
p = new pgBrowser . Panel ( {
2018-01-12 12:59:51 +05:30
name : 'node_props' ,
showTitle : true ,
isCloseable : true ,
isPrivate : true ,
2019-03-26 11:08:45 -04:00
isLayoutMember : false ,
2021-05-24 22:08:23 +05:30
canMaximise : true ,
2018-01-12 12:59:51 +05:30
elContainer : true ,
2021-09-17 20:47:03 +05:30
content : '<div class="obj_properties container-fluid h-100"><div role="status" class="pg-panel-message">' + gettext ( 'Please wait while we fetch information about the node from the server...' ) + '</div></div>' ,
2018-01-12 12:59:51 +05:30
onCreate : function ( myPanel , $container ) {
$container . addClass ( 'pg-no-overflow' ) ;
} ,
events : events ,
2016-09-26 10:04:49 +01:00
} ) ;
2015-06-30 11:21:55 +05:30
p . load ( pgBrowser . docker ) ;
} ,
2016-08-22 12:30:16 +01:00
/ *
* Default script type menu for node .
*
* Override this , to show more script type menus ( e . g hasScriptTypes : [ 'create' , 'select' , 'insert' , 'update' , 'delete' ] )
*
* Or set it to empty array to disable script type menu on node ( e . g hasScriptTypes : [ ] )
* /
hasScriptTypes : [ 'create' ] ,
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* This function determines the given item is editable or not .
*
* Override this , when a node is not editable .
* /
canEdit : true ,
2015-06-30 11:21:55 +05:30
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* This function determines the given item is deletable or not .
*
* Override this , when a node is not deletable .
* /
2016-01-04 21:57:18 +05:30
canDrop : false ,
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* This function determines the given item and children are deletable or
* not .
*
* Override this , when a node is not deletable .
* /
canDropCascade : false ,
2019-12-03 11:52:02 +05:30
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
dropAsRemove should be true in case , Drop object label needs to be replaced by Remove
* /
dropAsRemove : false ,
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
dropPriority is set to 2 by default , override it when change is required
* /
dropPriority : 2 ,
2021-08-25 17:01:48 +05:30
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
select collection node on deletion .
* /
selectParentNodeOnDelete : false ,
2015-06-30 11:21:55 +05:30
// List of common callbacks - that can be used for different
// operations!
callbacks : {
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* This function allows to create / edit / show properties of any
* object depending on the arguments provided .
*
* args must be a object containing :
* action - create / edit / properties
2017-11-07 20:27:10 -05:00
* item - The properties of the item ( tree node item )
2015-06-30 11:21:55 +05:30
*
* NOTE :
* if item is not provided , the action will be done on the
* currently selected tree item node .
*
* * /
2016-01-07 08:37:14 +05:30
show _obj _properties : function ( args , item ) {
2022-09-09 15:23:18 +05:30
let t = pgBrowser . tree ,
2018-02-09 12:07:57 +00:00
i = ( args && args . item ) || item || t . selected ( ) ,
2021-09-27 16:44:26 +05:30
d = i ? t . itemData ( i ) : undefined ,
2015-06-30 11:21:55 +05:30
o = this ,
2022-09-09 15:23:18 +05:30
l = o . title . apply ( this , [ d ] ) ,
p ;
2015-06-30 11:21:55 +05:30
// Make sure - the properties dialog type registered
pgBrowser . Node . register _node _panel ( ) ;
// No node selected.
if ( ! d )
return ;
2022-09-09 15:23:18 +05:30
let self = this ,
2018-01-12 12:59:51 +05:30
isParent = ( _ . isArray ( this . parent _type ) ?
2020-07-14 15:45:01 +05:30
function ( _d ) {
return ( _ . indexOf ( self . parent _type , _d . _type ) != - 1 ) ;
} : function ( _d ) {
return ( self . parent _type == _d . _type ) ;
2018-01-12 12:59:51 +05:30
} ) ,
addPanel = function ( ) {
2022-09-09 15:23:18 +05:30
let body = window . document . body ,
2020-07-14 15:45:01 +05:30
el = document . createElement ( 'div' ) ;
2018-01-12 12:59:51 +05:30
2020-07-14 15:45:01 +05:30
body . insertBefore ( el , body . firstChild ) ;
2018-01-12 12:59:51 +05:30
2019-01-02 15:05:15 +05:30
let w , h , x , y ;
if ( screen . width < 800 ) {
2020-07-01 11:49:39 +05:30
w = pgAdmin . toPx ( el , '95%' , 'width' , true ) ;
2019-01-02 15:05:15 +05:30
} else {
2020-07-01 11:49:39 +05:30
w = pgAdmin . toPx (
2020-07-03 11:26:06 +05:30
el , self . width || ( pgBrowser . stdW . default + 'px' ) ,
2020-07-01 11:49:39 +05:30
'width' , true
) ;
2019-01-02 15:05:15 +05:30
/* Fit to standard sizes */
if ( w <= pgBrowser . stdW . sm ) {
w = pgBrowser . stdW . sm ;
} else {
if ( w <= pgBrowser . stdW . md ) {
w = pgBrowser . stdW . md ;
} else {
w = pgBrowser . stdW . lg ;
}
}
}
if ( screen . height < 600 ) {
h = pgAdmin . toPx ( el , '95%' , 'height' , true ) ;
} else {
2020-07-01 11:49:39 +05:30
h = pgAdmin . toPx (
2020-07-03 11:26:06 +05:30
el , self . height || ( pgBrowser . stdH . default + 'px' ) ,
2020-07-01 11:49:39 +05:30
'height' , true
) ;
2019-01-02 15:05:15 +05:30
/* Fit to standard sizes */
if ( h <= pgBrowser . stdH . sm ) {
h = pgBrowser . stdH . sm ;
} else {
if ( h <= pgBrowser . stdH . md ) {
h = pgBrowser . stdH . md ;
} else {
h = pgBrowser . stdH . lg ;
}
}
}
2020-07-14 15:45:01 +05:30
x = ( body . offsetWidth - w ) / 2 ;
y = ( body . offsetHeight - h ) / 4 ;
2018-01-12 12:59:51 +05:30
2020-07-01 11:49:39 +05:30
// If the screen resolution is higher, but - it is zoomed, dialog
// may be go out of window, and will not be accessible through the
// keyboard.
if ( w > window . innerWidth ) {
x = 0 ;
w = window . innerWidth ;
}
if ( h > window . innerHeight ) {
y = 0 ;
h = window . innerHeight ;
}
2022-09-09 15:23:18 +05:30
let new _panel = pgBrowser . docker . addPanel (
2018-01-12 12:59:51 +05:30
'node_props' , wcDocker . DOCK . FLOAT , undefined , {
w : w + 'px' ,
h : h + 'px' ,
x : x + 'px' ,
y : y + 'px' ,
}
) ;
2016-05-21 14:18:24 +05:30
2020-07-14 15:45:01 +05:30
body . removeChild ( el ) ;
2016-05-21 14:18:24 +05:30
2020-07-14 15:45:01 +05:30
return new _panel ;
2018-01-12 12:59:51 +05:30
} ;
2016-01-04 17:52:30 +05:30
2015-06-30 11:21:55 +05:30
if ( args . action == 'create' ) {
// If we've parent, we will get the information of it for
// proper object manipulation.
//
// You know - we're working with RDBMS, relation is everything
// for us.
2016-01-04 23:25:21 +05:30
if ( self . parent _type && ! isParent ( d ) ) {
2015-06-30 11:21:55 +05:30
// In browser tree, I can be under any node, But - that
// does not mean, it is my parent.
//
// We have some group nodes too.
//
// i.e.
// Tables, Views, etc. nodes under Schema node
//
// And, actual parent of a table is schema, not Tables.
while ( i && t . hasParent ( i ) ) {
i = t . parent ( i ) ;
2022-09-09 15:23:18 +05:30
let pd = t . itemData ( i ) ;
2015-06-30 11:21:55 +05:30
2016-01-04 23:25:21 +05:30
if ( isParent ( pd ) ) {
2015-06-30 11:21:55 +05:30
// Assign the data, this is my actual parent.
d = pd ;
break ;
}
}
}
// Seriously - I really don't have parent data present?
//
// The only node - which I know - who does not have parent
// node, is the Server Group (and, comes directly under root
// node - which has no parent.)
2016-01-04 23:25:21 +05:30
if ( ! d || ( this . parent _type != null && ! isParent ( d ) ) ) {
2015-06-30 11:21:55 +05:30
// It should never come here.
// If it is here, that means - we do have some bug in code.
return ;
}
2019-10-10 12:05:28 +05:30
l = gettext ( 'Create - %s' , this . label ) ;
2022-02-14 12:13:48 +05:30
if ( this . type == 'server' ) {
l = gettext ( 'Register - %s' , this . label ) ;
}
2016-05-21 14:18:24 +05:30
p = addPanel ( ) ;
2015-06-30 11:21:55 +05:30
setTimeout ( function ( ) {
o . showProperties ( i , d , p , args . action ) ;
} , 10 ) ;
} else {
if ( pgBrowser . Node . panels && pgBrowser . Node . panels [ d . id ] &&
2018-01-12 12:59:51 +05:30
pgBrowser . Node . panels [ d . id ] . $container ) {
2022-09-09 15:23:18 +05:30
p = pgBrowser . Node . panels [ d . id ] ;
2015-06-30 11:21:55 +05:30
/ * * T O D O : :
* Run in edit mode ( if asked ) only when it is
* not already been running edit mode
* * /
2022-09-09 15:23:18 +05:30
let mode = p . $container . attr ( 'action-mode' ) ;
2015-06-30 11:21:55 +05:30
if ( mode ) {
2022-09-09 15:23:18 +05:30
let msg = gettext ( 'Are you sure want to stop editing the properties of %s "%s"?' ) ;
2015-06-30 11:21:55 +05:30
if ( args . action == 'edit' ) {
2017-06-07 15:53:02 +05:30
msg = gettext ( 'Are you sure want to reset the current changes and re-open the panel for %s "%s"?' ) ;
2015-06-30 11:21:55 +05:30
}
2021-12-07 18:52:40 +05:30
Notify . confirm (
2017-06-07 15:53:02 +05:30
gettext ( 'Edit in progress?' ) ,
2019-10-10 12:05:28 +05:30
commonUtils . sprintf ( msg , o . label . toLowerCase ( ) , d . label ) ,
2015-06-30 11:21:55 +05:30
function ( ) {
setTimeout ( function ( ) {
o . showProperties ( i , d , p , args . action ) ;
} , 10 ) ;
} ,
null ) . show ( ) ;
} else {
setTimeout ( function ( ) {
o . showProperties ( i , d , p , args . action ) ;
} , 10 ) ;
}
} else {
pgBrowser . Node . panels = pgBrowser . Node . panels || { } ;
2016-05-21 14:18:24 +05:30
p = pgBrowser . Node . panels [ d . id ] = addPanel ( ) ;
2015-06-30 11:21:55 +05:30
setTimeout ( function ( ) {
o . showProperties ( i , d , p , args . action ) ;
} , 10 ) ;
}
}
p . title ( l ) ;
p . icon ( 'icon-' + this . type ) ;
// Make sure the properties dialog is visible
p . focus ( ) ;
} ,
// Delete the selected object
2016-01-05 12:36:33 +05:30
delete _obj : function ( args , item ) {
2022-09-09 15:23:18 +05:30
let input = args || {
2018-01-12 12:59:51 +05:30
'url' : 'drop' ,
} ,
obj = this ,
t = pgBrowser . tree ,
i = input . item || item || t . selected ( ) ,
2021-09-27 16:44:26 +05:30
d = i ? t . itemData ( i ) : undefined ;
2015-06-30 11:21:55 +05:30
if ( ! d )
return ;
2016-01-05 12:36:33 +05:30
/ *
* Make sure - we ' re using the correct version of node
* /
obj = pgBrowser . Nodes [ d . _type ] ;
2022-09-09 15:23:18 +05:30
let objName = _ . unescape ( d . label ) ;
2016-01-05 12:36:33 +05:30
2022-09-09 15:23:18 +05:30
let msg , title ;
2019-12-03 11:52:02 +05:30
2016-01-04 21:57:18 +05:30
if ( input . url == 'delete' ) {
2019-10-10 12:05:28 +05:30
msg = gettext ( 'Are you sure you want to drop %s "%s" and all the objects that depend on it?' ,
obj . label . toLowerCase ( ) , d . label ) ;
title = gettext ( 'DROP CASCADE %s?' , obj . label ) ;
2016-01-04 21:57:18 +05:30
2016-01-05 12:36:33 +05:30
if ( ! ( _ . isFunction ( obj . canDropCascade ) ?
2019-03-14 15:11:16 +00:00
obj . canDropCascade . apply ( obj , [ d , i ] ) : obj . canDropCascade ) ) {
2021-12-02 16:05:52 +05:30
Notify . error (
2019-10-10 12:05:28 +05:30
gettext ( 'The %s "%s" cannot be dropped.' , obj . label , d . label ) ,
2021-12-02 16:05:52 +05:30
10000
2018-01-12 12:59:51 +05:30
) ;
2016-01-04 21:57:18 +05:30
return ;
}
} else {
2020-04-10 14:52:41 +05:30
if ( obj . dropAsRemove ) {
msg = gettext ( 'Are you sure you want to remove %s "%s"?' , obj . label . toLowerCase ( ) , d . label ) ;
title = gettext ( 'Remove %s?' , obj . label ) ;
} else {
msg = gettext ( 'Are you sure you want to drop %s "%s"?' , obj . label . toLowerCase ( ) , d . label ) ;
title = gettext ( 'Drop %s?' , obj . label ) ;
}
2015-06-30 11:21:55 +05:30
2016-01-05 12:36:33 +05:30
if ( ! ( _ . isFunction ( obj . canDrop ) ?
2019-03-14 15:11:16 +00:00
obj . canDrop . apply ( obj , [ d , i ] ) : obj . canDrop ) ) {
2021-12-02 16:05:52 +05:30
Notify . error (
2019-12-03 11:52:02 +05:30
gettext ( 'The %s "%s" cannot be dropped/removed.' , obj . label , d . label ) ,
2021-12-02 16:05:52 +05:30
10000
2019-12-03 11:52:02 +05:30
) ;
2016-01-04 21:57:18 +05:30
return ;
}
}
2021-12-07 18:52:40 +05:30
Notify . confirm ( title , msg ,
2016-01-04 21:57:18 +05:30
function ( ) {
$ . ajax ( {
url : obj . generate _url ( i , input . url , d , true ) ,
2018-01-12 12:59:51 +05:30
type : 'DELETE' ,
2018-07-09 13:54:00 +01:00
} )
2019-03-14 15:11:16 +00:00
. done ( function ( res ) {
2021-10-27 10:51:52 +05:30
if ( res . success == 2 ) {
2021-12-02 16:05:52 +05:30
Notify . error ( res . info , null ) ;
2021-10-27 10:51:52 +05:30
return ;
}
2019-03-14 15:11:16 +00:00
if ( res . success == 0 ) {
pgBrowser . report _error ( res . errormsg , res . info ) ;
} else {
2021-08-25 17:01:48 +05:30
// Remove the node from tree and set collection node as selected.
2022-09-09 15:23:18 +05:30
let selectNextNode = true ;
2021-08-25 17:01:48 +05:30
if ( obj . selectParentNodeOnDelete ) {
2022-09-09 15:23:18 +05:30
let prv _i = t . parent ( i ) ;
2021-08-25 17:01:48 +05:30
setTimeout ( function ( ) {
t . select ( prv _i ) ;
} , 10 ) ;
selectNextNode = false ;
}
pgBrowser . removeTreeNode ( i , selectNextNode ) ;
2016-01-04 21:57:18 +05:30
}
2019-03-14 15:11:16 +00:00
return true ;
} )
. fail ( function ( jqx ) {
2022-09-09 15:23:18 +05:30
let errmsg = jqx . responseText ;
2019-03-14 15:11:16 +00:00
/* Error from the server */
if ( jqx . status == 417 || jqx . status == 410 || jqx . status == 500 ) {
try {
2022-09-09 15:23:18 +05:30
let data = JSON . parse ( jqx . responseText ) ;
2020-07-14 15:45:01 +05:30
errmsg = data . info || data . errormsg ;
2019-03-14 15:11:16 +00:00
} catch ( e ) {
console . warn ( e . stack || e ) ;
}
}
2019-12-03 11:52:02 +05:30
pgBrowser . report _error (
2020-07-14 15:45:01 +05:30
gettext ( 'Error dropping/removing %s: "%s"' , obj . label , objName ) , errmsg ) ;
2019-03-14 15:11:16 +00:00
} ) ;
2021-12-07 18:52:40 +05:30
}
) ;
2015-06-30 11:21:55 +05:30
} ,
2016-05-16 00:25:31 +05:30
// Callback for creating script(s) & opening them in Query editor
show _script : function ( args , item ) {
2022-09-09 15:23:18 +05:30
let scriptType = args . script ,
2020-06-10 16:42:59 +01:00
obj ,
2016-05-16 00:25:31 +05:30
t = pgBrowser . tree ,
i = item || t . selected ( ) ,
2021-09-27 16:44:26 +05:30
d = i ? t . itemData ( i ) : undefined ;
2016-05-16 00:25:31 +05:30
if ( ! d )
return ;
/ *
* Make sure - we ' re using the correct version of node
* /
obj = pgBrowser . Nodes [ d . _type ] ;
2022-09-09 15:23:18 +05:30
let sql _url ;
2016-05-16 00:25:31 +05:30
// URL for script type
2018-01-12 12:59:51 +05:30
if ( scriptType == 'insert' ) {
2016-05-16 00:25:31 +05:30
sql _url = 'insert_sql' ;
2018-01-12 12:59:51 +05:30
} else if ( scriptType == 'update' ) {
2016-05-16 00:25:31 +05:30
sql _url = 'update_sql' ;
2018-01-12 12:59:51 +05:30
} else if ( scriptType == 'delete' ) {
2016-05-16 00:25:31 +05:30
sql _url = 'delete_sql' ;
2018-01-12 12:59:51 +05:30
} else if ( scriptType == 'select' ) {
2016-05-16 00:25:31 +05:30
sql _url = 'select_sql' ;
2018-01-12 12:59:51 +05:30
} else if ( scriptType == 'exec' ) {
2016-05-16 00:25:31 +05:30
sql _url = 'exec_sql' ;
} else {
// By Default get CREATE SQL
sql _url = 'sql' ;
}
// Open data grid & pass the URL for fetching
2022-04-07 17:36:56 +05:30
pgAdmin . Tools . SQLEditor . showQueryTool (
2017-06-15 12:19:47 +01:00
obj . generate _url ( i , sql _url , d , true ) ,
i , scriptType
2016-05-16 00:25:31 +05:30
) ;
} ,
2016-06-08 13:18:59 +01:00
// Callback to render query editor
show _query _tool : function ( args , item ) {
2022-09-09 15:23:18 +05:30
let preference = pgBrowser . get _preference ( 'sqleditor' , 'copy_sql_to_query_tool' ) ;
let t = pgBrowser . tree ,
2016-06-08 13:18:59 +01:00
i = item || t . selected ( ) ,
2021-09-27 16:44:26 +05:30
d = i ? t . itemData ( i ) : undefined ;
2016-06-08 13:18:59 +01:00
if ( ! d )
return ;
// Here call data grid method to render query tool
2021-08-09 14:29:31 +05:30
//Open query tool with create script if copy_sql_to_query_tool is true else open blank query tool
if ( preference . value && ! d . _type . includes ( 'coll-' ) ) {
2022-09-09 15:23:18 +05:30
let stype = d . _type . toLowerCase ( ) ;
let data = {
2021-08-09 14:29:31 +05:30
'script' : stype ,
data _disabled : gettext ( 'The selected tree node does not support this option.' ) ,
} ;
pgBrowser . Node . callbacks . show _script ( data ) ;
} else {
2022-04-07 17:36:56 +05:30
pgAdmin . Tools . SQLEditor . showQueryTool ( '' , i ) ;
2021-08-09 14:29:31 +05:30
}
2016-06-08 13:18:59 +01:00
} ,
2017-11-21 16:28:01 +00:00
2021-05-25 20:12:57 +05:30
// Callback to render psql tool.
show _psql _tool : function ( args ) {
2022-09-09 15:23:18 +05:30
let input = args || { } ,
2021-05-25 20:12:57 +05:30
t = pgBrowser . tree ,
i = input . item || t . selected ( ) ,
2021-09-27 16:44:26 +05:30
d = i ? t . itemData ( i ) : undefined ;
2021-05-25 20:12:57 +05:30
pgBrowser . psql . psql _tool ( d , i , true ) ;
} ,
2017-11-21 16:28:01 +00:00
// Logic to change the server background colour
// There is no way of applying CSS to parent element so we have to
// do it via JS code only
change _server _background : function ( item , data ) {
if ( ! item || ! data )
return ;
2021-10-16 12:40:57 +05:30
const treeH = pgBrowser . tree . getTreeNodeHierarchy ( item ) ;
const serverData = treeH [ 'server' ] ;
if ( ! serverData ) {
return ;
}
const index = item . path . indexOf ( serverData . id ) ;
2017-11-21 16:28:01 +00:00
// Go further only if node type is a Server
2021-10-16 12:40:57 +05:30
if ( index !== - 1 ) {
// First element will be icon and second will be colour code
2022-09-09 15:23:18 +05:30
let bgcolor = serverData . icon . split ( ' ' ) [ 1 ] || null ,
2021-10-16 12:40:57 +05:30
fgcolor = serverData . icon . split ( ' ' ) [ 2 ] || '' ;
2017-11-21 16:28:01 +00:00
2018-01-12 12:59:51 +05:30
if ( bgcolor ) {
2022-09-09 15:23:18 +05:30
let dynamic _class = 'pga_server_' + serverData . _id + '_bgcolor' ,
2017-11-21 16:28:01 +00:00
style _tag ;
// Prepare dynamic style tag
2018-01-12 12:59:51 +05:30
style _tag = '<style id=' + dynamic _class + ' type=\'text/css\'> \n' ;
2021-10-16 12:40:57 +05:30
style _tag += '.' + dynamic _class + ' .file-label {' ;
2018-01-12 12:59:51 +05:30
style _tag += ' border-radius: 3px; margin-bottom: 2px;' ;
2021-10-16 12:40:57 +05:30
style _tag += ' background: ' + bgcolor + ' !important;} \n' ;
2018-01-12 12:59:51 +05:30
if ( fgcolor ) {
2021-10-16 12:40:57 +05:30
style _tag += '.' + dynamic _class + ' span.file-name {' ;
2021-06-07 21:09:04 +05:30
style _tag += ' color: ' + fgcolor + ' !important;} \n' ;
2017-11-21 16:28:01 +00:00
}
2018-01-12 12:59:51 +05:30
style _tag += '</style>' ;
2017-11-21 16:28:01 +00:00
// Prepare dynamic style tag using template
$ ( '#' + dynamic _class ) . remove ( ) ;
2018-01-12 12:59:51 +05:30
$ ( style _tag ) . appendTo ( 'head' ) ;
2021-10-16 12:40:57 +05:30
// Add dynamic class to the tree node.
pgBrowser . tree . addCssClass ( item , dynamic _class ) ;
2017-11-21 16:28:01 +00:00
}
}
} ,
2021-09-27 16:44:26 +05:30
added : function ( item , data ) {
2022-09-07 17:40:52 +05:30
if ( pgBrowser . tree . getData ( item ) . _type . indexOf ( 'coll-' ) !== - 1 ) {
setTimeout ( function ( ) {
let _item = pgAdmin . Browser . Nodes [ pgBrowser . tree . getData ( item ) . nodes [ 0 ] ] ;
_item . clear _cache . apply ( _item ) ;
} , 0 ) ;
}
2018-10-08 10:03:19 +01:00
pgBrowser . Events . trigger ( 'pgadmin:browser:tree:expand-from-previous-tree-state' ,
2019-03-14 15:11:16 +00:00
item ) ;
2017-11-21 16:28:01 +00:00
pgBrowser . Node . callbacks . change _server _background ( item , data ) ;
2016-08-09 12:12:05 +01:00
} ,
2015-06-30 11:21:55 +05:30
// Callback called - when a node is selected in browser tree.
2015-10-30 13:07:09 +05:30
selected : function ( item , data , browser ) {
2015-10-20 12:33:18 +05:30
// Show the information about the selected node in the below panels,
// which are visible at this time:
2015-06-30 11:21:55 +05:30
// + Properties
2015-10-20 12:33:18 +05:30
// + Query (if applicable, otherwise empty)
2015-06-30 11:21:55 +05:30
// + Dependents
// + Dependencies
// + Statistics
2022-09-09 15:23:18 +05:30
let b = browser || pgBrowser ,
2018-01-12 12:59:51 +05:30
t = b . tree ,
d = data || t . itemData ( item ) ;
2015-06-30 11:21:55 +05:30
// Update the menu items
2015-10-28 22:36:09 +05:30
pgAdmin . Browser . enable _disable _menus . apply ( b , [ item ] ) ;
if ( d && b ) {
if ( 'properties' in b . panels &&
2018-01-12 12:59:51 +05:30
b . panels [ 'properties' ] &&
b . panels [ 'properties' ] . panel &&
b . panels [ 'properties' ] . panel . isVisible ( ) ) {
2015-10-28 22:36:09 +05:30
this . showProperties ( item , d , b . panels [ 'properties' ] . panel ) ;
2015-10-20 12:33:18 +05:30
}
2015-06-30 11:21:55 +05:30
}
2016-01-19 18:01:14 +05:30
2018-10-08 10:03:19 +01:00
pgBrowser . Events . trigger ( 'pgadmin:browser:tree:update-tree-state' ,
2019-03-14 15:11:16 +00:00
item ) ;
2016-01-19 18:01:14 +05:30
return true ;
2015-10-20 12:33:18 +05:30
} ,
2016-05-21 15:36:36 +05:30
removed : function ( item ) {
2022-09-09 15:23:18 +05:30
let self = this ;
2018-01-12 12:59:51 +05:30
setTimeout ( function ( ) {
self . clear _cache . apply ( self , item ) ;
} , 0 ) ;
2016-05-21 15:36:36 +05:30
} ,
2018-01-12 12:59:51 +05:30
refresh : function ( cmd , _item ) {
2022-09-09 15:23:18 +05:30
let self = this ,
2018-08-13 13:47:07 +01:00
t = pgBrowser . tree ,
data = _item && t . itemData ( _item ) ;
$ ( pgBrowser . panels [ 'properties' ] . panel ) . removeData ( 'node-prop' ) ;
2018-01-12 12:59:51 +05:30
pgBrowser . Events . trigger (
2018-08-13 13:47:07 +01:00
'pgadmin:browser:tree:refresh' , _item || pgBrowser . tree . selected ( ) , {
success : function ( ) {
self . callbacks . selected . apply ( self , [ _item , data , pgBrowser ] ) ;
} ,
} ) ;
2018-01-12 12:59:51 +05:30
} ,
2018-10-08 10:03:19 +01:00
opened : function ( item ) {
2019-02-14 09:18:08 +00:00
let tree = pgBrowser . tree ,
auto _expand = pgBrowser . get _preference ( 'browser' , 'auto_expand_sole_children' ) ;
2022-09-08 20:28:43 +05:30
if ( auto _expand && auto _expand . value && tree . children ( item ) . length == 1 ) {
2019-02-14 09:18:08 +00:00
// Automatically expand the child node, if a treeview node has only a single child.
2021-10-05 17:33:50 +05:30
const first _child = tree . first ( item ) ;
2022-09-08 20:28:43 +05:30
if ( first _child . _loaded ) {
2021-10-05 17:33:50 +05:30
tree . open ( first _child ) ;
} else {
const openSoleItem = setInterval ( ( ) => {
if ( first _child . _loaded ) {
tree . open ( first _child ) ;
clearSoleItemInterval ( ) ;
}
} , 200 ) ;
const clearSoleItemInterval = function ( ) {
clearInterval ( openSoleItem ) ;
} ;
}
2019-02-14 09:18:08 +00:00
}
2021-10-05 17:33:50 +05:30
pgBrowser . Events . trigger ( 'pgadmin:browser:tree:update-tree-state' , item ) ;
2018-10-08 10:03:19 +01:00
} ,
closed : function ( item ) {
pgBrowser . Events . trigger ( 'pgadmin:browser:tree:remove-from-tree-state' ,
2019-03-14 15:11:16 +00:00
item ) ;
2018-10-08 10:03:19 +01:00
} ,
2015-06-30 11:21:55 +05:30
} ,
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* A hook ( not a callback ) to show object properties in given HTML
* element .
*
* This has been used for the showing , editing properties of the node .
* This has also been used for creating a node .
* * /
showProperties : function ( item , data , panel , action ) {
2022-09-09 15:23:18 +05:30
let that = this ,
2022-11-21 10:54:15 +05:30
j = panel . $container . find ( '.obj_properties' ) . first ( ) ;
2018-01-12 12:59:51 +05:30
2022-09-10 14:22:49 +05:30
// Callback to show object properties
2022-11-21 10:54:15 +05:30
let properties = function ( ) {
2022-09-10 14:22:49 +05:30
let treeNodeInfo = pgBrowser . tree . getTreeNodeHierarchy ( item ) ;
getNodeView (
that . type , treeNodeInfo , 'properties' , data , 'tab' , j [ 0 ] , this , onEdit
) ;
return ;
2016-04-14 12:50:15 +05:30
} . bind ( panel ) ,
2016-05-16 11:25:51 -04:00
2015-06-30 11:21:55 +05:30
editFunc = function ( ) {
2022-09-09 15:23:18 +05:30
let self = this ;
2015-06-30 11:21:55 +05:30
if ( action && action == 'properties' ) {
action = 'edit' ;
}
2020-07-14 15:45:01 +05:30
self . $container . attr ( 'action-mode' , action ) ;
2021-06-29 14:33:36 +05:30
self . icon (
_ . isFunction ( that [ 'node_image' ] ) ?
( that [ 'node_image' ] ) . apply ( that , [ data ] ) :
( that [ 'node_image' ] || ( 'icon-' + that . type ) )
) ;
/* Remove any dom rendered by getNodeView */
removeNodeView ( j [ 0 ] ) ;
/* getSchema is a schema for React. Get the react node view */
2022-09-10 14:22:49 +05:30
let treeNodeInfo = pgBrowser . tree . getTreeNodeHierarchy ( item ) ;
getNodeView (
that . type , treeNodeInfo , action , data , 'dialog' , j [ 0 ] , this , onEdit ,
( nodeData ) => {
if ( nodeData . node ) {
onSaveFunc ( nodeData . node , treeNodeInfo ) ;
if ( nodeData . success === 0 ) {
Notify . alert ( gettext ( 'Error' ) ,
gettext ( nodeData . errormsg )
2019-11-05 14:28:03 +05:30
) ;
2020-04-06 13:13:21 +05:30
}
}
2020-02-04 11:30:33 +05:30
}
2022-09-10 14:22:49 +05:30
) ;
return ;
2016-04-14 12:50:15 +05:30
} . bind ( panel ) ,
2022-11-21 10:54:15 +05:30
2021-06-29 14:33:36 +05:30
updateTreeItem = function ( obj , tnode , node _info ) {
2022-09-09 15:23:18 +05:30
let _old = data ,
2022-11-21 10:54:15 +05:30
_new = tnode ,
info = node _info ;
2016-04-14 12:50:15 +05:30
2016-04-29 15:41:24 +05:30
// Clear the cache for this node now.
2018-01-12 12:59:51 +05:30
setTimeout ( function ( ) {
2020-07-14 15:45:01 +05:30
obj . clear _cache . apply ( obj , item ) ;
2018-01-12 12:59:51 +05:30
} , 0 ) ;
2016-04-29 15:41:24 +05:30
pgBrowser . Events . trigger (
2016-08-29 20:06:48 +05:30
'pgadmin:browser:tree:update' ,
_old , _new , info , {
2017-07-07 11:55:55 +05:30
success : function ( _item , _newNodeData , _oldNodeData ) {
pgBrowser . Events . trigger (
'pgadmin:browser:node:updated' , _item , _newNodeData ,
_oldNodeData
) ;
2016-08-29 20:06:48 +05:30
pgBrowser . Events . trigger (
2017-07-07 11:55:55 +05:30
'pgadmin:browser:node:' + _newNodeData . _type + ':updated' ,
_item , _newNodeData , _oldNodeData
2016-08-29 20:06:48 +05:30
) ;
2018-01-12 12:59:51 +05:30
} ,
2016-08-29 20:06:48 +05:30
}
2016-04-29 15:41:24 +05:30
) ;
2022-11-21 10:54:15 +05:30
this . close ( ) ;
2015-06-30 11:21:55 +05:30
} ,
2021-06-29 14:33:36 +05:30
saveNewNode = function ( obj , tnode , node _info ) {
2016-04-29 15:41:24 +05:30
// Clear the cache for this node now.
2018-01-12 12:59:51 +05:30
setTimeout ( function ( ) {
2020-07-14 15:45:01 +05:30
obj . clear _cache . apply ( obj , item ) ;
2018-01-12 12:59:51 +05:30
} , 0 ) ;
2016-08-29 20:06:48 +05:30
try {
pgBrowser . Events . trigger (
2022-11-21 10:54:15 +05:30
'pgadmin:browser:tree:add' , _ . clone ( tnode ) ,
_ . clone ( node _info )
2016-08-29 20:06:48 +05:30
) ;
} catch ( e ) {
2018-01-12 12:59:51 +05:30
console . warn ( e . stack || e ) ;
2015-06-30 11:21:55 +05:30
}
2022-11-21 10:54:15 +05:30
this . close ( ) ;
2016-04-29 15:41:24 +05:30
} . bind ( panel , that ) ,
2015-06-30 11:21:55 +05:30
editInNewPanel = function ( ) {
// Open edit in separate panel
setTimeout ( function ( ) {
that . callbacks . show _obj _properties . apply ( that , [ {
'action' : 'edit' ,
2018-01-12 12:59:51 +05:30
'item' : item ,
2015-06-30 11:21:55 +05:30
} ] ) ;
} , 0 ) ;
} ,
2016-04-29 15:41:24 +05:30
onSaveFunc = updateTreeItem . bind ( panel , that ) ,
2016-04-14 12:50:15 +05:30
onEdit = editFunc . bind ( panel ) ;
2015-06-30 11:21:55 +05:30
if ( action ) {
2018-01-12 12:59:51 +05:30
if ( action == 'create' ) {
2016-04-15 14:02:21 +01:00
onSaveFunc = saveNewNode ;
2015-06-30 11:21:55 +05:30
}
if ( action != 'properties' ) {
// We need to keep track edit/create mode for this panel.
editFunc ( ) ;
} else {
properties ( ) ;
}
} else {
/* Show properties */
2016-04-14 12:50:15 +05:30
onEdit = editInNewPanel . bind ( panel ) ;
2021-06-29 14:33:36 +05:30
properties ( ) ;
2015-06-30 11:21:55 +05:30
}
} ,
2016-06-03 05:57:48 +05:30
_find _parent _node : function ( t , i , d ) {
if ( this . parent _type ) {
d = d || t . itemData ( i ) ;
if ( _ . isString ( this . parent _type ) ) {
if ( this . parent _type == d . _type ) {
return i ;
}
2018-01-12 12:59:51 +05:30
while ( t . hasParent ( i ) ) {
2016-06-03 05:57:48 +05:30
i = t . parent ( i ) ;
d = t . itemData ( i ) ;
if ( this . parent _type == d . _type )
return i ;
}
} else {
if ( _ . indexOf ( this . parent _type , d . _type ) >= 0 ) {
return i ;
}
2018-01-12 12:59:51 +05:30
while ( t . hasParent ( i ) ) {
2016-06-03 05:57:48 +05:30
i = t . parent ( i ) ;
d = t . itemData ( i ) ;
if ( _ . indexOf ( this . parent _type , d . _type ) >= 0 )
return i ;
}
}
}
return null ;
} ,
2015-06-30 11:21:55 +05:30
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Generate the URL for different operations
*
* arguments :
* type : Create / drop / edit / properties / sql / depends / statistics
* d : Provide the ItemData for the current item node
* with _id : Required id information at the end ?
2020-01-01 12:59:48 +05:30
* jump _after _node : This will skip all the value between jump _after _node
* to the last node , excluding jump _after _node and the last node . This is particularly
* helpful in partition table where we need to skip parent table OID of a partitioned
* table in URL formation . Partitioned table itself is a "table" and can be multilevel
2015-06-30 11:21:55 +05:30
* Supports url generation for create , drop , edit , properties , sql ,
* depends , statistics
* /
2020-01-01 12:59:48 +05:30
generate _url : function ( item , type , d , with _id , info , jump _after _node ) {
2022-09-09 15:23:18 +05:30
let opURL = {
2018-01-12 12:59:51 +05:30
'create' : 'obj' ,
'drop' : 'obj' ,
'edit' : 'obj' ,
'properties' : 'obj' ,
'statistics' : 'stats' ,
} ,
self = this ,
2016-01-09 19:54:50 +05:30
priority = - Infinity ;
2022-09-09 15:23:18 +05:30
let treeInfo = ( _ . isUndefined ( item ) || _ . isNull ( item ) ) ?
2021-09-27 16:44:26 +05:30
info || { } : pgBrowser . tree . getTreeNodeHierarchy ( item ) ;
2022-09-09 15:23:18 +05:30
let actionType = type in opURL ? opURL [ type ] : type ;
let itemID = with _id && d . _type == self . type ? encodeURIComponent ( d . _id ) : '' ;
2016-01-09 19:54:50 +05:30
if ( self . parent _type ) {
if ( _ . isString ( self . parent _type ) ) {
2020-07-14 15:45:01 +05:30
let p = treeInfo [ self . parent _type ] ;
2016-01-09 19:54:50 +05:30
if ( p ) {
priority = p . priority ;
}
} else {
_ . each ( self . parent _type , function ( o ) {
2020-07-14 15:45:01 +05:30
let p = treeInfo [ o ] ;
2016-01-09 19:54:50 +05:30
if ( p ) {
if ( priority < p . priority ) {
priority = p . priority ;
}
}
} ) ;
}
}
2020-01-01 12:59:48 +05:30
let jump _after _priority = priority ;
if ( jump _after _node && treeInfo [ jump _after _node ] ) {
jump _after _priority = treeInfo [ jump _after _node ] . priority ;
}
2022-09-09 15:23:18 +05:30
let nodePickFunction = function ( treeInfoValue ) {
2020-01-01 12:59:48 +05:30
return ( treeInfoValue . priority <= jump _after _priority || treeInfoValue . priority == priority ) ;
2015-11-19 23:15:48 +05:30
} ;
2020-01-01 12:59:48 +05:30
2017-08-17 21:43:07 +05:30
return generateUrl . generate _url ( pgBrowser . URL , treeInfo , actionType , self . type , nodePickFunction , itemID ) ;
2015-06-30 11:21:55 +05:30
} ,
2016-01-05 14:36:30 +05:30
cache : function ( url , node _info , level , data ) {
2022-09-09 15:23:18 +05:30
let cached = this . cached = this . cached || { } ,
2018-01-12 12:59:51 +05:30
hash = url ,
min _priority = (
node _info && node _info [ level ] && node _info [ level ] . priority
) || 0 ;
2016-01-05 14:36:30 +05:30
if ( node _info ) {
2022-09-08 15:16:48 +05:30
_ . each ( _ . sortBy ( _ . values ( _ . pickBy (
2018-01-12 12:59:51 +05:30
node _info ,
function ( v ) {
return ( v . priority <= min _priority ) ;
}
) ) , function ( o ) {
return o . priority ;
} ) , function ( o ) {
2021-09-27 16:44:26 +05:30
hash = commonUtils . sprintf ( '%s_%s' , hash , encodeURI ( o . _id ) ) ;
2018-01-12 12:59:51 +05:30
} ) ;
2016-01-05 14:36:30 +05:30
}
2015-12-26 14:22:19 +05:30
if ( _ . isUndefined ( data ) ) {
2022-09-09 15:23:18 +05:30
let res = cached [ hash ] ;
2016-04-29 15:41:24 +05:30
if ( ! _ . isUndefined ( res ) &&
2018-01-12 12:59:51 +05:30
( res . at - Date . now ( ) > 300000 ) ) {
2016-04-29 15:41:24 +05:30
res = undefined ;
}
return res ;
2015-12-26 14:22:19 +05:30
}
2022-09-09 15:23:18 +05:30
let res = cached [ hash ] = {
2018-01-12 12:59:51 +05:30
data : data ,
at : Date . now ( ) ,
level : level ,
} ;
2016-01-05 14:36:30 +05:30
return res ;
2016-04-29 15:41:24 +05:30
} ,
clear _cache : function ( item ) {
/ *
* Reset the cache , when new node is created .
*
* FIXME :
* At the moment , we will clear all the cache for this node . But - we
* would like to clear the cache only this nodes parent , so that - it
* fetches the new data .
* /
this . cached = { } ;
2017-12-13 15:17:17 +00:00
// Trigger Notify event about node's cache
2022-09-09 15:23:18 +05:30
let self = this ;
2017-12-13 15:17:17 +00:00
pgBrowser . Events . trigger (
'pgadmin:browser:node:' + self . type + ':cache_cleared' ,
item , self
) ;
2016-04-29 15:41:24 +05:30
} ,
cache _level : function ( node _info , with _id ) {
if ( node _info ) {
if ( with _id && this . type in node _info ) {
return this . type ;
}
if ( _ . isArray ( this . parent _type ) ) {
2022-09-09 15:23:18 +05:30
for ( let parent in this . parent _type ) {
2016-04-29 15:41:24 +05:30
if ( parent in node _info ) {
return parent ;
}
}
return this . type ;
}
return this . parent _type ;
}
2018-01-12 12:59:51 +05:30
} ,
2015-06-30 11:21:55 +05:30
} ) ;
return pgAdmin . Browser . Node ;
} ) ;