diff --git a/web/.eslintrc.js b/web/.eslintrc.js index 4cf410eb1..70c3bac9c 100644 --- a/web/.eslintrc.js +++ b/web/.eslintrc.js @@ -42,6 +42,20 @@ module.exports = { 'react', '@babel', ], + 'overrides': [ + { + 'files': ['**/*.ts', '**/*.tsx'], + 'plugins': [ + '@typescript-eslint', + ], + 'extends': ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'plugin:@typescript-eslint/eslint-recommended'], + 'parser': '@typescript-eslint/parser', + 'rules': { + '@typescript-eslint/no-explicit-any': ['off'], + '@typescript-eslint/no-this-alias': ['off'], + } + }, + ], 'globals': { '_': true, 'module': true, diff --git a/web/package.json b/web/package.json index e0e06ce3f..591c34e68 100644 --- a/web/package.json +++ b/web/package.json @@ -20,6 +20,8 @@ "@emotion/styled": "^10.0.14", "@emotion/utils": "^1.0.0", "@svgr/webpack": "^6.2.1", + "@typescript-eslint/eslint-plugin": "^5.55.0", + "@typescript-eslint/parser": "^5.55.0", "@wojtekmaj/enzyme-adapter-react-17": "^0.4.1", "autoprefixer": "^10.2.4", "axios-mock-adapter": "^1.17.0", @@ -172,7 +174,7 @@ "xterm-addon-web-links": "^0.4.0" }, "scripts": { - "linter": "yarn eslint --no-eslintrc -c .eslintrc.js --ext .js --ext .jsx .", + "linter": "yarn eslint --no-eslintrc -c .eslintrc.js --ext .js --ext .jsx --ext .ts --ext .tsx .", "webpacker": "yarn run webpack --config webpack.config.js --progress", "webpacker:watch": "yarn run webpack --config webpack.config.js --progress --watch", "bundle:watch": "yarn run linter && yarn run webpacker:watch", diff --git a/web/pgadmin/static/js/components/PgTree/FileTreeItem/index.tsx b/web/pgadmin/static/js/components/PgTree/FileTreeItem/index.tsx index 0a0dd675e..ec4d023e9 100644 --- a/web/pgadmin/static/js/components/PgTree/FileTreeItem/index.tsx +++ b/web/pgadmin/static/js/components/PgTree/FileTreeItem/index.tsx @@ -1,10 +1,10 @@ -import cn from 'classnames' -import * as React from 'react' -import { ClasslistComposite } from 'aspen-decorations' -import { Directory, FileEntry, IItemRendererProps, ItemType, PromptHandle, RenamePromptHandle, FileType, FileOrDir} from 'react-aspen' -import {IFileTreeXTriggerEvents, FileTreeXEvent } from '../types' -import _ from 'lodash' -import { Notificar } from 'notificar' +import cn from 'classnames'; +import * as React from 'react'; +import { ClasslistComposite } from 'aspen-decorations'; +import { Directory, FileEntry, IItemRendererProps, ItemType, RenamePromptHandle, FileType, FileOrDir} from 'react-aspen'; +import {IFileTreeXTriggerEvents, FileTreeXEvent } from '../types'; +import _ from 'lodash'; +import { Notificar } from 'notificar'; interface IItemRendererXProps { /** @@ -24,13 +24,13 @@ interface IItemRendererXProps { // DO NOT EXTEND FROM PureComponent!!! You might miss critical changes made deep within `item` prop // as far as efficiency is concerned, `react-aspen` works hard to ensure unnecessary updates are ignored export class FileTreeItem extends React.Component { - public static getBoundingClientRectForItem(item: FileEntry | Directory): ClientRect { - const divRef = FileTreeItem.itemIdToRefMap.get(item.id) - if (divRef) { - return divRef.getBoundingClientRect() - } - return null + public static getBoundingClientRectForItem(item: FileEntry | Directory): ClientRect { + const divRef = FileTreeItem.itemIdToRefMap.get(item.id); + if (divRef) { + return divRef.getBoundingClientRect(); } + return null; + } // ensure this syncs up with what goes in CSS, (em, px, % etc.) and what ultimately renders on the page public static readonly renderHeight: number = 24 @@ -39,142 +39,140 @@ export class FileTreeItem extends React.Component 0 && item._metadata.data._type.indexOf('coll-') !== -1 ? "(" + item.children.length + ")" : "" - const is_root = this.props.item.parent.path === '/browser' - const extraClasses = item._metadata.data.extraClasses ? item._metadata.data.extraClasses.join(' ') : '' + const itemChildren = item.children && item.children.length > 0 && item._metadata.data._type.indexOf('coll-') !== -1 ? '(' + item.children.length + ')' : ''; + const extraClasses = item._metadata.data.extraClasses ? item._metadata.data.extraClasses.join(' ') : ''; - return ( -
+ return ( +
- {!isNewPrompt && fileOrDir === 'directory' ? - - : null - } + {!isNewPrompt && fileOrDir === 'directory' ? + + : null + } - - { - item._metadata && item._metadata.data.icon ? - : null - } - - { _.unescape(this.props.item.getMetadata('data')._label)} - {itemChildren} - + + { + item._metadata && item._metadata.data.icon ? + : null + } + + { _.unescape(this.props.item.getMetadata('data')._label)} + {itemChildren} + - -
) + +
); } public componentDidMount() { - this.events = this.props.events - this.props.item.resolvedPathCache = this.props.item.parent.path + "/" + this.props.item._metadata.data.id - if (this.props.decorations) { - this.props.decorations.addChangeListener(this.forceUpdate) - } - this.setActiveFile(this.props.item) + this.events = this.props.events; + this.props.item.resolvedPathCache = this.props.item.parent.path + '/' + this.props.item._metadata.data.id; + if (this.props.decorations) { + this.props.decorations.addChangeListener(this.forceUpdate); + } + this.setActiveFile(this.props.item); } private setActiveFile = async (FileOrDir): Promise => { - this.props.changeDirectoryCount(FileOrDir.parent) - if(FileOrDir._loaded !== true) { - this.events.dispatch(FileTreeXEvent.onTreeEvents, window.event, 'added', FileOrDir) - } - FileOrDir._loaded = true + this.props.changeDirectoryCount(FileOrDir.parent); + if(FileOrDir._loaded !== true) { + this.events.dispatch(FileTreeXEvent.onTreeEvents, window.event, 'added', FileOrDir); + } + FileOrDir._loaded = true; } public componentWillUnmount() { - if (this.props.decorations) { - this.props.decorations.removeChangeListener(this.forceUpdate) - } + if (this.props.decorations) { + this.props.decorations.removeChangeListener(this.forceUpdate); + } } public componentDidUpdate(prevProps: IItemRendererXProps) { - if (prevProps.decorations) { - prevProps.decorations.removeChangeListener(this.forceUpdate) - } - if (this.props.decorations) { - this.props.decorations.addChangeListener(this.forceUpdate) - } + if (prevProps.decorations) { + prevProps.decorations.removeChangeListener(this.forceUpdate); + } + if (this.props.decorations) { + this.props.decorations.addChangeListener(this.forceUpdate); + } } private handleDivRef = (r: HTMLDivElement) => { - if (r === null) { - FileTreeItem.itemIdToRefMap.delete(this.props.item.id) - } else { - FileTreeItem.itemIdToRefMap.set(this.props.item.id, r) - FileTreeItem.refToItemIdMap.set(r, this.props.item) - } + if (r === null) { + FileTreeItem.itemIdToRefMap.delete(this.props.item.id); + } else { + FileTreeItem.itemIdToRefMap.set(this.props.item.id, r); + FileTreeItem.refToItemIdMap.set(r, this.props.item); + } } private handleContextMenu = (ev: React.MouseEvent) => { - const { item, itemType, onContextMenu } = this.props - if (itemType === ItemType.File || itemType === ItemType.Directory) { - onContextMenu(ev, item as FileOrDir) - } + const { item, itemType, onContextMenu } = this.props; + if (itemType === ItemType.File || itemType === ItemType.Directory) { + onContextMenu(ev, item as FileOrDir); + } } private handleClick = (ev: React.MouseEvent) => { - const { item, itemType, onClick } = this.props - if (itemType === ItemType.File || itemType === ItemType.Directory) { - onClick(ev, item as FileEntry, itemType) - } + const { item, itemType, onClick } = this.props; + if (itemType === ItemType.File || itemType === ItemType.Directory) { + onClick(ev, item as FileEntry, itemType); + } } private handleDoubleClick = (ev: React.MouseEvent) => { - const { item, itemType, onDoubleClick } = this.props - if (itemType === ItemType.File || itemType === ItemType.Directory) { - onDoubleClick(ev, item as FileEntry, itemType) - } + const { item, itemType, onDoubleClick } = this.props; + if (itemType === ItemType.File || itemType === ItemType.Directory) { + onDoubleClick(ev, item as FileEntry, itemType); + } } private handleDragStartItem = (e: React.DragEvent) => { - const { item, itemType, events } = this.props - if (itemType === ItemType.File || itemType === ItemType.Directory) { - const ref = FileTreeItem.itemIdToRefMap.get(item.id) - if (ref) { - events.dispatch(FileTreeXEvent.onTreeEvents, e, 'dragstart', item) - } + const { item, itemType, events } = this.props; + if (itemType === ItemType.File || itemType === ItemType.Directory) { + const ref = FileTreeItem.itemIdToRefMap.get(item.id); + if (ref) { + events.dispatch(FileTreeXEvent.onTreeEvents, e, 'dragstart', item); } + } } } diff --git a/web/pgadmin/static/js/components/PgTree/FileTreeX/index.tsx b/web/pgadmin/static/js/components/PgTree/FileTreeX/index.tsx index 3c8cb3c97..5ff5b0a55 100644 --- a/web/pgadmin/static/js/components/PgTree/FileTreeX/index.tsx +++ b/web/pgadmin/static/js/components/PgTree/FileTreeX/index.tsx @@ -1,22 +1,22 @@ -import * as React from 'react' +import * as React from 'react'; import { - FileTree, - Directory, - FileEntry, - ItemType, - IFileTreeHandle, - WatchEvent, - FileType, - IItemRendererProps, - FileOrDir -} from 'react-aspen' -import { Decoration, TargetMatchMode } from 'aspen-decorations' -import { FileTreeItem } from '../FileTreeItem' -import { Notificar, DisposablesComposite } from 'notificar' -import { IFileTreeXHandle, IFileTreeXProps, FileTreeXEvent, IFileTreeXTriggerEvents } from '../types' -import { KeyboardHotkeys } from '../services/keyboardHotkeys' -import { TreeModelX } from '../TreeModelX' -import AutoSizer from "react-virtualized-auto-sizer"; + FileTree, + Directory, + FileEntry, + ItemType, + IFileTreeHandle, + WatchEvent, + FileType, + IItemRendererProps, + FileOrDir +} from 'react-aspen'; +import { Decoration, TargetMatchMode } from 'aspen-decorations'; +import { FileTreeItem } from '../FileTreeItem'; +import { Notificar, DisposablesComposite } from 'notificar'; +import { IFileTreeXHandle, IFileTreeXProps, FileTreeXEvent, IFileTreeXTriggerEvents } from '../types'; +import { KeyboardHotkeys } from '../services/keyboardHotkeys'; +import { TreeModelX } from '../TreeModelX'; +import AutoSizer from 'react-virtualized-auto-sizer'; export class FileTreeX extends React.Component { private fileTreeHandle: IFileTreeXHandle @@ -30,585 +30,583 @@ export class FileTreeX extends React.Component { private keyboardHotkeys: KeyboardHotkeys private fileTreeEvent: IFileTreeXTriggerEvents constructor(props: IFileTreeXProps) { - super(props) - this.events = new Notificar() - this.disposables = new DisposablesComposite() - this.activeFileDec = new Decoration('active') - this.pseudoActiveFileDec = new Decoration('pseudo-active') + super(props); + this.events = new Notificar(); + this.disposables = new DisposablesComposite(); + this.activeFileDec = new Decoration('active'); + this.pseudoActiveFileDec = new Decoration('pseudo-active'); } render() { - const { height, width, model, disableCache } = this.props - const { decorations } = model + const { height, model, disableCache } = this.props; + const { decorations } = model; - return
- - {({ width, height }) => ( + return
+ + {({ width, height }) => ( - {(props: IItemRendererProps) => } + height={height} + width={width} + model={model} + itemHeight={FileTreeItem.renderHeight} + onReady={this.handleTreeReady} + disableCache={disableCache ? disableCache : false} + > + {(props: IItemRendererProps) => } - )} - -
+ )} +
+
; } public componentDidMount() { - for(let child of this.props.model.root.children) { - this.events.dispatch(FileTreeXEvent.onTreeEvents, window.event, 'loaded', child) - } - } - - componentWillUnmount() { - const { model } = this.props - model.decorations.removeDecoration(this.activeFileDec) - model.decorations.removeDecoration(this.pseudoActiveFileDec) - this.disposables.dispose() + for(const child of this.props.model.root.children) { + this.events.dispatch(FileTreeXEvent.onTreeEvents, window.event, 'loaded', child); + } } - private handleTreeEvent = (event: IFileTreeXTriggerEvents) => { - this.fileTreeEvent = this.props.onEvent + componentWillUnmount() { + const { model } = this.props; + model.decorations.removeDecoration(this.activeFileDec); + model.decorations.removeDecoration(this.pseudoActiveFileDec); + this.disposables.dispose(); + } + + private handleTreeEvent = () => { + this.fileTreeEvent = this.props.onEvent; } private handleTreeReady = (handle: IFileTreeHandle) => { - const { onReady, model } = this.props - const scrollDiv = this.wrapperRef.current?.querySelector('div')?.querySelector('div') - if(this.props.onScroll) { - scrollDiv?.addEventListener('scroll', (ev: any)=>this.props.onScroll?.(ev)); - } + const { onReady, model } = this.props; + const scrollDiv = this.wrapperRef.current?.querySelector('div')?.querySelector('div'); + if(this.props.onScroll) { + scrollDiv?.addEventListener('scroll', (ev: any)=>this.props.onScroll?.(ev)); + } - this.fileTreeHandle = { - ...handle, - getModel: () => this.props.model, - getActiveFile: () => this.activeFile, - setActiveFile: this.setActiveFile, - getPseudoActiveFile: () => this.pseudoActiveFile, - setPseudoActiveFile: this.setPseudoActiveFile, - toggleDirectory: this.toggleDirectory, - closeDir: this.closeDir, - remove: this.removeDir, - newFile: async (dirOrPath: Directory | string) => this.supervisePrompt(await handle.promptNewFile(dirOrPath as any)), - newFolder: async (dirOrPath: Directory | string) => this.supervisePrompt(await handle.promptNewDirectory(dirOrPath as any)), - onBlur: (callback) => this.events.add(FileTreeXEvent.OnBlur, callback), - hasDirectFocus: () => this.wrapperRef.current === document.activeElement, - first: this.first, - parent: this.parent, - hasParent: this.hasParent, - isOpen: this.isOpen, - isClosed: this.isClosed, - itemData: this.itemData, - children: this.children, - getItemFromDOM: this.getItemFromDOM, - getDOMFromItem: this.getDOMFromItem, - onTreeEvents: (callback) => this.events.add(FileTreeXEvent.onTreeEvents, callback), - addIcon: this.addIcon, - addCssClass: this.addCssClass, - create: this.create, - remove: this.remove, - update: this.update, - refresh: this.refresh, - setLabel: this.setLabel, - unload: this.unload, - deSelectActiveFile: this.deSelectActiveFile, - resize: this.resize, - showLoader: this.showLoader, - hideLoader: this.hideLoader, - } + this.fileTreeHandle = { + ...handle, + getModel: () => this.props.model, + getActiveFile: () => this.activeFile, + setActiveFile: this.setActiveFile, + getPseudoActiveFile: () => this.pseudoActiveFile, + setPseudoActiveFile: this.setPseudoActiveFile, + toggleDirectory: this.toggleDirectory, + closeDir: this.closeDir, + remove: this.removeDir, + newFile: async (dirOrPath: Directory | string) => this.supervisePrompt(await handle.promptNewFile(dirOrPath as string)), + newFolder: async (dirOrPath: Directory | string) => this.supervisePrompt(await handle.promptNewDirectory(dirOrPath as string)), + onBlur: (callback) => this.events.add(FileTreeXEvent.OnBlur, callback), + hasDirectFocus: () => this.wrapperRef.current === document.activeElement, + first: this.first, + parent: this.parent, + hasParent: this.hasParent, + isOpen: this.isOpen, + isClosed: this.isClosed, + itemData: this.itemData, + children: this.children, + getItemFromDOM: this.getItemFromDOM, + getDOMFromItem: this.getDOMFromItem, + onTreeEvents: (callback) => this.events.add(FileTreeXEvent.onTreeEvents, callback), + addIcon: this.addIcon, + addCssClass: this.addCssClass, + create: this.create, + remove: this.remove, + update: this.update, + refresh: this.refresh, + setLabel: this.setLabel, + unload: this.unload, + deSelectActiveFile: this.deSelectActiveFile, + resize: this.resize, + showLoader: this.showLoader, + hideLoader: this.hideLoader, + }; - model.decorations.addDecoration(this.activeFileDec) - model.decorations.addDecoration(this.pseudoActiveFileDec) + model.decorations.addDecoration(this.activeFileDec); + model.decorations.addDecoration(this.pseudoActiveFileDec); - this.disposables.add(this.fileTreeHandle.onDidChangeModel((prevModel: TreeModelX, newModel: TreeModelX) => { - this.setActiveFile(null) - this.setPseudoActiveFile(null) - prevModel.decorations.removeDecoration(this.activeFileDec) - prevModel.decorations.removeDecoration(this.pseudoActiveFileDec) - newModel.decorations.addDecoration(this.activeFileDec) - newModel.decorations.addDecoration(this.pseudoActiveFileDec) - })) + this.disposables.add(this.fileTreeHandle.onDidChangeModel((prevModel: TreeModelX, newModel: TreeModelX) => { + this.setActiveFile(null); + this.setPseudoActiveFile(null); + prevModel.decorations.removeDecoration(this.activeFileDec); + prevModel.decorations.removeDecoration(this.pseudoActiveFileDec); + newModel.decorations.addDecoration(this.activeFileDec); + newModel.decorations.addDecoration(this.pseudoActiveFileDec); + })); - this.disposables.add(this.fileTreeHandle.onBlur(() => { - this.setPseudoActiveFile(null) - })) + this.disposables.add(this.fileTreeHandle.onBlur(() => { + this.setPseudoActiveFile(null); + })); - this.keyboardHotkeys = new KeyboardHotkeys(this.fileTreeHandle) + this.keyboardHotkeys = new KeyboardHotkeys(this.fileTreeHandle); - if (typeof onReady === 'function') { - onReady(this.fileTreeHandle) - } + if (typeof onReady === 'function') { + onReady(this.fileTreeHandle); + } } private setActiveFile = async (fileOrDirOrPath: FileOrDir | string, ensureVisible, align): Promise => { - const fileH = typeof fileOrDirOrPath === 'string' - ? await this.fileTreeHandle.getFileHandle(fileOrDirOrPath) - : fileOrDirOrPath + const fileH = typeof fileOrDirOrPath === 'string' + ? await this.fileTreeHandle.getFileHandle(fileOrDirOrPath) + : fileOrDirOrPath; - if (fileH === this.props.model.root) { return } - if (this.activeFile !== fileH) { - if (this.activeFile) { - this.activeFileDec.removeTarget(this.activeFile) - } - if (fileH) { - this.activeFileDec.addTarget(fileH as any, TargetMatchMode.Self) - } - this.activeFile = fileH - this.events.dispatch(FileTreeXEvent.onTreeEvents, window.event, 'selected', fileH) - - if (fileH && ensureVisible === true) { - const alignTree = align !== undefined && align !== null ? align : 'auto' - await this.fileTreeHandle.ensureVisible(fileH, alignTree) - } + if (fileH === this.props.model.root) { return; } + if (this.activeFile !== fileH) { + if (this.activeFile) { + this.activeFileDec.removeTarget(this.activeFile); } + if (fileH) { + this.activeFileDec.addTarget(fileH as Directory, TargetMatchMode.Self); + } + this.activeFile = fileH; + this.events.dispatch(FileTreeXEvent.onTreeEvents, window.event, 'selected', fileH); + + if (fileH && ensureVisible === true) { + const alignTree = align !== undefined && align !== null ? align : 'auto'; + await this.fileTreeHandle.ensureVisible(fileH, alignTree); + } + } } private ensureVisible = async (fileOrDirOrPath: FileOrDir | string): Promise => { - const fileH = typeof fileOrDirOrPath === 'string' - ? await this.fileTreeHandle.getFileHandle(fileOrDirOrPath) - : fileOrDirOrPath + const fileH = typeof fileOrDirOrPath === 'string' + ? await this.fileTreeHandle.getFileHandle(fileOrDirOrPath) + : fileOrDirOrPath; - if (fileH) { - await this.fileTreeHandle.ensureVisible(fileH) - } + if (fileH) { + await this.fileTreeHandle.ensureVisible(fileH); + } } private deSelectActiveFile = async (fileOrDirOrPath: FileOrDir | string): Promise => { - const fileH = typeof fileOrDirOrPath === 'string' - ? await this.fileTreeHandle.getFileHandle(fileOrDirOrPath) - : fileOrDirOrPath + const fileH = typeof fileOrDirOrPath === 'string' + ? await this.fileTreeHandle.getFileHandle(fileOrDirOrPath) + : fileOrDirOrPath; - if (fileH === this.props.model.root) { return } - if (this.activeFile === fileH) { - this.activeFileDec.removeTarget(this.activeFile) - this.activeFile = null - } + if (fileH === this.props.model.root) { return; } + if (this.activeFile === fileH) { + this.activeFileDec.removeTarget(this.activeFile); + this.activeFile = null; + } } private setPseudoActiveFile = async (fileOrDirOrPath: FileOrDir | string): Promise => { - const fileH = typeof fileOrDirOrPath === 'string' - ? await this.fileTreeHandle.getFileHandle(fileOrDirOrPath) - : fileOrDirOrPath + const fileH = typeof fileOrDirOrPath === 'string' + ? await this.fileTreeHandle.getFileHandle(fileOrDirOrPath) + : fileOrDirOrPath; - if (fileH === this.props.model.root) { return } - if (this.pseudoActiveFile !== fileH) { - if (this.pseudoActiveFile) { - this.pseudoActiveFileDec.removeTarget(this.pseudoActiveFile) - } - if (fileH) { - this.pseudoActiveFileDec.addTarget(fileH as any, TargetMatchMode.Self) - } - this.pseudoActiveFile = fileH + if (fileH === this.props.model.root) { return; } + if (this.pseudoActiveFile !== fileH) { + if (this.pseudoActiveFile) { + this.pseudoActiveFileDec.removeTarget(this.pseudoActiveFile); } if (fileH) { - await this.fileTreeHandle.ensureVisible(fileH) + this.pseudoActiveFileDec.addTarget(fileH as Directory, TargetMatchMode.Self); } - this.events.dispatch(FileTreeXEvent.onTreeEvents, window.event, 'selected', fileH) + this.pseudoActiveFile = fileH; + } + if (fileH) { + await this.fileTreeHandle.ensureVisible(fileH); + } + this.events.dispatch(FileTreeXEvent.onTreeEvents, window.event, 'selected', fileH); } private create = async (parentDir, itemData): Promise => { - if (parentDir == undefined || parentDir == null) { - parentDir = this.props.model.root - } - const {create, model } = this.props - const isOpen = parentDir.isExpanded - let maybeFile = undefined + if (parentDir == undefined || parentDir == null) { + parentDir = this.props.model.root; + } + const {create, model } = this.props; + const isOpen = parentDir.isExpanded; + let maybeFile = undefined; - if (isOpen && (parentDir._children == null || parentDir._children.length == 0)) { - await this.fileTreeHandle.closeDirectory(parentDir as Directory) + if (isOpen && (parentDir._children == null || parentDir._children.length == 0)) { + await this.fileTreeHandle.closeDirectory(parentDir as Directory); + } + if (!parentDir.isExpanded && (parentDir._children == null || parentDir._children.length == 0)) { + await this.fileTreeHandle.openDirectory(parentDir as Directory); + } else { + await this.fileTreeHandle.openDirectory(parentDir as Directory); + maybeFile = await create(parentDir.path, itemData); + if (maybeFile && maybeFile.type && maybeFile.name) { + model.root.inotify({ + type: WatchEvent.Added, + directory: parentDir.path, + file: maybeFile, + }); } - if (!parentDir.isExpanded && (parentDir._children == null || parentDir._children.length == 0)) { - await this.fileTreeHandle.openDirectory(parentDir as Directory) - } else { - await this.fileTreeHandle.openDirectory(parentDir as Directory) - maybeFile = await create(parentDir.path, itemData) - if (maybeFile && maybeFile.type && maybeFile.name) { - model.root.inotify({ - type: WatchEvent.Added, - directory: parentDir.path, - file: maybeFile, - }) - } - } - this.changeDirectoryCount(parentDir) - let newItem = parentDir._children.find((c) => c._metadata.data.id === itemData.id) - newItem.resolvedPathCache = newItem.parent.path + "/" + newItem._metadata.data.id - return newItem + } + this.changeDirectoryCount(parentDir); + const newItem = parentDir._children.find((c) => c._metadata.data.id === itemData.id); + newItem.resolvedPathCache = newItem.parent.path + '/' + newItem._metadata.data.id; + return newItem; } private update = async (item, itemData): Promise => { - item._metadata.data = itemData - await this.props.update(item.path, itemData) - this.events.dispatch(FileTreeXEvent.onTreeEvents, window.event, 'updated', item) + item._metadata.data = itemData; + await this.props.update(item.path, itemData); + this.events.dispatch(FileTreeXEvent.onTreeEvents, window.event, 'updated', item); } private refresh = async (item): Promise => { - const {remove, model } = this.props - const isOpen = item.isExpanded - if (item.children && item.children.length > 0) { - for(let entry of item.children) { - await this.remove(entry).then(val => {}, error => {console.warn("Error removing item")}) - } + const isOpen = item.isExpanded; + if (item.children && item.children.length > 0) { + for(const entry of item.children) { + await this.remove(entry).then(() => {/*intentional*/}, () => {console.warn('Error removing item');}); } - if (isOpen) { - const ref = FileTreeItem.itemIdToRefMap.get(item.id); + } + if (isOpen) { + const ref = FileTreeItem.itemIdToRefMap.get(item.id); - if (ref) { - this.showLoader(ref) - } - - await this.fileTreeHandle.closeDirectory(item as Directory) - await this.fileTreeHandle.openDirectory(item as Directory) - await this.changeResolvePath(item as Directory) - this.changeDirectoryCount(item) - - if (ref) { - this.hideLoader(ref) - } + if (ref) { + this.showLoader(ref); } - } + + await this.fileTreeHandle.closeDirectory(item as Directory); + await this.fileTreeHandle.openDirectory(item as Directory); + await this.changeResolvePath(item as Directory); + this.changeDirectoryCount(item); + + if (ref) { + this.hideLoader(ref); + } + } + } private unload = async (item): Promise => { - const {remove, model } = this.props - const isOpen = item.isExpanded - if (item.children && item.children.length > 0) { - for(let entry of item.children) { - await this.remove(entry).then(val => {}, error => {console.warn(error)}) - } - } - if (isOpen) { - await this.fileTreeHandle.closeDirectory(item as Directory) - this.changeDirectoryCount(item) - } + const isOpen = item.isExpanded; + if (item.children && item.children.length > 0) { + for(const entry of item.children) { + await this.remove(entry).then(() => {/*intentional*/}, error => {console.warn(error);}); + } + } + if (isOpen) { + await this.fileTreeHandle.closeDirectory(item as Directory); + this.changeDirectoryCount(item); + } } private remove = async (item): Promise => { - const {remove, model } = this.props - const path = item.path - await remove(path, false) - const dirName = model.root.pathfx.dirname(path); - const fileName = model.root.pathfx.basename(path); - const parent = item.parent - if (dirName === parent.path) { - const item_1 = parent._children.find((c) => c._metadata && c._metadata.data.id === fileName); - if (item_1) { - parent.unlinkItem(item_1); - if (parent._children.length == 0) { parent._children = null } - this.changeDirectoryCount(parent) - this.events.dispatch(FileTreeXEvent.onTreeEvents, window.event, 'removed', item) - } - else { - console.warn("Item not found") - } + const {remove, model } = this.props; + const path = item.path; + await remove(path, false); + const dirName = model.root.pathfx.dirname(path); + const fileName = model.root.pathfx.basename(path); + const parent = item.parent; + if (dirName === parent.path) { + const item_1 = parent._children.find((c) => c._metadata && c._metadata.data.id === fileName); + if (item_1) { + parent.unlinkItem(item_1); + if (parent._children.length == 0) { parent._children = null; } + this.changeDirectoryCount(parent); + this.events.dispatch(FileTreeXEvent.onTreeEvents, window.event, 'removed', item); } + else { + console.warn('Item not found'); + } + } } private first = async (fileOrDirOrPath: FileOrDir | string) => { - const fileH = typeof fileOrDirOrPath === 'string' - ? await this.fileTreeHandle.getFileHandle(fileOrDirOrPath) - : fileOrDirOrPath + const fileH = typeof fileOrDirOrPath === 'string' + ? await this.fileTreeHandle.getFileHandle(fileOrDirOrPath) + : fileOrDirOrPath; - if (fileH === undefined || fileH === null) { return this.props.model.root.children[0] } + if (fileH === undefined || fileH === null) { return this.props.model.root.children[0]; } - if (fileH.branchSize > 0) { - return fileH.children[0] - } - return null + if (fileH.branchSize > 0) { + return fileH.children[0]; + } + return null; } private parent = async (fileOrDirOrPath: FileOrDir | string) => { - const fileH = typeof fileOrDirOrPath === 'string' - ? await this.fileTreeHandle.getFileHandle(fileOrDirOrPath) - : fileOrDirOrPath + const fileH = typeof fileOrDirOrPath === 'string' + ? await this.fileTreeHandle.getFileHandle(fileOrDirOrPath) + : fileOrDirOrPath; - if (fileH === FileType.Directory || fileH === FileType.File) { - return fileH.parent - } + if (fileH === FileType.Directory || fileH === FileType.File) { + return fileH.parent; + } - return null + return null; } private hasParent = async (fileOrDirOrPath: FileOrDir | string) => { - const fileH = typeof fileOrDirOrPath === 'string' - ? await this.fileTreeHandle.getFileHandle(fileOrDirOrPath) - : fileOrDirOrPath + const fileH = typeof fileOrDirOrPath === 'string' + ? await this.fileTreeHandle.getFileHandle(fileOrDirOrPath) + : fileOrDirOrPath; - if (fileH === FileType.Directory || fileH === FileType.File) { - return fileH.parent ? true : false - } + if (fileH === FileType.Directory || fileH === FileType.File) { + return fileH.parent ? true : false; + } - return false + return false; } private children = async (fileOrDirOrPath: FileOrDir | string) => { - const fileH = typeof fileOrDirOrPath === 'string' - ? await this.fileTreeHandle.getFileHandle(fileOrDirOrPath) - : fileOrDirOrPath + const fileH = typeof fileOrDirOrPath === 'string' + ? await this.fileTreeHandle.getFileHandle(fileOrDirOrPath) + : fileOrDirOrPath; - if (fileH === FileType.Directory) { - return fileH.children - } + if (fileH === FileType.Directory) { + return fileH.children; + } - return null + return null; } private isOpen = async (fileOrDirOrPath: FileOrDir | string) => { - const fileH = typeof fileOrDirOrPath === 'string' - ? await this.fileTreeHandle.getFileHandle(fileOrDirOrPath) - : fileOrDirOrPath + const fileH = typeof fileOrDirOrPath === 'string' + ? await this.fileTreeHandle.getFileHandle(fileOrDirOrPath) + : fileOrDirOrPath; - if (fileH === FileType.Directory) { - return fileH.isExpanded - } + if (fileH === FileType.Directory) { + return fileH.isExpanded; + } - return false + return false; } private isClosed = async (fileOrDirOrPath: FileOrDir | string) => { - const fileH = typeof fileOrDirOrPath === 'string' - ? await this.fileTreeHandle.getFileHandle(fileOrDirOrPath) - : fileOrDirOrPath + const fileH = typeof fileOrDirOrPath === 'string' + ? await this.fileTreeHandle.getFileHandle(fileOrDirOrPath) + : fileOrDirOrPath; - if (fileH === FileType.Directory || fileH === FileType.File) { - return !fileH.isExpanded - } + if (fileH === FileType.Directory || fileH === FileType.File) { + return !fileH.isExpanded; + } - return false - } + return false; + } private itemData = async (fileOrDirOrPath: FileOrDir | string) => { - const fileH = typeof fileOrDirOrPath === 'string' - ? await this.fileTreeHandle.getFileHandle(fileOrDirOrPath) - : fileOrDirOrPath + const fileH = typeof fileOrDirOrPath === 'string' + ? await this.fileTreeHandle.getFileHandle(fileOrDirOrPath) + : fileOrDirOrPath; - if (fileH === FileType.Directory || fileH === FileType.File) { - return fileH._metadata.data - } + if (fileH === FileType.Directory || fileH === FileType.File) { + return fileH._metadata.data; + } - return null + return null; } private setLabel = async(pathOrDir: string | Directory, label: string): Promise => { - const dir = typeof pathOrDir === 'string' - ? await this.fileTreeHandle.getFileHandle(pathOrDir) - : pathOrDir + const dir = typeof pathOrDir === 'string' + ? await this.fileTreeHandle.getFileHandle(pathOrDir) + : pathOrDir; - const ref = FileTreeItem.itemIdToRefMap.get(dir.id); - if (ref) { - ref.style.background = 'none' - const label$ = ref.querySelector('span.file-name') as HTMLDivElement - - if (label$) { - if (typeof(label) == "object" && label.label) { - label = label.label - } - label$.innerHTML = label; - } + const ref = FileTreeItem.itemIdToRefMap.get(dir.id); + if (ref) { + ref.style.background = 'none'; + const label$ = ref.querySelector('span.file-name') as HTMLDivElement; + if (label$) { + if (typeof(label) == 'object' && label.label) { + label = label.label; + } + label$.innerHTML = label; } - } + } + + } private changeDirectoryCount = async(pathOrDir: string | Directory): Promise => { - const dir = typeof pathOrDir === 'string' - ? await this.fileTreeHandle.getFileHandle(pathOrDir) - : pathOrDir + const dir = typeof pathOrDir === 'string' + ? await this.fileTreeHandle.getFileHandle(pathOrDir) + : pathOrDir; - if (dir.type === FileType.Directory && dir._metadata.data && dir._metadata.data.is_collection === true) { - const ref = FileTreeItem.itemIdToRefMap.get(dir.id); - if (ref) { - ref.style.background = 'none' - const label$ = ref.querySelector('span.children-count') as HTMLDivElement - if(dir.children && dir.children.length > 0) { - label$.innerHTML = "(" + dir.children.length + ")"; - } else { - label$.innerHTML = ""; - } - } + if (dir.type === FileType.Directory && dir._metadata.data && dir._metadata.data.is_collection === true) { + const ref = FileTreeItem.itemIdToRefMap.get(dir.id); + if (ref) { + ref.style.background = 'none'; + const label$ = ref.querySelector('span.children-count') as HTMLDivElement; + if(dir.children && dir.children.length > 0) { + label$.innerHTML = '(' + dir.children.length + ')'; + } else { + label$.innerHTML = ''; + } } + } - } + } private closeDir = async (pathOrDir: string | Directory) => { - const dir = typeof pathOrDir === 'string' - ? await this.fileTreeHandle.getFileHandle(pathOrDir) - : pathOrDir + const dir = typeof pathOrDir === 'string' + ? await this.fileTreeHandle.getFileHandle(pathOrDir) + : pathOrDir; - if (dir.type === FileType.Directory) { - if ((dir as Directory).expanded) { - this.fileTreeHandle.closeDirectory(dir as Directory) - this.events.dispatch(FileTreeXEvent.onTreeEvents, window.event, 'closed', dir) + if (dir.type === FileType.Directory) { + if ((dir as Directory).expanded) { + this.fileTreeHandle.closeDirectory(dir as Directory); + this.events.dispatch(FileTreeXEvent.onTreeEvents, window.event, 'closed', dir); - } } + } } private toggleDirectory = async (pathOrDir: string | Directory) => { - const dir = typeof pathOrDir === 'string' - ? await this.fileTreeHandle.getFileHandle(pathOrDir) - : pathOrDir + const dir = typeof pathOrDir === 'string' + ? await this.fileTreeHandle.getFileHandle(pathOrDir) + : pathOrDir; - if (dir.type === FileType.Directory) { - if ((dir as Directory).expanded) { - this.fileTreeHandle.closeDirectory(dir as Directory) - this.events.dispatch(FileTreeXEvent.onTreeEvents, window.event, 'closed', dir) + if (dir.type === FileType.Directory) { + if ((dir as Directory).expanded) { + this.fileTreeHandle.closeDirectory(dir as Directory); + this.events.dispatch(FileTreeXEvent.onTreeEvents, window.event, 'closed', dir); - } else { - const ref = FileTreeItem.itemIdToRefMap.get(dir.id); - if (ref) { - this.showLoader(ref) - } + } else { + const ref = FileTreeItem.itemIdToRefMap.get(dir.id); + if (ref) { + this.showLoader(ref); + } - await this.events.dispatch(FileTreeXEvent.onTreeEvents, window.event, 'beforeopen', dir) - await this.fileTreeHandle.openDirectory(dir as Directory) - await this.changeResolvePath(dir as Directory) + await this.events.dispatch(FileTreeXEvent.onTreeEvents, window.event, 'beforeopen', dir); + await this.fileTreeHandle.openDirectory(dir as Directory); + await this.changeResolvePath(dir as Directory); - if (ref) { - this.hideLoader(ref) - } + if (ref) { + this.hideLoader(ref); + } - this.events.dispatch(FileTreeXEvent.onTreeEvents, window.event, 'opened', dir) - } + this.events.dispatch(FileTreeXEvent.onTreeEvents, window.event, 'opened', dir); } + } } private addIcon = async (pathOrDir: string | Directory, icon) => { - const dir = typeof pathOrDir === 'string' - ? await this.fileTreeHandle.getFileHandle(pathOrDir) - : pathOrDir + const dir = typeof pathOrDir === 'string' + ? await this.fileTreeHandle.getFileHandle(pathOrDir) + : pathOrDir; - const ref = FileTreeItem.itemIdToRefMap.get(dir.id); - if (ref) { - const label$ = ref.querySelector('.file-label i') as HTMLDivElement - label$.className = icon.icon; - } + const ref = FileTreeItem.itemIdToRefMap.get(dir.id); + if (ref) { + const label$ = ref.querySelector('.file-label i') as HTMLDivElement; + label$.className = icon.icon; + } } private addCssClass = async (pathOrDir: string | Directory, cssClass) => { - const dir = typeof pathOrDir === 'string' - ? await this.fileTreeHandle.getFileHandle(pathOrDir) - : pathOrDir + const dir = typeof pathOrDir === 'string' + ? await this.fileTreeHandle.getFileHandle(pathOrDir) + : pathOrDir; - const ref = FileTreeItem.itemIdToRefMap.get(dir.id); - if (ref) { - ref.classList.add(cssClass) - if (!dir._metadata.data.extraClasses) - dir._metadata.data.extraClasses = [] + const ref = FileTreeItem.itemIdToRefMap.get(dir.id); + if (ref) { + ref.classList.add(cssClass); + if (!dir._metadata.data.extraClasses) + dir._metadata.data.extraClasses = []; - dir._metadata.data.extraClasses.push(cssClass) - } + dir._metadata.data.extraClasses.push(cssClass); + } } private showLoader = (ref: HTMLDivElement) => { - // get label ref and add loading class - ref.style.background = 'none' - const label$ = ref.querySelector('i.directory-toggle') as HTMLDivElement - if (label$) label$.classList.add("loading") + // get label ref and add loading class + ref.style.background = 'none'; + const label$ = ref.querySelector('i.directory-toggle') as HTMLDivElement; + if (label$) label$.classList.add('loading'); } private hideLoader = (ref: HTMLDivElement) => { - // remove loading class. - ref.style.background = 'none' - const label$ = ref.querySelector('i.directory-toggle') as HTMLDivElement - if (label$) label$.classList.remove("loading") + // remove loading class. + ref.style.background = 'none'; + const label$ = ref.querySelector('i.directory-toggle') as HTMLDivElement; + if (label$) label$.classList.remove('loading'); } private handleBlur = () => { - this.events.dispatch(FileTreeXEvent.OnBlur) + this.events.dispatch(FileTreeXEvent.OnBlur); } private handleItemClicked = async (ev: React.MouseEvent, item: FileOrDir, type: ItemType) => { - if (type === ItemType.Directory && ev.target.className.includes("directory-toggle")) { - await this.toggleDirectory(item as Directory) - } - await this.setActiveFile(item as FileEntry) + if (type === ItemType.Directory && ev.target.className.includes('directory-toggle')) { + await this.toggleDirectory(item as Directory); + } + await this.setActiveFile(item as FileEntry); } - private handleItemDoubleClicked = async (ev: React.MouseEvent, item: FileOrDir, type: ItemType) => { - await this.toggleDirectory(item as Directory) - await this.setActiveFile(item as FileEntry) + private handleItemDoubleClicked = async (ev: React.MouseEvent, item: FileOrDir) => { + await this.toggleDirectory(item as Directory); + await this.setActiveFile(item as FileEntry); } private getItemFromDOM = (clientReact) => { - return FileTreeItem.refToItemIdMap.get(clientReact); + return FileTreeItem.refToItemIdMap.get(clientReact); } private getDOMFromItem = (item: FileOrDir) => { - return FileTreeItem.itemIdToRefMap.get(item.id); + return FileTreeItem.itemIdToRefMap.get(item.id); } private handleClick = (ev: React.MouseEvent) => { - // clicked in "blank space" - if (ev.currentTarget === ev.target) { - this.setPseudoActiveFile(null) - } + // clicked in "blank space" + if (ev.currentTarget === ev.target) { + this.setPseudoActiveFile(null); + } } private handleItemCtxMenu = (ev: React.MouseEvent, item: FileOrDir) => { - return this.props.onContextMenu?.(ev, item); + return this.props.onContextMenu?.(ev, item); } private handleKeyDown = (ev: React.KeyboardEvent) => { - return this.keyboardHotkeys.handleKeyDown(ev) + return this.keyboardHotkeys.handleKeyDown(ev); } - private onResize = (...args) => { - if (this.wrapperRef.current != null) { - this.resize() - } + private onResize = () => { + if (this.wrapperRef.current != null) { + this.resize(); + } } private resize = (scrollX, scrollY) => { - const scrollXPos = scrollX ? scrollX : 0 - const scrollYPos = scrollY ? scrollY : this.props.model.state.scrollOffset - const div = this.wrapperRef.current.querySelector('div').querySelector('div') as HTMLDivElement - div.scroll(scrollXPos, scrollYPos) + const scrollXPos = scrollX ? scrollX : 0; + const scrollYPos = scrollY ? scrollY : this.props.model.state.scrollOffset; + const div = this.wrapperRef.current.querySelector('div').querySelector('div') as HTMLDivElement; + div.scroll(scrollXPos, scrollYPos); } private changeResolvePath = async (item: FileOrDir): Promise => { - // Change the path as per pgAdmin requirement: Item Id wise - if (item.type === FileType.File) { - item.resolvedPathCache = item.parent.path + "/" + item._metadata.data.id - } - if (item.type === FileType.Directory && item.children && item.children.length > 0) { - for(let entry of item.children) { - entry.resolvedPathCache = entry.parent.path + "/" + entry._metadata.data.id - } + // Change the path as per pgAdmin requirement: Item Id wise + if (item.type === FileType.File) { + item.resolvedPathCache = item.parent.path + '/' + item._metadata.data.id; + } + if (item.type === FileType.Directory && item.children && item.children.length > 0) { + for(const entry of item.children) { + entry.resolvedPathCache = entry.parent.path + '/' + entry._metadata.data.id; } + } } } -export { IFileTreeXHandle, IFileTreeXProps } +export { IFileTreeXHandle, IFileTreeXProps }; diff --git a/web/pgadmin/static/js/components/PgTree/TreeModelX/index.ts b/web/pgadmin/static/js/components/PgTree/TreeModelX/index.ts index 8c3d2a0f9..5786dc344 100644 --- a/web/pgadmin/static/js/components/PgTree/TreeModelX/index.ts +++ b/web/pgadmin/static/js/components/PgTree/TreeModelX/index.ts @@ -1,10 +1,10 @@ -import { TreeModel, IBasicFileSystemHost } from 'react-aspen' -import { DecorationsManager } from 'aspen-decorations' +import { TreeModel, IBasicFileSystemHost, Root } from 'react-aspen'; +import { DecorationsManager } from 'aspen-decorations'; export class TreeModelX extends TreeModel { public readonly decorations: DecorationsManager constructor(host: IBasicFileSystemHost, mountPath: string) { - super(host, mountPath) - this.decorations = new DecorationsManager(this.root as any) + super(host, mountPath); + this.decorations = new DecorationsManager(this.root as Root); } } diff --git a/web/pgadmin/static/js/components/PgTree/index.ts b/web/pgadmin/static/js/components/PgTree/index.ts index bde582afd..66d0d524e 100644 --- a/web/pgadmin/static/js/components/PgTree/index.ts +++ b/web/pgadmin/static/js/components/PgTree/index.ts @@ -1,3 +1,3 @@ -export { FileTreeX } from './FileTreeX' -export { TreeModelX } from './TreeModelX' -export { IFileTreeXHandle, IFileTreeXProps, FileTreeXEvent, IFileTreeXTriggerEvents } from './types' +export { FileTreeX } from './FileTreeX'; +export { TreeModelX } from './TreeModelX'; +export { IFileTreeXHandle, IFileTreeXProps, FileTreeXEvent, IFileTreeXTriggerEvents } from './types'; diff --git a/web/pgadmin/static/js/components/PgTree/services/keyboardHotkeys.ts b/web/pgadmin/static/js/components/PgTree/services/keyboardHotkeys.ts index 9c7b09db8..c20675171 100644 --- a/web/pgadmin/static/js/components/PgTree/services/keyboardHotkeys.ts +++ b/web/pgadmin/static/js/components/PgTree/services/keyboardHotkeys.ts @@ -1,129 +1,129 @@ -import { FileEntry, Directory, FileType } from 'react-aspen' -import { IFileTreeXHandle } from '../types' +import { FileEntry, Directory, FileType } from 'react-aspen'; +import { IFileTreeXHandle } from '../types'; export class KeyboardHotkeys { private hotkeyActions = { - 'ArrowUp': () => this.jumpToPrevItem(), - 'ArrowDown': () => this.jumpToNextItem(), - 'ArrowRight': () => this.expandOrJumpToFirstChild(), - 'ArrowLeft': () => this.collapseOrJumpToFirstParent(), - 'Space': () => this.toggleDirectoryExpand(), - 'Enter': () => this.selectFileOrToggleDirState(), - 'Home': () => this.jumpToFirstItem(), - 'End': () => this.jumpToLastItem(), - 'Escape': () => this.resetSteppedOrSelectedItem(), + 'ArrowUp': () => this.jumpToPrevItem(), + 'ArrowDown': () => this.jumpToNextItem(), + 'ArrowRight': () => this.expandOrJumpToFirstChild(), + 'ArrowLeft': () => this.collapseOrJumpToFirstParent(), + 'Space': () => this.toggleDirectoryExpand(), + 'Enter': () => this.selectFileOrToggleDirState(), + 'Home': () => this.jumpToFirstItem(), + 'End': () => this.jumpToLastItem(), + 'Escape': () => this.resetSteppedOrSelectedItem(), } constructor(private readonly fileTreeX: IFileTreeXHandle) { } public handleKeyDown = (ev: React.KeyboardEvent) => { - if (!this.fileTreeX.hasDirectFocus()) { - return false - } - const { code } = ev.nativeEvent - if (code in this.hotkeyActions) { - ev.preventDefault() - this.hotkeyActions[code]() - return true - } + if (!this.fileTreeX.hasDirectFocus()) { + return false; + } + const { code } = ev.nativeEvent; + if (code in this.hotkeyActions) { + ev.preventDefault(); + this.hotkeyActions[code](); + return true; + } } private jumpToFirstItem = (): void => { - const { root } = this.fileTreeX.getModel() - this.fileTreeX.setActiveFile(root.getFileEntryAtIndex(0), true) + const { root } = this.fileTreeX.getModel(); + this.fileTreeX.setActiveFile(root.getFileEntryAtIndex(0), true); } private jumpToLastItem = (): void => { - const { root } = this.fileTreeX.getModel() - this.fileTreeX.setActiveFile(root.getFileEntryAtIndex(root.branchSize - 1), true) + const { root } = this.fileTreeX.getModel(); + this.fileTreeX.setActiveFile(root.getFileEntryAtIndex(root.branchSize - 1), true); } private jumpToNextItem = (): void => { - const { root } = this.fileTreeX.getModel() - let currentPseudoActive = this.fileTreeX.getActiveFile() - if (!currentPseudoActive) { - const selectedFile = this.fileTreeX.getActiveFile() - if (selectedFile) { - currentPseudoActive = selectedFile - } else { - return this.jumpToFirstItem() - } - } - const idx = root.getIndexAtFileEntry(currentPseudoActive) - if (idx + 1 > root.branchSize) { - return this.jumpToFirstItem() - } else if (idx > -1) { - this.fileTreeX.setActiveFile(root.getFileEntryAtIndex(idx + 1), true) + const { root } = this.fileTreeX.getModel(); + let currentPseudoActive = this.fileTreeX.getActiveFile(); + if (!currentPseudoActive) { + const selectedFile = this.fileTreeX.getActiveFile(); + if (selectedFile) { + currentPseudoActive = selectedFile; + } else { + return this.jumpToFirstItem(); } + } + const idx = root.getIndexAtFileEntry(currentPseudoActive); + if (idx + 1 > root.branchSize) { + return this.jumpToFirstItem(); + } else if (idx > -1) { + this.fileTreeX.setActiveFile(root.getFileEntryAtIndex(idx + 1), true); + } } private jumpToPrevItem = (): void => { - const { root } = this.fileTreeX.getModel() - let currentPseudoActive = this.fileTreeX.getActiveFile() - if (!currentPseudoActive) { - const selectedFile = this.fileTreeX.getActiveFile() - if (selectedFile) { - currentPseudoActive = selectedFile - } else { - return this.jumpToLastItem() - } - } - const idx = root.getIndexAtFileEntry(currentPseudoActive) - if (idx - 1 < 0) { - return this.jumpToLastItem() - } else if (idx > -1) { - this.fileTreeX.setActiveFile(root.getFileEntryAtIndex(idx - 1), true) + const { root } = this.fileTreeX.getModel(); + let currentPseudoActive = this.fileTreeX.getActiveFile(); + if (!currentPseudoActive) { + const selectedFile = this.fileTreeX.getActiveFile(); + if (selectedFile) { + currentPseudoActive = selectedFile; + } else { + return this.jumpToLastItem(); } + } + const idx = root.getIndexAtFileEntry(currentPseudoActive); + if (idx - 1 < 0) { + return this.jumpToLastItem(); + } else if (idx > -1) { + this.fileTreeX.setActiveFile(root.getFileEntryAtIndex(idx - 1), true); + } } private expandOrJumpToFirstChild(): void { - const currentPseudoActive = this.fileTreeX.getActiveFile() - if (currentPseudoActive && currentPseudoActive.type === FileType.Directory) { - if ((currentPseudoActive as Directory).expanded) { - return this.jumpToNextItem() - } else { - this.fileTreeX.openDirectory(currentPseudoActive as Directory) - } + const currentPseudoActive = this.fileTreeX.getActiveFile(); + if (currentPseudoActive && currentPseudoActive.type === FileType.Directory) { + if ((currentPseudoActive as Directory).expanded) { + return this.jumpToNextItem(); + } else { + this.fileTreeX.openDirectory(currentPseudoActive as Directory); } + } } private collapseOrJumpToFirstParent(): void { - const currentPseudoActive = this.fileTreeX.getActiveFile() - if (currentPseudoActive) { - if (currentPseudoActive.type === FileType.Directory && (currentPseudoActive as Directory).expanded) { - return this.fileTreeX.closeDirectory(currentPseudoActive as Directory) - } - this.fileTreeX.setActiveFile(currentPseudoActive.parent, true) + const currentPseudoActive = this.fileTreeX.getActiveFile(); + if (currentPseudoActive) { + if (currentPseudoActive.type === FileType.Directory && (currentPseudoActive as Directory).expanded) { + return this.fileTreeX.closeDirectory(currentPseudoActive as Directory); } + this.fileTreeX.setActiveFile(currentPseudoActive.parent, true); + } } private selectFileOrToggleDirState = (): void => { - const currentPseudoActive = this.fileTreeX.getActiveFile() - if (!currentPseudoActive) { return } - if (currentPseudoActive.type === FileType.Directory) { - this.fileTreeX.toggleDirectory(currentPseudoActive as Directory) - } else if (currentPseudoActive.type === FileType.File) { - this.fileTreeX.setActiveFile(currentPseudoActive as FileEntry, true) - } + const currentPseudoActive = this.fileTreeX.getActiveFile(); + if (!currentPseudoActive) { return; } + if (currentPseudoActive.type === FileType.Directory) { + this.fileTreeX.toggleDirectory(currentPseudoActive as Directory); + } else if (currentPseudoActive.type === FileType.File) { + this.fileTreeX.setActiveFile(currentPseudoActive as FileEntry, true); + } } private toggleDirectoryExpand = (): void => { - const currentPseudoActive = this.fileTreeX.getActiveFile() - if (!currentPseudoActive) { return } - if (currentPseudoActive.type === FileType.Directory) { - this.fileTreeX.toggleDirectory(currentPseudoActive as Directory) - } + const currentPseudoActive = this.fileTreeX.getActiveFile(); + if (!currentPseudoActive) { return; } + if (currentPseudoActive.type === FileType.Directory) { + this.fileTreeX.toggleDirectory(currentPseudoActive as Directory); + } } private resetSteppedOrSelectedItem = (): void => { - const currentPseudoActive = this.fileTreeX.getActiveFile() - if (currentPseudoActive) { - return this.resetSteppedItem() - } - this.fileTreeX.setActiveFile(null) + const currentPseudoActive = this.fileTreeX.getActiveFile(); + if (currentPseudoActive) { + return this.resetSteppedItem(); + } + this.fileTreeX.setActiveFile(null); } private resetSteppedItem = () => { - this.fileTreeX.setActiveFile(null) + this.fileTreeX.setActiveFile(null); } } diff --git a/web/pgadmin/static/js/components/PgTree/types.ts b/web/pgadmin/static/js/components/PgTree/types.ts index f5ced73ae..e89344116 100644 --- a/web/pgadmin/static/js/components/PgTree/types.ts +++ b/web/pgadmin/static/js/components/PgTree/types.ts @@ -1,8 +1,7 @@ -import { IFileTreeHandle, FileEntry, Directory, TreeModel, FileType, IFileEntryItem, IItemRenderer, FileOrDir } from 'react-aspen' -import { IDisposable } from 'notificar' -import { TreeModelX } from './TreeModelX' -import React, { MouseEventHandler } from 'react' -import { MenuItem } from '../../helpers/Menu' +import { IFileTreeHandle, FileEntry, Directory, FileType, IFileEntryItem, IItemRenderer, FileOrDir } from 'react-aspen'; +import { IDisposable } from 'notificar'; +import { TreeModelX } from './TreeModelX'; +import React from 'react'; export interface IFileTreeXTriggerEvents { diff --git a/web/pgadmin/static/js/tree/preference_nodes.ts b/web/pgadmin/static/js/tree/preference_nodes.ts index c9da6e745..6c611fdea 100644 --- a/web/pgadmin/static/js/tree/preference_nodes.ts +++ b/web/pgadmin/static/js/tree/preference_nodes.ts @@ -7,27 +7,27 @@ // ////////////////////////////////////////////////////////////// -import * as BrowserFS from 'browserfs' +import * as BrowserFS from 'browserfs'; import pgAdmin from 'sources/pgadmin'; import _ from 'lodash'; -import { FileType } from 'react-aspen' +import { FileType } from 'react-aspen'; import { findInTree } from './tree'; export class ManagePreferenceTreeNodes { constructor(data) { - this.tree = {} + 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 }; + public init = (_root: string) => new Promise((res) => { + const 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) => { + public updateNode = (_path, _data) => new Promise((res) => { const item = this.findNode(_path); if (item) { item.name = _data.label; @@ -36,7 +36,7 @@ export class ManagePreferenceTreeNodes { res(true); }) - public removeNode = async (_path, _removeOnlyChild) => { + public removeNode = async (_path) => { const item = this.findNode(_path); if (item && item.parentNode) { @@ -54,16 +54,16 @@ export class ManagePreferenceTreeNodes { return findInTree(this.tempTree, path); } - public addNode = (_parent: string, _path: string, _data: []) => new Promise((res, rej) => { + public addNode = (_parent: string, _path: string, _data: []) => new Promise((res) => { _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 }; + const 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); + const tmpParentNode = this.findNode(_parent); + const treeNode = new TreeNode(_data.id, _data, {}, tmpParentNode, nodeData, _data.type); if (tmpParentNode !== null && tmpParentNode !== undefined) tmpParentNode.children.push(treeNode); @@ -71,37 +71,37 @@ export class ManagePreferenceTreeNodes { }) public readNode = (_path: string) => new Promise((res, rej) => { - let temp_tree_path = _path, + const 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") + rej('It\'s a leaf node'); } else { - if (node?.children.length != 0) res(node.children) + if (node?.children.length != 0) res(node.children); } } - var self = this; + const self = this; async function loadData() { - const Path = BrowserFS.BFSRequire('path') + 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) + for (const 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 = []; + const _data = self.treeData.find((el) => el.id == node.id); + const subNodes = []; _data.childrenNodes.forEach(element => { - subNodes.push(element) + subNodes.push(element); }); await fill(subNodes); @@ -109,7 +109,7 @@ export class ManagePreferenceTreeNodes { await fill(self.treeData); } - self.returnChildrens(node, res) + self.returnChildrens(node, res); } loadData(); }) @@ -130,7 +130,7 @@ export class TreeNode { this.children = []; this.domNode = domNode; this.metadata = metadata; - this.name = metadata ? metadata.data.label : ""; + this.name = metadata ? metadata.data.label : ''; this.type = type ? type : undefined; } @@ -170,10 +170,10 @@ export class TreeNode { * Find the ancestor with matches this condition */ ancestorNode(condition) { - let node = this; + let node; - while (node.hasParent()) { - node = node.parent(); + while (this.hasParent()) { + node = this.parent(); if (condition(node)) { return node; } @@ -233,7 +233,7 @@ export class TreeNode { } else if (tree.isOpen(this.domNode)) { resolve(true); } else { - tree.open(this.domNode).then(val => resolve(true), err => reject(true)); + tree.open(this.domNode).then(() => resolve(true), () => reject(true)); } }); } diff --git a/web/pgadmin/static/js/tree/tree_init.tsx b/web/pgadmin/static/js/tree/tree_init.tsx index b12900aa7..15a0ea0a1 100644 --- a/web/pgadmin/static/js/tree/tree_init.tsx +++ b/web/pgadmin/static/js/tree/tree_init.tsx @@ -18,12 +18,12 @@ import { FileTreeX, TreeModelX } from '../components/PgTree'; import Theme from '../Theme'; import { PgMenu, PgMenuDivider, PgMenuItem, PgSubMenu } from '../components/Menu'; -var initBrowserTree = (pgBrowser) => { - return new Promise((resolve, reject)=>{ - const MOUNT_POINT = '/browser' +const initBrowserTree = (pgBrowser) => { + return new Promise((resolve)=>{ + const MOUNT_POINT = '/browser'; // Setup host - let mtree = new ManageTreeNodes(); + const mtree = new ManageTreeNodes(); // Init Tree with the Tree Parent node '/browser' mtree.init(MOUNT_POINT); @@ -48,45 +48,45 @@ var initBrowserTree = (pgBrowser) => { } return retval; }, - } + }; // Create Node const create = async (parentPath, _data): Promise => { try { - let _node_path = parentPath + "/" + _data.id - return mtree.addNode(parentPath, _node_path, _data) + const _node_path = parentPath + '/' + _data.id; + return mtree.addNode(parentPath, _node_path, _data); } catch (error) { - return null // or throw error as you see fit + return null; // or throw error as you see fit } - } + }; // Remove Node const remove = async (path: string, _removeOnlyChild): Promise => { try { await mtree.removeNode(path, _removeOnlyChild); - return true + return true; } catch (error) { - return false // or throw error as you see fit + return false; // or throw error as you see fit } - } + }; // Update Node const update = async (path: string, data): Promise => { try { await mtree.updateNode(path, data); - return true + return true; } catch (error) { - return false // or throw error as you see fit + return false; // or throw error as you see fit } - } + }; - const treeModelX = new TreeModelX(host, MOUNT_POINT) + const treeModelX = new TreeModelX(host, MOUNT_POINT); const itemHandle = function onReady(handler) { // Initialize pgBrowser Tree pgBrowser.tree = new Tree(handler, mtree, pgBrowser); resolve(pgBrowser); - } + }; treeModelX.root.ensureLoaded().then(()=>{ // Render Browser Tree @@ -97,7 +97,7 @@ var initBrowserTree = (pgBrowser) => { ); }); }); -} +}; function BrowserTree(props) { const [contextPos, setContextPos] = React.useState<{x: number, y: number} | null>(null); @@ -105,7 +105,7 @@ function BrowserTree(props) { const getPgMenuItem = (menuItem, i)=>{ if(menuItem.type == 'separator') { - return ; + return ; } if(menuItem.isDisabled) { return
{menuItem.label}
; @@ -113,13 +113,13 @@ function BrowserTree(props) { const hasCheck = typeof menuItem.checked == 'boolean'; return { - menuItem.callback(); - }} - hasCheck={hasCheck} - checked={menuItem.checked} + key={i} + disabled={menuItem.isDisabled} + onClick={()=>{ + menuItem.callback(); + }} + hasCheck={hasCheck} + checked={menuItem.checked} >{menuItem.label}; }; @@ -134,35 +134,35 @@ function BrowserTree(props) { return ( { - contextPos && setContextPos(null); - }} + {...props} height={'100%'} disableCache={true} onContextMenu={onContextMenu} + onScroll={()=>{ + contextPos && setContextPos(null); + }} /> setContextPos(null)} - label="context" - portal + anchorPoint={{ + x: contextPos?.x, + y: contextPos?.y + }} + open={Boolean(contextPos) && contextMenuItems.length !=0} + onClose={()=>setContextPos(null)} + label="context" + portal > {contextMenuItems.length !=0 && contextMenuItems.map((menuItem, i)=>{ - const submenus = menuItem.getMenuItems(); - if(submenus) { - return - {submenus.map((submenuItem, si)=>{ - return getPgMenuItem(submenuItem, i+'-'+si); - })} - ; - } - return getPgMenuItem(menuItem, i); + const submenus = menuItem.getMenuItems(); + if(submenus) { + return + {submenus.map((submenuItem, si)=>{ + return getPgMenuItem(submenuItem, i+'-'+si); + })} + ; + } + return getPgMenuItem(menuItem, i); })} - ) + ); } module.exports = { diff --git a/web/pgadmin/static/js/tree/tree_nodes.ts b/web/pgadmin/static/js/tree/tree_nodes.ts index 2097af1cc..0e96b52d8 100644 --- a/web/pgadmin/static/js/tree/tree_nodes.ts +++ b/web/pgadmin/static/js/tree/tree_nodes.ts @@ -7,29 +7,29 @@ // ////////////////////////////////////////////////////////////// -import * as BrowserFS from 'browserfs' +import * as BrowserFS from 'browserfs'; import url_for from 'sources/url_for'; import pgAdmin from 'sources/pgadmin'; import _ from 'lodash'; -import { FileType } from 'react-aspen' +import { FileType } from 'react-aspen'; import { findInTree } from './tree'; import { unix } from 'path-fx'; export class ManageTreeNodes { - constructor(fs) { - this.tree = {} - this.tempTree = new TreeNode(undefined, {}); + constructor() { + this.tree = {}; + this.tempTree = new TreeNode(undefined, {}); } - public init = (_root: string) => new Promise((res, rej) => { - let node = {parent: null, children: [], data: null}; + public init = (_root: string) => new Promise((res) => { + const 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) => { + public updateNode = (_path, _data) => new Promise((res) => { const item = this.findNode(_path); if (item) { item.name = _data.label; @@ -38,7 +38,7 @@ export class ManageTreeNodes { res(true); }) - public removeNode = async (_path, _removeOnlyChild) => { + public removeNode = async (_path) => { const item = this.findNode(_path); if (item && item.parentNode) { @@ -55,16 +55,16 @@ export class ManageTreeNodes { return findInTree(this.tempTree, path); } - public addNode = (_parent: string, _path: string, _data: []) => new Promise((res, rej) => { + public addNode = (_parent: string, _path: string, _data: []) => new Promise((res) => { _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: _data}; + const nodeData = {parent: _parent, children: [], data: _data}; - let tmpParentNode = this.findNode(_parent); - let treeNode = new TreeNode(_data.id, _data, {}, tmpParentNode, nodeData, _data.type); + const tmpParentNode = this.findNode(_parent); + const treeNode = new TreeNode(_data.id, _data, {}, tmpParentNode, nodeData, _data.type); if (tmpParentNode !== null && tmpParentNode !== undefined) tmpParentNode.children.push(treeNode); @@ -72,33 +72,33 @@ export class ManageTreeNodes { }) public readNode = (_path: string) => new Promise((res, rej) => { - let temp_tree_path = _path, - node = this.findNode(_path), - base_url = pgAdmin.Browser.URL; + let temp_tree_path = _path; + const node = this.findNode(_path); + const base_url = pgAdmin.Browser.URL; if (node && node.children.length > 0) { if (!node.type === FileType.File) { - rej("It's a leaf node") + rej('It\'s a leaf node'); } else { - if (node.children.length != 0) res(node.children) + if (node.children.length != 0) res(node.children); } } - var self = this; + const self = this; async function loadData() { let url = ''; if (_path == '/browser') { url = url_for('browser.nodes'); } else { - let _parent_url = self.generate_url(_path); + const _parent_url = self.generate_url(_path); if (node.metadata.data._pid == null ) { url = node.metadata.data._type + '/children/' + node.metadata.data._id; } else { - if (node.metadata.data._type.includes("coll-")) { - let _type = node.metadata.data._type.replace("coll-", "") + if (node.metadata.data._type.includes('coll-')) { + const _type = node.metadata.data._type.replace('coll-', ''); url = _type + '/nodes/' + _parent_url + '/'; } else { @@ -116,7 +116,7 @@ export class ManageTreeNodes { } async function jsonData(fetch_url) { - let result = await fetch(fetch_url, { + const result = await fetch(fetch_url, { headers: { 'X-Requested-With': 'XMLHttpRequest', 'X-pgA-CSRFToken': pgAdmin.csrf_token @@ -125,26 +125,26 @@ export class ManageTreeNodes { if (result.status == 200) { try { - let json = await result.json(); + const json = await result.json(); return json.data; } catch (e) { console.warn(e); } } - throw new Error("Node Load Error..."); + throw new Error('Node Load Error...'); } let treeData = null; if (url) treeData = await jsonData(url); - const Path = BrowserFS.BFSRequire('path') + 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) + for (const idx in tree) { + const _node = tree[idx]; + const _pathl = Path.join(_path, _node.id); await self.addNode(temp_tree_path, _pathl, _node); } - } + }; await fill(treeData); if (node.children.length > 0) res(node.children); @@ -156,11 +156,11 @@ export class ManageTreeNodes { public generate_url = (path: string) => { let _path = path; - let _parent_path = []; + const _parent_path = []; let _partitions = []; while(_path != '/') { - let node = this.findNode(_path); - let _parent = unix.dirname(_path); + const node = this.findNode(_path); + const _parent = unix.dirname(_path); if(node.parentNode && node.parentNode.path == _parent) { if (node.parentNode.metadata.data !== null && !node.parentNode.metadata.data._type.includes('coll-')) if(node.parentNode.metadata.data._type.includes('partition')) { @@ -168,14 +168,14 @@ export class ManageTreeNodes { } else { _parent_path.push(node.parentNode.metadata.data._id); } - } - _path = _parent; + } + _path = _parent; } _partitions = _partitions.reverse(); // Replace the table with the last partition as in reality partition node is not child of the table if(_partitions.length > 0) _parent_path[0] = _partitions[_partitions.length-1]; - return _parent_path.reverse().join("/"); + return _parent_path.reverse().join('/'); } } @@ -189,7 +189,7 @@ export class TreeNode { this.children = []; this.domNode = domNode; this.metadata = metadata; - this.name = metadata ? metadata.data.label : ""; + this.name = metadata ? metadata.data.label : ''; this.type = type ? type : undefined; } @@ -292,7 +292,7 @@ export class TreeNode { } else if(tree.isOpen(this.domNode)) { resolve(true); } else { - tree.open(this.domNode).then(val => resolve(true), err => reject(true)); + tree.open(this.domNode).then(() => resolve(true), () => reject(true)); } }); } @@ -300,9 +300,9 @@ export class TreeNode { } 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; + 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; } diff --git a/web/pgadmin/tools/debugger/static/js/components/DebuggerComponent.jsx b/web/pgadmin/tools/debugger/static/js/components/DebuggerComponent.jsx index e51b31c77..1292cf479 100644 --- a/web/pgadmin/tools/debugger/static/js/components/DebuggerComponent.jsx +++ b/web/pgadmin/tools/debugger/static/js/components/DebuggerComponent.jsx @@ -840,7 +840,7 @@ export default function DebuggerComponent({ pgAdmin, selectedNodeInfo, panel, ev }; const getBreakpointList = (br_list) => { - let breakpoint_list = new Array(); + let breakpoint_list = []; for (let val of br_list) { if (val.linenumber != -1) { breakpoint_list.push(val.linenumber); diff --git a/web/yarn.lock b/web/yarn.lock index db0331fe4..8061ed023 100644 --- a/web/yarn.lock +++ b/web/yarn.lock @@ -1236,6 +1236,18 @@ resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.3.0.tgz#ea89004119dc42db2e1dba0f97d553f7372f6fcb" integrity sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg== +"@eslint-community/eslint-utils@^4.2.0": + version "4.2.0" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.2.0.tgz#a831e6e468b4b2b5ae42bf658bea015bf10bc518" + integrity sha512-gB8T4H4DEfX2IV9zGDJPOBgP1e/DbfCPDTtEqUMckpvzS1OYtva8JdFYBqMwYk7xAQ429WGF/UPqn8uQ//h2vQ== + dependencies: + eslint-visitor-keys "^3.3.0" + +"@eslint-community/regexpp@^4.4.0": + version "4.4.0" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.4.0.tgz#3e61c564fcd6b921cb789838631c5ee44df09403" + integrity sha512-A9983Q0LnDGdLPjxyXQ00sbV+K+O+ko2Dr+CZigbHWtX9pNfxlaBkMR8X1CztI73zuEyEBXTVjx7CE+/VSwDiQ== + "@eslint/eslintrc@^0.4.3": version "0.4.3" resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c" @@ -1813,6 +1825,11 @@ resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39" integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew== +"@types/semver@^7.3.12": + version "7.3.13" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.13.tgz#da4bfd73f49bd541d28920ab0e2bf0ee80f71c91" + integrity sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw== + "@types/styled-jsx@^2.2.8": version "2.2.9" resolved "https://registry.yarnpkg.com/@types/styled-jsx/-/styled-jsx-2.2.9.tgz#e50b3f868c055bcbf9bc353eca6c10fdad32a53f" @@ -1820,6 +1837,90 @@ dependencies: "@types/react" "*" +"@typescript-eslint/eslint-plugin@^5.55.0": + version "5.55.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.55.0.tgz#bc2400c3a23305e8c9a9c04aa40933868aaaeb47" + integrity sha512-IZGc50rtbjk+xp5YQoJvmMPmJEYoC53SiKPXyqWfv15XoD2Y5Kju6zN0DwlmaGJp1Iw33JsWJcQ7nw0lGCGjVg== + dependencies: + "@eslint-community/regexpp" "^4.4.0" + "@typescript-eslint/scope-manager" "5.55.0" + "@typescript-eslint/type-utils" "5.55.0" + "@typescript-eslint/utils" "5.55.0" + debug "^4.3.4" + grapheme-splitter "^1.0.4" + ignore "^5.2.0" + natural-compare-lite "^1.4.0" + semver "^7.3.7" + tsutils "^3.21.0" + +"@typescript-eslint/parser@^5.55.0": + version "5.55.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.55.0.tgz#8c96a0b6529708ace1dcfa60f5e6aec0f5ed2262" + integrity sha512-ppvmeF7hvdhUUZWSd2EEWfzcFkjJzgNQzVST22nzg958CR+sphy8A6K7LXQZd6V75m1VKjp+J4g/PCEfSCmzhw== + dependencies: + "@typescript-eslint/scope-manager" "5.55.0" + "@typescript-eslint/types" "5.55.0" + "@typescript-eslint/typescript-estree" "5.55.0" + debug "^4.3.4" + +"@typescript-eslint/scope-manager@5.55.0": + version "5.55.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.55.0.tgz#e863bab4d4183ddce79967fe10ceb6c829791210" + integrity sha512-OK+cIO1ZGhJYNCL//a3ROpsd83psf4dUJ4j7pdNVzd5DmIk+ffkuUIX2vcZQbEW/IR41DYsfJTB19tpCboxQuw== + dependencies: + "@typescript-eslint/types" "5.55.0" + "@typescript-eslint/visitor-keys" "5.55.0" + +"@typescript-eslint/type-utils@5.55.0": + version "5.55.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.55.0.tgz#74bf0233523f874738677bb73cb58094210e01e9" + integrity sha512-ObqxBgHIXj8rBNm0yh8oORFrICcJuZPZTqtAFh0oZQyr5DnAHZWfyw54RwpEEH+fD8suZaI0YxvWu5tYE/WswA== + dependencies: + "@typescript-eslint/typescript-estree" "5.55.0" + "@typescript-eslint/utils" "5.55.0" + debug "^4.3.4" + tsutils "^3.21.0" + +"@typescript-eslint/types@5.55.0": + version "5.55.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.55.0.tgz#9830f8d3bcbecf59d12f821e5bc6960baaed41fd" + integrity sha512-M4iRh4AG1ChrOL6Y+mETEKGeDnT7Sparn6fhZ5LtVJF1909D5O4uqK+C5NPbLmpfZ0XIIxCdwzKiijpZUOvOug== + +"@typescript-eslint/typescript-estree@5.55.0": + version "5.55.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.55.0.tgz#8db7c8e47ecc03d49b05362b8db6f1345ee7b575" + integrity sha512-I7X4A9ovA8gdpWMpr7b1BN9eEbvlEtWhQvpxp/yogt48fy9Lj3iE3ild/1H3jKBBIYj5YYJmS2+9ystVhC7eaQ== + dependencies: + "@typescript-eslint/types" "5.55.0" + "@typescript-eslint/visitor-keys" "5.55.0" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + semver "^7.3.7" + tsutils "^3.21.0" + +"@typescript-eslint/utils@5.55.0": + version "5.55.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.55.0.tgz#34e97322e7ae5b901e7a870aabb01dad90023341" + integrity sha512-FkW+i2pQKcpDC3AY6DU54yl8Lfl14FVGYDgBTyGKB75cCwV3KpkpTMFi9d9j2WAJ4271LR2HeC5SEWF/CZmmfw== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@types/json-schema" "^7.0.9" + "@types/semver" "^7.3.12" + "@typescript-eslint/scope-manager" "5.55.0" + "@typescript-eslint/types" "5.55.0" + "@typescript-eslint/typescript-estree" "5.55.0" + eslint-scope "^5.1.1" + semver "^7.3.7" + +"@typescript-eslint/visitor-keys@5.55.0": + version "5.55.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.55.0.tgz#01ad414fca8367706d76cdb94adf788dc5b664a2" + integrity sha512-q2dlHHwWgirKh1D3acnuApXG+VNXpEY5/AwRxDVuEQpxWaB0jCDe0jFMVMALJ3ebSfuOVE8/rMS+9ZOYGg1GWw== + dependencies: + "@typescript-eslint/types" "5.55.0" + eslint-visitor-keys "^3.3.0" + "@vusion/webfonts-generator@^0.8.0": version "0.8.0" resolved "https://registry.yarnpkg.com/@vusion/webfonts-generator/-/webfonts-generator-0.8.0.tgz#3ff41b9ec4b83decd87650637ee050741741e794" @@ -4484,6 +4585,11 @@ eslint-visitor-keys@^2.0.0, eslint-visitor-keys@^2.1.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== +eslint-visitor-keys@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" + integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== + eslint@^7.19.0: version "7.32.0" resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.32.0.tgz#c6d328a14be3fb08c8d1d21e12c02fdb7a2a812d" @@ -5141,7 +5247,7 @@ globby@^10.0.0: merge2 "^1.2.3" slash "^3.0.0" -globby@^11.0.1: +globby@^11.0.1, globby@^11.1.0: version "11.1.0" resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== @@ -5220,6 +5326,11 @@ graceful-fs@^4.1.10, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== +grapheme-splitter@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e" + integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ== + graphlib@^2.1.8: version "2.1.8" resolved "https://registry.yarnpkg.com/graphlib/-/graphlib-2.1.8.tgz#5761d414737870084c92ec7b5dbcb0592c9d35da" @@ -5863,7 +5974,7 @@ is-generator-function@^1.0.7: dependencies: has-tostringtag "^1.0.0" -is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: version "4.0.3" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== @@ -7289,6 +7400,11 @@ nanopop@^2.1.0: resolved "https://registry.yarnpkg.com/nanopop/-/nanopop-2.2.0.tgz#bd1c25588a7beaf68865bc2df19db4c58c77dcc9" integrity sha512-E9JaHcxh3ere8/BEZHAcnuD10RluTSPyTToBvoFWS9/7DcCx6gyKjbn7M7Bx7E1veCxCuY1iO6h4+gdAf1j73Q== +natural-compare-lite@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz#17b09581988979fddafe0201e931ba933c96cbb4" + integrity sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g== + natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" @@ -9171,7 +9287,7 @@ semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== -semver@^7.2.1, semver@^7.3.4, semver@^7.3.5, semver@^7.3.8: +semver@^7.2.1, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8: version "7.3.8" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798" integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A== @@ -10021,11 +10137,23 @@ tslib@2.3.1: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== +tslib@^1.8.1: + version "1.14.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + tslib@^2.4.0: version "2.4.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.1.tgz#0d0bfbaac2880b91e22df0768e55be9753a5b17e" integrity sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA== +tsutils@^3.21.0: + version "3.21.0" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" + integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== + dependencies: + tslib "^1.8.1" + ttf2eot@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/ttf2eot/-/ttf2eot-3.1.0.tgz#c8971af7c68c5b996d8cfdb8847cdadfbf195e05"