Files
pgadmin4/web/pgadmin/static/js/tree/preference_nodes.ts
Nikhil Mohite 2f37f0ca51 Fixes for the preferences dialog
1) Add server mode validation in the binary path.
  2) Updated preferences tree rendering to avoid using the ReactDOM render.
  3) Updated CSS for keyboard shortcuts checkbox border makes it consistent with input box border.
  4) Fixed jasmine test case and improved code coverage.
  5) Fixed SonarQube issues.
  6) Added validation to disable "Maximum column with" option if "Column sized by" option is set to "Column name" in Query Tool -> Result grid.
  7) Updated documentation with the latest screenshots.
  8) Correct typo in the documentation. Fixes #7261

refs #7149
2022-03-23 13:28:35 +05:30

250 lines
6.2 KiB
TypeScript

/////////////////////////////////////////////////////////////
//
// pgAdmin 4 - PostgreSQL Tools
//
// Copyright (C) 2013 - 2022, The pgAdmin Development Team
// This software is released under the PostgreSQL Licence
//
//////////////////////////////////////////////////////////////
import * as BrowserFS from 'browserfs'
import pgAdmin from 'sources/pgadmin';
import _ from 'underscore';
import { FileType } from 'react-aspen'
import { findInTree } from './tree';
export class ManagePreferenceTreeNodes {
constructor(data) {
this.tree = {}
this.tempTree = new TreeNode(undefined, {});
this.treeData = data || [];
}
public init = (_root: string) => new Promise((res, rej) => {
let node = { parent: null, children: [], data: null };
this.tree = {};
this.tree[_root] = { name: 'root', type: FileType.Directory, metadata: node };
res();
})
public updateNode = (_path, _data) => new Promise((res, rej) => {
const item = this.findNode(_path);
if (item) {
item.name = _data.label;
item.metadata.data = _data;
}
res(true);
})
public removeNode = async (_path, _removeOnlyChild) => {
const item = this.findNode(_path);
if (item && item.parentNode) {
item.children = [];
item.parentNode.children.splice(item.parentNode.children.indexOf(item), 1);
}
return true;
};
findNode(path) {
if (path === null || path === undefined || path.length === 0 || path == '/preferences') {
return this.tempTree;
}
return findInTree(this.tempTree, path);
}
public addNode = (_parent: string, _path: string, _data: []) => new Promise((res, rej) => {
_data.type = _data.inode ? FileType.Directory : FileType.File;
_data._label = _data.label;
_data.label = _.escape(_data.label);
_data.is_collection = isCollectionNode(_data._type);
let nodeData = { parent: _parent, children: _data?.children ? _data.children : [], data: _data };
let tmpParentNode = this.findNode(_parent);
let treeNode = new TreeNode(_data.id, _data, {}, tmpParentNode, nodeData, _data.type);
if (tmpParentNode !== null && tmpParentNode !== undefined) tmpParentNode.children.push(treeNode);
res(treeNode);
})
public readNode = (_path: string) => new Promise<string[]>((res, rej) => {
let temp_tree_path = _path,
node = this.findNode(_path);
node.children = [];
if (node && node.children.length > 0) {
if (!node.type === FileType.File) {
rej("It's a leaf node")
}
else {
if (node?.children.length != 0) res(node.children)
}
}
var self = this;
async function loadData() {
const Path = BrowserFS.BFSRequire('path')
const fill = async (tree) => {
for (let idx in tree) {
const _node = tree[idx]
const _pathl = Path.join(_path, _node.id)
await self.addNode(temp_tree_path, _pathl, _node);
}
}
if (node && !_.isUndefined(node.id)) {
let _data = self.treeData.find((el) => el.id == node.id);
let subNodes = [];
_data.childrenNodes.forEach(element => {
subNodes.push(element)
});
await fill(subNodes);
} else {
await fill(self.treeData);
}
self.returnChildrens(node, res)
}
loadData();
})
public returnChildrens = (node: any, res: any) =>{
if (node?.children.length > 0) return res(node.children);
else return res(null);
}
}
export class TreeNode {
constructor(id, data, domNode, parent, metadata, type) {
this.id = id;
this.data = data;
this.setParent(parent);
this.children = [];
this.domNode = domNode;
this.metadata = metadata;
this.name = metadata ? metadata.data.label : "";
this.type = type ? type : undefined;
}
hasParent() {
return this.parentNode !== null && this.parentNode !== undefined;
}
parent() {
return this.parentNode;
}
setParent(parent) {
this.parentNode = parent;
this.path = this.id;
if (this.id)
if (parent !== null && parent !== undefined && parent.path !== undefined) {
this.path = parent.path + '/' + this.id;
} else {
this.path = '/preferences/' + this.id;
}
}
getData() {
if (this.data === undefined) {
return undefined;
} else if (this.data === null) {
return null;
}
return Object.assign({}, this.data);
}
getHtmlIdentifier() {
return this.domNode;
}
/*
* Find the ancestor with matches this condition
*/
ancestorNode(condition) {
let node = this;
while (node.hasParent()) {
node = node.parent();
if (condition(node)) {
return node;
}
}
return null;
}
/**
* Given a condition returns true if the current node
* or any of the parent nodes condition result is true
*/
anyFamilyMember(condition) {
if (condition(this)) {
return true;
}
return this.ancestorNode(condition) !== null;
}
anyParent(condition) {
return this.ancestorNode(condition) !== null;
}
reload(tree) {
return new Promise((resolve) => {
this.unload(tree)
.then(() => {
tree.setInode(this.domNode);
tree.deselect(this.domNode);
setTimeout(() => {
tree.selectNode(this.domNode);
}, 0);
resolve();
});
});
}
unload(tree) {
return new Promise((resolve, reject) => {
this.children = [];
tree.unload(this.domNode)
.then(
() => {
resolve(true);
},
() => {
reject();
});
});
}
open(tree, suppressNoDom) {
return new Promise((resolve, reject) => {
if (suppressNoDom && (this.domNode == null || typeof (this.domNode) === 'undefined')) {
resolve(true);
} else if (tree.isOpen(this.domNode)) {
resolve(true);
} else {
tree.open(this.domNode).then(val => resolve(true), err => reject(true));
}
});
}
}
export function isCollectionNode(node) {
if (pgAdmin.Browser.Nodes && node in pgAdmin.Browser.Nodes) {
if (pgAdmin.Browser.Nodes[node].is_collection !== undefined) return pgAdmin.Browser.Nodes[node].is_collection;
else return false;
}
return false;
}