Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
pgadmin_tree_save_state.js371 linesDownload Raw Back to tree
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 _ from 'lodash';11import url_for from 'sources/url_for';12import gettext from 'sources/gettext';13import pgAdmin from 'sources/pgadmin';14import getApiInstance, { callFetch } from '../api_instance';15import usePreferences from '../../../preferences/static/js/store';16 17export const pgBrowser = pgAdmin.Browser = pgAdmin.Browser || {};18 19 20export const browserTreeState = pgBrowser.browserTreeState = pgBrowser.browserTreeState || {};21 22_.extend(pgBrowser.browserTreeState, {23 24  // Parent node to start saving / reloading the tree state25  parent: 'server',26 27  // The original parent of the browser tree28  orig_parent: 'server_group',29 30  // Stored tree state31  // Sample Object32  //  {1:33  //    'paths': [34  //      server_group/1,/server/1,/coll-database/1,/database/1,35  //      server_group/1,/server/1,/coll-database/1,/database/2,36  //    ],37  //    'selected': {38  //       'server/1': 'database/2',39  //       'database/1': 'table/1',40  //     },41  //    'conn_status': {42  //      'database/1': 1,43  //      'database/2': 0 ,44  //    },45  //  }46  // Here key is server ID47 48  stored_state: {},49 50  // Previous tree state51  last_state: {},52 53  is_selected: false,54 55  // Current tree state56  current_state: {},57 58  init: function() {59 60    let saveIntervalId, offExpandFromPrevState, offRemoveFromTreeState, offUpdateTreeState;61    usePreferences.subscribe((prefStore)=>{62      // Subscribe to listen for preferences change63      const save_tree_state_period = prefStore.getPreferences('browser', 'browser_tree_state_save_interval')?.value;64      if (saveIntervalId) {65        clearInterval(saveIntervalId);66        saveIntervalId = null;67        offEventListener();68      }69      if (!_.isUndefined(save_tree_state_period) &&  save_tree_state_period !== -1) {70        // Save the tree state at given save_tree_state_period71        saveIntervalId = setInterval(this.save_state, (save_tree_state_period) * 1000);72        this.fetch_state.apply(this);73        onEventListener();74      } else if (!_.isUndefined(save_tree_state_period)) {75        offEventListener();76        getApiInstance().delete(url_for('settings.reset_tree_state'))77          .catch(function(error) {78            console.warn(79              gettext('Error resetting the tree saved state."'), error);80          });81      }82    });83 84    const onEventListener = () => {85      // Register event listener86      offExpandFromPrevState = pgBrowser.Events.on('pgadmin:browser:tree:expand-from-previous-tree-state',87        this.expand_from_previous_state.bind(this));88      offRemoveFromTreeState = pgBrowser.Events.on('pgadmin:browser:tree:remove-from-tree-state',89        this.remove_from_cache.bind(this));90      offUpdateTreeState = pgBrowser.Events.on('pgadmin:browser:tree:update-tree-state',91        this.update_cache.bind(this));92    };93 94    const offEventListener = () => {95      // Deregister event listener96      offExpandFromPrevState?.();97      offRemoveFromTreeState?.();98      offUpdateTreeState?.();99    };100 101  },102  save_state: function() {103 104    let self = pgBrowser.browserTreeState;105    if(self.last_state == JSON.stringify(self.current_state))106      return;107 108    /* Using fetch with keepalive as the browser may109    cancel the axios request on tab close. keepalive will110    make sure the request is completed */111    callFetch(112      url_for('settings.save_tree_state'), {113        keepalive: true,114        method: 'POST',115        body: JSON.stringify(self.current_state)116      })117      .then(()=> {118        self.last_state = JSON.stringify(self.current_state);119        self.fetch_state();120      })121      .catch((error)=> {122        console.warn(123          gettext('Error resetting the tree saved state."'), error);124      });125  },126  fetch_state: function() {127 128    let self = this;129 130    getApiInstance().get(131      url_for('settings.get_tree_state'),132    ).then((res)=> {133      self.stored_state = res.data;134    }).catch(function(error) {135      console.warn(136        gettext('Error resetting the tree saved state."'), error);137    });138  },139  update_cache: function(item) {140    let data = item && pgBrowser.tree.itemData(item),141      treeHierarchy = pgBrowser.tree.getTreeNodeHierarchy(item),142      topParent,143      pathIDs = pgBrowser.tree.pathId(pgBrowser.tree.parent(item)),144      oldPath = pathIDs.join(),145      path = [],146      tmpIndex = -1;147 148    // If no parent or the server not in tree hierarchy then return149    if (!pgBrowser.tree.hasParent(item) || !(this.parent in treeHierarchy) || (data._type === 'server' && !data.connected))150      return;151 152    topParent = treeHierarchy[this.parent]['_id'];153 154 155    if (pgBrowser.tree.isOpen(item)) {156      // Store paths157 158      pathIDs.push(data.id);159      path = pathIDs.join();160 161      if (!(topParent in this.current_state)) {162        this.current_state[topParent] = {'paths': [], 'selected': {}, 'conn_status': {}, 'is_opened': {}};163      }164 165      // IF the current path is already saved then return166      let index = _.find(this.current_state[topParent]['paths'], function(tData) {167        return (tData.search(path) !== -1);168      });169      if(_.isUndefined(index)) {170 171        // Add / Update the current item into the tree path172        if (!_.isUndefined(this.current_state[topParent]['paths'])) {173          tmpIndex = this.current_state[topParent]['paths'].indexOf(oldPath);174        } else {175          this.current_state[topParent]['paths'] = [];176        }177        if (tmpIndex !== -1) {178          this.current_state[topParent]['paths'][tmpIndex] = path;179        }180        else {181          this.current_state[topParent]['paths'].push(path);182        }183      }184 185    }186 187    // Store current selected item and database connection status188    this.update_database_status(item);189    this.update_current_selected_item(treeHierarchy);190 191  },192  remove_from_cache: function(item) {193    let self= this,194      treeData = self.stored_state || {},195      data = item && pgBrowser.tree.itemData(item),196      treeHierarchy = pgBrowser.tree.getTreeNodeHierarchy(item);197 198    if (treeHierarchy === null || !pgBrowser.tree.hasParent(item) || !(treeHierarchy.hasOwnProperty(self.parent)))199      return;200 201    let topParent = treeHierarchy?.[self.parent]['_id'],202      origParent = treeHierarchy?.[self.orig_parent]['id'];203 204    this.update_database_status(item);205 206    if (data._type == self.parent || data._type == 'database') {207      if (treeData?.[topParent]?.['paths'] && self.current_state?.[topParent]?.['paths']) {208        treeData[topParent]['paths'] = self.current_state[topParent]['paths'];209        self.save_state();210      }211      return;212    }213 214    if (pgBrowser.tree.isClosed(item)) {215      let tmpTreeData =  self.current_state[topParent]['paths'],216        databaseId;217 218      if (treeHierarchy.hasOwnProperty('database'))219        databaseId = treeHierarchy['database']['id'];220 221      if (!_.isUndefined(tmpTreeData) && !_.isUndefined(tmpTreeData.length)) {222        let tcnt = 0, tmpItemDataStr;223        _.each(tmpTreeData, function(tData) {224          if (_.isUndefined(tData))225            return;226 227          let tmpItemData = tData.split(',');228 229          if (tmpItemData.indexOf(data.id) !== -1 ) {230            if (databaseId === undefined || (databaseId !== undefined && tmpItemData.indexOf(databaseId) !== -1)) {231 232              let index = tmpItemData.indexOf(data.id);233              tmpItemData.splice(index);234              tmpItemDataStr = tmpItemData.join();235 236              if (tmpItemDataStr == origParent)237                self.current_state[topParent]['paths'].splice(tData, 1);238              else239                self.current_state[topParent]['paths'][tcnt] = tmpItemDataStr;240            }241          }242          tcnt ++;243        });244      }245    }246  },247  expand_from_previous_state: function(item) {248    let self = this,249      treeData = this.stored_state || {},250      data = item && pgBrowser.tree.itemData(item),251      treeHierarchy = pgBrowser.tree.getTreeNodeHierarchy(item);252 253 254    if (treeHierarchy === null || !pgBrowser.tree.hasParent(item) || !(treeHierarchy.hasOwnProperty(self.parent)))255      return;256 257    // If the server node is open then only we should populate the tree258    if (data['_type'] == self.parent && (pgBrowser.tree.isOpen(item) === false))259      return;260 261    let tmpTreeData = treeData[treeHierarchy[self.parent]['_id']];262 263 264    // If the server node is open then only we should populate the tree265    if (data['_type'] == 'database' && tmpTreeData && 'conn_status' in tmpTreeData && 'is_opened' in tmpTreeData &&266     (tmpTreeData['conn_status'][data['id']] === 0 || tmpTreeData['is_opened'][data['id']] === 0 ||267      !(data['id'] in tmpTreeData['is_opened'])))268      return;269 270 271    if (!_.isUndefined(tmpTreeData) && ('paths' in tmpTreeData) && !_.isUndefined(tmpTreeData['paths'].length)) {272      let tmpTreeDataPaths = [...tmpTreeData['paths']],273        databaseId;274 275      if (treeHierarchy.hasOwnProperty('database'))276        databaseId = treeHierarchy['database']['id'];277 278      _.each(tmpTreeDataPaths, function(tData) {279        if (_.isUndefined(tData))280          return;281 282        let tmpItemData = tData.split(',');283 284        // If the item is in the lastTreeState then open it285        if (tmpItemData.indexOf(data.id) !== -1) {286          if (databaseId === undefined ||  (databaseId !== undefined && tmpItemData.indexOf(databaseId) !== -1)) {287 288            let index = tmpItemData.indexOf(data.id);289 290            pgBrowser.tree.open(item);291            pgBrowser.tree.ensureLoaded(item);292            if (index == (tmpItemData.length - 1 )) {293              let tIndex = treeData[treeHierarchy[self.parent]['_id']]['paths'].indexOf(tData);294              treeData[treeHierarchy[self.parent]['_id']]['paths'].splice(tIndex, 1);295            }296          }297        }298      });299    }300 301    this.select_tree_item(item);302 303  },304  update_database_status: function(item) {305    let data = item && pgBrowser.tree.itemData(item),306      treeHierarchy = pgBrowser.tree.getTreeNodeHierarchy(item);307 308    if (treeHierarchy.hasOwnProperty('database')) {309      let databaseItem = treeHierarchy['database']['id'],310        topParent = treeHierarchy?.[this.parent]['_id'];311 312      if (topParent in this.current_state && 'selected' in this.current_state[topParent]) {313        if (treeHierarchy['database'].connected) {314          this.current_state[topParent]['conn_status'][databaseItem] = 1;315        }316        else {317          this.current_state[topParent]['conn_status'][databaseItem] = 0;318        }319 320        if(data._type == 'database') {321          if (pgBrowser.tree.isOpen(item)) {322            this.current_state[topParent]['is_opened'][databaseItem] = 1;323          }324          else {325            this.current_state[topParent]['is_opened'][databaseItem] = 0;326          }327        }328      }329    }330  },331  update_current_selected_item(treeHierarchy) {332    if (!(this.parent in treeHierarchy))333      return;334 335    let topParent = treeHierarchy?.[this.parent]['_id'],336      selectedItem = pgBrowser.tree.itemData(pgBrowser.tree.selected()),337      databaseItem;338 339    selectedItem = selectedItem ? selectedItem.id : undefined;340 341    if (treeHierarchy.hasOwnProperty('database')) {342      databaseItem = treeHierarchy['database']['id'];343    }344 345    if (topParent in this.current_state && 'selected' in this.current_state[topParent]346    && !_.isUndefined(selectedItem)) {347      this.current_state[topParent]['selected'][treeHierarchy[this.parent]['id']] = selectedItem;348 349      if (!_.isUndefined(databaseItem))350        this.current_state[topParent]['selected'][databaseItem] = selectedItem;351    }352  },353  select_tree_item(item) {354    let treeData = this.stored_state || {},355      data = item && pgBrowser.tree.itemData(item),356      treeHierarchy = pgBrowser.tree.getTreeNodeHierarchy(item),357      tmpTreeData = treeData[treeHierarchy[this.parent]['_id']];358 359    if (treeHierarchy.hasOwnProperty('server')) {360      let selectedItem = treeHierarchy['server']['id'];361 362      if (tmpTreeData && 'selected' in tmpTreeData && selectedItem in tmpTreeData['selected']) {363        if (tmpTreeData['selected'][selectedItem] == data.id) {364          this.is_selected = true;365          pgBrowser.tree.select(item, true, 'center');366        }367      }368    }369  },370});371 
codekingpro/portable-devtools · Team Ai