From 380ee1acac1c0b7972d7d423cf804af146dc0edf Mon Sep 17 00:00:00 2001 From: bobzel Date: Sun, 10 Dec 2023 20:19:27 -0500 Subject: massive changes to use mobx 6 which means not accessing props directly in @computed functions. --- .../views/collections/CollectionTreeView.tsx | 192 +++++++++++---------- 1 file changed, 102 insertions(+), 90 deletions(-) (limited to 'src/client/views/collections/CollectionTreeView.tsx') diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 5c165fe70..938af002f 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -1,4 +1,4 @@ -import { action, computed, IReactionDisposer, observable, reaction } from 'mobx'; +import { action, computed, IReactionDisposer, makeObservable, observable, override, reaction } from 'mobx'; import { observer } from 'mobx-react'; import { Doc, DocListCast, Opt, StrListCast } from '../../../fields/Doc'; import { DocData } from '../../../fields/DocSymbols'; @@ -7,7 +7,7 @@ import { listSpec } from '../../../fields/Schema'; import { ScriptField } from '../../../fields/ScriptField'; import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Types'; import { TraceMobx } from '../../../fields/util'; -import { emptyFunction, returnAll, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnNone, returnOne, returnTrue, returnZero } from '../../../Utils'; +import { copyProps, emptyFunction, returnAll, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnNone, returnOne, returnTrue, returnZero } from '../../../Utils'; import { DocUtils } from '../../documents/Documents'; import { DocumentManager } from '../../util/DocumentManager'; import { DragManager, dropActionType } from '../../util/DragManager'; @@ -23,7 +23,7 @@ import { FieldViewProps } from '../nodes/FieldView'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; import { StyleProp } from '../StyleProvider'; import { CollectionFreeFormView } from './collectionFreeForm'; -import { CollectionSubView } from './CollectionSubView'; +import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView'; import './CollectionTreeView.scss'; import { TreeView } from './TreeView'; import * as React from 'react'; @@ -59,27 +59,35 @@ export class CollectionTreeView extends CollectionSubView = new Set(); // list of tree view items to monitor for height changes private observer: any; // observer for monitoring tree view items. - @computed get doc() { - return this.props.Document; + _prevProps: React.PropsWithChildren>; + @override _props: React.PropsWithChildren>; + constructor(props: React.PropsWithChildren>) { + super(props); + this._props = this._prevProps = props; + makeObservable(this); } - @computed get dataDoc() { - return this.props.TemplateDataDocument || this.doc; + componentDidUpdate() { + copyProps(this); + } + + get dataDoc() { + return this._props.TemplateDataDocument || this.Document; } @computed get treeViewtruncateTitleWidth() { - return NumCast(this.doc.treeView_TruncateTitleWidth, this.panelWidth()); + return NumCast(this.Document.treeView_TruncateTitleWidth, this.panelWidth()); } @computed get treeChildren() { TraceMobx(); - return this.props.childDocuments || this.childDocs; + return this._props.childDocuments || this.childDocs; } @computed get outlineMode() { - return this.doc.treeView_Type === TreeViewType.outline; + return this.Document.treeView_Type === TreeViewType.outline; } @computed get fileSysMode() { - return this.doc.treeView_Type === TreeViewType.fileSystem; + return this.Document.treeView_Type === TreeViewType.fileSystem; } @computed get dashboardMode() { - return this.doc === Doc.MyDashboards; + return this.Document === Doc.MyDashboards; } @observable _titleHeight = 0; // height of the title bar @@ -88,8 +96,8 @@ export class CollectionTreeView extends CollectionSubView this.props.whenChildContentsActiveChanged((this._isAnyChildContentActive = isActive))); - isContentActive = (outsideReaction?: boolean) => (this._isAnyChildContentActive ? true : this.props.isContentActive() ? true : false); + whenChildContentsActiveChanged = action((isActive: boolean) => this._props.whenChildContentsActiveChanged((this._isAnyChildContentActive = isActive))); + isContentActive = (outsideReaction?: boolean) => (this._isAnyChildContentActive ? true : this._props.isContentActive() ? true : false); componentWillUnmount() { this._isDisposing = true; @@ -99,7 +107,7 @@ export class CollectionTreeView extends CollectionSubView this.layoutDoc.layout_autoHeight, auto => auto && this.computeHeight(), @@ -112,7 +120,7 @@ export class CollectionTreeView extends CollectionSubView p + Number(getComputedStyle(r).height.replace('px', '')), this.marginBot()) + 6; this.layoutDoc._layout_autoHeightMargins = bodyHeight; - !this.props.dontRegisterView && this.props.setHeight?.(bodyHeight + titleHeight); + !this._props.dontRegisterView && this._props.setHeight?.(bodyHeight + titleHeight); } }; unobserveHeight = (ref: any) => { @@ -135,7 +143,7 @@ export class CollectionTreeView extends CollectionSubView { this._treedropDisposer?.(); - if ((this._mainEle = ele)) this._treedropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.doc, this.onInternalPreDrop.bind(this)); + if ((this._mainEle = ele)) this._treedropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.Document, this.onInternalPreDrop.bind(this)); }; protected onInternalPreDrop = (e: Event, de: DragManager.DropEvent) => { @@ -143,7 +151,7 @@ export class CollectionTreeView extends CollectionSubView sameTree || dragData.draggedDocuments.some(d => d.embedContainer === this.doc && this.childDocs.includes(d)); + const isAlreadyInTree = () => sameTree || dragData.draggedDocuments.some(d => d.embedContainer === this.Document && this.childDocs.includes(d)); if (isAlreadyInTree() !== sameTree) { console.log('WHAAAT'); } @@ -152,22 +160,22 @@ export class CollectionTreeView extends CollectionSubView this.props.ScreenToLocalTransform().translate(0, -this._headerHeight); + screenToLocalTransform = () => this._props.ScreenToLocalTransform().translate(0, -this._headerHeight); @action remove = (doc: Doc | Doc[]): boolean => { const docs = doc instanceof Doc ? [doc] : doc; - const targetDataDoc = this.doc[DocData]; - const value = DocListCast(targetDataDoc[this.props.fieldKey]); + const targetDataDoc = this.Document[DocData]; + const value = DocListCast(targetDataDoc[this._props.fieldKey]); const result = value.filter(v => !docs.includes(v)); if ((doc instanceof Doc ? [doc] : doc).some(doc => SelectionManager.Views().some(dv => Doc.AreProtosEqual(dv.Document, doc)))) SelectionManager.DeselectAll(); if (result.length !== value.length && doc instanceof Doc) { - const ind = DocListCast(targetDataDoc[this.props.fieldKey]).indexOf(doc); - const prev = ind && DocListCast(targetDataDoc[this.props.fieldKey])[ind - 1]; - this.props.removeDocument?.(doc); + const ind = DocListCast(targetDataDoc[this._props.fieldKey]).indexOf(doc); + const prev = ind && DocListCast(targetDataDoc[this._props.fieldKey])[ind - 1]; + this._props.removeDocument?.(doc); if (ind > 0 && prev) { FormattedTextBox.SetSelectOnLoad(prev); - DocumentManager.Instance.getDocumentView(prev, this.props.DocumentView?.())?.select(false); + DocumentManager.Instance.getDocumentView(prev, this._props.DocumentView?.())?.select(false); } return true; } @@ -178,24 +186,28 @@ export class CollectionTreeView extends CollectionSubView, before?: boolean): boolean => { const doAddDoc = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => { - const res = flg && Doc.AddDocToList(this.doc[DocData], this.props.fieldKey, doc, relativeTo, before); - res && Doc.SetContainer(doc, this.props.Document); + const res = flg && Doc.AddDocToList(this.Document[DocData], this._props.fieldKey, doc, relativeTo, before); + res && Doc.SetContainer(doc, this.Document); return res; }, true); - if (this.doc.resolvedDataDoc instanceof Promise) return false; - return relativeTo === undefined ? this.props.addDocument?.(docs) || false : doAddDoc(docs); + if (this.Document.resolvedDataDoc instanceof Promise) return false; + return relativeTo === undefined ? this._props.addDocument?.(docs) || false : doAddDoc(docs); }; onContextMenu = (e: React.MouseEvent): void => { // need to test if propagation has stopped because GoldenLayout forces a parallel react hierarchy to be created for its top-level layout if (!Doc.noviceMode) { const layoutItems: ContextMenuProps[] = []; - layoutItems.push({ description: 'Make tree state ' + (this.doc.treeView_OpenIsTransient ? 'persistent' : 'transient'), event: () => (this.doc.treeView_OpenIsTransient = !this.doc.treeView_OpenIsTransient), icon: 'paint-brush' }); - layoutItems.push({ description: (this.doc.treeView_HideHeaderFields ? 'Show' : 'Hide') + ' Header Fields', event: () => (this.doc.treeView_HideHeaderFields = !this.doc.treeView_HideHeaderFields), icon: 'paint-brush' }); - layoutItems.push({ description: (this.doc.treeView_HideTitle ? 'Show' : 'Hide') + ' Title', event: () => (this.doc.treeView_HideTitle = !this.doc.treeView_HideTitle), icon: 'paint-brush' }); + layoutItems.push({ + description: 'Make tree state ' + (this.Document.treeView_OpenIsTransient ? 'persistent' : 'transient'), + event: () => (this.Document.treeView_OpenIsTransient = !this.Document.treeView_OpenIsTransient), + icon: 'paint-brush', + }); + layoutItems.push({ description: (this.Document.treeView_HideHeaderFields ? 'Show' : 'Hide') + ' Header Fields', event: () => (this.Document.treeView_HideHeaderFields = !this.Document.treeView_HideHeaderFields), icon: 'paint-brush' }); + layoutItems.push({ description: (this.Document.treeView_HideTitle ? 'Show' : 'Hide') + ' Title', event: () => (this.Document.treeView_HideTitle = !this.Document.treeView_HideTitle), icon: 'paint-brush' }); ContextMenu.Instance.addItem({ description: 'Options...', subitems: layoutItems, icon: 'eye' }); const existingOnClick = ContextMenu.Instance.findByDescription('OnClick...'); const onClicks: ContextMenuProps[] = existingOnClick && 'subitems' in existingOnClick ? existingOnClick.subitems : []; - onClicks.push({ description: 'Edit onChecked Script', event: () => UndoManager.RunInBatch(() => DocUtils.makeCustomViewClicked(this.doc, undefined, 'onCheckedClick'), 'edit onCheckedClick'), icon: 'edit' }); + onClicks.push({ description: 'Edit onChecked Script', event: () => UndoManager.RunInBatch(() => DocUtils.makeCustomViewClicked(this.Document, undefined, 'onCheckedClick'), 'edit onCheckedClick'), icon: 'edit' }); !existingOnClick && ContextMenu.Instance.addItem({ description: 'OnClick...', noexpand: true, subitems: onClicks, icon: 'mouse-pointer' }); } }; @@ -213,7 +225,7 @@ export class CollectionTreeView extends CollectionSubView StrCast(this.dataDoc.title)} SetValue={undoBatch((value: string, shift: boolean, enter: boolean) => { - if (enter && this.props.Document.treeView_Type === TreeViewType.outline) this.makeTextCollection(this.treeChildren); + if (enter && this.Document.treeView_Type === TreeViewType.outline) this.makeTextCollection(this.treeChildren); this.dataDoc.title = value; return true; })} @@ -231,9 +243,9 @@ export class CollectionTreeView extends CollectionSubView { - const customScripts = Cast(this.doc.childContextMenuScripts, listSpec(ScriptField), []); - const customFilters = Cast(this.doc.childContextMenuFilters, listSpec(ScriptField), []); - const icons = StrListCast(this.doc.childContextMenuIcons); - return StrListCast(this.doc.childContextMenuLabels).map((label, i) => ({ script: customScripts[i], filter: customFilters[i], icon: icons[i], label })); + const customScripts = Cast(this.Document.childContextMenuScripts, listSpec(ScriptField), []); + const customFilters = Cast(this.Document.childContextMenuFilters, listSpec(ScriptField), []); + const icons = StrListCast(this.Document.childContextMenuIcons); + return StrListCast(this.Document.childContextMenuLabels).map((label, i) => ({ script: customScripts[i], filter: customFilters[i], icon: icons[i], label })); }; - headerFields = () => this.props.treeViewHideHeaderFields || BoolCast(this.doc.treeView_HideHeaderFields); + headerFields = () => this._props.treeViewHideHeaderFields || BoolCast(this.Document.treeView_HideHeaderFields); @observable _renderCount = 1; @computed get treeViewElements() { TraceMobx(); - const dragAction = StrCast(this.doc.childDragAction) as dropActionType; + const dragAction = StrCast(this.Document.childDragAction) as dropActionType; const addDoc = (doc: Doc | Doc[], relativeTo?: Doc, before?: boolean) => this.addDoc(doc, relativeTo, before); - const moveDoc = (d: Doc | Doc[], target: Doc | undefined, addDoc: (doc: Doc | Doc[]) => boolean) => this.props.moveDocument?.(d, target, addDoc) || false; + const moveDoc = (d: Doc | Doc[], target: Doc | undefined, addDoc: (doc: Doc | Doc[]) => boolean) => this._props.moveDocument?.(d, target, addDoc) || false; if (this._renderCount < this.treeChildren.length) setTimeout(action(() => (this._renderCount = Math.min(this.treeChildren.length, this._renderCount + 20)))); return TreeView.GetChildElements( this.treeChildren, this, this, - this.doc, - this.props.TemplateDataDocument, + this.Document, + this._props.TemplateDataDocument, undefined, undefined, addDoc, this.remove, moveDoc, dragAction, - this.props.addDocTab, - this.props.styleProvider, + this._props.addDocTab, + this._props.styleProvider, this.screenToLocalTransform, this.isContentActive, this.panelWidth, - this.props.renderDepth, + this._props.renderDepth, this.headerFields, [], - this.props.onCheckedClick, + this._props.onCheckedClick, this.onChildClick, - this.props.treeViewSkipFields, + this._props.treeViewSkipFields, true, this.whenChildContentsActiveChanged, - this.props.dontRegisterView || Cast(this.props.Document.childDontRegisterViews, 'boolean', null), + this._props.dontRegisterView || Cast(this.Document.childDontRegisterViews, 'boolean', null), this.observeHeight, this.unobserveHeight, this.childContextMenuItems(), //TODO: [AL] add these - this.props.AddToMap, - this.props.RemFromMap, - this.props.hierarchyIndex, + this._props.AddToMap, + this._props.RemFromMap, + this._props.hierarchyIndex, this._renderCount ); } @@ -306,8 +318,8 @@ export class CollectionTreeView extends CollectionSubView (this._titleRef = r) && (this._titleHeight = r.getBoundingClientRect().height * this.props.ScreenToLocalTransform().Scale))} - key={this.doc[Id]} + ref={action((r: any) => (this._titleRef = r) && (this._titleHeight = r.getBoundingClientRect().height * this._props.ScreenToLocalTransform().Scale))} + key={this.Document[Id]} style={!this.outlineMode ? { marginLeft: this.marginX(), paddingTop: this.marginTop() } : {}}> {this.outlineMode ? this.documentTitle : this.editableTitle} @@ -327,26 +339,26 @@ export class CollectionTreeView extends CollectionSubView ); @@ -363,30 +375,30 @@ export class CollectionTreeView extends CollectionSubView NumCast(this.doc._xMargin); - marginTop = () => NumCast(this.doc._yMargin); - marginBot = () => NumCast(this.doc._yMargin); + marginX = () => NumCast(this.Document._xMargin); + marginTop = () => NumCast(this.Document._yMargin); + marginBot = () => NumCast(this.Document._yMargin); documentTitleWidth = () => Math.min(NumCast(this.layoutDoc?._width), this.panelWidth()); documentTitleHeight = () => NumCast(this.layoutDoc?._height) - NumCast(this.layoutDoc.layout_autoHeightMargins); truncateTitleWidth = () => this.treeViewtruncateTitleWidth; - onChildClick = () => this.props.onChildClick?.() || ScriptCast(this.doc.onChildClick); - panelWidth = () => Math.max(0, this.props.PanelWidth() - 2 * this.marginX() * (this.props.NativeDimScaling?.() || 1)); + onChildClick = () => this._props.onChildClick?.() || ScriptCast(this.Document.onChildClick); + panelWidth = () => Math.max(0, this._props.PanelWidth() - 2 * this.marginX() * (this._props.NativeDimScaling?.() || 1)); - addAnnotationDocument = (doc: Doc | Doc[]) => this.addDocument(doc, `${this.props.fieldKey}_annotations`) || false; - remAnnotationDocument = (doc: Doc | Doc[]) => this.removeDocument(doc, `${this.props.fieldKey}_annotations`) || false; + addAnnotationDocument = (doc: Doc | Doc[]) => this.addDocument(doc, `${this._props.fieldKey}_annotations`) || false; + remAnnotationDocument = (doc: Doc | Doc[]) => this.removeDocument(doc, `${this._props.fieldKey}_annotations`) || false; moveAnnotationDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[], annotationKey?: string) => boolean) => - this.moveDocument(doc, targetCollection, addDocument, `${this.props.fieldKey}_annotations`) || false; + this.moveDocument(doc, targetCollection, addDocument, `${this._props.fieldKey}_annotations`) || false; @observable _headerHeight = 0; @computed get content() { - const background = () => this.props.styleProvider?.(this.doc, this.props, StyleProp.BackgroundColor); - const color = () => this.props.styleProvider?.(this.doc, this.props, StyleProp.Color); - const pointerEvents = () => (this.props.isContentActive() === false ? 'none' : undefined); - const titleBar = this.props.treeViewHideTitle || this.doc.treeView_HideTitle ? null : this.titleBar; + const background = () => this._props.styleProvider?.(this.Document, this._props, StyleProp.BackgroundColor); + const color = () => this._props.styleProvider?.(this.Document, this._props, StyleProp.Color); + const pointerEvents = () => (this._props.isContentActive() === false ? 'none' : undefined); + const titleBar = this._props.treeViewHideTitle || this.Document.treeView_HideTitle ? null : this.titleBar; return (
{!this.buttonMenu && !this.noviceExplainer ? null : ( @@ -398,7 +410,7 @@ export class CollectionTreeView extends CollectionSubView !this.doc.treeView_HasOverlay && r && this.createTreeDropTarget(r)} + ref={r => !this.Document.treeView_HasOverlay && r && this.createTreeDropTarget(r)} style={{ ...(!titleBar ? { marginLeft: this.marginX(), paddingTop: this.marginTop() } : {}), color: color(), @@ -423,7 +435,7 @@ export class CollectionTreeView extends CollectionSubView e.stopPropagation()} - onClick={e => (!this.layoutDoc.forceActive ? this.props.select(false) : SelectionManager.DeselectAll())} + onClick={e => (!this.layoutDoc.forceActive ? this._props.select(false) : SelectionManager.DeselectAll())} onDrop={this.onTreeDrop}>
    {this.treeViewElements}
@@ -435,27 +447,27 @@ export class CollectionTreeView extends CollectionSubView - {!(this.doc instanceof Doc) || !this.treeChildren ? null : this.doc.treeView_HasOverlay ? ( + {!(this.Document instanceof Doc) || !this.treeChildren ? null : this.Document.treeView_HasOverlay ? ( + renderDepth={this._props.renderDepth + 1}> {this.content} ) : ( -- cgit v1.2.3-70-g09d2