613 lines
21 KiB
TypeScript
613 lines
21 KiB
TypeScript
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';
|
|
|
|
export class FileTreeX extends React.Component<IFileTreeXProps> {
|
|
private fileTreeHandle: IFileTreeXHandle
|
|
private activeFileDec: Decoration
|
|
private pseudoActiveFileDec: Decoration
|
|
private activeFile: FileOrDir
|
|
private pseudoActiveFile: FileOrDir
|
|
private wrapperRef: React.RefObject<HTMLDivElement> = React.createRef()
|
|
private events: Notificar<FileTreeXEvent>
|
|
private disposables: DisposablesComposite
|
|
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');
|
|
}
|
|
|
|
render() {
|
|
const { height, model, disableCache } = this.props;
|
|
const { decorations } = model;
|
|
|
|
return <div
|
|
onKeyDown={this.handleKeyDown}
|
|
className='file-tree'
|
|
onBlur={this.handleBlur}
|
|
onClick={this.handleClick}
|
|
onScroll={this.props.onScroll}
|
|
ref={this.wrapperRef}
|
|
style={{
|
|
height: height ? height : 'calc(100vh - 60px)',
|
|
width: '100%',
|
|
display: 'flex',
|
|
flexDirection: 'column',
|
|
flex: 1
|
|
}}
|
|
tabIndex={-1}>
|
|
<AutoSizer onResize={this.onResize}>
|
|
{({ width, height }) => (
|
|
<FileTree
|
|
height={height}
|
|
width={width}
|
|
model={model}
|
|
itemHeight={FileTreeItem.renderHeight}
|
|
onReady={this.handleTreeReady}
|
|
disableCache={disableCache ? disableCache : false}
|
|
>
|
|
{(props: IItemRendererProps) => <FileTreeItem
|
|
item={props.item}
|
|
itemType={props.itemType}
|
|
decorations={decorations.getDecorations(props.item as FileEntry|Directory)}
|
|
onClick={this.handleItemClicked}
|
|
onDoubleClick={this.handleItemDoubleClicked}
|
|
onContextMenu={this.handleItemCtxMenu}
|
|
changeDirectoryCount={this.changeDirectoryCount}
|
|
events={this.events}/>}
|
|
</FileTree>
|
|
)}
|
|
</AutoSizer>
|
|
</div>;
|
|
}
|
|
|
|
public componentDidMount() {
|
|
for(const 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();
|
|
}
|
|
|
|
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));
|
|
}
|
|
|
|
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);
|
|
|
|
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.keyboardHotkeys = new KeyboardHotkeys(this.fileTreeHandle);
|
|
|
|
if (typeof onReady === 'function') {
|
|
onReady(this.fileTreeHandle);
|
|
}
|
|
}
|
|
|
|
private setActiveFile = async (fileOrDirOrPath: FileOrDir | string, ensureVisible, align): Promise<void> => {
|
|
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 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<void> => {
|
|
const fileH = typeof fileOrDirOrPath === 'string'
|
|
? await this.fileTreeHandle.getFileHandle(fileOrDirOrPath)
|
|
: fileOrDirOrPath;
|
|
|
|
if (fileH) {
|
|
await this.fileTreeHandle.ensureVisible(fileH);
|
|
}
|
|
}
|
|
|
|
private deSelectActiveFile = async (fileOrDirOrPath: FileOrDir | string): Promise<void> => {
|
|
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;
|
|
}
|
|
}
|
|
|
|
private setPseudoActiveFile = async (fileOrDirOrPath: FileOrDir | string): Promise<void> => {
|
|
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 Directory, TargetMatchMode.Self);
|
|
}
|
|
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<void> => {
|
|
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 (!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);
|
|
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<void> => {
|
|
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<void> => {
|
|
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 (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<void> => {
|
|
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<void> => {
|
|
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;
|
|
|
|
if (fileH === undefined || fileH === null) { return this.props.model.root.children[0]; }
|
|
|
|
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;
|
|
|
|
if (fileH === FileType.Directory || fileH === FileType.File) {
|
|
return fileH.parent;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
|
|
private hasParent = async (fileOrDirOrPath: FileOrDir | string) => {
|
|
const fileH = typeof fileOrDirOrPath === 'string'
|
|
? await this.fileTreeHandle.getFileHandle(fileOrDirOrPath)
|
|
: fileOrDirOrPath;
|
|
|
|
if (fileH === FileType.Directory || fileH === FileType.File) {
|
|
return fileH.parent ? true : false;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private children = async (fileOrDirOrPath: FileOrDir | string) => {
|
|
const fileH = typeof fileOrDirOrPath === 'string'
|
|
? await this.fileTreeHandle.getFileHandle(fileOrDirOrPath)
|
|
: fileOrDirOrPath;
|
|
|
|
if (fileH === FileType.Directory) {
|
|
return fileH.children;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
|
|
private isOpen = async (fileOrDirOrPath: FileOrDir | string) => {
|
|
const fileH = typeof fileOrDirOrPath === 'string'
|
|
? await this.fileTreeHandle.getFileHandle(fileOrDirOrPath)
|
|
: fileOrDirOrPath;
|
|
|
|
if (fileH === FileType.Directory) {
|
|
return fileH.isExpanded;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private isClosed = async (fileOrDirOrPath: FileOrDir | string) => {
|
|
const fileH = typeof fileOrDirOrPath === 'string'
|
|
? await this.fileTreeHandle.getFileHandle(fileOrDirOrPath)
|
|
: fileOrDirOrPath;
|
|
|
|
if (fileH === FileType.Directory || fileH === FileType.File) {
|
|
return !fileH.isExpanded;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private itemData = async (fileOrDirOrPath: FileOrDir | string) => {
|
|
const fileH = typeof fileOrDirOrPath === 'string'
|
|
? await this.fileTreeHandle.getFileHandle(fileOrDirOrPath)
|
|
: fileOrDirOrPath;
|
|
|
|
if (fileH === FileType.Directory || fileH === FileType.File) {
|
|
return fileH._metadata.data;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private setLabel = async(pathOrDir: string | Directory, label: string): Promise<void> => {
|
|
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;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
private changeDirectoryCount = async(pathOrDir: string | Directory): Promise<void> => {
|
|
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 = '';
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
private closeDir = async (pathOrDir: string | Directory) => {
|
|
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);
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
private toggleDirectory = async (pathOrDir: string | Directory) => {
|
|
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);
|
|
|
|
} 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);
|
|
|
|
if (ref) {
|
|
this.hideLoader(ref);
|
|
}
|
|
|
|
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 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 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);
|
|
}
|
|
|
|
}
|
|
|
|
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');
|
|
}
|
|
|
|
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');
|
|
}
|
|
|
|
private handleBlur = () => {
|
|
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);
|
|
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
private getDOMFromItem = (item: FileOrDir) => {
|
|
return FileTreeItem.itemIdToRefMap.get(item.id);
|
|
}
|
|
|
|
private handleClick = (ev: React.MouseEvent) => {
|
|
// 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);
|
|
}
|
|
|
|
private handleKeyDown = (ev: React.KeyboardEvent) => {
|
|
return this.keyboardHotkeys.handleKeyDown(ev);
|
|
}
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
private changeResolvePath = async (item: FileOrDir): Promise<void> => {
|
|
// 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 };
|