Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
browser.js1754 linesDownload Raw Back to js
1/////////////////////////////////////////////////////////////2//3// pgAdmin 4 - PostgreSQL Tools4//5// Copyright (C) 2013 - 2024, The pgAdmin Development Team6// This software is released under the PostgreSQL Licence7//8//////////////////////////////////////////////////////////////9 10import MainMenuFactory from './MainMenuFactory';11import _ from 'lodash';12import { checkMasterPassword, showQuickSearch } from '../../../static/js/Dialogs/index';13import { pgHandleItemError } from '../../../static/js/utils';14import { send_heartbeat, stop_heartbeat } from './heartbeat';15import getApiInstance from '../../../static/js/api_instance';16import usePreferences, { setupPreferenceBroadcast } from '../../../preferences/static/js/store';17import checkNodeVisibility from '../../../static/js/check_node_visibility';18 19define('pgadmin.browser', [20  'sources/gettext', 'sources/url_for', 'sources/pgadmin',21  'sources/csrf', 'pgadmin.authenticate.kerberos',22  'pgadmin.browser.utils', 'pgadmin.browser.messages',23  'pgadmin.browser.node', 'pgadmin.browser.collection', 'pgadmin.browser.activity',24  'pgadmin.browser.keyboard', 'sources/tree/pgadmin_tree_save_state',25], function(26  gettext, url_for, pgAdmin, csrfToken, Kerberos,27) {28  let pgBrowser = pgAdmin.Browser = pgAdmin.Browser || {};29  let select_object_msg = gettext('Please select an object in the tree view.');30 31  csrfToken.setPGCSRFToken(pgAdmin.csrf_token_header, pgAdmin.csrf_token);32 33  Kerberos.validate_kerberos_ticket();34 35  // Extend the browser class attributes36  _.extend(pgAdmin.Browser, {37    // The base url for browser38    URL: url_for('browser.index'),39    docker:null,40    // Reversed Engineer query for the selected database node object goes41    // here42    editor:null,43    // Left hand browser tree44    tree:null,45    // list of script to be loaded, when a certain type of node is loaded46    // It will be used to register extensions, tools, child node scripts,47    // etc.48    scripts: {},49    // Standard Widths and Height for dialogs in px50    stdW: {51      sm: 500,52      md: 700,53      lg: 900,54      default: 500,55      // If you change above values then make sure to update56      // calc method logic57      calc: (passed_width) => {58        let iw = window.innerWidth;59        if(iw > passed_width)60          return passed_width;61        else if (iw > pgAdmin.Browser.stdW.lg)62          return pgAdmin.Browser.stdW.lg;63        else if (iw > pgAdmin.Browser.stdW.md)64          return pgAdmin.Browser.stdW.md;65        else if (iw > pgAdmin.Browser.stdW.sm)66          return pgAdmin.Browser.stdW.sm;67        else68          // if avilable screen resolution is still69          // less then return the width value as it70          return iw;71      },72    },73    stdH: {74      sm: 200,75      md: 400,76      lg: 550,77      default: 550,78      // If you change above values then make sure to update79      // calc method logic80      calc: (passed_height) => {81        // We are excluding sm as it is too small for dialog82        let ih = window.innerHeight;83        if (ih > passed_height)84          return passed_height;85        else if (ih > pgAdmin.Browser.stdH.lg)86          return pgAdmin.Browser.stdH.lg;87        else if (ih > pgAdmin.Browser.stdH.md)88          return pgAdmin.Browser.stdH.md;89        else90          // if avilable screen resolution is still91          // less then return the height value as it92          return ih;93      },94    },95    // Default panels96    panels: {},97    // We also support showing dashboards, HTML file, external URL98    frames: {},99    /* Menus */100    // add_menus(...) will register all the menus101    // in this container102    all_menus_cache: {103      // All context menu goes here under certain menu types.104      // i.e. context: {'server': [...], 'server-group': [...]}105      context: {},106      // File menus107      file: {},108      // Edit menus109      edit: {},110      // Object menus111      object: {},112      // Management menus113      management: {},114      // Tools menus115      tools: {},116      // Help menus117      help: {},118    },119    MainMenus: [],120    BrowserContextMenu: [],121 122    menu_categories: {123      /* name, label (pair) */124      'register': {125        label: gettext('Register'),126        priority: 1,127        /* separator above this menu */128        above: false,129        below: true,130        /* icon: 'fa fa-magic', */131        single: true,132      },133      'create': {134        label: gettext('Create'),135        priority: 2,136        /* separator above this menu */137        above: false,138        below: true,139        /* icon: 'fa fa-magic', */140        single: true,141      },142    },143    // A callback to load/fetch a script when a certain node is loaded144    register_script: function(n, m, p) {145      let scripts = this.scripts;146      scripts[n] = _.isArray(scripts[n]) ? scripts[n] : [];147      scripts[n].push({'name': m, 'path': p, loaded: false});148    },149    masterpass_callback_queue: [],150    getMenuList: function(name, item, d, skipDisabled=false) {151      let obj = this;152      //This 'checkNoMenuOptionForNode' function will check if showMenu flag is present or not for selected node153      let {flag,showMenu}=MainMenuFactory.checkNoMenuOptionForNode(d);154      if(flag){155        if(showMenu===false){156          return [MainMenuFactory.createMenuItem({157            enable : false,158            label: gettext('No menu available for this object.'),159            name:'',160            priority: 1,161            category: 'create',162          })];163        }164      }else{165        let category = {166          'common': []167        };168        const nodeTypeMenus = obj.all_menus_cache[name][d._type];169        for(let key of Object.keys(nodeTypeMenus)) {170          let menuItem = nodeTypeMenus[key];171          let menuCategory = menuItem.category ?? 'common';172          category[menuCategory] = category[menuCategory] ?? [];173          category[menuCategory].push(menuItem);174        }175        let menuItemList = [];176 177        for(let c in category) {178          if((c in obj.menu_categories || category[c].length > 1) && c != 'common' ) {179            let allMenuItemsDisabled = true;180            category[c].forEach((mi)=> {181              mi.checkAndSetDisabled(d, item);182              if(allMenuItemsDisabled) {183                allMenuItemsDisabled = mi.isDisabled;184              }185            });186 187            const categoryMenuOptions = obj.menu_categories[c];188            let label = categoryMenuOptions?.label ?? c;189            let priority = categoryMenuOptions?.priority ?? 10;190 191            if(categoryMenuOptions?.above) {192              menuItemList.push(MainMenuFactory.getSeparator(label, priority));193            }194            if(!allMenuItemsDisabled && skipDisabled) {195              let _menuItem = MainMenuFactory.createMenuItem({196                name: c,197                label: label,198                module: c,199                category: c,200                menu_items: category[c],201                priority: priority202              });203 204              menuItemList.push(_menuItem);205            } else if(!skipDisabled){206              let _menuItem = MainMenuFactory.createMenuItem({207                name: c,208                label: label,209                module:c,210                category: c,211                menu_items: category[c],212                priority: priority213              });214 215              menuItemList.push(_menuItem);216            }217            if(categoryMenuOptions?.below) {218              menuItemList.push(MainMenuFactory.getSeparator(label, priority));219            }220          } else {221            category[c].forEach((c)=> {222              c.checkAndSetDisabled(d, item);223            });224 225            category[c].forEach((m)=> {226              if(!skipDisabled) {227                menuItemList.push(m);228              } else if(skipDisabled && !m.isDisabled){229                menuItemList.push(m);230              }231            });232          }233        }234 235        return menuItemList;236      }237    },238    // Enable/disable menu options239    enable_disable_menus: function(item) {240      let obj = this;241      let d = item ? obj.tree.itemData(item) : undefined;242 243      // All menus (except for the object menus) are already present.244      // They will just require to check, whether they are245      // enabled/disabled.246      pgBrowser.MainMenus.filter((m)=>m.name != 'object').forEach((menu) => {247        menu.menuItems.forEach((mitem) => {248          mitem.checkAndSetDisabled(d, item);249        });250      });251 252      // Create the object menu dynamically253      let objectMenu = pgBrowser.MainMenus.find((menu) => menu.name == 'object');254      if (item && obj.all_menus_cache['object']?.[d._type]) {255        let menuItemList = obj.getMenuList('object', item, d);256        objectMenu && MainMenuFactory.refreshMainMenuItems(objectMenu, menuItemList);257        let ctxMenuList = obj.getMenuList('context', item, d, true);258        obj.BrowserContextMenu = MainMenuFactory.getContextMenu(ctxMenuList);259      } else {260        objectMenu && MainMenuFactory.refreshMainMenuItems(objectMenu, [261          MainMenuFactory.createMenuItem({262            name: '',263            label: gettext('No object selected'),264            category: 'create',265            priority: 1,266            enable: false,267          })268        ]);269      }270    },271    init: function() {272      let obj=this;273      if (obj.initialized) {274        return;275      }276      obj.initialized = true;277 278      // Cache preferences279      usePreferences.getState().cache();280      setupPreferenceBroadcast();281 282      setTimeout(function() {283        obj?.editor?.setValue('-- ' + select_object_msg);284        obj?.editor?.refresh();285      }, 10);286 287      // Register scripts and add menus288      pgBrowser.utils.registerScripts(this);289 290      // Ping the server every 5 minutes291      setInterval(function() {292        getApiInstance().post(293          url_for('misc.cleanup')294        ).then(()=> {295          /*This is intentional (SonarQube)*/296        }).catch(function() {297          /*This is intentional (SonarQube)*/298        });299      }, 300000);300 301      obj.Events.on(302        'pgadmin:server:connected', send_heartbeat.bind(obj)303      );304 305      obj.Events.on(306        'pgadmin:server:disconnect', stop_heartbeat.bind(obj)307      );308 309      obj.check_corrupted_db_file();310      obj.Events.on('pgadmin:browser:tree:add', obj.onAddTreeNode.bind(obj));311      obj.Events.on('pgadmin:browser:tree:update', obj.onUpdateTreeNode.bind(obj));312      obj.Events.on('pgadmin:browser:tree:refresh', obj.onRefreshTreeNodeReact.bind(obj));313      obj.Events.on('pgadmin-browser:tree:loadfail', obj.onLoadFailNode.bind(obj));314      obj.bind_beforeunload();315 316      /* User UI activity */317      obj.log_activity(); /* The starting point */318      obj.register_to_activity_listener(document);319      obj.start_inactivity_timeout_daemon();320    },321    uiloaded: function() {322      this.set_master_password('');323      this.check_version_update();324    },325    check_corrupted_db_file: function() {326      getApiInstance().get(327        url_for('browser.check_corrupted_db_file')328      ).then(({data: res})=> {329        if(res.data.length > 0) {330 331          pgAdmin.Browser.notifier.alert(332            'Warning',333            'pgAdmin detected unrecoverable corruption in it\'s SQLite configuration database. ' +334            'The database has been backed up and recreated with default settings. '+335            'It may be possible to recover data such as query history manually from '+336            'the original/corrupt file using a tool such as DB Browser for SQLite if desired.'+337            '<br><br>Original file: ' + res.data + '<br>Replacement file: ' +338            res.data.substring(0, res.data.length - 14),339          );340        }341      }).catch(function(error) {342        pgAdmin.Browser.notifier.alert(error);343      });344    },345    check_master_password: function(on_resp_callback) {346      getApiInstance().get(347        url_for('browser.check_master_password')348      ).then(({data: res})=> {349        if(on_resp_callback) {350          if(res.data) {351            on_resp_callback(true);352          } else {353            on_resp_callback(false);354          }355        }356      }).catch(function(error) {357        pgAdmin.Browser.notifier.pgRespErrorNotify(error);358      });359    },360 361    reset_master_password: function() {362      let self = this;363      getApiInstance().delete(364        url_for('browser.set_master_password')365      ).then(({data: res})=> {366        if(!res.data) {367          self.set_master_password('');368        }369      }).catch(function(error) {370        pgAdmin.Browser.notifier.pgRespErrorNotify(error);371      });372    },373 374    set_master_password: function(password='',375      set_callback=()=>{/*This is intentional (SonarQube)*/},376      cancel_callback=()=>{/*This is intentional (SonarQube)*/}) {377      let data=null, self = this;378 379      data = {380        'password': password,381      };382 383      self.masterpass_callback_queue.push(set_callback);384      // Check master passowrd.385      checkMasterPassword(data, self.masterpass_callback_queue, cancel_callback);386    },387 388    check_version_update: function() {389      getApiInstance().get(390        url_for('misc.upgrade_check')391      ).then((res)=> {392        const data = res.data.data;393        if(data.outdated) {394          pgAdmin.Browser.notifier.warning(395            `396            ${gettext('You are currently running version %s of %s, <br/>however the current version is %s.', data.current_version, data.product_name, data.upgrade_version)}397            <br/><br/>398            ${gettext('Please click <a href="%s" target="_new" style="color:inherit">here</a> for more information.', data.download_url)}399            `,400            null401          );402        }403 404      }).catch(function() {405        // Suppress any errors406      });407    },408 409    bind_beforeunload: function() {410      window.addEventListener('beforeunload', function(e) {411        /* Can open you in new tab */412        const prefStore = usePreferences.getState();413        let tree_save_interval = prefStore.getPreferences('browser', 'browser_tree_state_save_interval'),414          confirm_on_refresh_close = prefStore.getPreferences('browser', 'confirm_on_refresh_close');415 416        if (!_.isUndefined(tree_save_interval) && tree_save_interval.value !== -1)417          pgAdmin.Browser.browserTreeState.save_state();418 419        if(!_.isUndefined(confirm_on_refresh_close) && confirm_on_refresh_close.value) {420          /* This message will not be displayed in Chrome, Firefox, Safari as they have disabled it*/421          let msg = gettext('Are you sure you want to close the %s browser?', pgBrowser.utils.app_name);422          if(e.originalEvent?.returnValue) {423            e.originalEvent.returnValue = msg;424          }425          return msg;426        }427      });428    },429 430    add_menu_category: function(431      id, label, priority, icon, above_separator, below_separator, single432    ) {433      this.menu_categories[id] = {434        label: label,435        priority: priority,436        icon: icon,437        above: (above_separator === true),438        below: (below_separator === true),439        single: single,440      };441    },442 443    // Add menus of module/extension at appropriate menu444    add_menus: function(menus) {445      let pgMenu = this.all_menus_cache;446 447      _.each(menus, function(m) {448        _.each(m.applies, function(a) {449          /* We do support menu type only from this list */450          if(['context', 'file', 'edit', 'object','management', 'tools', 'help'].indexOf(a) > -1){451            let _menus;452 453            // If current node is not visible in browser tree454            // then return from here455            if(!checkNodeVisibility(m.node)) {456              return;457            } else if(_.has(m, 'module') && !_.isUndefined(m.module)) {458              // If module to which this menu applies is not visible in459              // browser tree then also we do not display menu460              if(!checkNodeVisibility(m.module.type)) {461                return;462              }463            }464 465            pgMenu[a] = pgMenu[a] || {};466            if (_.isString(m.node)) {467              _menus = pgMenu[a][m.node] = pgMenu[a][m.node] || {};468            } else if (_.isString(m.category)) {469              _menus = pgMenu[a][m.category] = pgMenu[a][m.category] || {};470            }471            else {472              _menus = pgMenu[a];473            }474 475            let get_menuitem_obj = function(_m) {476              let enable = _m.enable;477              if(_m.enable == '') {478                enable = true;479              } else if(_.isString(_m.enable) && _m.enable.toLowerCase() == 'false') {480                enable = false;481              }482 483              // This is to handel quick search callback484              if(_m.name == 'mnu_quick_search_help') {485                _m.callback = () => {486                  showQuickSearch();487                };488              }489 490              return MainMenuFactory.createMenuItem({491                name: _m.name,492                label: _m.label,493                module: _m.module,494                category: _m.category,495                callback: typeof _m.module == 'object' && _m.module[_m.callback] && _m.callback in _m.module[_m.callback] ? _m.module[_m.callback] : _m.callback,496                priority: _m.priority,497                data: _m.data,498                url: _m.url || '#',499                target: _m.target,500                icon: _m.icon,501                enable: enable || true,502                node: _m.node,503                checked: _m.checked,504                below: _m.below,505                applies: _m.applies,506              });507            };508 509            if (!_.has(_menus, m.name)) {510              _menus[m.name] = get_menuitem_obj(m);511 512              if(m.menu_items) {513                let sub_menu_items = [];514 515                for(let mnu_val of m.menu_items) {516                  sub_menu_items.push(get_menuitem_obj(mnu_val));517                }518                _menus[m.name]['menu_items'] = sub_menu_items;519              }520            }521          } else  {522            console.warn(523              'Developer warning: Category \'' +524                  a +525                  '\' is not supported!\nSupported categories are: context, file, edit, object, tools, management, help'526            );527          }528        });529      });530    },531    _findTreeChildNode: function(_i, _d, _o) {532      let loaded = _o.t.wasLoad(_i),533        onLoad = function() {534          let items = _o.t.children(_i),535            i, d, n, idx = 0, size = items.length;536          for (; idx < size; idx++) {537            i = items[idx];538            d = _o.t.itemData(i);539            if (d._type === _d._type) {540              if (!_o.hasId || d._id == _d._id) {541                _o.i = i;542                _o.d = _d;543                _o.pathOfTreeItems.push({coll: false, item: i, d: _d});544 545                _o.success();546                return;547              }548            } else {549              n = _o.b.Nodes[d._type];550              // Are we looking at the collection node for the given node?551              if (552                n?.collection_node && d.nodes &&553                  _.indexOf(d.nodes, _d._type) != -1554              ) {555                _o.i = i;556                _o.d = null;557                _o.pathOfTreeItems.push({coll: true, item: i, d: d});558 559                // Set load to false when the current collection node's inode is false560                if (!_o.t.isInode(i)) {561                  _o.load = false;562                }563                _o.b._findTreeChildNode(i, _d, _o);564                return;565              }566            }567          }568          _o.notFound && typeof(_o.notFound) == 'function' &&569            _o.notFound(_d);570        };571 572      if (!loaded && _o.load) {573        _o.t.open(_i).then(574          () => {575            onLoad();576          },577          () => {578            let fail = _o?.o?.fail;579            if (fail && typeof(fail) == 'function') {580              fail.apply(_o.t, []);581            }582          }583        );584      } else if (loaded) {585        onLoad();586      } else {587        _o.notFound && typeof(_o.notFound) == 'function' &&588          _o.notFound(_d);589      }590    },591 592    onAddTreeNode: function(_data, _hierarchy, _opts) {593      let ctx = {594          b: this, // Browser595          d: null, // current parent596          hasId: true,597          i: null, // current item598          p: _.toArray(_hierarchy || {}).sort(599            function(a, b) {600              if (a.priority === b.priority) {601                return 0;602              }603              return (a.priority < b.priority ? -1 : 1);604            }605          ), // path of the parent606          pathOfTreeItems: [], // path Item607          t: this.tree, // Tree Api608          o: _opts,609        },610        traversePath = function() {611          let _ctx = this, data;612 613          _ctx.success = traversePath;614          if (_ctx.p.length) {615            data = _ctx.p.shift();616            // This is the parent node.617            // Replace the parent-id of the data, which could be different618            // from the given hierarchy.619            if (!_ctx.p.length) {620              data._id = _data._pid;621              _ctx.success = addItemNode;622            }623            _ctx.b._findTreeChildNode(624              _ctx.i, data, _ctx625            );626            // if parent node is null627            if (!_data._pid) {628              addItemNode.apply(_ctx, arguments);629            }630          }631          return true;632        }.bind(ctx),633        addItemNode = function() {634          // Append the new data in the tree under the current item.635          // We may need to pass it to proper collection node.636          let _ctx = this,637            first = (_ctx.i || this.t.wasLoad(_ctx.i)) &&638            this.t.first(_ctx.i),639            findChildNode = function(success, notFound) {640              let __ctx = this;641              __ctx.success = success;642              __ctx.notFound = notFound;643 644              __ctx.b._findTreeChildNode(__ctx.i, _data, __ctx);645            }.bind(_ctx),646            selectNode = function() {647              this.t.openPath(this.i);648              this.t.select(this.i);649              if (typeof(_ctx?.o?.success) == 'function') {650                _ctx.o.success.apply(_ctx.t, [_ctx.i, _data]);651              }652            }.bind(_ctx),653            addNode = function() {654              let __ctx = this,655                items = __ctx.t.children(__ctx.i),656                s = 0, e = items.length - 1, i,657                linearSearch = function() {658                  while (e >= s) {659                    i = items[s];660                    let d = __ctx.t.itemData(i);661                    if (d._type === 'column') {662                      if (pgAdmin.numeric_comparator(d._id, _data._id) == 1)663                        return true;664                    } else if (pgAdmin.natural_sort(d._label, _data._label) == 1)665                      return true;666                    s++;667                  }668                  //when the current element is greater than the end element669                  if (e != items.length - 1) {670                    i = items[e+1];671                    return true;672                  }673                  i = null;674                  return false;675                },676                binarySearch = function() {677                  let d, m;678                  // Binary search only outperforms Linear search for n > 44.679                  // Reference:680                  // https://en.wikipedia.org/wiki/Binary_search_algorithm#cite_note-30681                  //682                  // We will try until it's half.683                  while (e - s > 22) {684                    i = items[s];685                    d = __ctx.t.itemData(i);686                    if (d._type === 'column') {687                      if (pgAdmin.numeric_comparator(d._id, _data._id) != -1)688                        return true;689                    } else if (pgAdmin.natural_sort(d._label, _data._label) != -1)690                      return true;691                    i = items[e];692                    d = __ctx.t.itemData(i);693                    let result;694                    if (d._type === 'column') {695                      result = pgAdmin.numeric_comparator(d._id, _data._id);696                    } else {697                      result = pgAdmin.natural_sort(d._label, _data._label);698                    }699                    if (result !=1) {700                      if (e != items.length - 1) {701                        i = items[e+1];702                        return true;703                      }704                      i = null;705                      return false;706                    }707                    m = s + Math.round((e - s) / 2);708                    i = items[m];709                    d = __ctx.t.itemData(i);710                    if(d._type === 'column'){711                      result = pgAdmin.numeric_comparator(d._id, _data._id);712                    } else {713                      result = pgAdmin.natural_sort(d._label, _data._label);714                    }715                    //result will never become 0 because of remove operation716                    //which happens with updateTreeNode717                    if (result == 0)718                      return true;719 720                    if (result == -1) {721                      s = m + 1;722                      e--;723                    } else {724                      s++;725                      e = m - 1;726                    }727                  }728                  return linearSearch();729                };730 731              if (binarySearch()) {732                __ctx.t.before(i, _data).then((_item) => {733                  if (typeof(__ctx?.o?.success) == 'function') {734                    __ctx.o.success.apply(__ctx.t, [i, _data]);735                  } else {736                    __ctx.t.select(_item);737                  }738                }, () => {739                  console.warn('Failed to add before...', arguments);740                  if (typeof(__ctx.o?.fail) == 'function') {741                    __ctx.o.fail.apply(__ctx.t, [i, _data]);742                  }743                });744              } else {745                let _append = function() {746                  let ___ctx = this,747                    _parent_data = ___ctx.t.itemData(___ctx.i);748 749                  ___ctx.t.append(___ctx.i, _data).then(750                    (_i) => {751                      // Open the item path only if its parent is loaded752                      // or parent type is same as nodes753                      if(754                        ___ctx.t.wasLoad(___ctx.i) &&755                          _parent_data &&  _parent_data._type.search(756                          _data._type757                        ) > -1758                      ) {759                        ___ctx.t.open(___ctx.i);760                        ___ctx.t.select(_i);761                      } else if (_parent_data) {762                        // Unload the parent node so that we'll get763                        // latest data when we try to expand it764                        ___ctx.t.unload(___ctx.i).then(765                          () => {766                            ___ctx.t.open(___ctx.i);767                          }768                        );769                      }770                      if (typeof(___ctx?.o?.success) == 'function') {771                        ___ctx.o.success.apply(___ctx.t, [_i, _data]);772                      }773                    },774                    () => {775                      console.warn('Failed to append...', arguments);776                      if (typeof(___ctx?.o?.fail) == 'function') {777                        ___ctx.o.fail.apply(___ctx.t, [___ctx.i, _data]);778                      }779                    }780                  );781                }.bind(__ctx);782 783                if (__ctx.i && !__ctx.t.isInode(__ctx.i)) {784                  __ctx.t.setInode(__ctx.i).then(785                    () => {786                      _append();787                    }788                  );789                } else {790                  // Handle case for node without parent i.e. server-group791                  // or if parent node's inode is true.792                  _append();793                }794              }795            }.bind(_ctx);796 797          // Parent node do not have any children, let me unload it.798          if (!first && _ctx.t.wasLoad(_ctx.i)) {799            _ctx.t.unload(_ctx.i).then(() => {800              findChildNode(801                selectNode,802                function() {803                  let o = this && this.o;804                  if (typeof(o?.fail) == 'function') {805                    o.fail.apply(this.t, [this.i, _data]);806                  }807                }.bind(this)808              );809            },810            () => {811              let o = this && this.o;812              if (typeof(o?.fail) == 'function') {813                o.fail.apply(this.t, [this.i, _data]);814              }815            });816            return;817          }818 819          // We can find the collection node using _findTreeChildNode820          // indirectly.821          findChildNode(selectNode, addNode);822        }.bind(ctx);823 824      if (!ctx.t.wasInit() || !_data) {825        return;826      }827 828      traversePath();829    },830 831    onUpdateTreeNode: function(_old, _new, _hierarchy, _opts) {832      let ctx = {833          b: this, // Browser834          d: null, // current parent835          i: null, // current item836          hasId: true,837          p: _.toArray(_hierarchy || {}).sort(838            function(a, b) {839              if (a.priority === b.priority) {840                return 0;841              }842              return (a.priority < b.priority ? -1 : 1);843            }844          ), // path of the old object845          pathOfTreeItems: [], // path items846          t: this.tree, // Tree Api847          o: _opts,848          load: true,849          old: _old,850          new: _new,851          op: null,852        },853        errorOut = function() {854          let fail = this.o?.fail;855          if (fail && typeof(fail) == 'function') {856            fail.apply(this.t, [this.i, _new, _old]);857          }858        }.bind(ctx),859        deleteNode = function() {860          let self = this,861            pathOfTreeItems = this.pathOfTreeItems,862            findParent = function() {863              if (pathOfTreeItems.length) {864                pathOfTreeItems.pop();865                let length = pathOfTreeItems.length;866                this.i = (length && pathOfTreeItems[length - 1].item) || null;867                this.d = (length && pathOfTreeItems[length - 1].d) || null;868 869                // It is a collection item, let's find the node item870                if (length && pathOfTreeItems[length - 1].coll) {871                  pathOfTreeItems.pop();872                  length = pathOfTreeItems.length;873                  this.i = (length && pathOfTreeItems[length - 1].item) || null;874                  this.d = (length && pathOfTreeItems[length - 1].d) || null;875                }876              } else {877                this.i = null;878                this.d = null;879              }880            }.bind(this);881 882          let _item_parent = (this.i883            && this.t.hasParent(this.i)884              && this.t.parent(this.i)) || null,885            _item_grand_parent = _item_parent ?886              (this.t.hasParent(_item_parent)887              && this.t.parent(_item_parent) &&888              _item_parent.root != this.t.parent(_item_parent))889              : null;890 891          // Remove the current node first.892          if (893            this.i && this.d && this.old._id == this.d._id &&894              this.old._type == this.d._type895          ) {896            let _parent = this.t.parent(this.i) || null;897 898            // If there is no parent then just update the node899            if(this.t.isRootNode(_parent) ||900             (_parent && _parent.length == 0 && ctx.op == 'UPDATE')) {901              //Update node if browser has single child node.902              if(this.t.children().length === 1) {903                updateNode();904              } else {905                let that = this;906                this.t.remove(this.i).then(() => {907                  that.t.before(that.i, that.new).then((new_item) => {908                    that.t.select(new_item);909                  }, () => {910                    console.warn('Failed to add before..', arguments);911                  });912                });913              }914            } else {915              let postRemove = function() {916                // If item has parent but no grand parent917                if (_item_parent.path !== '/browser' && !_item_grand_parent) {918                  let parent = null;919                  // We need to search in all parent siblings (eg: server groups)920                  let parents = this.t.siblings(this.i) || [];921                  parents.push(this.i);922                  _.each(parents, function (p) {923                    let d = self.t.itemData(p);924                    // If new server group found then assign it parent925                    if(d._id == self.new._pid) {926                      parent = p;927                      self.pathOfTreeItems.push({coll: true, item: parent, d: d});928                    }929                  });930 931                  if (parent) {932                    this.load = true;933 934                    this.success = function() {935                      addItemNode();936                    }.bind(this);937                    // We can refresh the collection node, but - let's not bother about938                    // it right now.939                    this.notFound = errorOut;940 941                    let loaded = this.t.wasLoad(parent),942                      onLoad = function() {943                        self.i = parent;944                        self.pathOfTreeItems.push({coll: false, item: parent, d: self.d});945                        self.success();946                      };947 948                    if (!loaded && self.load) {949                      self.t.open(parent).then(950                        () => {951                          onLoad();952                        },953                        () => {954                          let fail = self?.o?.fail;955                          if (956                            fail && typeof(fail) == 'function'957                          ) {958                            fail.apply(self.t, []);959                          }960                        }961                      );962                    } else {963                      onLoad();964                    }965                  }966                } else {967                  // This is for rest of the nodes968                  let _parentData = this.d;969                  // Find the grand-parent, or the collection node of parent.970                  findParent();971 972                  if (this.i) {973                    this.load = true;974 975                    this.success = function() {976                      addItemNode();977                    }.bind(this);978                    // We can refresh the collection node, but - let's not bother about979                    // it right now.980                    this.notFound = errorOut;981 982                    // Find the new parent983                    this.b._findTreeChildNode(984                      this.i, {_id: this.new._pid, _type: _parentData._type}, this985                    );986                  } else {987                    addItemNode();988                  }989                }990              }.bind(this);991 992              this.t.remove(this.i).then(() => {993                findParent();994                if (_item_parent && !_item_grand_parent && _parent995                    && self.t.children(_parent).length == 0) {996                  self.t.unload(_parent).then( () => { setTimeout(postRemove); });997                }998                else {999                  setTimeout(postRemove);1000                }1001                return true;1002              });1003            }1004 1005          }1006          errorOut();1007 1008        }.bind(ctx),1009        findNewParent = function(_d) {1010          let findParent = function() {1011            let pathOfTreeItems = this.pathOfTreeItems;1012 1013            if (pathOfTreeItems.length) {1014              pathOfTreeItems.pop();1015              let length = pathOfTreeItems.length;1016              this.i = (length && pathOfTreeItems[length - 1].item) || null;1017              this.d = (length && pathOfTreeItems[length - 1].d) || null;1018 1019              // It is a collection item, let's find the node item1020              if (length && pathOfTreeItems[length - 1].coll) {1021                pathOfTreeItems.pop();1022                length = pathOfTreeItems.length;1023                this.i = (length && pathOfTreeItems[length - 1].item) || null;1024                this.d = (length && pathOfTreeItems[length - 1].d) || null;1025              }1026            } else {1027              this.i = null;1028              this.d = null;1029            }1030          }.bind(this);1031 1032          // old parent was not found, can we find the new parent?1033          if (this.i) {1034            this.load = true;1035            this.success = function() {1036              addItemNode();1037            }.bind(this);1038 1039            if (_d._type == this.old._type) {1040              // We were already searching the old object under the parent.1041              findParent();1042              _d = this.d;1043              // Find the grand parent1044              findParent();1045            }1046            _d = this.new._pid;1047 1048            // We can refresh the collection node, but - let's not bother about1049            // it right now.1050            this.notFound = errorOut;1051 1052            // Find the new parent1053            this.b._findTreeChildNode(this.i, _d, this);1054          } else {1055            addItemNode();1056          }1057        }.bind(ctx),1058        updateNode = function() {1059          if (1060            this.i && this.d && this.new._type == this.d._type1061          ) {1062            let self = this,1063              _id = this.d._id;1064            if (this.new._id != this.d._id) {1065              // Found the new oid, update its node_id1066              let node_data = this.t.itemData(ctx.i);1067              node_data._id = _id = this.new._id;1068            }1069            if (this.new._id == _id) {1070              // Found the current1071              _.extend(this.d, this.new);1072              this.t.update(ctx.i, this.d);1073              this.t.setLabel(ctx.i, {label: this.new.label});1074              this.t.addIcon(ctx.i, {icon: this.new.icon});1075              this.t.setId(ctx.i, {id: this.new.id});1076              this.t.openPath(this.i);1077              this.t.deselect(this.i);1078 1079              // select tree item1080              self.t.select(self.i);1081            }1082          }1083          let success = this.o?.success;1084          if (success && typeof(success) == 'function') {1085            success.apply(this.t, [this.i, _old, _new]);1086          }1087        }.bind(ctx),1088        traversePath = function() {1089          let _ctx = this, data;1090 1091          _ctx.success = traversePath;1092          if (_ctx.p.length) {1093            data = _ctx.p.shift();1094            // This is the node, we can now do the required operations.1095            // We should first delete the existing node, if the parent-id is1096            // different.1097            if (!_ctx.p.length) {1098              if (_ctx.op == 'RECREATE') {1099                _ctx.load = false;1100                _ctx.success = deleteNode;1101                _ctx.notFound = findNewParent;1102              } else {1103                _ctx.success = updateNode;1104                _ctx.notFound = errorOut;1105              }1106            }1107            _ctx.b._findTreeChildNode(1108              _ctx.i, data, _ctx1109            );1110          } else if (_ctx.p.length == 1) {1111            _ctx.notFound = findNewParent;1112          }1113          return true;1114        }.bind(ctx),1115        addItemNode = function() {1116          let _ctx = this,1117            first = (_ctx.i || this.t.wasLoad(_ctx.i)) &&1118            this.t.first(_ctx.i),1119            findChildNode = function(success, notFound) {1120              let __ctx = this;1121              __ctx.success = success;1122              __ctx.notFound = notFound;1123 1124              __ctx.b._findTreeChildNode(__ctx.i, _new, __ctx);1125            }.bind(_ctx),1126            selectNode = function() {1127              this.t.openPath(this.i);1128              this.t.select(this.i);1129              if (1130                _ctx.o && _ctx.o.success && typeof(_ctx.o.success) == 'function'1131              ) {1132                _ctx.o.success.apply(_ctx.t, [_ctx.i, _new]);1133              }1134            }.bind(_ctx),1135            addNode = function() {1136              let __ctx = this,1137                items = __ctx.t.children(__ctx.i),1138                s = 0, e = items.length - 1, i,1139                linearSearch = function() {1140                  while (e >= s) {1141                    i = items[s];1142                    let d = __ctx.t.itemData(i);1143                    if (d._type === 'column') {1144                      if (pgAdmin.numeric_comparator(d._id, _new._id) == 1)1145                        return true;1146                    } else if (pgAdmin.natural_sort(d._label, _new._label) == 1)1147                      return true;1148                    s++;1149                  }1150                  if (e != items.length - 1) {1151                    i = items[e+1];1152                    return true;1153                  }1154                  i = null;1155                  return false;1156                },1157                binarySearch = function() {1158                  while (e - s > 22) {1159                    i = items[s];1160                    let d = __ctx.t.itemData(i);1161                    if (d._type === 'column') {1162                      if (pgAdmin.numeric_comparator(d._id, _new._id) != -1)1163                        return true;1164                    } else if (pgAdmin.natural_sort(d._label, _new._label) != -1)1165                      return true;1166                    i = items[e];1167                    d = __ctx.t.itemData(i);1168                    let result;1169                    if (d._type === 'column') {1170                      result = pgAdmin.numeric_comparator(d._id, _new._id);1171                    } else {1172                      result = pgAdmin.natural_sort(d._label, _new._label);1173                    }1174                    if (result !=1) {1175                      if (e != items.length - 1) {1176                        i = items[e+1];1177                        return true;1178                      }1179                      i = null;1180                      return false;1181                    }1182                    let m = s + Math.round((e - s) / 2);1183                    i = items[m];1184                    d = __ctx.t.itemData(i);1185                    if(d._type === 'column'){1186                      result = pgAdmin.numeric_comparator(d._id, _new._id);1187                    } else {1188                      result = pgAdmin.natural_sort(d._label, _new._label);1189                    }1190                    //result will never become 0 because of remove operation1191                    //which happens with updateTreeNode1192                    if (result == 0)1193                      return true;1194 1195                    if (result == -1) {1196                      s = m + 1;1197                      e--;1198                    } else {1199                      s++;1200                      e = m - 1;

Showing the first 1,200 of 1754 lines. Download the file for the rest.

codekingpro/portable-devtools · Team Ai