Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
ObjectNodeProperties.jsx272 linesDownload Raw Back to properties
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 React, { useEffect, useMemo, useRef } from 'react';11 12import getApiInstance from 'sources/api_instance';13import {getHelpUrl, getEPASHelpUrl} from 'pgadmin.help';14import SchemaView from 'sources/SchemaView';15import gettext from 'sources/gettext';16import { generateNodeUrl } from '../../browser/static/js/node_ajax';17import { usePgAdmin } from '../../static/js/BrowserComponent';18import { LAYOUT_EVENTS, LayoutDockerContext } from '../../static/js/helpers/Layout';19import usePreferences from '../../preferences/static/js/store';20import PropTypes from 'prop-types';21 22export default function ObjectNodeProperties({panelId, node, treeNodeInfo, nodeData, actionType, formType, onEdit, onSave, onClose,23  isActive, setIsStale, isStale}) {24  const layoutDocker = React.useContext(LayoutDockerContext);25  const nodeType = nodeData?._type;26  const pgAdmin = usePgAdmin();27  let serverInfo = treeNodeInfo && ('server' in treeNodeInfo) &&28      pgAdmin.Browser.serverInfo && pgAdmin.Browser.serverInfo[treeNodeInfo.server._id];29  let inCatalog = treeNodeInfo && ('catalog' in treeNodeInfo);30  let isActionTypeCopy = actionType == 'copy';31  // If the actionType is set to 'copy' it is necessary to retrieve the details32  // of the existing node. Therefore, specify the actionType as 'edit' to33  // facilitate this process.34  let urlBase = generateNodeUrl.call(node, treeNodeInfo, isActionTypeCopy ? 'edit' : actionType, nodeData, false, node.url_jump_after_node);35  const api = getApiInstance();36  // To check node data is updated or not37  const staleCounter = useRef(0);38  const url = (isNew)=>{39    return urlBase + (isNew ? '' : nodeData._id);40  };41  const isDirty = useRef(false); // useful for warnings42  let warnOnCloseFlag = true;43  const confirmOnCloseReset = usePreferences().getPreferencesForModule('browser').confirm_on_properties_close;44  let updatedData =  ['table', 'partition'].includes(nodeType) && !_.isEmpty(nodeData.rows_cnt) ? {rows_cnt: nodeData.rows_cnt} : undefined;45  let schema = node.getSchema(treeNodeInfo, nodeData);46 47  // We only have two actionTypes, 'create' and 'edit' to initiate the dialog,48  // so if isActionTypeCopy is true, we should revert back to "create" since49  // we are duplicating the node.50  if (isActionTypeCopy) {51    actionType = 'create';52  }53 54  let onError = (err)=> {55    if(err.response){56      console.error('error resp', err.response);57    } else if(err.request){58      console.error('error req', err.request);59    } else if(err.message){60      console.error('error msg', err.message);61    }62  };63 64  /* Called when dialog is opened in edit mode, promise required */65  let initData = ()=>new Promise((resolve, reject)=>{66    if(actionType === 'create' && !isActionTypeCopy) {67      resolve({});68    } else {69      // Do not call the API if tab is not active.70      if(!isActive && actionType == 'properties') {71        return;72      }73      api.get(url(false))74        .then((res)=>{75          let data = res.data;76          if (isActionTypeCopy) {77            // Delete the idAttribute while copying the node.78            delete data[schema.idAttribute];79            data = node.copy(data);80          }81          resolve(data);82        })83        .catch((err)=>{84          pgAdmin.Browser.notifier.pgNotifier('error', err, gettext('Failed to fetch data'), function(msg) {85            if (msg == 'CRYPTKEY_SET') {86              return Promise.resolve(initData());87            } else if (msg == 'CRYPTKEY_NOT_SET') {88              reject(gettext('The master password is not set.'));89            }90            reject(err);91          });92 93        })94        .then(()=>{95          // applies only for properties tab96          setIsStale?.(false);97        });98    }99  });100 101  /* on save button callback, promise required */102  const onSaveClick = (isNew, data)=>new Promise((resolve, reject)=>{103    return api({104      url: url(isNew),105      method: isNew ? 'POST' : 'PUT',106      data: data,107    }).then((res)=>{108      /* Don't warn the user before closing dialog */109      warnOnCloseFlag = false;110      resolve(res.data);111      onSave?.(res.data);112    }).catch((err)=>{113      pgAdmin.Browser.notifier.pgNotifier('error-noalert', err, '', function(msg) {114        if (msg == 'CRYPTKEY_SET') {115          return Promise.resolve(onSaveClick(isNew, data));116        } else if (msg == 'CRYPTKEY_NOT_SET') {117          reject(gettext('The master password is not set.'));118        }119        reject(err);120      });121    });122  });123 124  /* Called when switched to SQL tab, promise required */125  const getSQLValue = (isNew, changedData)=>{126    const msqlUrl = generateNodeUrl.call(node, treeNodeInfo, 'msql', nodeData, !isNew, node.url_jump_after_node);127    return new Promise((resolve, reject)=>{128      api({129        url: msqlUrl,130        method: 'GET',131        params: changedData,132      }).then((res)=>{133        resolve(res.data.data);134      }).catch((err)=>{135        onError(err);136        reject(err);137      });138    });139  };140 141  /* Callback for help button */142  const onHelp = (isSqlHelp=false, isNew=false)=>{143    if(isSqlHelp) {144      let server = treeNodeInfo.server;145      let helpUrl = pgAdmin.Browser.utils.pg_help_path;146      let fullUrl = '';147 148      if (server.server_type == 'ppas' && node.epasHelp) {149        fullUrl = getEPASHelpUrl(server.version, node.epasURL);150      } else if (node.sqlCreateHelp == '' && node.sqlAlterHelp != '') {151        fullUrl = getHelpUrl(helpUrl, node.sqlAlterHelp, server.version);152      } else if (node.sqlCreateHelp != '' && node.sqlAlterHelp == '') {153        fullUrl = getHelpUrl(helpUrl, node.sqlCreateHelp, server.version);154      } else if (isNew) {155        fullUrl = getHelpUrl(helpUrl, node.sqlCreateHelp, server.version);156      } else {157        fullUrl = getHelpUrl(helpUrl, node.sqlAlterHelp, server.version);158      }159 160      window.open(fullUrl, 'postgres_help');161    } else {162      window.open(node.dialogHelp, 'pgadmin_help');163    }164  };165 166  /* A warning before closing the dialog with unsaved changes, based on preference */167  const warnBeforeChangesLost = (id)=>{168    if(panelId != id) {169      warnBeforeChangesLost();170    }171    if (warnOnCloseFlag && confirmOnCloseReset) {172      if(isDirty.current) {173        pgAdmin.Browser.notifier.confirm(174          gettext('Warning'),175          gettext('Changes will be lost. Are you sure you want to close the dialog?'),176          function() {177            onClose(true);178          },179          null180        );181      } else {182        onClose(true);183      }184    } else {185      onClose(true);186    }187  };188 189  useEffect(()=>{190    if(formType == 'dialog') {191      /* Bind the close event and check if user should be warned */192      layoutDocker.eventBus.registerListener(LAYOUT_EVENTS.CLOSING, warnBeforeChangesLost);193    }194    return ()=>{195      layoutDocker.eventBus.deregisterListener(LAYOUT_EVENTS.CLOSING, warnBeforeChangesLost);196    };197  }, []);198 199  /* All other useful details can go with this object */200  const viewHelperProps = {201    mode: actionType,202    serverInfo: serverInfo ? {203      type: serverInfo.server_type,204      version: serverInfo.version,205    }: undefined,206    inCatalog: inCatalog,207  };208 209  // Show/Hide security group for nodes under the catalog210  if('catalog' in treeNodeInfo211    && formType !== 'tab') {212    schema.filterGroups = [gettext('Security')];213  }214  // Reset stale counter.215  useMemo(()=> {216    staleCounter.current = 0;217  }, [nodeData?._id]);218 219  const key = useMemo(()=>{220    // If node data is updated increase the counter to show updated data.221    if(isStale) {222      staleCounter.current += 1;223    }224    if( actionType != 'properties' || isActive) {225      // Not required any action.226    } else {227      initData = ()=>Promise.resolve({});228    }229 230    return nodeData?._id + '-' + staleCounter.current;231  }, [isActive, nodeData?._id, isStale]);232 233  /* Fire at will, mount the DOM */234  return (235    <SchemaView236      key={key}237      formType={formType}238      getInitData={initData}239      updatedData={updatedData}240      schema={schema}241      viewHelperProps={viewHelperProps}242      onSave={onSaveClick}243      onClose={()=>onClose()}244      onHelp={onHelp}245      onEdit={onEdit}246      onDataChange={(dataChanged)=>{247        isDirty.current = dataChanged;248      }}249      confirmOnCloseReset={confirmOnCloseReset}250      hasSQL={node.hasSQL && (actionType === 'create' || actionType === 'edit')}251      getSQLValue={getSQLValue}252      disableSqlHelp={node.sqlAlterHelp == '' && node.sqlCreateHelp == '' && !node.epasHelp}253      disableDialogHelp={node.dialogHelp == undefined || node.dialogHelp == ''}254    />255  );256}257 258ObjectNodeProperties.propTypes = {259  panelId: PropTypes.string,260  node: PropTypes.func,261  treeNodeInfo: PropTypes.object,262  nodeData: PropTypes.object,263  actionType: PropTypes.string,264  formType: PropTypes.string,265  onEdit: PropTypes.func,266  onSave: PropTypes.func,267  onClose: PropTypes.func,268  isActive: PropTypes.bool,269  setIsStale: PropTypes.func,270  isStale: PropTypes.bool,271};272 
codekingpro/portable-devtools · Team Ai