From 19aa61f593c896f4d3bd0ffae6dbe306c2a9546d Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Wed, 10 Aug 2022 11:51:41 -0400
Subject: basic table in progress

---
 .../collections/collectionSchema/SchemaRowBox.tsx  | 33 ++++++++++++++++++++++
 1 file changed, 33 insertions(+)
 create mode 100644 src/client/views/collections/collectionSchema/SchemaRowBox.tsx

(limited to 'src/client/views/collections/collectionSchema/SchemaRowBox.tsx')

diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
new file mode 100644
index 000000000..50e2502dc
--- /dev/null
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -0,0 +1,33 @@
+import React = require('react');
+import { observer } from 'mobx-react';
+import './CollectionSchemaView.scss';
+import { ViewBoxAnnotatableComponent, ViewBoxBaseComponent } from '../../DocComponent';
+import { FieldViewProps } from '../../nodes/FieldView';
+import { SchemaTableCell } from './SchemaTableCell';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { undoBatch } from '../../../util/UndoManager';
+
+export interface SchemaRowBoxProps extends FieldViewProps {
+    columnKeys: string[];
+    columnWidths: number[];
+}
+
+@observer
+export class SchemaRowBox extends ViewBoxAnnotatableComponent<SchemaRowBoxProps>() {
+    render() {
+        return (
+            <div className="schema-row" /*style={this.props.isSelected() ? { backgroundColor: 'grey' } : {}}*/>
+                <div className="row-menu">
+                    <div className="row-button" onPointerDown={undoBatch(() => this.props.removeDocument?.(this.props.Document))}>
+                        <FontAwesomeIcon icon={'times'} />
+                    </div>
+                </div>
+                <div className="row-cells">
+                    {this.props.columnKeys.map((key, index) => (
+                        <SchemaTableCell Document={this.props.Document} key={key} fieldKey={key} columnWidth={this.props.columnWidths[index]} />
+                    ))}
+                </div>
+            </div>
+        );
+    }
+}
-- 
cgit v1.2.3-70-g09d2


From 9f39b14b2e321e09d071ad1c5bf8e3978ff7f181 Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Wed, 10 Aug 2022 19:33:19 -0400
Subject: basic selection complete

---
 .../collections/CollectionStackedTimeline.scss     |  1 +
 .../collections/CollectionStackedTimeline.tsx      |  2 +-
 .../collectionSchema/CollectionSchemaView.scss     |  1 -
 .../collectionSchema/CollectionSchemaView.tsx      | 57 ++++++++++++++--------
 .../collections/collectionSchema/SchemaRowBox.tsx  | 35 +++++++++----
 src/client/views/nodes/AudioBox.tsx                |  1 +
 6 files changed, 65 insertions(+), 32 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaRowBox.tsx')

diff --git a/src/client/views/collections/CollectionStackedTimeline.scss b/src/client/views/collections/CollectionStackedTimeline.scss
index 6611477e5..c296e1172 100644
--- a/src/client/views/collections/CollectionStackedTimeline.scss
+++ b/src/client/views/collections/CollectionStackedTimeline.scss
@@ -2,6 +2,7 @@
 
 .collectionStackedTimeline-timelineContainer {
     height: 100%;
+    position: absolute;
     overflow-x: auto;
     overflow-y: hidden;
     border: none;
diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx
index 48e3abbc7..2543624d3 100644
--- a/src/client/views/collections/CollectionStackedTimeline.tsx
+++ b/src/client/views/collections/CollectionStackedTimeline.tsx
@@ -668,7 +668,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
                         )}
                     </div>
                 </div>
-                <div className="timeline-hoverUI" style={{ left: `calc(${((this._hoverTime - this.clipStart) / this.clipDuration) * 100}%` }}>
+                <div className="timeline-hoverUI" style={{ left: ((this._hoverTime - this.clipStart) / this.clipDuration) * this.timelineContentWidth - this._scroll }}>
                     <div className="hoverTime">{formatTime(this._hoverTime - this.clipStart)}</div>
                     {this._thumbnail && <img className="videoBox-thumbnail" src={this._thumbnail} />}
                 </div>
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
index 0a51aea4e..0f4053127 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
@@ -36,7 +36,6 @@
                 display: flex;
                 flex-direction: row;
                 justify-content: center;
-                width: 100px;
 
                 .row-button {
                     width: 20px;
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 7e903ca92..20d809232 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -1,15 +1,14 @@
 import React = require('react');
+import { action, computed, observable, ObservableMap, ObservableSet } from 'mobx';
 import { observer } from 'mobx-react';
 import { Doc } from '../../../../fields/Doc';
+import { List } from '../../../../fields/List';
+import { listSpec } from '../../../../fields/Schema';
+import { Cast } from '../../../../fields/Types';
 import { CollectionSubView } from '../CollectionSubView';
 import './CollectionSchemaView.scss';
-import { SchemaRowBox } from './SchemaRowBox';
-import { action, computed, observable } from 'mobx';
-import { BoolCast, Cast, StrCast } from '../../../../fields/Types';
-import { listSpec } from '../../../../fields/Schema';
 import { SchemaColumnHeader } from './SchemaColumnHeader';
-import { List } from '../../../../fields/List';
-import { dropActionType } from '../../../util/DragManager';
+import { SchemaRowBox } from './SchemaRowBox';
 
 export enum ColumnType {
     Number,
@@ -23,11 +22,10 @@ const defaultColumnKeys: string[] = ['title', 'type', 'author', 'text', 'data',
 
 @observer
 export class CollectionSchemaView extends CollectionSubView() {
-    isChildContentActive = () => (this.props.isDocumentActive?.() && (this.props.childDocumentsActive?.() || BoolCast(this.rootDoc.childDocumentsActive)) ? true : undefined);
+    private _lastSelectedRow: number | undefined;
 
-    @computed get layoutDoc() {
-        return Doc.Layout(this.props.Document);
-    }
+    @observable _rowMenuWidth: number = 60;
+    @observable _selectedDocs: ObservableSet = new ObservableSet<Doc>();
 
     @computed get columnKeys() {
         return Cast(this.props.Document.columnKeys, listSpec('string'), defaultColumnKeys);
@@ -37,7 +35,7 @@ export class CollectionSchemaView extends CollectionSubView() {
         return Cast(
             this.props.Document.columnWidths,
             listSpec('number'),
-            this.columnKeys.map(() => (this.props.PanelWidth() - 100) / this.columnKeys.length)
+            this.columnKeys.map(() => (this.props.PanelWidth() - this._rowMenuWidth) / this.columnKeys.length)
         );
     }
 
@@ -49,6 +47,30 @@ export class CollectionSchemaView extends CollectionSubView() {
         return true;
     };
 
+    @action
+    selectRow = (doc: Doc, ctrl?: boolean, shift?: boolean) => {
+        if (shift && this._lastSelectedRow !== undefined) {
+            const currSelectedRow = this.childDocs.indexOf(doc);
+            const startRow = Math.min(this._lastSelectedRow, currSelectedRow);
+            const endRow = Math.max(this._lastSelectedRow, currSelectedRow);
+            for (let i = startRow; i <= endRow; i++) {
+                const currDoc = this.childDocs[i];
+                if (!this._selectedDocs.has(currDoc)) this._selectedDocs.add(currDoc);
+            }
+        } else if (ctrl) {
+            if (!this._selectedDocs.has(doc)) {
+                this._selectedDocs.add(doc);
+                this._lastSelectedRow = this.childDocs.indexOf(doc);
+            } else {
+                this._selectedDocs.delete(doc);
+            }
+        } else {
+            this._selectedDocs.clear();
+            this._selectedDocs.add(doc);
+            this._lastSelectedRow = this.childDocs.indexOf(doc);
+        }
+    };
+
     render() {
         return (
             <div className="collectionSchemaView">
@@ -63,17 +85,13 @@ export class CollectionSchemaView extends CollectionSubView() {
                             <SchemaRowBox
                                 {...this.props}
                                 Document={doc}
-                                renderDepth={this.props.renderDepth + 1}
-                                isContentActive={this.isChildContentActive}
-                                rootSelected={this.rootSelected}
-                                dropAction={StrCast(this.layoutDoc.childDropAction) as dropActionType}
-                                docFilters={this.childDocFilters}
-                                docRangeFilters={this.childDocRangeFilters}
-                                searchFilterDocs={this.searchFilterDocs}
                                 ContainingCollectionDoc={this.props.CollectionView?.props.Document}
                                 ContainingCollectionView={this.props.CollectionView}
                                 columnKeys={this.columnKeys}
                                 columnWidths={this.columnWidths}
+                                rowMenuWidth={this._rowMenuWidth}
+                                selectedRows={this._selectedDocs}
+                                selectRow={this.selectRow}
                             />
                         ))}
                     </div>
@@ -82,6 +100,3 @@ export class CollectionSchemaView extends CollectionSubView() {
         );
     }
 }
-function DocListCast(childDocs: Doc[]): any {
-    throw new Error('Function not implemented.');
-}
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 50e2502dc..33f4e0bfc 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -1,25 +1,42 @@
 import React = require('react');
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { action, ObservableMap, ObservableSet } from 'mobx';
 import { observer } from 'mobx-react';
-import './CollectionSchemaView.scss';
-import { ViewBoxAnnotatableComponent, ViewBoxBaseComponent } from '../../DocComponent';
+import { Doc } from '../../../../fields/Doc';
+import { undoBatch } from '../../../util/UndoManager';
+import { ViewBoxBaseComponent } from '../../DocComponent';
+import { Colors } from '../../global/globalEnums';
 import { FieldViewProps } from '../../nodes/FieldView';
+import './CollectionSchemaView.scss';
 import { SchemaTableCell } from './SchemaTableCell';
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { undoBatch } from '../../../util/UndoManager';
 
 export interface SchemaRowBoxProps extends FieldViewProps {
     columnKeys: string[];
     columnWidths: number[];
+    rowMenuWidth: number;
+    selectedRows: ObservableSet<Doc>;
+    selectRow: (doc: Doc, cmd?: boolean, shift?: boolean) => void;
 }
 
 @observer
-export class SchemaRowBox extends ViewBoxAnnotatableComponent<SchemaRowBoxProps>() {
+export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
+    isSelected = () => this.props.selectedRows.has(this.props.Document);
+
+    @action
+    onRowPointerDown = (e: React.PointerEvent) => {
+        e.stopPropagation();
+        this.props.selectRow(this.props.Document, e.ctrlKey || e.metaKey, e.shiftKey);
+    }
+
     render() {
         return (
-            <div className="schema-row" /*style={this.props.isSelected() ? { backgroundColor: 'grey' } : {}}*/>
-                <div className="row-menu">
-                    <div className="row-button" onPointerDown={undoBatch(() => this.props.removeDocument?.(this.props.Document))}>
-                        <FontAwesomeIcon icon={'times'} />
+            <div className="schema-row" style={this.isSelected() ? { backgroundColor: Colors.LIGHT_BLUE } : {}} onPointerDown={this.onRowPointerDown}>
+                <div className="row-menu" style={{width: this.props.rowMenuWidth}}>
+                    <div className="row-button" onPointerDown={undoBatch((e) => {e.stopPropagation(); this.props.removeDocument?.(this.props.Document)})}>
+                        <FontAwesomeIcon icon="times" />
+                    </div>
+                    <div className="row-button" onPointerDown={(e) => {e.stopPropagation(); this.props.addDocTab(this.props.Document, 'add:right')}}>
+                        <FontAwesomeIcon icon="external-link-alt" />
                     </div>
                 </div>
                 <div className="row-cells">
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index 8437736ae..7bbd7c055 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -18,6 +18,7 @@ import { ContextMenuProps } from '../ContextMenuItem';
 import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent';
 import './AudioBox.scss';
 import { FieldView, FieldViewProps } from './FieldView';
+import { SelectionManager } from '../../util/SelectionManager';
 
 /**
  * AudioBox
-- 
cgit v1.2.3-70-g09d2


From 5c4b22b50e4693419daac777669b258b155f6ea9 Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Thu, 11 Aug 2022 13:08:56 -0400
Subject: bad dragging code in progress

---
 .../collectionSchema/CollectionSchemaView.tsx      | 75 ++++++++++++++++++++--
 .../collections/collectionSchema/SchemaRowBox.tsx  | 53 ++++++++++++++-
 2 files changed, 119 insertions(+), 9 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaRowBox.tsx')

diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 20d809232..9ca1644e3 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -9,6 +9,10 @@ import { CollectionSubView } from '../CollectionSubView';
 import './CollectionSchemaView.scss';
 import { SchemaColumnHeader } from './SchemaColumnHeader';
 import { SchemaRowBox } from './SchemaRowBox';
+import { DragManager } from '../../../util/DragManager';
+import { PresBox } from '../../nodes/trails/PresBox';
+import { UndoManager } from '../../../util/UndoManager';
+import { returnFalse } from '../../../../Utils';
 
 export enum ColumnType {
     Number,
@@ -25,7 +29,8 @@ export class CollectionSchemaView extends CollectionSubView() {
     private _lastSelectedRow: number | undefined;
 
     @observable _rowMenuWidth: number = 60;
-    @observable _selectedDocs: ObservableSet = new ObservableSet<Doc>();
+    @observable _selectedDocs: ObservableSet = new ObservableSet<SchemaRowBox>();
+    @observable _isDragging: boolean = false;
 
     @computed get columnKeys() {
         return Cast(this.props.Document.columnKeys, listSpec('string'), defaultColumnKeys);
@@ -48,15 +53,18 @@ export class CollectionSchemaView extends CollectionSubView() {
     };
 
     @action
-    selectRow = (doc: Doc, ctrl?: boolean, shift?: boolean) => {
+    selectRow = (e: React.PointerEvent, doc: Doc) => {
+        const ctrl = e.ctrlKey || e.metaKey;
+        const shift = e.shiftKey;
         if (shift && this._lastSelectedRow !== undefined) {
-            const currSelectedRow = this.childDocs.indexOf(doc);
-            const startRow = Math.min(this._lastSelectedRow, currSelectedRow);
-            const endRow = Math.max(this._lastSelectedRow, currSelectedRow);
+            const currRowIndex = this.childDocs.indexOf(doc);
+            const startRow = Math.min(this._lastSelectedRow, currRowIndex);
+            const endRow = Math.max(this._lastSelectedRow, currRowIndex);
             for (let i = startRow; i <= endRow; i++) {
-                const currDoc = this.childDocs[i];
+                const currDoc: Doc = this.childDocs[i];
                 if (!this._selectedDocs.has(currDoc)) this._selectedDocs.add(currDoc);
             }
+            this._lastSelectedRow = endRow;
         } else if (ctrl) {
             if (!this._selectedDocs.has(doc)) {
                 this._selectedDocs.add(doc);
@@ -71,6 +79,58 @@ export class CollectionSchemaView extends CollectionSubView() {
         }
     };
 
+    @action
+    sortedSelectedDocs = (): Doc[] => {
+        return this.childDocs.filter(doc => this._selectedDocs.has(doc));
+    };
+
+    @action.bound
+    moveDocument = (document: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => {
+        console.log('hello');
+        console.log(targetCollection?.title);
+        if (Doc.AreProtosEqual(this.props.Document, targetCollection)) {
+            console.log('hi');
+            return true;
+        }
+        const first = document instanceof Doc ? document : document[0];
+        if (!first?._stayInCollection && addDocument !== returnFalse) {
+            UndoManager.RunInTempBatch(() => this.props.removeDocument?.(document) && addDocument(document));
+            return true;
+        }
+        return false;
+    };
+
+    @action
+    startDrag = (e: React.PointerEvent, doc: Doc) => {
+        if (this._selectedDocs.size === 0) this._selectedDocs.add(doc);
+        this._isDragging = true;
+        const dragData = new DragManager.DocumentDragData(this.sortedSelectedDocs(), 'move');
+        dragData.moveDocument = this.moveDocument;
+        const dragItem: HTMLElement[] = [];
+        const dragDiv = document.createElement('div');
+        dragDiv.className = 'presItem-multiDrag';
+        dragDiv.innerText = 'Move ' + this._selectedDocs.size + '  rows';
+        dragDiv.style.position = 'absolute';
+        dragDiv.style.top = e.clientY + 'px';
+        dragDiv.style.left = e.clientX - 50 + 'px';
+        dragItem.push(dragDiv);
+
+        DragManager.StartDocumentDrag(
+            dragItem.map(ele => ele),
+            dragData,
+            e.clientX,
+            e.clientY,
+            undefined
+        );
+        this._isDragging = false;
+        return true;
+    };
+
+    @action
+    endDrag = (e: React.PointerEvent) => {
+        // this._isDragging = false;
+    };
+
     render() {
         return (
             <div className="collectionSchemaView">
@@ -92,6 +152,9 @@ export class CollectionSchemaView extends CollectionSubView() {
                                 rowMenuWidth={this._rowMenuWidth}
                                 selectedRows={this._selectedDocs}
                                 selectRow={this.selectRow}
+                                startDrag={this.startDrag}
+                                endDrag={this.endDrag}
+                                dragging={this._isDragging}
                             />
                         ))}
                     </div>
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 33f4e0bfc..0065a0938 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -9,28 +9,75 @@ import { Colors } from '../../global/globalEnums';
 import { FieldViewProps } from '../../nodes/FieldView';
 import './CollectionSchemaView.scss';
 import { SchemaTableCell } from './SchemaTableCell';
+import { emptyFunction, setupMoveUpEvents } from '../../../../Utils';
+import { DragManager } from '../../../util/DragManager';
 
 export interface SchemaRowBoxProps extends FieldViewProps {
     columnKeys: string[];
     columnWidths: number[];
     rowMenuWidth: number;
     selectedRows: ObservableSet<Doc>;
-    selectRow: (doc: Doc, cmd?: boolean, shift?: boolean) => void;
+    selectRow: (e: any, doc: Doc) => void;
+    startDrag: (e: any, doc: Doc) => boolean;
+    endDrag: (e: any) => void
+    dragging: boolean;
 }
 
 @observer
 export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
+    private _ref: HTMLDivElement | null = null;
+
     isSelected = () => this.props.selectedRows.has(this.props.Document);
+    bounds = () => this._ref?.getBoundingClientRect();
 
     @action
     onRowPointerDown = (e: React.PointerEvent) => {
         e.stopPropagation();
-        this.props.selectRow(this.props.Document, e.ctrlKey || e.metaKey, e.shiftKey);
+
+        setupMoveUpEvents(
+            this, e,
+            (e) => this.props.startDrag(e, this.props.Document),
+            emptyFunction,
+            (e) => this.props.selectRow(e, this.props.Document)
+        )
     }
 
+    onPointerEnter = (e: any) => {
+        document.removeEventListener('pointermove', this.onPointerMove);
+        document.addEventListener('pointermove', this.onPointerMove);
+    };
+
+    onPointerMove = (e: any) => {
+        let dragIsRow: boolean = true;
+        DragManager.docsBeingDragged.forEach(doc => {
+            dragIsRow = this.props.selectedRows.has(doc);
+        })
+        if (this._ref && dragIsRow) {
+            const rect = this._ref.getBoundingClientRect();
+            const y = e.clientY - rect.top; //y position within the element.
+            const height = this._ref.clientHeight;
+            const halfLine = height / 2;
+            if (y <= halfLine) {
+                this._ref.style.borderTop = `solid 2px ${Colors.MEDIUM_BLUE}`;
+                this._ref.style.borderBottom = '0px';
+            } else if (y > halfLine) {
+                this._ref.style.borderTop = '0px';
+                this._ref.style.borderBottom = `solid 2px ${Colors.MEDIUM_BLUE}`;
+            }
+        }
+    };
+
+    onPointerLeave = (e: any) => {
+        if (this._ref) {
+            this._ref.style.borderTop = '0px';
+            this._ref.style.borderBottom = '0px';
+        }
+        document.removeEventListener('pointermove', this.onPointerMove);
+    };
+
     render() {
         return (
-            <div className="schema-row" style={this.isSelected() ? { backgroundColor: Colors.LIGHT_BLUE } : {}} onPointerDown={this.onRowPointerDown}>
+            <div className="schema-row" style={this.isSelected() ? { backgroundColor: Colors.LIGHT_BLUE, opacity: this.props.dragging ? 0.5 : 1} : {}} onPointerDown={this.onRowPointerDown} onPointerEnter={this.onPointerEnter} onPointerLeave={this.onPointerLeave} ref={(row: HTMLDivElement | null) => (this._ref = row)}>
                 <div className="row-menu" style={{width: this.props.rowMenuWidth}}>
                     <div className="row-button" onPointerDown={undoBatch((e) => {e.stopPropagation(); this.props.removeDocument?.(this.props.Document)})}>
                         <FontAwesomeIcon icon="times" />
-- 
cgit v1.2.3-70-g09d2


From ee77b8ff032d4b06c2f0b6ac8153a32e54ab8355 Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Thu, 11 Aug 2022 14:28:09 -0400
Subject: drag and drop rows works, needs cleaning up

---
 .../collectionSchema/CollectionSchemaView.scss     |  1 +
 .../collectionSchema/CollectionSchemaView.tsx      | 78 ++++++++++++----------
 .../collections/collectionSchema/SchemaRowBox.tsx  | 14 +++-
 3 files changed, 54 insertions(+), 39 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaRowBox.tsx')

diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
index 0f4053127..5ead99c02 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
@@ -2,6 +2,7 @@
 
 .collectionSchemaView {
     cursor: default;
+    height: 100%;
 
     .schema-table {
         background-color: $white;
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 9ca1644e3..dc0cd8eac 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -1,18 +1,15 @@
 import React = require('react');
-import { action, computed, observable, ObservableMap, ObservableSet } from 'mobx';
+import { action, computed, observable, ObservableSet } from 'mobx';
 import { observer } from 'mobx-react';
 import { Doc } from '../../../../fields/Doc';
 import { List } from '../../../../fields/List';
 import { listSpec } from '../../../../fields/Schema';
 import { Cast } from '../../../../fields/Types';
+import { DragManager } from '../../../util/DragManager';
 import { CollectionSubView } from '../CollectionSubView';
 import './CollectionSchemaView.scss';
 import { SchemaColumnHeader } from './SchemaColumnHeader';
 import { SchemaRowBox } from './SchemaRowBox';
-import { DragManager } from '../../../util/DragManager';
-import { PresBox } from '../../nodes/trails/PresBox';
-import { UndoManager } from '../../../util/UndoManager';
-import { returnFalse } from '../../../../Utils';
 
 export enum ColumnType {
     Number,
@@ -26,9 +23,12 @@ const defaultColumnKeys: string[] = ['title', 'type', 'author', 'text', 'data',
 
 @observer
 export class CollectionSchemaView extends CollectionSubView() {
+    private _ref: HTMLDivElement | null = null;
     private _lastSelectedRow: number | undefined;
+    private _selectedDocSortedArray: Doc[] = [];
+    private _closestDropIndex: number = 0;
 
-    @observable _rowMenuWidth: number = 60;
+    @observable _rowMenuWidth: number = 100;
     @observable _selectedDocs: ObservableSet = new ObservableSet<SchemaRowBox>();
     @observable _isDragging: boolean = false;
 
@@ -53,13 +53,12 @@ export class CollectionSchemaView extends CollectionSubView() {
     };
 
     @action
-    selectRow = (e: React.PointerEvent, doc: Doc) => {
+    selectRow = (e: React.PointerEvent, doc: Doc, index: number) => {
         const ctrl = e.ctrlKey || e.metaKey;
         const shift = e.shiftKey;
         if (shift && this._lastSelectedRow !== undefined) {
-            const currRowIndex = this.childDocs.indexOf(doc);
-            const startRow = Math.min(this._lastSelectedRow, currRowIndex);
-            const endRow = Math.max(this._lastSelectedRow, currRowIndex);
+            const startRow = Math.min(this._lastSelectedRow, index);
+            const endRow = Math.max(this._lastSelectedRow, index);
             for (let i = startRow; i <= endRow; i++) {
                 const currDoc: Doc = this.childDocs[i];
                 if (!this._selectedDocs.has(currDoc)) this._selectedDocs.add(currDoc);
@@ -68,14 +67,14 @@ export class CollectionSchemaView extends CollectionSubView() {
         } else if (ctrl) {
             if (!this._selectedDocs.has(doc)) {
                 this._selectedDocs.add(doc);
-                this._lastSelectedRow = this.childDocs.indexOf(doc);
+                this._lastSelectedRow = index;
             } else {
                 this._selectedDocs.delete(doc);
             }
         } else {
             this._selectedDocs.clear();
             this._selectedDocs.add(doc);
-            this._lastSelectedRow = this.childDocs.indexOf(doc);
+            this._lastSelectedRow = index;
         }
     };
 
@@ -84,17 +83,19 @@ export class CollectionSchemaView extends CollectionSubView() {
         return this.childDocs.filter(doc => this._selectedDocs.has(doc));
     };
 
-    @action.bound
-    moveDocument = (document: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => {
-        console.log('hello');
-        console.log(targetCollection?.title);
-        if (Doc.AreProtosEqual(this.props.Document, targetCollection)) {
-            console.log('hi');
-            return true;
-        }
-        const first = document instanceof Doc ? document : document[0];
-        if (!first?._stayInCollection && addDocument !== returnFalse) {
-            UndoManager.RunInTempBatch(() => this.props.removeDocument?.(document) && addDocument(document));
+    setDropIndex = (index: number) => {
+        this._closestDropIndex = index;
+    };
+
+    @action
+    onInternalDrop = (e: Event, de: DragManager.DropEvent) => {
+        if (super.onInternalDrop(e, de)) {
+            this._isDragging = false;
+            const pushedDocs: Doc[] = this.childDocs.filter((doc: Doc, index: number) => index >= this._closestDropIndex && !this._selectedDocs.has(doc));
+            this.props.removeDocument?.(pushedDocs);
+            this.props.removeDocument?.(this._selectedDocSortedArray);
+            this.addDocument(this._selectedDocSortedArray);
+            this.addDocument(pushedDocs);
             return true;
         }
         return false;
@@ -102,14 +103,18 @@ export class CollectionSchemaView extends CollectionSubView() {
 
     @action
     startDrag = (e: React.PointerEvent, doc: Doc) => {
-        if (this._selectedDocs.size === 0) this._selectedDocs.add(doc);
+        if (!this._selectedDocs.has(doc)) {
+            this._selectedDocs.clear();
+            this._selectedDocs.add(doc);
+        }
         this._isDragging = true;
-        const dragData = new DragManager.DocumentDragData(this.sortedSelectedDocs(), 'move');
-        dragData.moveDocument = this.moveDocument;
+        this._selectedDocSortedArray = this.sortedSelectedDocs();
+        const dragData = new DragManager.DocumentDragData(this._selectedDocSortedArray, 'move');
+        dragData.moveDocument = this.props.moveDocument;
         const dragItem: HTMLElement[] = [];
         const dragDiv = document.createElement('div');
         dragDiv.className = 'presItem-multiDrag';
-        dragDiv.innerText = 'Move ' + this._selectedDocs.size + '  rows';
+        dragDiv.innerText = 'Move ' + this._selectedDocs.size + '  row' + (this._selectedDocs.size > 1 ? 's' : '');
         dragDiv.style.position = 'absolute';
         dragDiv.style.top = e.clientY + 'px';
         dragDiv.style.left = e.clientX - 50 + 'px';
@@ -122,18 +127,18 @@ export class CollectionSchemaView extends CollectionSubView() {
             e.clientY,
             undefined
         );
-        this._isDragging = false;
         return true;
     };
 
-    @action
-    endDrag = (e: React.PointerEvent) => {
-        // this._isDragging = false;
-    };
-
     render() {
         return (
-            <div className="collectionSchemaView">
+            <div
+                className="collectionSchemaView"
+                ref={(ele: HTMLDivElement | null) => {
+                    this._ref = ele;
+                    this.createDashEventsTarget(ele);
+                }}
+                onPointerDown={() => this._selectedDocs.clear()}>
                 <div className="schema-table">
                     <div className="schema-header-row">
                         {this.columnKeys.map((key, index) => (
@@ -141,20 +146,21 @@ export class CollectionSchemaView extends CollectionSubView() {
                         ))}
                     </div>
                     <div className="schema-table-content">
-                        {this.childDocs.map((doc: Doc) => (
+                        {this.childDocs.map((doc: Doc, index: number) => (
                             <SchemaRowBox
                                 {...this.props}
                                 Document={doc}
                                 ContainingCollectionDoc={this.props.CollectionView?.props.Document}
                                 ContainingCollectionView={this.props.CollectionView}
+                                rowIndex={index}
                                 columnKeys={this.columnKeys}
                                 columnWidths={this.columnWidths}
                                 rowMenuWidth={this._rowMenuWidth}
                                 selectedRows={this._selectedDocs}
                                 selectRow={this.selectRow}
                                 startDrag={this.startDrag}
-                                endDrag={this.endDrag}
                                 dragging={this._isDragging}
+                                dropIndex={this.setDropIndex}
                             />
                         ))}
                     </div>
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 0065a0938..8b658d834 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -13,14 +13,15 @@ import { emptyFunction, setupMoveUpEvents } from '../../../../Utils';
 import { DragManager } from '../../../util/DragManager';
 
 export interface SchemaRowBoxProps extends FieldViewProps {
+    rowIndex: number;
     columnKeys: string[];
     columnWidths: number[];
     rowMenuWidth: number;
     selectedRows: ObservableSet<Doc>;
-    selectRow: (e: any, doc: Doc) => void;
+    selectRow: (e: any, doc: Doc, index: number) => void;
     startDrag: (e: any, doc: Doc) => boolean;
-    endDrag: (e: any) => void
     dragging: boolean;
+    dropIndex: (index: number) => void;
 }
 
 @observer
@@ -38,16 +39,18 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
             this, e,
             (e) => this.props.startDrag(e, this.props.Document),
             emptyFunction,
-            (e) => this.props.selectRow(e, this.props.Document)
+            (e) => this.props.selectRow(e, this.props.Document, this.props.rowIndex)
         )
     }
 
     onPointerEnter = (e: any) => {
+        if (!this.props.dragging) return;
         document.removeEventListener('pointermove', this.onPointerMove);
         document.addEventListener('pointermove', this.onPointerMove);
     };
 
     onPointerMove = (e: any) => {
+        if (!this.props.dragging) return;
         let dragIsRow: boolean = true;
         DragManager.docsBeingDragged.forEach(doc => {
             dragIsRow = this.props.selectedRows.has(doc);
@@ -60,9 +63,11 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
             if (y <= halfLine) {
                 this._ref.style.borderTop = `solid 2px ${Colors.MEDIUM_BLUE}`;
                 this._ref.style.borderBottom = '0px';
+                this.props.dropIndex(this.props.rowIndex);
             } else if (y > halfLine) {
                 this._ref.style.borderTop = '0px';
                 this._ref.style.borderBottom = `solid 2px ${Colors.MEDIUM_BLUE}`;
+                this.props.dropIndex(this.props.rowIndex + 1);
             }
         }
     };
@@ -85,6 +90,9 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
                     <div className="row-button" onPointerDown={(e) => {e.stopPropagation(); this.props.addDocTab(this.props.Document, 'add:right')}}>
                         <FontAwesomeIcon icon="external-link-alt" />
                     </div>
+                    <div className="row-button">
+                        {this.props.rowIndex}
+                    </div>
                 </div>
                 <div className="row-cells">
                     {this.props.columnKeys.map((key, index) => (
-- 
cgit v1.2.3-70-g09d2


From d0d10426510e1bc8397eea927a65714b5b48f966 Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Mon, 15 Aug 2022 22:36:56 -0400
Subject: add new doc as schema row

---
 .../collectionSchema/CollectionSchemaView.scss     |  11 ++-
 .../collectionSchema/CollectionSchemaView.tsx      | 107 ++++++++++++++++++++-
 .../collections/collectionSchema/SchemaRowBox.tsx  |   7 +-
 3 files changed, 111 insertions(+), 14 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaRowBox.tsx')

diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
index 5ead99c02..4f644717b 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
@@ -31,7 +31,7 @@
         }
 
         .schema-row {
-            justify-content: space-evenly;
+            justify-content: flex-end;
 
             .row-menu {
                 display: flex;
@@ -39,13 +39,16 @@
                 justify-content: center;
 
                 .row-button {
-                    width: 20px;
-                    height: 20px;
+                    width: 25px;
+                    height: 25px;
                     border-radius: 100%;
                     background-color: $dark-gray;
                     color: white;
-                    padding: 5px;
+                    margin: 3px;
                     cursor: pointer;
+                    display: flex;
+                    align-items: center;
+                    justify-content: center;
                 }
             }
 
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index dc0cd8eac..02bc55e7a 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -1,15 +1,26 @@
 import React = require('react');
 import { action, computed, observable, ObservableSet } from 'mobx';
 import { observer } from 'mobx-react';
-import { Doc } from '../../../../fields/Doc';
+import { Doc, DocListCast } from '../../../../fields/Doc';
 import { List } from '../../../../fields/List';
 import { listSpec } from '../../../../fields/Schema';
-import { Cast } from '../../../../fields/Types';
+import { Cast, StrCast } from '../../../../fields/Types';
 import { DragManager } from '../../../util/DragManager';
 import { CollectionSubView } from '../CollectionSubView';
 import './CollectionSchemaView.scss';
 import { SchemaColumnHeader } from './SchemaColumnHeader';
 import { SchemaRowBox } from './SchemaRowBox';
+import { SelectionManager } from '../../../util/SelectionManager';
+import { undoBatch } from '../../../util/UndoManager';
+import { EditableView } from '../../EditableView';
+import { returnEmptyString } from '../../../../Utils';
+import { Docs, DocUtils } from '../../../documents/Documents';
+import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox';
+import { ContextMenu } from '../../ContextMenu';
+import { ContextMenuProps } from '../../ContextMenuItem';
+import { Id } from '../../../../fields/FieldSymbols';
+import { RichTextField } from '../../../../fields/RichTextField';
+import { ImageField } from '../../../../fields/URLField';
 
 export enum ColumnType {
     Number,
@@ -33,18 +44,19 @@ export class CollectionSchemaView extends CollectionSubView() {
     @observable _isDragging: boolean = false;
 
     @computed get columnKeys() {
-        return Cast(this.props.Document.columnKeys, listSpec('string'), defaultColumnKeys);
+        return Cast(this.layoutDoc.columnKeys, listSpec('string'), defaultColumnKeys);
     }
 
     @computed get columnWidths() {
         return Cast(
-            this.props.Document.columnWidths,
+            this.layoutDoc.columnWidths,
             listSpec('number'),
             this.columnKeys.map(() => (this.props.PanelWidth() - this._rowMenuWidth) / this.columnKeys.length)
         );
     }
 
     @action
+    @undoBatch
     changeColumnKey = (index: number, newKey: string) => {
         let currKeys = this.columnKeys;
         currKeys[index] = newKey;
@@ -76,6 +88,13 @@ export class CollectionSchemaView extends CollectionSubView() {
             this._selectedDocs.add(doc);
             this._lastSelectedRow = index;
         }
+        
+        if (this._lastSelectedRow && this._selectedDocs.size > 0) {
+            SelectionManager.SelectSchemaViewDoc(this.childDocs[this._lastSelectedRow]);
+        }
+        else {
+            SelectionManager.SelectSchemaViewDoc(undefined);
+        }
     };
 
     @action
@@ -106,6 +125,8 @@ export class CollectionSchemaView extends CollectionSubView() {
         if (!this._selectedDocs.has(doc)) {
             this._selectedDocs.clear();
             this._selectedDocs.add(doc);
+            this._lastSelectedRow = this.childDocs.indexOf(doc);
+            SelectionManager.SelectSchemaViewDoc(doc);
         }
         this._isDragging = true;
         this._selectedDocSortedArray = this.sortedSelectedDocs();
@@ -130,6 +151,83 @@ export class CollectionSchemaView extends CollectionSubView() {
         return true;
     };
 
+    @action
+    addNewTextDoc = (value: string, shiftDown?: boolean, forceEmptyNote?: boolean) => {
+        if (!value && !forceEmptyNote) return false;
+        const newDoc = Docs.Create.TextDocument(value, {title: value});
+        FormattedTextBox.SelectOnLoad = newDoc[Id];
+        FormattedTextBox.SelectOnLoadChar = forceEmptyNote ? '' : ' ';
+        return this.props.addDocument?.(newDoc) || false;
+    };
+
+    menuCallback = (x: number, y: number) => {
+        ContextMenu.Instance.clearItems();
+        const layoutItems: ContextMenuProps[] = [];
+        const docItems: ContextMenuProps[] = [];
+        const dataDoc = this.props.DataDoc || this.props.Document;
+
+        DocUtils.addDocumentCreatorMenuItems(
+            doc => {
+                FormattedTextBox.SelectOnLoad = StrCast(doc[Id]);
+                return this.addDocument(doc);
+            },
+            this.addDocument,
+            x,
+            y,
+            true
+        );
+
+        Array.from(Object.keys(Doc.GetProto(dataDoc)))
+            .filter(fieldKey => dataDoc[fieldKey] instanceof RichTextField || dataDoc[fieldKey] instanceof ImageField || typeof dataDoc[fieldKey] === 'string')
+            .map(fieldKey =>
+                docItems.push({
+                    description: ':' + fieldKey,
+                    event: () => {
+                        const created = DocUtils.DocumentFromField(dataDoc, fieldKey, Doc.GetProto(this.props.Document));
+                        if (created) {
+                            if (this.props.Document.isTemplateDoc) {
+                                Doc.MakeMetadataFieldTemplate(created, this.props.Document);
+                            }
+                            return this.props.addDocument?.(created);
+                        }
+                    },
+                    icon: 'compress-arrows-alt',
+                })
+            );
+        Array.from(Object.keys(Doc.GetProto(dataDoc)))
+            .filter(fieldKey => DocListCast(dataDoc[fieldKey]).length)
+            .map(fieldKey =>
+                docItems.push({
+                    description: ':' + fieldKey,
+                    event: () => {
+                        const created = Docs.Create.CarouselDocument([], { _width: 400, _height: 200, title: fieldKey });
+                        if (created) {
+                            const container = this.props.Document.resolvedDataDoc ? Doc.GetProto(this.props.Document) : this.props.Document;
+                            if (container.isTemplateDoc) {
+                                Doc.MakeMetadataFieldTemplate(created, container);
+                                return Doc.AddDocToList(container, Doc.LayoutFieldKey(container), created);
+                            }
+                            return this.props.addDocument?.(created) || false;
+                        }
+                    },
+                    icon: 'compress-arrows-alt',
+                })
+            );
+        !Doc.noviceMode && ContextMenu.Instance.addItem({ description: 'Doc Fields ...', subitems: docItems, icon: 'eye' });
+        !Doc.noviceMode && ContextMenu.Instance.addItem({ description: 'Containers ...', subitems: layoutItems, icon: 'eye' });
+        ContextMenu.Instance.setDefaultItem('::', (name: string): void => {
+            Doc.GetProto(this.props.Document)[name] = '';
+            const created = Docs.Create.TextDocument('', { title: name, _width: 250, _autoHeight: true });
+            if (created) {
+                if (this.props.Document.isTemplateDoc) {
+                    Doc.MakeMetadataFieldTemplate(created, this.props.Document);
+                }
+                this.props.addDocument?.(created);
+            }
+        });
+        ContextMenu.Instance.displayMenu(x, y, undefined, true);
+    };
+
     render() {
         return (
             <div
@@ -165,6 +263,7 @@ export class CollectionSchemaView extends CollectionSubView() {
                         ))}
                     </div>
                 </div>
+                <EditableView GetValue={returnEmptyString} SetValue={this.addNewTextDoc} placeholder={"Type ':' for commands"} contents={'+ New Node'} menuCallback={this.menuCallback} />
             </div>
         );
     }
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 8b658d834..ea2ebed7a 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -90,14 +90,9 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
                     <div className="row-button" onPointerDown={(e) => {e.stopPropagation(); this.props.addDocTab(this.props.Document, 'add:right')}}>
                         <FontAwesomeIcon icon="external-link-alt" />
                     </div>
-                    <div className="row-button">
-                        {this.props.rowIndex}
-                    </div>
                 </div>
                 <div className="row-cells">
-                    {this.props.columnKeys.map((key, index) => (
-                        <SchemaTableCell Document={this.props.Document} key={key} fieldKey={key} columnWidth={this.props.columnWidths[index]} />
-                    ))}
+                    {this.props.columnKeys.map((key, index) => (<SchemaTableCell Document={this.props.Document} fieldKey={key} columnWidth={this.props.columnWidths[index]} />))}
                 </div>
             </div>
         );
-- 
cgit v1.2.3-70-g09d2


From a20a40b86bf5df9200218cb713f48e593c41b0ae Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Tue, 16 Aug 2022 17:28:33 -0400
Subject: got formatter to work

---
 package-lock.json                                  | 1349 +++++++-------------
 .../collectionSchema/CollectionSchemaView.tsx      |    7 +-
 .../collectionSchema/SchemaColumnHeader.tsx        |    5 +-
 .../collections/collectionSchema/SchemaRowBox.tsx  |   41 +-
 .../collectionSchema/SchemaTableCell.tsx           |    1 -
 5 files changed, 500 insertions(+), 903 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaRowBox.tsx')

diff --git a/package-lock.json b/package-lock.json
index cafeebd3e..da921592a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -5050,16 +5050,6 @@
             "integrity": "sha512-NJGVKPS81XejHcLhaLJS7plab0fK3slPh11mESeeDq2W4ZI5kUKK/LRRdVDvjJseojbPB7ZwjnyOybg3Igea/A==",
             "dev": true
         },
-        "d": {
-            "version": "1.0.1",
-            "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz",
-            "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==",
-            "dev": true,
-            "requires": {
-                "es5-ext": "^0.10.50",
-                "type": "^1.0.1"
-            }
-        },
         "d3-array": {
             "version": "2.12.1",
             "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz",
@@ -6112,8 +6102,8 @@
             "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw=="
         },
         "equation-editor-react": {
-            "version": "github:bobzel/equation-editor-react#75915e852b4b36a6a4cd3e1cbc80598da6b65227",
-            "from": "github:bobzel/equation-editor-react#useLocally",
+            "version": "git+ssh://git@github.com/bobzel/equation-editor-react.git#75915e852b4b36a6a4cd3e1cbc80598da6b65227",
+            "from": "equation-editor-react@github:bobzel/equation-editor-react#useLocally",
             "requires": {
                 "jquery": "^3.4.1",
                 "mathquill": "^0.10.1-a"
@@ -6210,9 +6200,9 @@
             }
         },
         "es5-ext": {
-            "version": "0.10.61",
-            "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.61.tgz",
-            "integrity": "sha512-yFhIqQAzu2Ca2I4SE2Au3rxVfmohU9Y7wqGR+s7+H7krk26NXhIRAZDgqd6xqjCEFUomDEA3/Bo/7fKmIkW1kA==",
+            "version": "0.10.62",
+            "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz",
+            "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==",
             "dev": true,
             "requires": {
                 "es6-iterator": "^2.0.3",
@@ -6229,6 +6219,18 @@
                 "d": "1",
                 "es5-ext": "^0.10.35",
                 "es6-symbol": "^3.1.1"
+            },
+            "dependencies": {
+                "d": {
+                    "version": "1.0.1",
+                    "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz",
+                    "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==",
+                    "dev": true,
+                    "requires": {
+                        "es5-ext": "^0.10.50",
+                        "type": "^1.0.1"
+                    }
+                }
             }
         },
         "es6-promise": {
@@ -6244,6 +6246,18 @@
             "requires": {
                 "d": "^1.0.1",
                 "ext": "^1.1.2"
+            },
+            "dependencies": {
+                "d": {
+                    "version": "1.0.1",
+                    "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz",
+                    "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==",
+                    "dev": true,
+                    "requires": {
+                        "es5-ext": "^0.10.50",
+                        "type": "^1.0.1"
+                    }
+                }
             }
         },
         "escalade": {
@@ -9500,14 +9514,14 @@
             "resolved": "https://registry.npmjs.org/image-size-stream/-/image-size-stream-1.1.0.tgz",
             "integrity": "sha512-N505B5FSy2Xf5l/Haef+99TwfJqTu40hnU560+rC0Cm6cxtwVz2yRFh9WpOk1YEjfv3dI0PgVYAH0hmXQmjDcw==",
             "requires": {
-                "image-size": "github:netroy/image-size#da2c863807a3e9602617bdd357b0de3ab4a064c1",
+                "image-size": "image-size@git+https://github.com/netroy/image-size#da2c863807a3e9602617bdd357b0de3ab4a064c1",
                 "readable-stream": "^1.0.33",
                 "tryit": "^1.0.1"
             },
             "dependencies": {
                 "image-size": {
-                    "version": "github:netroy/image-size#da2c863807a3e9602617bdd357b0de3ab4a064c1",
-                    "from": "github:netroy/image-size#da2c863807a3e9602617bdd357b0de3ab4a064c1"
+                    "version": "git+ssh://git@github.com/netroy/image-size.git#da2c863807a3e9602617bdd357b0de3ab4a064c1",
+                    "from": "image-size@git+https://github.com/netroy/image-size#da2c863807a3e9602617bdd357b0de3ab4a064c1"
                 },
                 "isarray": {
                     "version": "0.0.1",
@@ -12505,70 +12519,59 @@
                 },
                 "abbrev": {
                     "version": "1.1.1",
-                    "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
-                    "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
+                    "bundled": true
                 },
                 "agent-base": {
                     "version": "4.3.0",
-                    "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz",
-                    "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==",
+                    "bundled": true,
                     "requires": {
                         "es6-promisify": "^5.0.0"
                     }
                 },
                 "agentkeepalive": {
                     "version": "3.5.2",
-                    "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-3.5.2.tgz",
-                    "integrity": "sha512-e0L/HNe6qkQ7H19kTlRRqUibEAwDK5AFk6y3PtMsuut2VAH6+Q4xZml1tNDJD7kSAyqmbG/K08K5WEJYtUrSlQ==",
+                    "bundled": true,
                     "requires": {
                         "humanize-ms": "^1.2.1"
                     }
                 },
                 "ansi-align": {
                     "version": "2.0.0",
-                    "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-2.0.0.tgz",
-                    "integrity": "sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=",
+                    "bundled": true,
                     "requires": {
                         "string-width": "^2.0.0"
                     }
                 },
                 "ansi-regex": {
                     "version": "2.1.1",
-                    "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
-                    "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
+                    "bundled": true
                 },
                 "ansi-styles": {
                     "version": "3.2.1",
-                    "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
-                    "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+                    "bundled": true,
                     "requires": {
                         "color-convert": "^1.9.0"
                     }
                 },
                 "ansicolors": {
                     "version": "0.3.2",
-                    "resolved": "https://registry.npmjs.org/ansicolors/-/ansicolors-0.3.2.tgz",
-                    "integrity": "sha1-ZlWX3oap/+Oqm/vmyuXG6kJrSXk="
+                    "bundled": true
                 },
                 "ansistyles": {
                     "version": "0.1.3",
-                    "resolved": "https://registry.npmjs.org/ansistyles/-/ansistyles-0.1.3.tgz",
-                    "integrity": "sha1-XeYEFb2gcbs3EnhUyGT0GyMlRTk="
+                    "bundled": true
                 },
                 "aproba": {
                     "version": "2.0.0",
-                    "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz",
-                    "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ=="
+                    "bundled": true
                 },
                 "archy": {
                     "version": "1.0.0",
-                    "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz",
-                    "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA="
+                    "bundled": true
                 },
                 "are-we-there-yet": {
                     "version": "1.1.4",
-                    "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz",
-                    "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=",
+                    "bundled": true,
                     "requires": {
                         "delegates": "^1.0.0",
                         "readable-stream": "^2.0.6"
@@ -12576,8 +12579,7 @@
                     "dependencies": {
                         "readable-stream": {
                             "version": "2.3.6",
-                            "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
-                            "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+                            "bundled": true,
                             "requires": {
                                 "core-util-is": "~1.0.0",
                                 "inherits": "~2.0.3",
@@ -12590,8 +12592,7 @@
                         },
                         "string_decoder": {
                             "version": "1.1.1",
-                            "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
-                            "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+                            "bundled": true,
                             "requires": {
                                 "safe-buffer": "~5.1.0"
                             }
@@ -12600,46 +12601,38 @@
                 },
                 "asap": {
                     "version": "2.0.6",
-                    "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
-                    "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY="
+                    "bundled": true
                 },
                 "asn1": {
                     "version": "0.2.4",
-                    "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
-                    "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
+                    "bundled": true,
                     "requires": {
                         "safer-buffer": "~2.1.0"
                     }
                 },
                 "assert-plus": {
                     "version": "1.0.0",
-                    "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
-                    "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
+                    "bundled": true
                 },
                 "asynckit": {
                     "version": "0.4.0",
-                    "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
-                    "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
+                    "bundled": true
                 },
                 "aws-sign2": {
                     "version": "0.7.0",
-                    "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
-                    "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg="
+                    "bundled": true
                 },
                 "aws4": {
                     "version": "1.8.0",
-                    "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz",
-                    "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ=="
+                    "bundled": true
                 },
                 "balanced-match": {
                     "version": "1.0.0",
-                    "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
-                    "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
+                    "bundled": true
                 },
                 "bcrypt-pbkdf": {
                     "version": "1.0.2",
-                    "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
-                    "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
+                    "bundled": true,
                     "optional": true,
                     "requires": {
                         "tweetnacl": "^0.14.3"
@@ -12647,8 +12640,7 @@
                 },
                 "bin-links": {
                     "version": "1.1.8",
-                    "resolved": "https://registry.npmjs.org/bin-links/-/bin-links-1.1.8.tgz",
-                    "integrity": "sha512-KgmVfx+QqggqP9dA3iIc5pA4T1qEEEL+hOhOhNPaUm77OTrJoOXE/C05SJLNJe6m/2wUK7F1tDSou7n5TfCDzQ==",
+                    "bundled": true,
                     "requires": {
                         "bluebird": "^3.5.3",
                         "cmd-shim": "^3.0.0",
@@ -12660,13 +12652,11 @@
                 },
                 "bluebird": {
                     "version": "3.5.5",
-                    "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.5.tgz",
-                    "integrity": "sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w=="
+                    "bundled": true
                 },
                 "boxen": {
                     "version": "1.3.0",
-                    "resolved": "https://registry.npmjs.org/boxen/-/boxen-1.3.0.tgz",
-                    "integrity": "sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==",
+                    "bundled": true,
                     "requires": {
                         "ansi-align": "^2.0.0",
                         "camelcase": "^4.0.0",
@@ -12679,8 +12669,7 @@
                 },
                 "brace-expansion": {
                     "version": "1.1.11",
-                    "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
-                    "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+                    "bundled": true,
                     "requires": {
                         "balanced-match": "^1.0.0",
                         "concat-map": "0.0.1"
@@ -12688,28 +12677,23 @@
                 },
                 "buffer-from": {
                     "version": "1.0.0",
-                    "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.0.0.tgz",
-                    "integrity": "sha512-83apNb8KK0Se60UE1+4Ukbe3HbfELJ6UlI4ldtOGs7So4KD26orJM8hIY9lxdzP+UpItH1Yh/Y8GUvNFWFFRxA=="
+                    "bundled": true
                 },
                 "builtins": {
                     "version": "1.0.3",
-                    "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz",
-                    "integrity": "sha1-y5T662HIaWRR2zZTThQi+U8K7og="
+                    "bundled": true
                 },
                 "byline": {
                     "version": "5.0.0",
-                    "resolved": "https://registry.npmjs.org/byline/-/byline-5.0.0.tgz",
-                    "integrity": "sha1-dBxSFkaOrcRXsDQQEYrXfejB3bE="
+                    "bundled": true
                 },
                 "byte-size": {
                     "version": "5.0.1",
-                    "resolved": "https://registry.npmjs.org/byte-size/-/byte-size-5.0.1.tgz",
-                    "integrity": "sha512-/XuKeqWocKsYa/cBY1YbSJSWWqTi4cFgr9S6OyM7PBaPbr9zvNGwWP33vt0uqGhwDdN+y3yhbXVILEUpnwEWGw=="
+                    "bundled": true
                 },
                 "cacache": {
                     "version": "12.0.3",
-                    "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.3.tgz",
-                    "integrity": "sha512-kqdmfXEGFepesTuROHMs3MpFLWrPkSSpRqOw80RCflZXy/khxaArvFrQ7uJxSUduzAufc6G0g1VUCOZXxWavPw==",
+                    "bundled": true,
                     "requires": {
                         "bluebird": "^3.5.5",
                         "chownr": "^1.1.1",
@@ -12730,28 +12714,23 @@
                 },
                 "call-limit": {
                     "version": "1.1.1",
-                    "resolved": "https://registry.npmjs.org/call-limit/-/call-limit-1.1.1.tgz",
-                    "integrity": "sha512-5twvci5b9eRBw2wCfPtN0GmlR2/gadZqyFpPhOK6CvMFoFgA+USnZ6Jpu1lhG9h85pQ3Ouil3PfXWRD4EUaRiQ=="
+                    "bundled": true
                 },
                 "camelcase": {
                     "version": "4.1.0",
-                    "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz",
-                    "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0="
+                    "bundled": true
                 },
                 "capture-stack-trace": {
                     "version": "1.0.0",
-                    "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz",
-                    "integrity": "sha1-Sm+gc5nCa7pH8LJJa00PtAjFVQ0="
+                    "bundled": true
                 },
                 "caseless": {
                     "version": "0.12.0",
-                    "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
-                    "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
+                    "bundled": true
                 },
                 "chalk": {
                     "version": "2.4.1",
-                    "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz",
-                    "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==",
+                    "bundled": true,
                     "requires": {
                         "ansi-styles": "^3.2.1",
                         "escape-string-regexp": "^1.0.5",
@@ -12760,31 +12739,26 @@
                 },
                 "chownr": {
                     "version": "1.1.4",
-                    "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
-                    "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="
+                    "bundled": true
                 },
                 "ci-info": {
                     "version": "2.0.0",
-                    "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz",
-                    "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ=="
+                    "bundled": true
                 },
                 "cidr-regex": {
                     "version": "2.0.10",
-                    "resolved": "https://registry.npmjs.org/cidr-regex/-/cidr-regex-2.0.10.tgz",
-                    "integrity": "sha512-sB3ogMQXWvreNPbJUZMRApxuRYd+KoIo4RGQ81VatjmMW6WJPo+IJZ2846FGItr9VzKo5w7DXzijPLGtSd0N3Q==",
+                    "bundled": true,
                     "requires": {
                         "ip-regex": "^2.1.0"
                     }
                 },
                 "cli-boxes": {
                     "version": "1.0.0",
-                    "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz",
-                    "integrity": "sha1-T6kXw+WclKAEzWH47lCdplFocUM="
+                    "bundled": true
                 },
                 "cli-columns": {
                     "version": "3.1.2",
-                    "resolved": "https://registry.npmjs.org/cli-columns/-/cli-columns-3.1.2.tgz",
-                    "integrity": "sha1-ZzLZcpee/CrkRKHwjgj6E5yWoY4=",
+                    "bundled": true,
                     "requires": {
                         "string-width": "^2.0.0",
                         "strip-ansi": "^3.0.1"
@@ -12792,8 +12766,7 @@
                 },
                 "cli-table3": {
                     "version": "0.5.1",
-                    "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.5.1.tgz",
-                    "integrity": "sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw==",
+                    "bundled": true,
                     "requires": {
                         "colors": "^1.1.2",
                         "object-assign": "^4.1.0",
@@ -12802,8 +12775,7 @@
                 },
                 "cliui": {
                     "version": "5.0.0",
-                    "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
-                    "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==",
+                    "bundled": true,
                     "requires": {
                         "string-width": "^3.1.0",
                         "strip-ansi": "^5.2.0",
@@ -12812,18 +12784,15 @@
                     "dependencies": {
                         "ansi-regex": {
                             "version": "4.1.1",
-                            "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz",
-                            "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g=="
+                            "bundled": true
                         },
                         "is-fullwidth-code-point": {
                             "version": "2.0.0",
-                            "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
-                            "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="
+                            "bundled": true
                         },
                         "string-width": {
                             "version": "3.1.0",
-                            "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
-                            "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
+                            "bundled": true,
                             "requires": {
                                 "emoji-regex": "^7.0.1",
                                 "is-fullwidth-code-point": "^2.0.0",
@@ -12832,8 +12801,7 @@
                         },
                         "strip-ansi": {
                             "version": "5.2.0",
-                            "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
-                            "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+                            "bundled": true,
                             "requires": {
                                 "ansi-regex": "^4.1.0"
                             }
@@ -12842,13 +12810,11 @@
                 },
                 "clone": {
                     "version": "1.0.4",
-                    "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
-                    "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4="
+                    "bundled": true
                 },
                 "cmd-shim": {
                     "version": "3.0.3",
-                    "resolved": "https://registry.npmjs.org/cmd-shim/-/cmd-shim-3.0.3.tgz",
-                    "integrity": "sha512-DtGg+0xiFhQIntSBRzL2fRQBnmtAVwXIDo4Qq46HPpObYquxMaZS4sb82U9nH91qJrlosC1wa9gwr0QyL/HypA==",
+                    "bundled": true,
                     "requires": {
                         "graceful-fs": "^4.1.2",
                         "mkdirp": "~0.5.0"
@@ -12856,32 +12822,27 @@
                 },
                 "code-point-at": {
                     "version": "1.1.0",
-                    "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
-                    "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
+                    "bundled": true
                 },
                 "color-convert": {
                     "version": "1.9.1",
-                    "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz",
-                    "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==",
+                    "bundled": true,
                     "requires": {
                         "color-name": "^1.1.1"
                     }
                 },
                 "color-name": {
                     "version": "1.1.3",
-                    "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-                    "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
+                    "bundled": true
                 },
                 "colors": {
                     "version": "1.3.3",
-                    "resolved": "https://registry.npmjs.org/colors/-/colors-1.3.3.tgz",
-                    "integrity": "sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg==",
+                    "bundled": true,
                     "optional": true
                 },
                 "columnify": {
                     "version": "1.5.4",
-                    "resolved": "https://registry.npmjs.org/columnify/-/columnify-1.5.4.tgz",
-                    "integrity": "sha1-Rzfd8ce2mop8NAVweC6UfuyOeLs=",
+                    "bundled": true,
                     "requires": {
                         "strip-ansi": "^3.0.0",
                         "wcwidth": "^1.0.0"
@@ -12889,21 +12850,18 @@
                 },
                 "combined-stream": {
                     "version": "1.0.6",
-                    "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz",
-                    "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=",
+                    "bundled": true,
                     "requires": {
                         "delayed-stream": "~1.0.0"
                     }
                 },
                 "concat-map": {
                     "version": "0.0.1",
-                    "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
-                    "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
+                    "bundled": true
                 },
                 "concat-stream": {
                     "version": "1.6.2",
-                    "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
-                    "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
+                    "bundled": true,
                     "requires": {
                         "buffer-from": "^1.0.0",
                         "inherits": "^2.0.3",
@@ -12913,8 +12871,7 @@
                     "dependencies": {
                         "readable-stream": {
                             "version": "2.3.6",
-                            "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
-                            "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+                            "bundled": true,
                             "requires": {
                                 "core-util-is": "~1.0.0",
                                 "inherits": "~2.0.3",
@@ -12927,8 +12884,7 @@
                         },
                         "string_decoder": {
                             "version": "1.1.1",
-                            "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
-                            "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+                            "bundled": true,
                             "requires": {
                                 "safe-buffer": "~5.1.0"
                             }
@@ -12937,8 +12893,7 @@
                 },
                 "config-chain": {
                     "version": "1.1.12",
-                    "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz",
-                    "integrity": "sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==",
+                    "bundled": true,
                     "requires": {
                         "ini": "^1.3.4",
                         "proto-list": "~1.2.1"
@@ -12946,8 +12901,7 @@
                 },
                 "configstore": {
                     "version": "3.1.5",
-                    "resolved": "https://registry.npmjs.org/configstore/-/configstore-3.1.5.tgz",
-                    "integrity": "sha512-nlOhI4+fdzoK5xmJ+NY+1gZK56bwEaWZr8fYuXohZ9Vkc1o3a4T/R3M+yE/w7x/ZVJ1zF8c+oaOvF0dztdUgmA==",
+                    "bundled": true,
                     "requires": {
                         "dot-prop": "^4.2.1",
                         "graceful-fs": "^4.1.2",
@@ -12959,13 +12913,11 @@
                 },
                 "console-control-strings": {
                     "version": "1.1.0",
-                    "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
-                    "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4="
+                    "bundled": true
                 },
                 "copy-concurrently": {
                     "version": "1.0.5",
-                    "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz",
-                    "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==",
+                    "bundled": true,
                     "requires": {
                         "aproba": "^1.1.1",
                         "fs-write-stream-atomic": "^1.0.8",
@@ -12977,33 +12929,28 @@
                     "dependencies": {
                         "aproba": {
                             "version": "1.2.0",
-                            "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
-                            "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw=="
+                            "bundled": true
                         },
                         "iferr": {
                             "version": "0.1.5",
-                            "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz",
-                            "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE="
+                            "bundled": true
                         }
                     }
                 },
                 "core-util-is": {
                     "version": "1.0.2",
-                    "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
-                    "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
+                    "bundled": true
                 },
                 "create-error-class": {
                     "version": "3.0.2",
-                    "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz",
-                    "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=",
+                    "bundled": true,
                     "requires": {
                         "capture-stack-trace": "^1.0.0"
                     }
                 },
                 "cross-spawn": {
                     "version": "5.1.0",
-                    "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
-                    "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=",
+                    "bundled": true,
                     "requires": {
                         "lru-cache": "^4.0.1",
                         "shebang-command": "^1.2.0",
@@ -13012,8 +12959,7 @@
                     "dependencies": {
                         "lru-cache": {
                             "version": "4.1.5",
-                            "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
-                            "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==",
+                            "bundled": true,
                             "requires": {
                                 "pseudomap": "^1.0.2",
                                 "yallist": "^2.1.2"
@@ -13021,104 +12967,87 @@
                         },
                         "yallist": {
                             "version": "2.1.2",
-                            "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
-                            "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI="
+                            "bundled": true
                         }
                     }
                 },
                 "crypto-random-string": {
                     "version": "1.0.0",
-                    "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz",
-                    "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4="
+                    "bundled": true
                 },
                 "cyclist": {
                     "version": "0.2.2",
-                    "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-0.2.2.tgz",
-                    "integrity": "sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA="
+                    "bundled": true
                 },
                 "dashdash": {
                     "version": "1.14.1",
-                    "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
-                    "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
+                    "bundled": true,
                     "requires": {
                         "assert-plus": "^1.0.0"
                     }
                 },
                 "debug": {
                     "version": "3.1.0",
-                    "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
-                    "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
+                    "bundled": true,
                     "requires": {
                         "ms": "2.0.0"
                     },
                     "dependencies": {
                         "ms": {
                             "version": "2.0.0",
-                            "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-                            "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+                            "bundled": true
                         }
                     }
                 },
                 "debuglog": {
                     "version": "1.0.1",
-                    "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz",
-                    "integrity": "sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI="
+                    "bundled": true
                 },
                 "decamelize": {
                     "version": "1.2.0",
-                    "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
-                    "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA="
+                    "bundled": true
                 },
                 "decode-uri-component": {
                     "version": "0.2.0",
-                    "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
-                    "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU="
+                    "bundled": true
                 },
                 "deep-extend": {
                     "version": "0.6.0",
-                    "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
-                    "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="
+                    "bundled": true
                 },
                 "defaults": {
                     "version": "1.0.3",
-                    "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz",
-                    "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=",
+                    "bundled": true,
                     "requires": {
                         "clone": "^1.0.2"
                     }
                 },
                 "define-properties": {
                     "version": "1.1.3",
-                    "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
-                    "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==",
+                    "bundled": true,
                     "requires": {
                         "object-keys": "^1.0.12"
                     }
                 },
                 "delayed-stream": {
                     "version": "1.0.0",
-                    "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
-                    "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
+                    "bundled": true
                 },
                 "delegates": {
                     "version": "1.0.0",
-                    "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
-                    "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o="
+                    "bundled": true
                 },
                 "detect-indent": {
                     "version": "5.0.0",
-                    "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-5.0.0.tgz",
-                    "integrity": "sha1-OHHMCmoALow+Wzz38zYmRnXwa50="
+                    "bundled": true
                 },
                 "detect-newline": {
                     "version": "2.1.0",
-                    "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz",
-                    "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I="
+                    "bundled": true
                 },
                 "dezalgo": {
                     "version": "1.0.3",
-                    "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz",
-                    "integrity": "sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY=",
+                    "bundled": true,
                     "requires": {
                         "asap": "^2.0.0",
                         "wrappy": "1"
@@ -13126,26 +13055,22 @@
                 },
                 "dot-prop": {
                     "version": "4.2.1",
-                    "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.1.tgz",
-                    "integrity": "sha512-l0p4+mIuJIua0mhxGoh4a+iNL9bmeK5DvnSVQa6T0OhrVmaEa1XScX5Etc673FePCJOArq/4Pa2cLGODUWTPOQ==",
+                    "bundled": true,
                     "requires": {
                         "is-obj": "^1.0.0"
                     }
                 },
                 "dotenv": {
                     "version": "5.0.1",
-                    "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-5.0.1.tgz",
-                    "integrity": "sha512-4As8uPrjfwb7VXC+WnLCbXK7y+Ueb2B3zgNCePYfhxS1PYeaO1YTeplffTEcbfLhvFNGLAz90VvJs9yomG7bow=="
+                    "bundled": true
                 },
                 "duplexer3": {
                     "version": "0.1.4",
-                    "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz",
-                    "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI="
+                    "bundled": true
                 },
                 "duplexify": {
                     "version": "3.6.0",
-                    "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.6.0.tgz",
-                    "integrity": "sha512-fO3Di4tBKJpYTFHAxTU00BcfWMY9w24r/x21a6rZRbsD/ToUgGxsMbiGRmB7uVAXeGKXD9MwiLZa5E97EVgIRQ==",
+                    "bundled": true,
                     "requires": {
                         "end-of-stream": "^1.0.0",
                         "inherits": "^2.0.1",
@@ -13155,8 +13080,7 @@
                     "dependencies": {
                         "readable-stream": {
                             "version": "2.3.6",
-                            "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
-                            "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+                            "bundled": true,
                             "requires": {
                                 "core-util-is": "~1.0.0",
                                 "inherits": "~2.0.3",
@@ -13169,8 +13093,7 @@
                         },
                         "string_decoder": {
                             "version": "1.1.1",
-                            "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
-                            "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+                            "bundled": true,
                             "requires": {
                                 "safe-buffer": "~5.1.0"
                             }
@@ -13179,8 +13102,7 @@
                 },
                 "ecc-jsbn": {
                     "version": "0.1.2",
-                    "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
-                    "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
+                    "bundled": true,
                     "optional": true,
                     "requires": {
                         "jsbn": "~0.1.0",
@@ -13189,52 +13111,44 @@
                 },
                 "editor": {
                     "version": "1.0.0",
-                    "resolved": "https://registry.npmjs.org/editor/-/editor-1.0.0.tgz",
-                    "integrity": "sha1-YMf4e9YrzGqJT6jM1q+3gjok90I="
+                    "bundled": true
                 },
                 "emoji-regex": {
                     "version": "7.0.3",
-                    "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
-                    "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA=="
+                    "bundled": true
                 },
                 "encoding": {
                     "version": "0.1.12",
-                    "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz",
-                    "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=",
+                    "bundled": true,
                     "requires": {
                         "iconv-lite": "~0.4.13"
                     }
                 },
                 "end-of-stream": {
                     "version": "1.4.1",
-                    "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz",
-                    "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==",
+                    "bundled": true,
                     "requires": {
                         "once": "^1.4.0"
                     }
                 },
                 "env-paths": {
                     "version": "2.2.0",
-                    "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.0.tgz",
-                    "integrity": "sha512-6u0VYSCo/OW6IoD5WCLLy9JUGARbamfSavcNXry/eu8aHVFei6CD3Sw+VGX5alea1i9pgPHW0mbu6Xj0uBh7gA=="
+                    "bundled": true
                 },
                 "err-code": {
                     "version": "1.1.2",
-                    "resolved": "https://registry.npmjs.org/err-code/-/err-code-1.1.2.tgz",
-                    "integrity": "sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA="
+                    "bundled": true
                 },
                 "errno": {
                     "version": "0.1.7",
-                    "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz",
-                    "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==",
+                    "bundled": true,
                     "requires": {
                         "prr": "~1.0.1"
                     }
                 },
                 "es-abstract": {
                     "version": "1.12.0",
-                    "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.12.0.tgz",
-                    "integrity": "sha512-C8Fx/0jFmV5IPoMOFPA9P9G5NtqW+4cOPit3MIuvR2t7Ag2K15EJTpxnHAYTzL+aYQJIESYeXZmDBfOBE1HcpA==",
+                    "bundled": true,
                     "requires": {
                         "es-to-primitive": "^1.1.1",
                         "function-bind": "^1.1.1",
@@ -13245,8 +13159,7 @@
                 },
                 "es-to-primitive": {
                     "version": "1.2.0",
-                    "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz",
-                    "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==",
+                    "bundled": true,
                     "requires": {
                         "is-callable": "^1.1.4",
                         "is-date-object": "^1.0.1",
@@ -13255,26 +13168,22 @@
                 },
                 "es6-promise": {
                     "version": "4.2.8",
-                    "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz",
-                    "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w=="
+                    "bundled": true
                 },
                 "es6-promisify": {
                     "version": "5.0.0",
-                    "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz",
-                    "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=",
+                    "bundled": true,
                     "requires": {
                         "es6-promise": "^4.0.3"
                     }
                 },
                 "escape-string-regexp": {
                     "version": "1.0.5",
-                    "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
-                    "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
+                    "bundled": true
                 },
                 "execa": {
                     "version": "0.7.0",
-                    "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz",
-                    "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=",
+                    "bundled": true,
                     "requires": {
                         "cross-spawn": "^5.0.1",
                         "get-stream": "^3.0.0",
@@ -13287,40 +13196,33 @@
                     "dependencies": {
                         "get-stream": {
                             "version": "3.0.0",
-                            "resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
-                            "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ="
+                            "bundled": true
                         }
                     }
                 },
                 "extend": {
                     "version": "3.0.2",
-                    "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
-                    "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
+                    "bundled": true
                 },
                 "extsprintf": {
                     "version": "1.3.0",
-                    "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
-                    "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
+                    "bundled": true
                 },
                 "fast-json-stable-stringify": {
                     "version": "2.0.0",
-                    "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
-                    "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I="
+                    "bundled": true
                 },
                 "figgy-pudding": {
                     "version": "3.5.1",
-                    "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.1.tgz",
-                    "integrity": "sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w=="
+                    "bundled": true
                 },
                 "find-npm-prefix": {
                     "version": "1.0.2",
-                    "resolved": "https://registry.npmjs.org/find-npm-prefix/-/find-npm-prefix-1.0.2.tgz",
-                    "integrity": "sha512-KEftzJ+H90x6pcKtdXZEPsQse8/y/UnvzRKrOSQFprnrGaFuJ62fVkP34Iu2IYuMvyauCyoLTNkJZgrrGA2wkA=="
+                    "bundled": true
                 },
                 "flush-write-stream": {
                     "version": "1.0.3",
-                    "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.0.3.tgz",
-                    "integrity": "sha512-calZMC10u0FMUqoiunI2AiGIIUtUIvifNwkHhNupZH4cbNnW1Itkoh/Nf5HFYmDrwWPjrUxpkZT0KhuCq0jmGw==",
+                    "bundled": true,
                     "requires": {
                         "inherits": "^2.0.1",
                         "readable-stream": "^2.0.4"
@@ -13328,8 +13230,7 @@
                     "dependencies": {
                         "readable-stream": {
                             "version": "2.3.6",
-                            "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
-                            "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+                            "bundled": true,
                             "requires": {
                                 "core-util-is": "~1.0.0",
                                 "inherits": "~2.0.3",
@@ -13342,8 +13243,7 @@
                         },
                         "string_decoder": {
                             "version": "1.1.1",
-                            "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
-                            "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+                            "bundled": true,
                             "requires": {
                                 "safe-buffer": "~5.1.0"
                             }
@@ -13352,13 +13252,11 @@
                 },
                 "forever-agent": {
                     "version": "0.6.1",
-                    "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
-                    "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE="
+                    "bundled": true
                 },
                 "form-data": {
                     "version": "2.3.2",
-                    "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz",
-                    "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=",
+                    "bundled": true,
                     "requires": {
                         "asynckit": "^0.4.0",
                         "combined-stream": "1.0.6",
@@ -13367,8 +13265,7 @@
                 },
                 "from2": {
                     "version": "2.3.0",
-                    "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz",
-                    "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=",
+                    "bundled": true,
                     "requires": {
                         "inherits": "^2.0.1",
                         "readable-stream": "^2.0.0"
@@ -13376,8 +13273,7 @@
                     "dependencies": {
                         "readable-stream": {
                             "version": "2.3.6",
-                            "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
-                            "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+                            "bundled": true,
                             "requires": {
                                 "core-util-is": "~1.0.0",
                                 "inherits": "~2.0.3",
@@ -13390,8 +13286,7 @@
                         },
                         "string_decoder": {
                             "version": "1.1.1",
-                            "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
-                            "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+                            "bundled": true,
                             "requires": {
                                 "safe-buffer": "~5.1.0"
                             }
@@ -13400,16 +13295,14 @@
                 },
                 "fs-minipass": {
                     "version": "1.2.7",
-                    "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz",
-                    "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==",
+                    "bundled": true,
                     "requires": {
                         "minipass": "^2.6.0"
                     },
                     "dependencies": {
                         "minipass": {
                             "version": "2.9.0",
-                            "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz",
-                            "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==",
+                            "bundled": true,
                             "requires": {
                                 "safe-buffer": "^5.1.2",
                                 "yallist": "^3.0.0"
@@ -13419,8 +13312,7 @@
                 },
                 "fs-vacuum": {
                     "version": "1.2.10",
-                    "resolved": "https://registry.npmjs.org/fs-vacuum/-/fs-vacuum-1.2.10.tgz",
-                    "integrity": "sha1-t2Kb7AekAxolSP35n17PHMizHjY=",
+                    "bundled": true,
                     "requires": {
                         "graceful-fs": "^4.1.2",
                         "path-is-inside": "^1.0.1",
@@ -13429,8 +13321,7 @@
                 },
                 "fs-write-stream-atomic": {
                     "version": "1.0.10",
-                    "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz",
-                    "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=",
+                    "bundled": true,
                     "requires": {
                         "graceful-fs": "^4.1.2",
                         "iferr": "^0.1.5",
@@ -13440,13 +13331,11 @@
                     "dependencies": {
                         "iferr": {
                             "version": "0.1.5",
-                            "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz",
-                            "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE="
+                            "bundled": true
                         },
                         "readable-stream": {
                             "version": "2.3.6",
-                            "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
-                            "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+                            "bundled": true,
                             "requires": {
                                 "core-util-is": "~1.0.0",
                                 "inherits": "~2.0.3",
@@ -13459,8 +13348,7 @@
                         },
                         "string_decoder": {
                             "version": "1.1.1",
-                            "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
-                            "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+                            "bundled": true,
                             "requires": {
                                 "safe-buffer": "~5.1.0"
                             }
@@ -13469,18 +13357,15 @@
                 },
                 "fs.realpath": {
                     "version": "1.0.0",
-                    "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
-                    "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
+                    "bundled": true
                 },
                 "function-bind": {
                     "version": "1.1.1",
-                    "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
-                    "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
+                    "bundled": true
                 },
                 "gauge": {
                     "version": "2.7.4",
-                    "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
-                    "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
+                    "bundled": true,
                     "requires": {
                         "aproba": "^1.0.3",
                         "console-control-strings": "^1.0.0",
@@ -13494,13 +13379,11 @@
                     "dependencies": {
                         "aproba": {
                             "version": "1.2.0",
-                            "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
-                            "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw=="
+                            "bundled": true
                         },
                         "string-width": {
                             "version": "1.0.2",
-                            "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
-                            "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+                            "bundled": true,
                             "requires": {
                                 "code-point-at": "^1.0.0",
                                 "is-fullwidth-code-point": "^1.0.0",
@@ -13511,13 +13394,11 @@
                 },
                 "genfun": {
                     "version": "5.0.0",
-                    "resolved": "https://registry.npmjs.org/genfun/-/genfun-5.0.0.tgz",
-                    "integrity": "sha512-KGDOARWVga7+rnB3z9Sd2Letx515owfk0hSxHGuqjANb1M+x2bGZGqHLiozPsYMdM2OubeMni/Hpwmjq6qIUhA=="
+                    "bundled": true
                 },
                 "gentle-fs": {
                     "version": "2.3.1",
-                    "resolved": "https://registry.npmjs.org/gentle-fs/-/gentle-fs-2.3.1.tgz",
-                    "integrity": "sha512-OlwBBwqCFPcjm33rF2BjW+Pr6/ll2741l+xooiwTCeaX2CA1ZuclavyMBe0/KlR21/XGsgY6hzEQZ15BdNa13Q==",
+                    "bundled": true,
                     "requires": {
                         "aproba": "^1.1.2",
                         "chownr": "^1.1.2",
@@ -13534,41 +13415,35 @@
                     "dependencies": {
                         "aproba": {
                             "version": "1.2.0",
-                            "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
-                            "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw=="
+                            "bundled": true
                         },
                         "iferr": {
                             "version": "0.1.5",
-                            "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz",
-                            "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE="
+                            "bundled": true
                         }
                     }
                 },
                 "get-caller-file": {
                     "version": "2.0.5",
-                    "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
-                    "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="
+                    "bundled": true
                 },
                 "get-stream": {
                     "version": "4.1.0",
-                    "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
-                    "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
+                    "bundled": true,
                     "requires": {
                         "pump": "^3.0.0"
                     }
                 },
                 "getpass": {
                     "version": "0.1.7",
-                    "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
-                    "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
+                    "bundled": true,
                     "requires": {
                         "assert-plus": "^1.0.0"
                     }
                 },
                 "glob": {
                     "version": "7.1.6",
-                    "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
-                    "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+                    "bundled": true,
                     "requires": {
                         "fs.realpath": "^1.0.0",
                         "inflight": "^1.0.4",
@@ -13580,16 +13455,14 @@
                 },
                 "global-dirs": {
                     "version": "0.1.1",
-                    "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz",
-                    "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=",
+                    "bundled": true,
                     "requires": {
                         "ini": "^1.3.4"
                     }
                 },
                 "got": {
                     "version": "6.7.1",
-                    "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz",
-                    "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=",
+                    "bundled": true,
                     "requires": {
                         "create-error-class": "^3.0.0",
                         "duplexer3": "^0.1.4",
@@ -13606,25 +13479,21 @@
                     "dependencies": {
                         "get-stream": {
                             "version": "3.0.0",
-                            "resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
-                            "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ="
+                            "bundled": true
                         }
                     }
                 },
                 "graceful-fs": {
                     "version": "4.2.4",
-                    "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
-                    "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw=="
+                    "bundled": true
                 },
                 "har-schema": {
                     "version": "2.0.0",
-                    "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
-                    "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI="
+                    "bundled": true
                 },
                 "har-validator": {
                     "version": "5.1.5",
-                    "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz",
-                    "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==",
+                    "bundled": true,
                     "requires": {
                         "ajv": "^6.12.3",
                         "har-schema": "^2.0.0"
@@ -13632,8 +13501,7 @@
                     "dependencies": {
                         "ajv": {
                             "version": "6.12.6",
-                            "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
-                            "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+                            "bundled": true,
                             "requires": {
                                 "fast-deep-equal": "^3.1.1",
                                 "fast-json-stable-stringify": "^2.0.0",
@@ -13643,53 +13511,44 @@
                         },
                         "fast-deep-equal": {
                             "version": "3.1.3",
-                            "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
-                            "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
+                            "bundled": true
                         },
                         "json-schema-traverse": {
                             "version": "0.4.1",
-                            "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
-                            "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
+                            "bundled": true
                         }
                     }
                 },
                 "has": {
                     "version": "1.0.3",
-                    "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
-                    "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+                    "bundled": true,
                     "requires": {
                         "function-bind": "^1.1.1"
                     }
                 },
                 "has-flag": {
                     "version": "3.0.0",
-                    "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-                    "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
+                    "bundled": true
                 },
                 "has-symbols": {
                     "version": "1.0.0",
-                    "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz",
-                    "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q="
+                    "bundled": true
                 },
                 "has-unicode": {
                     "version": "2.0.1",
-                    "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
-                    "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk="
+                    "bundled": true
                 },
                 "hosted-git-info": {
                     "version": "2.8.9",
-                    "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz",
-                    "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw=="
+                    "bundled": true
                 },
                 "http-cache-semantics": {
                     "version": "3.8.1",
-                    "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz",
-                    "integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w=="
+                    "bundled": true
                 },
                 "http-proxy-agent": {
                     "version": "2.1.0",
-                    "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz",
-                    "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==",
+                    "bundled": true,
                     "requires": {
                         "agent-base": "4",
                         "debug": "3.1.0"
@@ -13697,8 +13556,7 @@
                 },
                 "http-signature": {
                     "version": "1.2.0",
-                    "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
-                    "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
+                    "bundled": true,
                     "requires": {
                         "assert-plus": "^1.0.0",
                         "jsprim": "^1.2.2",
@@ -13707,8 +13565,7 @@
                 },
                 "https-proxy-agent": {
                     "version": "2.2.4",
-                    "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz",
-                    "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==",
+                    "bundled": true,
                     "requires": {
                         "agent-base": "^4.3.0",
                         "debug": "^3.1.0"
@@ -13716,52 +13573,44 @@
                 },
                 "humanize-ms": {
                     "version": "1.2.1",
-                    "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz",
-                    "integrity": "sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0=",
+                    "bundled": true,
                     "requires": {
                         "ms": "^2.0.0"
                     }
                 },
                 "iconv-lite": {
                     "version": "0.4.23",
-                    "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz",
-                    "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==",
+                    "bundled": true,
                     "requires": {
                         "safer-buffer": ">= 2.1.2 < 3"
                     }
                 },
                 "iferr": {
                     "version": "1.0.2",
-                    "resolved": "https://registry.npmjs.org/iferr/-/iferr-1.0.2.tgz",
-                    "integrity": "sha512-9AfeLfji44r5TKInjhz3W9DyZI1zR1JAf2hVBMGhddAKPqBsupb89jGfbCTHIGZd6fGZl9WlHdn4AObygyMKwg=="
+                    "bundled": true
                 },
                 "ignore-walk": {
                     "version": "3.0.3",
-                    "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz",
-                    "integrity": "sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw==",
+                    "bundled": true,
                     "requires": {
                         "minimatch": "^3.0.4"
                     }
                 },
                 "import-lazy": {
                     "version": "2.1.0",
-                    "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz",
-                    "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM="
+                    "bundled": true
                 },
                 "imurmurhash": {
                     "version": "0.1.4",
-                    "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
-                    "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o="
+                    "bundled": true
                 },
                 "infer-owner": {
                     "version": "1.0.4",
-                    "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz",
-                    "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A=="
+                    "bundled": true
                 },
                 "inflight": {
                     "version": "1.0.6",
-                    "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
-                    "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+                    "bundled": true,
                     "requires": {
                         "once": "^1.3.0",
                         "wrappy": "1"
@@ -13769,18 +13618,15 @@
                 },
                 "inherits": {
                     "version": "2.0.4",
-                    "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
-                    "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+                    "bundled": true
                 },
                 "ini": {
                     "version": "1.3.8",
-                    "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
-                    "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="
+                    "bundled": true
                 },
                 "init-package-json": {
                     "version": "1.10.3",
-                    "resolved": "https://registry.npmjs.org/init-package-json/-/init-package-json-1.10.3.tgz",
-                    "integrity": "sha512-zKSiXKhQveNteyhcj1CoOP8tqp1QuxPIPBl8Bid99DGLFqA1p87M6lNgfjJHSBoWJJlidGOv5rWjyYKEB3g2Jw==",
+                    "bundled": true,
                     "requires": {
                         "glob": "^7.1.1",
                         "npm-package-arg": "^4.0.0 || ^5.0.0 || ^6.0.0",
@@ -13794,59 +13640,50 @@
                 },
                 "ip": {
                     "version": "1.1.5",
-                    "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz",
-                    "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo="
+                    "bundled": true
                 },
                 "ip-regex": {
                     "version": "2.1.0",
-                    "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz",
-                    "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk="
+                    "bundled": true
                 },
                 "is-callable": {
                     "version": "1.1.4",
-                    "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz",
-                    "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA=="
+                    "bundled": true
                 },
                 "is-ci": {
                     "version": "1.2.1",
-                    "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz",
-                    "integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==",
+                    "bundled": true,
                     "requires": {
                         "ci-info": "^1.5.0"
                     },
                     "dependencies": {
                         "ci-info": {
                             "version": "1.6.0",
-                            "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz",
-                            "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A=="
+                            "bundled": true
                         }
                     }
                 },
                 "is-cidr": {
                     "version": "3.0.0",
-                    "resolved": "https://registry.npmjs.org/is-cidr/-/is-cidr-3.0.0.tgz",
-                    "integrity": "sha512-8Xnnbjsb0x462VoYiGlhEi+drY8SFwrHiSYuzc/CEwco55vkehTaxAyIjEdpi3EMvLPPJAJi9FlzP+h+03gp0Q==",
+                    "bundled": true,
                     "requires": {
                         "cidr-regex": "^2.0.10"
                     }
                 },
                 "is-date-object": {
                     "version": "1.0.1",
-                    "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz",
-                    "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY="
+                    "bundled": true
                 },
                 "is-fullwidth-code-point": {
                     "version": "1.0.0",
-                    "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
-                    "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
+                    "bundled": true,
                     "requires": {
                         "number-is-nan": "^1.0.0"
                     }
                 },
                 "is-installed-globally": {
                     "version": "0.1.0",
-                    "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.1.0.tgz",
-                    "integrity": "sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA=",
+                    "bundled": true,
                     "requires": {
                         "global-dirs": "^0.1.0",
                         "is-path-inside": "^1.0.0"
@@ -13854,103 +13691,85 @@
                 },
                 "is-npm": {
                     "version": "1.0.0",
-                    "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-1.0.0.tgz",
-                    "integrity": "sha1-8vtjpl5JBbQGyGBydloaTceTufQ="
+                    "bundled": true
                 },
                 "is-obj": {
                     "version": "1.0.1",
-                    "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz",
-                    "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8="
+                    "bundled": true
                 },
                 "is-path-inside": {
                     "version": "1.0.1",
-                    "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz",
-                    "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=",
+                    "bundled": true,
                     "requires": {
                         "path-is-inside": "^1.0.1"
                     }
                 },
                 "is-redirect": {
                     "version": "1.0.0",
-                    "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz",
-                    "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ="
+                    "bundled": true
                 },
                 "is-regex": {
                     "version": "1.0.4",
-                    "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz",
-                    "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=",
+                    "bundled": true,
                     "requires": {
                         "has": "^1.0.1"
                     }
                 },
                 "is-retry-allowed": {
                     "version": "1.2.0",
-                    "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz",
-                    "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg=="
+                    "bundled": true
                 },
                 "is-stream": {
                     "version": "1.1.0",
-                    "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
-                    "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ="
+                    "bundled": true
                 },
                 "is-symbol": {
                     "version": "1.0.2",
-                    "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz",
-                    "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==",
+                    "bundled": true,
                     "requires": {
                         "has-symbols": "^1.0.0"
                     }
                 },
                 "is-typedarray": {
                     "version": "1.0.0",
-                    "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
-                    "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
+                    "bundled": true
                 },
                 "isarray": {
                     "version": "1.0.0",
-                    "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
-                    "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
+                    "bundled": true
                 },
                 "isexe": {
                     "version": "2.0.0",
-                    "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
-                    "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
+                    "bundled": true
                 },
                 "isstream": {
                     "version": "0.1.2",
-                    "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
-                    "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
+                    "bundled": true
                 },
                 "jsbn": {
                     "version": "0.1.1",
-                    "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
-                    "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
+                    "bundled": true,
                     "optional": true
                 },
                 "json-parse-better-errors": {
                     "version": "1.0.2",
-                    "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
-                    "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw=="
+                    "bundled": true
                 },
                 "json-schema": {
                     "version": "0.4.0",
-                    "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz",
-                    "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA=="
+                    "bundled": true
                 },
                 "json-stringify-safe": {
                     "version": "5.0.1",
-                    "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
-                    "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
+                    "bundled": true
                 },
                 "jsonparse": {
                     "version": "1.3.1",
-                    "resolved": false,
-                    "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA="
+                    "bundled": true
                 },
                 "jsprim": {
                     "version": "1.4.2",
-                    "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz",
-                    "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==",
+                    "bundled": true,
                     "requires": {
                         "assert-plus": "1.0.0",
                         "extsprintf": "1.3.0",
@@ -13960,21 +13779,18 @@
                 },
                 "latest-version": {
                     "version": "3.1.0",
-                    "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-3.1.0.tgz",
-                    "integrity": "sha1-ogU4P+oyKzO1rjsYq+4NwvNW7hU=",
+                    "bundled": true,
                     "requires": {
                         "package-json": "^4.0.0"
                     }
                 },
                 "lazy-property": {
                     "version": "1.0.0",
-                    "resolved": "https://registry.npmjs.org/lazy-property/-/lazy-property-1.0.0.tgz",
-                    "integrity": "sha1-hN3Es3Bnm6i9TNz6TAa0PVcREUc="
+                    "bundled": true
                 },
                 "libcipm": {
                     "version": "4.0.8",
-                    "resolved": "https://registry.npmjs.org/libcipm/-/libcipm-4.0.8.tgz",
-                    "integrity": "sha512-IN3hh2yDJQtZZ5paSV4fbvJg4aHxCCg5tcZID/dSVlTuUiWktsgaldVljJv6Z5OUlYspx6xQkbR0efNodnIrOA==",
+                    "bundled": true,
                     "requires": {
                         "bin-links": "^1.1.2",
                         "bluebird": "^3.5.1",
@@ -13995,8 +13811,7 @@
                 },
                 "libnpm": {
                     "version": "3.0.1",
-                    "resolved": "https://registry.npmjs.org/libnpm/-/libnpm-3.0.1.tgz",
-                    "integrity": "sha512-d7jU5ZcMiTfBqTUJVZ3xid44fE5ERBm9vBnmhp2ECD2Ls+FNXWxHSkO7gtvrnbLO78gwPdNPz1HpsF3W4rjkBQ==",
+                    "bundled": true,
                     "requires": {
                         "bin-links": "^1.1.2",
                         "bluebird": "^3.5.3",
@@ -14022,8 +13837,7 @@
                 },
                 "libnpmaccess": {
                     "version": "3.0.2",
-                    "resolved": "https://registry.npmjs.org/libnpmaccess/-/libnpmaccess-3.0.2.tgz",
-                    "integrity": "sha512-01512AK7MqByrI2mfC7h5j8N9V4I7MHJuk9buo8Gv+5QgThpOgpjB7sQBDDkeZqRteFb1QM/6YNdHfG7cDvfAQ==",
+                    "bundled": true,
                     "requires": {
                         "aproba": "^2.0.0",
                         "get-stream": "^4.0.0",
@@ -14033,8 +13847,7 @@
                 },
                 "libnpmconfig": {
                     "version": "1.2.1",
-                    "resolved": "https://registry.npmjs.org/libnpmconfig/-/libnpmconfig-1.2.1.tgz",
-                    "integrity": "sha512-9esX8rTQAHqarx6qeZqmGQKBNZR5OIbl/Ayr0qQDy3oXja2iFVQQI81R6GZ2a02bSNZ9p3YOGX1O6HHCb1X7kA==",
+                    "bundled": true,
                     "requires": {
                         "figgy-pudding": "^3.5.1",
                         "find-up": "^3.0.0",
@@ -14043,16 +13856,14 @@
                     "dependencies": {
                         "find-up": {
                             "version": "3.0.0",
-                            "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
-                            "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
+                            "bundled": true,
                             "requires": {
                                 "locate-path": "^3.0.0"
                             }
                         },
                         "locate-path": {
                             "version": "3.0.0",
-                            "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
-                            "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
+                            "bundled": true,
                             "requires": {
                                 "p-locate": "^3.0.0",
                                 "path-exists": "^3.0.0"
@@ -14060,31 +13871,27 @@
                         },
                         "p-limit": {
                             "version": "2.2.0",
-                            "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz",
-                            "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==",
+                            "bundled": true,
                             "requires": {
                                 "p-try": "^2.0.0"
                             }
                         },
                         "p-locate": {
                             "version": "3.0.0",
-                            "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
-                            "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
+                            "bundled": true,
                             "requires": {
                                 "p-limit": "^2.0.0"
                             }
                         },
                         "p-try": {
                             "version": "2.2.0",
-                            "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
-                            "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="
+                            "bundled": true
                         }
                     }
                 },
                 "libnpmhook": {
                     "version": "5.0.3",
-                    "resolved": "https://registry.npmjs.org/libnpmhook/-/libnpmhook-5.0.3.tgz",
-                    "integrity": "sha512-UdNLMuefVZra/wbnBXECZPefHMGsVDTq5zaM/LgKNE9Keyl5YXQTnGAzEo+nFOpdRqTWI9LYi4ApqF9uVCCtuA==",
+                    "bundled": true,
                     "requires": {
                         "aproba": "^2.0.0",
                         "figgy-pudding": "^3.4.1",
@@ -14094,8 +13901,7 @@
                 },
                 "libnpmorg": {
                     "version": "1.0.1",
-                    "resolved": "https://registry.npmjs.org/libnpmorg/-/libnpmorg-1.0.1.tgz",
-                    "integrity": "sha512-0sRUXLh+PLBgZmARvthhYXQAWn0fOsa6T5l3JSe2n9vKG/lCVK4nuG7pDsa7uMq+uTt2epdPK+a2g6btcY11Ww==",
+                    "bundled": true,
                     "requires": {
                         "aproba": "^2.0.0",
                         "figgy-pudding": "^3.4.1",
@@ -14105,8 +13911,7 @@
                 },
                 "libnpmpublish": {
                     "version": "1.1.2",
-                    "resolved": "https://registry.npmjs.org/libnpmpublish/-/libnpmpublish-1.1.2.tgz",
-                    "integrity": "sha512-2yIwaXrhTTcF7bkJKIKmaCV9wZOALf/gsTDxVSu/Gu/6wiG3fA8ce8YKstiWKTxSFNC0R7isPUb6tXTVFZHt2g==",
+                    "bundled": true,
                     "requires": {
                         "aproba": "^2.0.0",
                         "figgy-pudding": "^3.5.1",
@@ -14121,8 +13926,7 @@
                 },
                 "libnpmsearch": {
                     "version": "2.0.2",
-                    "resolved": "https://registry.npmjs.org/libnpmsearch/-/libnpmsearch-2.0.2.tgz",
-                    "integrity": "sha512-VTBbV55Q6fRzTdzziYCr64+f8AopQ1YZ+BdPOv16UegIEaE8C0Kch01wo4s3kRTFV64P121WZJwgmBwrq68zYg==",
+                    "bundled": true,
                     "requires": {
                         "figgy-pudding": "^3.5.1",
                         "get-stream": "^4.0.0",
@@ -14131,8 +13935,7 @@
                 },
                 "libnpmteam": {
                     "version": "1.0.2",
-                    "resolved": "https://registry.npmjs.org/libnpmteam/-/libnpmteam-1.0.2.tgz",
-                    "integrity": "sha512-p420vM28Us04NAcg1rzgGW63LMM6rwe+6rtZpfDxCcXxM0zUTLl7nPFEnRF3JfFBF5skF/yuZDUthTsHgde8QA==",
+                    "bundled": true,
                     "requires": {
                         "aproba": "^2.0.0",
                         "figgy-pudding": "^3.4.1",
@@ -14142,8 +13945,7 @@
                 },
                 "libnpx": {
                     "version": "10.2.4",
-                    "resolved": "https://registry.npmjs.org/libnpx/-/libnpx-10.2.4.tgz",
-                    "integrity": "sha512-BPc0D1cOjBeS8VIBKUu5F80s6njm0wbVt7CsGMrIcJ+SI7pi7V0uVPGpEMH9H5L8csOcclTxAXFE2VAsJXUhfA==",
+                    "bundled": true,
                     "requires": {
                         "dotenv": "^5.0.1",
                         "npm-package-arg": "^6.0.0",
@@ -14157,8 +13959,7 @@
                 },
                 "lock-verify": {
                     "version": "2.1.0",
-                    "resolved": "https://registry.npmjs.org/lock-verify/-/lock-verify-2.1.0.tgz",
-                    "integrity": "sha512-vcLpxnGvrqisKvLQ2C2v0/u7LVly17ak2YSgoK4PrdsYBXQIax19vhKiLfvKNFx7FRrpTnitrpzF/uuCMuorIg==",
+                    "bundled": true,
                     "requires": {
                         "npm-package-arg": "^6.1.0",
                         "semver": "^5.4.1"
@@ -14166,21 +13967,18 @@
                 },
                 "lockfile": {
                     "version": "1.0.4",
-                    "resolved": "https://registry.npmjs.org/lockfile/-/lockfile-1.0.4.tgz",
-                    "integrity": "sha512-cvbTwETRfsFh4nHsL1eGWapU1XFi5Ot9E85sWAwia7Y7EgB7vfqcZhTKZ+l7hCGxSPoushMv5GKhT5PdLv03WA==",
+                    "bundled": true,
                     "requires": {
                         "signal-exit": "^3.0.2"
                     }
                 },
                 "lodash._baseindexof": {
                     "version": "3.1.0",
-                    "resolved": "https://registry.npmjs.org/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz",
-                    "integrity": "sha1-/lK1OhxnYeQmGNZU5KJXie1hgiw="
+                    "bundled": true
                 },
                 "lodash._baseuniq": {
                     "version": "4.6.0",
-                    "resolved": "https://registry.npmjs.org/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz",
-                    "integrity": "sha1-DrtE5FaBSveQXGIS+iybLVG4Qeg=",
+                    "bundled": true,
                     "requires": {
                         "lodash._createset": "~4.0.0",
                         "lodash._root": "~3.0.0"
@@ -14188,87 +13986,72 @@
                 },
                 "lodash._bindcallback": {
                     "version": "3.0.1",
-                    "resolved": "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz",
-                    "integrity": "sha1-5THCdkTPi1epnhftlbNcdIeJOS4="
+                    "bundled": true
                 },
                 "lodash._cacheindexof": {
                     "version": "3.0.2",
-                    "resolved": "https://registry.npmjs.org/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz",
-                    "integrity": "sha1-PcaayCSY0u5ePOVgkbr9Ktx73pI="
+                    "bundled": true
                 },
                 "lodash._createcache": {
                     "version": "3.1.2",
-                    "resolved": "https://registry.npmjs.org/lodash._createcache/-/lodash._createcache-3.1.2.tgz",
-                    "integrity": "sha1-VtagZAF2JeeevKa4AY4XRAvc8JM=",
+                    "bundled": true,
                     "requires": {
                         "lodash._getnative": "^3.0.0"
                     }
                 },
                 "lodash._createset": {
                     "version": "4.0.3",
-                    "resolved": "https://registry.npmjs.org/lodash._createset/-/lodash._createset-4.0.3.tgz",
-                    "integrity": "sha1-D0ZZ+7CddRlPqeK4imZE02PJ/iY="
+                    "bundled": true
                 },
                 "lodash._getnative": {
                     "version": "3.9.1",
-                    "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz",
-                    "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U="
+                    "bundled": true
                 },
                 "lodash._root": {
                     "version": "3.0.1",
-                    "resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz",
-                    "integrity": "sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI="
+                    "bundled": true
                 },
                 "lodash.clonedeep": {
                     "version": "4.5.0",
-                    "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
-                    "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8="
+                    "bundled": true
                 },
                 "lodash.restparam": {
                     "version": "3.6.1",
-                    "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz",
-                    "integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU="
+                    "bundled": true
                 },
                 "lodash.union": {
                     "version": "4.6.0",
-                    "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz",
-                    "integrity": "sha1-SLtQiECfFvGCFmZkHETdGqrjzYg="
+                    "bundled": true
                 },
                 "lodash.uniq": {
                     "version": "4.5.0",
-                    "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz",
-                    "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M="
+                    "bundled": true
                 },
                 "lodash.without": {
                     "version": "4.4.0",
-                    "resolved": "https://registry.npmjs.org/lodash.without/-/lodash.without-4.4.0.tgz",
-                    "integrity": "sha1-PNRXSgC2e643OpS3SHcmQFB7eqw="
+                    "bundled": true
                 },
                 "lowercase-keys": {
                     "version": "1.0.1",
-                    "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz",
-                    "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA=="
+                    "bundled": true
                 },
                 "lru-cache": {
                     "version": "5.1.1",
-                    "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
-                    "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
+                    "bundled": true,
                     "requires": {
                         "yallist": "^3.0.2"
                     }
                 },
                 "make-dir": {
                     "version": "1.3.0",
-                    "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz",
-                    "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==",
+                    "bundled": true,
                     "requires": {
                         "pify": "^3.0.0"
                     }
                 },
                 "make-fetch-happen": {
                     "version": "5.0.2",
-                    "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-5.0.2.tgz",
-                    "integrity": "sha512-07JHC0r1ykIoruKO8ifMXu+xEU8qOXDFETylktdug6vJDACnP+HKevOu3PXyNPzFyTSlz8vrBYlBO1JZRe8Cag==",
+                    "bundled": true,
                     "requires": {
                         "agentkeepalive": "^3.4.1",
                         "cacache": "^12.0.0",
@@ -14285,47 +14068,40 @@
                 },
                 "meant": {
                     "version": "1.0.2",
-                    "resolved": "https://registry.npmjs.org/meant/-/meant-1.0.2.tgz",
-                    "integrity": "sha512-KN+1uowN/NK+sT/Lzx7WSGIj2u+3xe5n2LbwObfjOhPZiA+cCfCm6idVl0RkEfjThkw5XJ96CyRcanq6GmKtUg=="
+                    "bundled": true
                 },
                 "mime-db": {
                     "version": "1.35.0",
-                    "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.35.0.tgz",
-                    "integrity": "sha512-JWT/IcCTsB0Io3AhWUMjRqucrHSPsSf2xKLaRldJVULioggvkJvggZ3VXNNSRkCddE6D+BUI4HEIZIA2OjwIvg=="
+                    "bundled": true
                 },
                 "mime-types": {
                     "version": "2.1.19",
-                    "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.19.tgz",
-                    "integrity": "sha512-P1tKYHVSZ6uFo26mtnve4HQFE3koh1UWVkp8YUC+ESBHe945xWSoXuHHiGarDqcEZ+whpCDnlNw5LON0kLo+sw==",
+                    "bundled": true,
                     "requires": {
                         "mime-db": "~1.35.0"
                     }
                 },
                 "minimatch": {
                     "version": "3.0.4",
-                    "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
-                    "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+                    "bundled": true,
                     "requires": {
                         "brace-expansion": "^1.1.7"
                     }
                 },
                 "minimist": {
                     "version": "1.2.6",
-                    "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
-                    "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q=="
+                    "bundled": true
                 },
                 "minizlib": {
                     "version": "1.3.3",
-                    "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz",
-                    "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==",
+                    "bundled": true,
                     "requires": {
                         "minipass": "^2.9.0"
                     },
                     "dependencies": {
                         "minipass": {
                             "version": "2.9.0",
-                            "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz",
-                            "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==",
+                            "bundled": true,
                             "requires": {
                                 "safe-buffer": "^5.1.2",
                                 "yallist": "^3.0.0"
@@ -14335,8 +14111,7 @@
                 },
                 "mississippi": {
                     "version": "3.0.0",
-                    "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz",
-                    "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==",
+                    "bundled": true,
                     "requires": {
                         "concat-stream": "^1.5.0",
                         "duplexify": "^3.4.2",
@@ -14352,23 +14127,20 @@
                 },
                 "mkdirp": {
                     "version": "0.5.5",
-                    "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
-                    "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
+                    "bundled": true,
                     "requires": {
                         "minimist": "^1.2.5"
                     },
                     "dependencies": {
                         "minimist": {
                             "version": "1.2.6",
-                            "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
-                            "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q=="
+                            "bundled": true
                         }
                     }
                 },
                 "move-concurrently": {
                     "version": "1.0.1",
-                    "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
-                    "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=",
+                    "bundled": true,
                     "requires": {
                         "aproba": "^1.1.1",
                         "copy-concurrently": "^1.0.0",
@@ -14380,25 +14152,21 @@
                     "dependencies": {
                         "aproba": {
                             "version": "1.2.0",
-                            "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
-                            "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw=="
+                            "bundled": true
                         }
                     }
                 },
                 "ms": {
                     "version": "2.1.1",
-                    "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
-                    "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
+                    "bundled": true
                 },
                 "mute-stream": {
                     "version": "0.0.7",
-                    "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz",
-                    "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s="
+                    "bundled": true
                 },
                 "node-fetch-npm": {
                     "version": "2.0.2",
-                    "resolved": "https://registry.npmjs.org/node-fetch-npm/-/node-fetch-npm-2.0.2.tgz",
-                    "integrity": "sha512-nJIxm1QmAj4v3nfCvEeCrYSoVwXyxLnaPBK5W1W5DGEJwjlKuC2VEUycGw5oxk+4zZahRrB84PUJJgEmhFTDFw==",
+                    "bundled": true,
                     "requires": {
                         "encoding": "^0.1.11",
                         "json-parse-better-errors": "^1.0.0",
@@ -14407,8 +14175,7 @@
                 },
                 "node-gyp": {
                     "version": "5.1.0",
-                    "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-5.1.0.tgz",
-                    "integrity": "sha512-OUTryc5bt/P8zVgNUmC6xdXiDJxLMAW8cF5tLQOT9E5sOQj+UeQxnnPy74K3CLCa/SOjjBlbuzDLR8ANwA+wmw==",
+                    "bundled": true,
                     "requires": {
                         "env-paths": "^2.2.0",
                         "glob": "^7.1.4",
@@ -14425,8 +14192,7 @@
                 },
                 "nopt": {
                     "version": "4.0.3",
-                    "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz",
-                    "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==",
+                    "bundled": true,
                     "requires": {
                         "abbrev": "1",
                         "osenv": "^0.1.4"
@@ -14434,8 +14200,7 @@
                 },
                 "normalize-package-data": {
                     "version": "2.5.0",
-                    "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
-                    "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
+                    "bundled": true,
                     "requires": {
                         "hosted-git-info": "^2.1.4",
                         "resolve": "^1.10.0",
@@ -14445,8 +14210,7 @@
                     "dependencies": {
                         "resolve": {
                             "version": "1.10.0",
-                            "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz",
-                            "integrity": "sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==",
+                            "bundled": true,
                             "requires": {
                                 "path-parse": "^1.0.6"
                             }
@@ -14455,8 +14219,7 @@
                 },
                 "npm-audit-report": {
                     "version": "1.3.3",
-                    "resolved": "https://registry.npmjs.org/npm-audit-report/-/npm-audit-report-1.3.3.tgz",
-                    "integrity": "sha512-8nH/JjsFfAWMvn474HB9mpmMjrnKb1Hx/oTAdjv4PT9iZBvBxiZ+wtDUapHCJwLqYGQVPaAfs+vL5+5k9QndXw==",
+                    "bundled": true,
                     "requires": {
                         "cli-table3": "^0.5.0",
                         "console-control-strings": "^1.1.0"
@@ -14464,29 +14227,25 @@
                 },
                 "npm-bundled": {
                     "version": "1.1.1",
-                    "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.1.tgz",
-                    "integrity": "sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA==",
+                    "bundled": true,
                     "requires": {
                         "npm-normalize-package-bin": "^1.0.1"
                     }
                 },
                 "npm-cache-filename": {
                     "version": "1.0.2",
-                    "resolved": "https://registry.npmjs.org/npm-cache-filename/-/npm-cache-filename-1.0.2.tgz",
-                    "integrity": "sha1-3tMGxbC/yHCp6fr4I7xfKD4FrhE="
+                    "bundled": true
                 },
                 "npm-install-checks": {
                     "version": "3.0.2",
-                    "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-3.0.2.tgz",
-                    "integrity": "sha512-E4kzkyZDIWoin6uT5howP8VDvkM+E8IQDcHAycaAxMbwkqhIg5eEYALnXOl3Hq9MrkdQB/2/g1xwBINXdKSRkg==",
+                    "bundled": true,
                     "requires": {
                         "semver": "^2.3.0 || 3.x || 4 || 5"
                     }
                 },
                 "npm-lifecycle": {
                     "version": "3.1.5",
-                    "resolved": "https://registry.npmjs.org/npm-lifecycle/-/npm-lifecycle-3.1.5.tgz",
-                    "integrity": "sha512-lDLVkjfZmvmfvpvBzA4vzee9cn+Me4orq0QF8glbswJVEbIcSNWib7qGOffolysc3teCqbbPZZkzbr3GQZTL1g==",
+                    "bundled": true,
                     "requires": {
                         "byline": "^5.0.0",
                         "graceful-fs": "^4.1.15",
@@ -14500,18 +14259,15 @@
                 },
                 "npm-logical-tree": {
                     "version": "1.2.1",
-                    "resolved": "https://registry.npmjs.org/npm-logical-tree/-/npm-logical-tree-1.2.1.tgz",
-                    "integrity": "sha512-AJI/qxDB2PWI4LG1CYN579AY1vCiNyWfkiquCsJWqntRu/WwimVrC8yXeILBFHDwxfOejxewlmnvW9XXjMlYIg=="
+                    "bundled": true
                 },
                 "npm-normalize-package-bin": {
                     "version": "1.0.1",
-                    "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz",
-                    "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA=="
+                    "bundled": true
                 },
                 "npm-package-arg": {
                     "version": "6.1.1",
-                    "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-6.1.1.tgz",
-                    "integrity": "sha512-qBpssaL3IOZWi5vEKUKW0cO7kzLeT+EQO9W8RsLOZf76KF9E/K9+wH0C7t06HXPpaH8WH5xF1MExLuCwbTqRUg==",
+                    "bundled": true,
                     "requires": {
                         "hosted-git-info": "^2.7.1",
                         "osenv": "^0.1.5",
@@ -14521,8 +14277,7 @@
                 },
                 "npm-packlist": {
                     "version": "1.4.8",
-                    "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.8.tgz",
-                    "integrity": "sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A==",
+                    "bundled": true,
                     "requires": {
                         "ignore-walk": "^3.0.1",
                         "npm-bundled": "^1.0.1",
@@ -14531,8 +14286,7 @@
                 },
                 "npm-pick-manifest": {
                     "version": "3.0.2",
-                    "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-3.0.2.tgz",
-                    "integrity": "sha512-wNprTNg+X5nf+tDi+hbjdHhM4bX+mKqv6XmPh7B5eG+QY9VARfQPfCEH013H5GqfNj6ee8Ij2fg8yk0mzps1Vw==",
+                    "bundled": true,
                     "requires": {
                         "figgy-pudding": "^3.5.1",
                         "npm-package-arg": "^6.0.0",
@@ -14541,8 +14295,7 @@
                 },
                 "npm-profile": {
                     "version": "4.0.4",
-                    "resolved": "https://registry.npmjs.org/npm-profile/-/npm-profile-4.0.4.tgz",
-                    "integrity": "sha512-Ta8xq8TLMpqssF0H60BXS1A90iMoM6GeKwsmravJ6wYjWwSzcYBTdyWa3DZCYqPutacBMEm7cxiOkiIeCUAHDQ==",
+                    "bundled": true,
                     "requires": {
                         "aproba": "^1.1.2 || 2",
                         "figgy-pudding": "^3.4.1",
@@ -14551,8 +14304,7 @@
                 },
                 "npm-registry-fetch": {
                     "version": "4.0.7",
-                    "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-4.0.7.tgz",
-                    "integrity": "sha512-cny9v0+Mq6Tjz+e0erFAB+RYJ/AVGzkjnISiobqP8OWj9c9FLoZZu8/SPSKJWE17F1tk4018wfjV+ZbIbqC7fQ==",
+                    "bundled": true,
                     "requires": {
                         "JSONStream": "^1.3.4",
                         "bluebird": "^3.5.1",
@@ -14565,28 +14317,24 @@
                     "dependencies": {
                         "safe-buffer": {
                             "version": "5.2.1",
-                            "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
-                            "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
+                            "bundled": true
                         }
                     }
                 },
                 "npm-run-path": {
                     "version": "2.0.2",
-                    "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
-                    "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=",
+                    "bundled": true,
                     "requires": {
                         "path-key": "^2.0.0"
                     }
                 },
                 "npm-user-validate": {
                     "version": "1.0.1",
-                    "resolved": "https://registry.npmjs.org/npm-user-validate/-/npm-user-validate-1.0.1.tgz",
-                    "integrity": "sha512-uQwcd/tY+h1jnEaze6cdX/LrhWhoBxfSknxentoqmIuStxUExxjWd3ULMLFPiFUrZKbOVMowH6Jq2FRWfmhcEw=="
+                    "bundled": true
                 },
                 "npmlog": {
                     "version": "4.1.2",
-                    "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
-                    "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
+                    "bundled": true,
                     "requires": {
                         "are-we-there-yet": "~1.1.2",
                         "console-control-strings": "~1.1.0",
@@ -14596,28 +14344,23 @@
                 },
                 "number-is-nan": {
                     "version": "1.0.1",
-                    "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
-                    "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0="
+                    "bundled": true
                 },
                 "oauth-sign": {
                     "version": "0.9.0",
-                    "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
-                    "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ=="
+                    "bundled": true
                 },
                 "object-assign": {
                     "version": "4.1.1",
-                    "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
-                    "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
+                    "bundled": true
                 },
                 "object-keys": {
                     "version": "1.0.12",
-                    "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz",
-                    "integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag=="
+                    "bundled": true
                 },
                 "object.getownpropertydescriptors": {
                     "version": "2.0.3",
-                    "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz",
-                    "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=",
+                    "bundled": true,
                     "requires": {
                         "define-properties": "^1.1.2",
                         "es-abstract": "^1.5.1"
@@ -14625,31 +14368,26 @@
                 },
                 "once": {
                     "version": "1.4.0",
-                    "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
-                    "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+                    "bundled": true,
                     "requires": {
                         "wrappy": "1"
                     }
                 },
                 "opener": {
                     "version": "1.5.2",
-                    "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz",
-                    "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A=="
+                    "bundled": true
                 },
                 "os-homedir": {
                     "version": "1.0.2",
-                    "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
-                    "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M="
+                    "bundled": true
                 },
                 "os-tmpdir": {
                     "version": "1.0.2",
-                    "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
-                    "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ="
+                    "bundled": true
                 },
                 "osenv": {
                     "version": "0.1.5",
-                    "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz",
-                    "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
+                    "bundled": true,
                     "requires": {
                         "os-homedir": "^1.0.0",
                         "os-tmpdir": "^1.0.0"
@@ -14657,13 +14395,11 @@
                 },
                 "p-finally": {
                     "version": "1.0.0",
-                    "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
-                    "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4="
+                    "bundled": true
                 },
                 "package-json": {
                     "version": "4.0.1",
-                    "resolved": "https://registry.npmjs.org/package-json/-/package-json-4.0.1.tgz",
-                    "integrity": "sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0=",
+                    "bundled": true,
                     "requires": {
                         "got": "^6.7.1",
                         "registry-auth-token": "^3.0.1",
@@ -14673,8 +14409,7 @@
                 },
                 "pacote": {
                     "version": "9.5.12",
-                    "resolved": "https://registry.npmjs.org/pacote/-/pacote-9.5.12.tgz",
-                    "integrity": "sha512-BUIj/4kKbwWg4RtnBncXPJd15piFSVNpTzY0rysSr3VnMowTYgkGKcaHrbReepAkjTr8lH2CVWRi58Spg2CicQ==",
+                    "bundled": true,
                     "requires": {
                         "bluebird": "^3.5.3",
                         "cacache": "^12.0.2",
@@ -14710,8 +14445,7 @@
                     "dependencies": {
                         "minipass": {
                             "version": "2.9.0",
-                            "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz",
-                            "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==",
+                            "bundled": true,
                             "requires": {
                                 "safe-buffer": "^5.1.2",
                                 "yallist": "^3.0.0"
@@ -14721,8 +14455,7 @@
                 },
                 "parallel-transform": {
                     "version": "1.1.0",
-                    "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.1.0.tgz",
-                    "integrity": "sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY=",
+                    "bundled": true,
                     "requires": {
                         "cyclist": "~0.2.2",
                         "inherits": "^2.0.3",
@@ -14731,8 +14464,7 @@
                     "dependencies": {
                         "readable-stream": {
                             "version": "2.3.6",
-                            "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
-                            "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+                            "bundled": true,
                             "requires": {
                                 "core-util-is": "~1.0.0",
                                 "inherits": "~2.0.3",
@@ -14745,8 +14477,7 @@
                         },
                         "string_decoder": {
                             "version": "1.1.1",
-                            "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
-                            "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+                            "bundled": true,
                             "requires": {
                                 "safe-buffer": "~5.1.0"
                             }
@@ -14755,58 +14486,47 @@
                 },
                 "path-exists": {
                     "version": "3.0.0",
-                    "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
-                    "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU="
+                    "bundled": true
                 },
                 "path-is-absolute": {
                     "version": "1.0.1",
-                    "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
-                    "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
+                    "bundled": true
                 },
                 "path-is-inside": {
                     "version": "1.0.2",
-                    "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz",
-                    "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM="
+                    "bundled": true
                 },
                 "path-key": {
                     "version": "2.0.1",
-                    "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
-                    "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A="
+                    "bundled": true
                 },
                 "path-parse": {
                     "version": "1.0.7",
-                    "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
-                    "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
+                    "bundled": true
                 },
                 "performance-now": {
                     "version": "2.1.0",
-                    "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
-                    "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
+                    "bundled": true
                 },
                 "pify": {
                     "version": "3.0.0",
-                    "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
-                    "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY="
+                    "bundled": true
                 },
                 "prepend-http": {
                     "version": "1.0.4",
-                    "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz",
-                    "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw="
+                    "bundled": true
                 },
                 "process-nextick-args": {
                     "version": "2.0.0",
-                    "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
-                    "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw=="
+                    "bundled": true
                 },
                 "promise-inflight": {
                     "version": "1.0.1",
-                    "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz",
-                    "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM="
+                    "bundled": true
                 },
                 "promise-retry": {
                     "version": "1.1.1",
-                    "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-1.1.1.tgz",
-                    "integrity": "sha1-ZznpaOMFHaIM5kl/srUPaRHfPW0=",
+                    "bundled": true,
                     "requires": {
                         "err-code": "^1.0.0",
                         "retry": "^0.10.0"
@@ -14814,51 +14534,43 @@
                     "dependencies": {
                         "retry": {
                             "version": "0.10.1",
-                            "resolved": "https://registry.npmjs.org/retry/-/retry-0.10.1.tgz",
-                            "integrity": "sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q="
+                            "bundled": true
                         }
                     }
                 },
                 "promzard": {
                     "version": "0.3.0",
-                    "resolved": "https://registry.npmjs.org/promzard/-/promzard-0.3.0.tgz",
-                    "integrity": "sha1-JqXW7ox97kyxIggwWs+5O6OCqe4=",
+                    "bundled": true,
                     "requires": {
                         "read": "1"
                     }
                 },
                 "proto-list": {
                     "version": "1.2.4",
-                    "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz",
-                    "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk="
+                    "bundled": true
                 },
                 "protoduck": {
                     "version": "5.0.1",
-                    "resolved": "https://registry.npmjs.org/protoduck/-/protoduck-5.0.1.tgz",
-                    "integrity": "sha512-WxoCeDCoCBY55BMvj4cAEjdVUFGRWed9ZxPlqTKYyw1nDDTQ4pqmnIMAGfJlg7Dx35uB/M+PHJPTmGOvaCaPTg==",
+                    "bundled": true,
                     "requires": {
                         "genfun": "^5.0.0"
                     }
                 },
                 "prr": {
                     "version": "1.0.1",
-                    "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",
-                    "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY="
+                    "bundled": true
                 },
                 "pseudomap": {
                     "version": "1.0.2",
-                    "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
-                    "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM="
+                    "bundled": true
                 },
                 "psl": {
                     "version": "1.1.29",
-                    "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.29.tgz",
-                    "integrity": "sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ=="
+                    "bundled": true
                 },
                 "pump": {
                     "version": "3.0.0",
-                    "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
-                    "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
+                    "bundled": true,
                     "requires": {
                         "end-of-stream": "^1.1.0",
                         "once": "^1.3.1"
@@ -14866,8 +14578,7 @@
                 },
                 "pumpify": {
                     "version": "1.5.1",
-                    "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz",
-                    "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==",
+                    "bundled": true,
                     "requires": {
                         "duplexify": "^3.6.0",
                         "inherits": "^2.0.3",
@@ -14876,8 +14587,7 @@
                     "dependencies": {
                         "pump": {
                             "version": "2.0.1",
-                            "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz",
-                            "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==",
+                            "bundled": true,
                             "requires": {
                                 "end-of-stream": "^1.1.0",
                                 "once": "^1.3.1"
@@ -14887,23 +14597,19 @@
                 },
                 "punycode": {
                     "version": "1.4.1",
-                    "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
-                    "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4="
+                    "bundled": true
                 },
                 "qrcode-terminal": {
                     "version": "0.12.0",
-                    "resolved": "https://registry.npmjs.org/qrcode-terminal/-/qrcode-terminal-0.12.0.tgz",
-                    "integrity": "sha512-EXtzRZmC+YGmGlDFbXKxQiMZNwCLEO6BANKXG4iCtSIM0yqc/pappSx3RIKr4r0uh5JsBckOXeKrB3Iz7mdQpQ=="
+                    "bundled": true
                 },
                 "qs": {
                     "version": "6.5.2",
-                    "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
-                    "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
+                    "bundled": true
                 },
                 "query-string": {
                     "version": "6.8.2",
-                    "resolved": "https://registry.npmjs.org/query-string/-/query-string-6.8.2.tgz",
-                    "integrity": "sha512-J3Qi8XZJXh93t2FiKyd/7Ec6GNifsjKXUsVFkSBj/kjLsDylWhnCz4NT1bkPcKotttPW+QbKGqqPH8OoI2pdqw==",
+                    "bundled": true,
                     "requires": {
                         "decode-uri-component": "^0.2.0",
                         "split-on-first": "^1.0.0",
@@ -14912,13 +14618,11 @@
                 },
                 "qw": {
                     "version": "1.0.1",
-                    "resolved": "https://registry.npmjs.org/qw/-/qw-1.0.1.tgz",
-                    "integrity": "sha1-77/cdA+a0FQwRCassYNBLMi5ltQ="
+                    "bundled": true
                 },
                 "rc": {
                     "version": "1.2.8",
-                    "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
-                    "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
+                    "bundled": true,
                     "requires": {
                         "deep-extend": "^0.6.0",
                         "ini": "~1.3.0",
@@ -14928,24 +14632,21 @@
                 },
                 "read": {
                     "version": "1.0.7",
-                    "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz",
-                    "integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=",
+                    "bundled": true,
                     "requires": {
                         "mute-stream": "~0.0.4"
                     }
                 },
                 "read-cmd-shim": {
                     "version": "1.0.5",
-                    "resolved": "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-1.0.5.tgz",
-                    "integrity": "sha512-v5yCqQ/7okKoZZkBQUAfTsQ3sVJtXdNfbPnI5cceppoxEVLYA3k+VtV2omkeo8MS94JCy4fSiUwlRBAwCVRPUA==",
+                    "bundled": true,
                     "requires": {
                         "graceful-fs": "^4.1.2"
                     }
                 },
                 "read-installed": {
                     "version": "4.0.3",
-                    "resolved": "https://registry.npmjs.org/read-installed/-/read-installed-4.0.3.tgz",
-                    "integrity": "sha1-/5uLZ/GH0eTCm5/rMfayI6zRkGc=",
+                    "bundled": true,
                     "requires": {
                         "debuglog": "^1.0.1",
                         "graceful-fs": "^4.1.2",
@@ -14958,8 +14659,7 @@
                 },
                 "read-package-json": {
                     "version": "2.1.1",
-                    "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-2.1.1.tgz",
-                    "integrity": "sha512-dAiqGtVc/q5doFz6096CcnXhpYk0ZN8dEKVkGLU0CsASt8SrgF6SF7OTKAYubfvFhWaqofl+Y8HK19GR8jwW+A==",
+                    "bundled": true,
                     "requires": {
                         "glob": "^7.1.1",
                         "graceful-fs": "^4.1.2",
@@ -14970,8 +14670,7 @@
                 },
                 "read-package-tree": {
                     "version": "5.3.1",
-                    "resolved": "https://registry.npmjs.org/read-package-tree/-/read-package-tree-5.3.1.tgz",
-                    "integrity": "sha512-mLUDsD5JVtlZxjSlPPx1RETkNjjvQYuweKwNVt1Sn8kP5Jh44pvYuUHCp6xSVDZWbNxVxG5lyZJ921aJH61sTw==",
+                    "bundled": true,
                     "requires": {
                         "read-package-json": "^2.0.0",
                         "readdir-scoped-modules": "^1.0.0",
@@ -14980,8 +14679,7 @@
                 },
                 "readable-stream": {
                     "version": "3.6.0",
-                    "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
-                    "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+                    "bundled": true,
                     "requires": {
                         "inherits": "^2.0.3",
                         "string_decoder": "^1.1.1",
@@ -14990,8 +14688,7 @@
                 },
                 "readdir-scoped-modules": {
                     "version": "1.1.0",
-                    "resolved": "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz",
-                    "integrity": "sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw==",
+                    "bundled": true,
                     "requires": {
                         "debuglog": "^1.0.1",
                         "dezalgo": "^1.0.0",
@@ -15001,8 +14698,7 @@
                 },
                 "registry-auth-token": {
                     "version": "3.4.0",
-                    "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.4.0.tgz",
-                    "integrity": "sha512-4LM6Fw8eBQdwMYcES4yTnn2TqIasbXuwDx3um+QRs7S55aMKCBKBxvPXl2RiUjHwuJLTyYfxSpmfSAjQpcuP+A==",
+                    "bundled": true,
                     "requires": {
                         "rc": "^1.1.6",
                         "safe-buffer": "^5.0.1"
@@ -15010,16 +14706,14 @@
                 },
                 "registry-url": {
                     "version": "3.1.0",
-                    "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz",
-                    "integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=",
+                    "bundled": true,
                     "requires": {
                         "rc": "^1.0.1"
                     }
                 },
                 "request": {
                     "version": "2.88.0",
-                    "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz",
-                    "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==",
+                    "bundled": true,
                     "requires": {
                         "aws-sign2": "~0.7.0",
                         "aws4": "^1.8.0",
@@ -15045,115 +14739,96 @@
                 },
                 "require-directory": {
                     "version": "2.1.1",
-                    "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
-                    "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I="
+                    "bundled": true
                 },
                 "require-main-filename": {
                     "version": "2.0.0",
-                    "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
-                    "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg=="
+                    "bundled": true
                 },
                 "resolve-from": {
                     "version": "4.0.0",
-                    "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
-                    "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="
+                    "bundled": true
                 },
                 "retry": {
                     "version": "0.12.0",
-                    "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz",
-                    "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs="
+                    "bundled": true
                 },
                 "rimraf": {
                     "version": "2.7.1",
-                    "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
-                    "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
+                    "bundled": true,
                     "requires": {
                         "glob": "^7.1.3"
                     }
                 },
                 "run-queue": {
                     "version": "1.0.3",
-                    "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz",
-                    "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=",
+                    "bundled": true,
                     "requires": {
                         "aproba": "^1.1.1"
                     },
                     "dependencies": {
                         "aproba": {
                             "version": "1.2.0",
-                            "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
-                            "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw=="
+                            "bundled": true
                         }
                     }
                 },
                 "safe-buffer": {
                     "version": "5.1.2",
-                    "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
-                    "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+                    "bundled": true
                 },
                 "safer-buffer": {
                     "version": "2.1.2",
-                    "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
-                    "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+                    "bundled": true
                 },
                 "semver": {
                     "version": "5.7.1",
-                    "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
-                    "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
+                    "bundled": true
                 },
                 "semver-diff": {
                     "version": "2.1.0",
-                    "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-2.1.0.tgz",
-                    "integrity": "sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=",
+                    "bundled": true,
                     "requires": {
                         "semver": "^5.0.3"
                     }
                 },
                 "set-blocking": {
                     "version": "2.0.0",
-                    "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
-                    "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="
+                    "bundled": true
                 },
                 "sha": {
                     "version": "3.0.0",
-                    "resolved": "https://registry.npmjs.org/sha/-/sha-3.0.0.tgz",
-                    "integrity": "sha512-DOYnM37cNsLNSGIG/zZWch5CKIRNoLdYUQTQlcgkRkoYIUwDYjqDyye16YcDZg/OPdcbUgTKMjc4SY6TB7ZAPw==",
+                    "bundled": true,
                     "requires": {
                         "graceful-fs": "^4.1.2"
                     }
                 },
                 "shebang-command": {
                     "version": "1.2.0",
-                    "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
-                    "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
+                    "bundled": true,
                     "requires": {
                         "shebang-regex": "^1.0.0"
                     }
                 },
                 "shebang-regex": {
                     "version": "1.0.0",
-                    "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
-                    "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM="
+                    "bundled": true
                 },
                 "signal-exit": {
                     "version": "3.0.2",
-                    "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
-                    "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0="
+                    "bundled": true
                 },
                 "slide": {
                     "version": "1.1.6",
-                    "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz",
-                    "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc="
+                    "bundled": true
                 },
                 "smart-buffer": {
                     "version": "4.1.0",
-                    "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.1.0.tgz",
-                    "integrity": "sha512-iVICrxOzCynf/SNaBQCw34eM9jROU/s5rzIhpOvzhzuYHfJR/DhZfDkXiZSgKXfgv26HT3Yni3AV/DGw0cGnnw=="
+                    "bundled": true
                 },
                 "socks": {
                     "version": "2.3.3",
-                    "resolved": "https://registry.npmjs.org/socks/-/socks-2.3.3.tgz",
-                    "integrity": "sha512-o5t52PCNtVdiOvzMry7wU4aOqYWL0PeCXRWBEiJow4/i/wr+wpsJQ9awEu1EonLIqsfGd5qSgDdxEOvCdmBEpA==",
+                    "bundled": true,
                     "requires": {
                         "ip": "1.1.5",
                         "smart-buffer": "^4.1.0"
@@ -15161,8 +14836,7 @@
                 },
                 "socks-proxy-agent": {
                     "version": "4.0.2",
-                    "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-4.0.2.tgz",
-                    "integrity": "sha512-NT6syHhI9LmuEMSK6Kd2V7gNv5KFZoLE7V5udWmn0de+3Mkj3UMA/AJPLyeNUVmElCurSHtUdM3ETpR3z770Wg==",
+                    "bundled": true,
                     "requires": {
                         "agent-base": "~4.2.1",
                         "socks": "~2.3.2"
@@ -15170,8 +14844,7 @@
                     "dependencies": {
                         "agent-base": {
                             "version": "4.2.1",
-                            "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz",
-                            "integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==",
+                            "bundled": true,
                             "requires": {
                                 "es6-promisify": "^5.0.0"
                             }
@@ -15180,13 +14853,11 @@
                 },
                 "sorted-object": {
                     "version": "2.0.1",
-                    "resolved": "https://registry.npmjs.org/sorted-object/-/sorted-object-2.0.1.tgz",
-                    "integrity": "sha1-fWMfS9OnmKJK8d/8+/6DM3pd9fw="
+                    "bundled": true
                 },
                 "sorted-union-stream": {
                     "version": "2.1.3",
-                    "resolved": "https://registry.npmjs.org/sorted-union-stream/-/sorted-union-stream-2.1.3.tgz",
-                    "integrity": "sha1-x3lMfgd4gAUv9xqNSi27Sppjisc=",
+                    "bundled": true,
                     "requires": {
                         "from2": "^1.3.0",
                         "stream-iterate": "^1.1.0"
@@ -15194,8 +14865,7 @@
                     "dependencies": {
                         "from2": {
                             "version": "1.3.0",
-                            "resolved": "https://registry.npmjs.org/from2/-/from2-1.3.0.tgz",
-                            "integrity": "sha1-iEE7qqX5pZfP3pIh2GmGzTwGHf0=",
+                            "bundled": true,
                             "requires": {
                                 "inherits": "~2.0.1",
                                 "readable-stream": "~1.1.10"
@@ -15203,13 +14873,11 @@
                         },
                         "isarray": {
                             "version": "0.0.1",
-                            "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
-                            "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
+                            "bundled": true
                         },
                         "readable-stream": {
                             "version": "1.1.14",
-                            "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
-                            "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
+                            "bundled": true,
                             "requires": {
                                 "core-util-is": "~1.0.0",
                                 "inherits": "~2.0.1",
@@ -15219,15 +14887,13 @@
                         },
                         "string_decoder": {
                             "version": "0.10.31",
-                            "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
-                            "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
+                            "bundled": true
                         }
                     }
                 },
                 "spdx-correct": {
                     "version": "3.0.0",
-                    "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz",
-                    "integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==",
+                    "bundled": true,
                     "requires": {
                         "spdx-expression-parse": "^3.0.0",
                         "spdx-license-ids": "^3.0.0"
@@ -15235,13 +14901,11 @@
                 },
                 "spdx-exceptions": {
                     "version": "2.1.0",
-                    "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz",
-                    "integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg=="
+                    "bundled": true
                 },
                 "spdx-expression-parse": {
                     "version": "3.0.0",
-                    "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz",
-                    "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==",
+                    "bundled": true,
                     "requires": {
                         "spdx-exceptions": "^2.1.0",
                         "spdx-license-ids": "^3.0.0"
@@ -15249,18 +14913,15 @@
                 },
                 "spdx-license-ids": {
                     "version": "3.0.5",
-                    "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz",
-                    "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q=="
+                    "bundled": true
                 },
                 "split-on-first": {
                     "version": "1.1.0",
-                    "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz",
-                    "integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw=="
+                    "bundled": true
                 },
                 "sshpk": {
                     "version": "1.14.2",
-                    "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz",
-                    "integrity": "sha1-xvxhZIo9nE52T9P8306hBeSSupg=",
+                    "bundled": true,
                     "requires": {
                         "asn1": "~0.2.3",
                         "assert-plus": "^1.0.0",
@@ -15275,16 +14936,14 @@
                 },
                 "ssri": {
                     "version": "6.0.2",
-                    "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.2.tgz",
-                    "integrity": "sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q==",
+                    "bundled": true,
                     "requires": {
                         "figgy-pudding": "^3.5.1"
                     }
                 },
                 "stream-each": {
                     "version": "1.2.2",
-                    "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.2.tgz",
-                    "integrity": "sha512-mc1dbFhGBxvTM3bIWmAAINbqiuAk9TATcfIQC8P+/+HJefgaiTlMn2dHvkX8qlI12KeYKSQ1Ua9RrIqrn1VPoA==",
+                    "bundled": true,
                     "requires": {
                         "end-of-stream": "^1.1.0",
                         "stream-shift": "^1.0.0"
@@ -15292,8 +14951,7 @@
                 },
                 "stream-iterate": {
                     "version": "1.2.0",
-                    "resolved": "https://registry.npmjs.org/stream-iterate/-/stream-iterate-1.2.0.tgz",
-                    "integrity": "sha1-K9fHcpbBcCpGSIuK1B95hl7s1OE=",
+                    "bundled": true,
                     "requires": {
                         "readable-stream": "^2.1.5",
                         "stream-shift": "^1.0.0"
@@ -15301,8 +14959,7 @@
                     "dependencies": {
                         "readable-stream": {
                             "version": "2.3.6",
-                            "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
-                            "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+                            "bundled": true,
                             "requires": {
                                 "core-util-is": "~1.0.0",
                                 "inherits": "~2.0.3",
@@ -15315,8 +14972,7 @@
                         },
                         "string_decoder": {
                             "version": "1.1.1",
-                            "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
-                            "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+                            "bundled": true,
                             "requires": {
                                 "safe-buffer": "~5.1.0"
                             }
@@ -15325,18 +14981,15 @@
                 },
                 "stream-shift": {
                     "version": "1.0.0",
-                    "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz",
-                    "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI="
+                    "bundled": true
                 },
                 "strict-uri-encode": {
                     "version": "2.0.0",
-                    "resolved": false,
-                    "integrity": "sha1-ucczDHBChi9rFC3CdLvMWGbONUY="
+                    "bundled": true
                 },
                 "string-width": {
                     "version": "2.1.1",
-                    "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
-                    "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
+                    "bundled": true,
                     "requires": {
                         "is-fullwidth-code-point": "^2.0.0",
                         "strip-ansi": "^4.0.0"
@@ -15344,18 +14997,15 @@
                     "dependencies": {
                         "ansi-regex": {
                             "version": "3.0.0",
-                            "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
-                            "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg="
+                            "bundled": true
                         },
                         "is-fullwidth-code-point": {
                             "version": "2.0.0",
-                            "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
-                            "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="
+                            "bundled": true
                         },
                         "strip-ansi": {
                             "version": "4.0.0",
-                            "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
-                            "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+                            "bundled": true,
                             "requires": {
                                 "ansi-regex": "^3.0.0"
                             }
@@ -15377,39 +15027,33 @@
                 },
                 "stringify-package": {
                     "version": "1.0.1",
-                    "resolved": "https://registry.npmjs.org/stringify-package/-/stringify-package-1.0.1.tgz",
-                    "integrity": "sha512-sa4DUQsYciMP1xhKWGuFM04fB0LG/9DlluZoSVywUMRNvzid6XucHK0/90xGxRoHrAaROrcHK1aPKaijCtSrhg=="
+                    "bundled": true
                 },
                 "strip-ansi": {
                     "version": "3.0.1",
-                    "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
-                    "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+                    "bundled": true,
                     "requires": {
                         "ansi-regex": "^2.0.0"
                     }
                 },
                 "strip-eof": {
                     "version": "1.0.0",
-                    "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
-                    "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8="
+                    "bundled": true
                 },
                 "strip-json-comments": {
                     "version": "2.0.1",
-                    "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
-                    "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo="
+                    "bundled": true
                 },
                 "supports-color": {
                     "version": "5.4.0",
-                    "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz",
-                    "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==",
+                    "bundled": true,
                     "requires": {
                         "has-flag": "^3.0.0"
                     }
                 },
                 "tar": {
                     "version": "4.4.19",
-                    "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.19.tgz",
-                    "integrity": "sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA==",
+                    "bundled": true,
                     "requires": {
                         "chownr": "^1.1.4",
                         "fs-minipass": "^1.2.7",
@@ -15422,8 +15066,7 @@
                     "dependencies": {
                         "minipass": {
                             "version": "2.9.0",
-                            "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz",
-                            "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==",
+                            "bundled": true,
                             "requires": {
                                 "safe-buffer": "^5.1.2",
                                 "yallist": "^3.0.0"
@@ -15431,38 +15074,32 @@
                         },
                         "safe-buffer": {
                             "version": "5.2.1",
-                            "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
-                            "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
+                            "bundled": true
                         },
                         "yallist": {
                             "version": "3.1.1",
-                            "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
-                            "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="
+                            "bundled": true
                         }
                     }
                 },
                 "term-size": {
                     "version": "1.2.0",
-                    "resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz",
-                    "integrity": "sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=",
+                    "bundled": true,
                     "requires": {
                         "execa": "^0.7.0"
                     }
                 },
                 "text-table": {
                     "version": "0.2.0",
-                    "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
-                    "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ="
+                    "bundled": true
                 },
                 "through": {
                     "version": "2.3.8",
-                    "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
-                    "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU="
+                    "bundled": true
                 },
                 "through2": {
                     "version": "2.0.3",
-                    "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz",
-                    "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=",
+                    "bundled": true,
                     "requires": {
                         "readable-stream": "^2.1.5",
                         "xtend": "~4.0.1"
@@ -15470,8 +15107,7 @@
                     "dependencies": {
                         "readable-stream": {
                             "version": "2.3.6",
-                            "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
-                            "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+                            "bundled": true,
                             "requires": {
                                 "core-util-is": "~1.0.0",
                                 "inherits": "~2.0.3",
@@ -15484,8 +15120,7 @@
                         },
                         "string_decoder": {
                             "version": "1.1.1",
-                            "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
-                            "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+                            "bundled": true,
                             "requires": {
                                 "safe-buffer": "~5.1.0"
                             }
@@ -15494,18 +15129,15 @@
                 },
                 "timed-out": {
                     "version": "4.0.1",
-                    "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz",
-                    "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8="
+                    "bundled": true
                 },
                 "tiny-relative-date": {
                     "version": "1.3.0",
-                    "resolved": "https://registry.npmjs.org/tiny-relative-date/-/tiny-relative-date-1.3.0.tgz",
-                    "integrity": "sha512-MOQHpzllWxDCHHaDno30hhLfbouoYlOI8YlMNtvKe1zXbjEVhbcEovQxvZrPvtiYW630GQDoMMarCnjfyfHA+A=="
+                    "bundled": true
                 },
                 "tough-cookie": {
                     "version": "2.4.3",
-                    "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz",
-                    "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==",
+                    "bundled": true,
                     "requires": {
                         "psl": "^1.1.24",
                         "punycode": "^1.4.1"
@@ -15513,71 +15145,60 @@
                 },
                 "tunnel-agent": {
                     "version": "0.6.0",
-                    "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
-                    "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
+                    "bundled": true,
                     "requires": {
                         "safe-buffer": "^5.0.1"
                     }
                 },
                 "tweetnacl": {
                     "version": "0.14.5",
-                    "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
-                    "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
+                    "bundled": true,
                     "optional": true
                 },
                 "typedarray": {
                     "version": "0.0.6",
-                    "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
-                    "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
+                    "bundled": true
                 },
                 "uid-number": {
                     "version": "0.0.6",
-                    "resolved": "https://registry.npmjs.org/uid-number/-/uid-number-0.0.6.tgz",
-                    "integrity": "sha1-DqEOgDXo61uOREnwbaHHMGY7qoE="
+                    "bundled": true
                 },
                 "umask": {
                     "version": "1.1.0",
-                    "resolved": "https://registry.npmjs.org/umask/-/umask-1.1.0.tgz",
-                    "integrity": "sha1-8pzr8B31F5ErtY/5xOUP3o4zMg0="
+                    "bundled": true
                 },
                 "unique-filename": {
                     "version": "1.1.1",
-                    "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz",
-                    "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==",
+                    "bundled": true,
                     "requires": {
                         "unique-slug": "^2.0.0"
                     }
                 },
                 "unique-slug": {
                     "version": "2.0.0",
-                    "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.0.tgz",
-                    "integrity": "sha1-22Z258fMBimHj/GWCXx4hVrp9Ks=",
+                    "bundled": true,
                     "requires": {
                         "imurmurhash": "^0.1.4"
                     }
                 },
                 "unique-string": {
                     "version": "1.0.0",
-                    "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz",
-                    "integrity": "sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=",
+                    "bundled": true,
                     "requires": {
                         "crypto-random-string": "^1.0.0"
                     }
                 },
                 "unpipe": {
                     "version": "1.0.0",
-                    "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
-                    "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
+                    "bundled": true
                 },
                 "unzip-response": {
                     "version": "2.0.1",
-                    "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz",
-                    "integrity": "sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c="
+                    "bundled": true
                 },
                 "update-notifier": {
                     "version": "2.5.0",
-                    "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-2.5.0.tgz",
-                    "integrity": "sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw==",
+                    "bundled": true,
                     "requires": {
                         "boxen": "^1.2.1",
                         "chalk": "^2.0.1",
@@ -15593,54 +15214,46 @@
                 },
                 "uri-js": {
                     "version": "4.4.0",
-                    "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz",
-                    "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==",
+                    "bundled": true,
                     "requires": {
                         "punycode": "^2.1.0"
                     },
                     "dependencies": {
                         "punycode": {
                             "version": "2.1.1",
-                            "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
-                            "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
+                            "bundled": true
                         }
                     }
                 },
                 "url-parse-lax": {
                     "version": "1.0.0",
-                    "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz",
-                    "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=",
+                    "bundled": true,
                     "requires": {
                         "prepend-http": "^1.0.1"
                     }
                 },
                 "util-deprecate": {
                     "version": "1.0.2",
-                    "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
-                    "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
+                    "bundled": true
                 },
                 "util-extend": {
                     "version": "1.0.3",
-                    "resolved": "https://registry.npmjs.org/util-extend/-/util-extend-1.0.3.tgz",
-                    "integrity": "sha1-p8IW0mdUUWljeztu3GypEZ4v+T8="
+                    "bundled": true
                 },
                 "util-promisify": {
                     "version": "2.1.0",
-                    "resolved": "https://registry.npmjs.org/util-promisify/-/util-promisify-2.1.0.tgz",
-                    "integrity": "sha1-PCI2R2xNMsX/PEcAKt18E7moKlM=",
+                    "bundled": true,
                     "requires": {
                         "object.getownpropertydescriptors": "^2.0.3"
                     }
                 },
                 "uuid": {
                     "version": "3.3.3",
-                    "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz",
-                    "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ=="
+                    "bundled": true
                 },
                 "validate-npm-package-license": {
                     "version": "3.0.4",
-                    "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
-                    "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
+                    "bundled": true,
                     "requires": {
                         "spdx-correct": "^3.0.0",
                         "spdx-expression-parse": "^3.0.0"
@@ -15648,16 +15261,14 @@
                 },
                 "validate-npm-package-name": {
                     "version": "3.0.0",
-                    "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz",
-                    "integrity": "sha1-X6kS2B630MdK/BQN5zF/DKffQ34=",
+                    "bundled": true,
                     "requires": {
                         "builtins": "^1.0.3"
                     }
                 },
                 "verror": {
                     "version": "1.10.0",
-                    "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
-                    "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
+                    "bundled": true,
                     "requires": {
                         "assert-plus": "^1.0.0",
                         "core-util-is": "1.0.2",
@@ -15666,37 +15277,32 @@
                 },
                 "wcwidth": {
                     "version": "1.0.1",
-                    "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz",
-                    "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=",
+                    "bundled": true,
                     "requires": {
                         "defaults": "^1.0.3"
                     }
                 },
                 "which": {
                     "version": "1.3.1",
-                    "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
-                    "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+                    "bundled": true,
                     "requires": {
                         "isexe": "^2.0.0"
                     }
                 },
                 "which-module": {
                     "version": "2.0.0",
-                    "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
-                    "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho="
+                    "bundled": true
                 },
                 "wide-align": {
                     "version": "1.1.2",
-                    "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz",
-                    "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==",
+                    "bundled": true,
                     "requires": {
                         "string-width": "^1.0.2"
                     },
                     "dependencies": {
                         "string-width": {
                             "version": "1.0.2",
-                            "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
-                            "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+                            "bundled": true,
                             "requires": {
                                 "code-point-at": "^1.0.0",
                                 "is-fullwidth-code-point": "^1.0.0",
@@ -15707,24 +15313,21 @@
                 },
                 "widest-line": {
                     "version": "2.0.1",
-                    "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.1.tgz",
-                    "integrity": "sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==",
+                    "bundled": true,
                     "requires": {
                         "string-width": "^2.1.1"
                     }
                 },
                 "worker-farm": {
                     "version": "1.7.0",
-                    "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz",
-                    "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==",
+                    "bundled": true,
                     "requires": {
                         "errno": "~0.1.7"
                     }
                 },
                 "wrap-ansi": {
                     "version": "5.1.0",
-                    "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",
-                    "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==",
+                    "bundled": true,
                     "requires": {
                         "ansi-styles": "^3.2.0",
                         "string-width": "^3.0.0",
@@ -15733,18 +15336,15 @@
                     "dependencies": {
                         "ansi-regex": {
                             "version": "4.1.1",
-                            "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz",
-                            "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g=="
+                            "bundled": true
                         },
                         "is-fullwidth-code-point": {
                             "version": "2.0.0",
-                            "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
-                            "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="
+                            "bundled": true
                         },
                         "string-width": {
                             "version": "3.1.0",
-                            "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
-                            "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
+                            "bundled": true,
                             "requires": {
                                 "emoji-regex": "^7.0.1",
                                 "is-fullwidth-code-point": "^2.0.0",
@@ -15753,8 +15353,7 @@
                         },
                         "strip-ansi": {
                             "version": "5.2.0",
-                            "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
-                            "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+                            "bundled": true,
                             "requires": {
                                 "ansi-regex": "^4.1.0"
                             }
@@ -15763,13 +15362,11 @@
                 },
                 "wrappy": {
                     "version": "1.0.2",
-                    "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
-                    "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
+                    "bundled": true
                 },
                 "write-file-atomic": {
                     "version": "2.4.3",
-                    "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz",
-                    "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==",
+                    "bundled": true,
                     "requires": {
                         "graceful-fs": "^4.1.11",
                         "imurmurhash": "^0.1.4",
@@ -15778,28 +15375,23 @@
                 },
                 "xdg-basedir": {
                     "version": "3.0.0",
-                    "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz",
-                    "integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ="
+                    "bundled": true
                 },
                 "xtend": {
                     "version": "4.0.1",
-                    "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
-                    "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68="
+                    "bundled": true
                 },
                 "y18n": {
                     "version": "4.0.1",
-                    "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz",
-                    "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ=="
+                    "bundled": true
                 },
                 "yallist": {
                     "version": "3.0.3",
-                    "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz",
-                    "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A=="
+                    "bundled": true
                 },
                 "yargs": {
                     "version": "14.2.3",
-                    "resolved": "https://registry.npmjs.org/yargs/-/yargs-14.2.3.tgz",
-                    "integrity": "sha512-ZbotRWhF+lkjijC/VhmOT9wSgyBQ7+zr13+YLkhfsSiTriYsMzkTUFP18pFhWwBeMa5gUc1MzbhrO6/VB7c9Xg==",
+                    "bundled": true,
                     "requires": {
                         "cliui": "^5.0.0",
                         "decamelize": "^1.2.0",
@@ -15816,26 +15408,22 @@
                     "dependencies": {
                         "ansi-regex": {
                             "version": "4.1.0",
-                            "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
-                            "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg=="
+                            "bundled": true
                         },
                         "find-up": {
                             "version": "3.0.0",
-                            "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
-                            "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
+                            "bundled": true,
                             "requires": {
                                 "locate-path": "^3.0.0"
                             }
                         },
                         "is-fullwidth-code-point": {
                             "version": "2.0.0",
-                            "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
-                            "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="
+                            "bundled": true
                         },
                         "locate-path": {
                             "version": "3.0.0",
-                            "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
-                            "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
+                            "bundled": true,
                             "requires": {
                                 "p-locate": "^3.0.0",
                                 "path-exists": "^3.0.0"
@@ -15843,29 +15431,25 @@
                         },
                         "p-limit": {
                             "version": "2.3.0",
-                            "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
-                            "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+                            "bundled": true,
                             "requires": {
                                 "p-try": "^2.0.0"
                             }
                         },
                         "p-locate": {
                             "version": "3.0.0",
-                            "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
-                            "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
+                            "bundled": true,
                             "requires": {
                                 "p-limit": "^2.0.0"
                             }
                         },
                         "p-try": {
                             "version": "2.2.0",
-                            "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
-                            "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="
+                            "bundled": true
                         },
                         "string-width": {
                             "version": "3.1.0",
-                            "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
-                            "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
+                            "bundled": true,
                             "requires": {
                                 "emoji-regex": "^7.0.1",
                                 "is-fullwidth-code-point": "^2.0.0",
@@ -15874,8 +15458,7 @@
                         },
                         "strip-ansi": {
                             "version": "5.2.0",
-                            "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
-                            "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+                            "bundled": true,
                             "requires": {
                                 "ansi-regex": "^4.1.0"
                             }
@@ -15884,8 +15467,7 @@
                 },
                 "yargs-parser": {
                     "version": "15.0.1",
-                    "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-15.0.1.tgz",
-                    "integrity": "sha512-0OAMV2mAZQrs3FkNpDQcBk1x5HXb8X4twADss4S0Iuk+2dGnLOE/fRHrsYm542GduMveyA77OF4wrNJuanRCWw==",
+                    "bundled": true,
                     "requires": {
                         "camelcase": "^5.0.0",
                         "decamelize": "^1.2.0"
@@ -15893,8 +15475,7 @@
                     "dependencies": {
                         "camelcase": {
                             "version": "5.3.1",
-                            "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
-                            "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="
+                            "bundled": true
                         }
                     }
                 }
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 02bc55e7a..bcfa695f0 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -88,11 +88,10 @@ export class CollectionSchemaView extends CollectionSubView() {
             this._selectedDocs.add(doc);
             this._lastSelectedRow = index;
         }
-        
+
         if (this._lastSelectedRow && this._selectedDocs.size > 0) {
             SelectionManager.SelectSchemaViewDoc(this.childDocs[this._lastSelectedRow]);
-        }
-        else {
+        } else {
             SelectionManager.SelectSchemaViewDoc(undefined);
         }
     };
@@ -154,7 +153,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     @action
     addNewTextDoc = (value: string, shiftDown?: boolean, forceEmptyNote?: boolean) => {
         if (!value && !forceEmptyNote) return false;
-        const newDoc = Docs.Create.TextDocument(value, {title: value});
+        const newDoc = Docs.Create.TextDocument(value, { title: value });
         FormattedTextBox.SelectOnLoad = newDoc[Id];
         FormattedTextBox.SelectOnLoadChar = forceEmptyNote ? '' : ' ';
         return this.props.addDocument?.(newDoc) || false;
diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
index 9bd1b843f..b9dbf4f57 100644
--- a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
@@ -1,9 +1,8 @@
 import React = require('react');
+import { computed } from 'mobx';
 import { observer } from 'mobx-react';
-import './CollectionSchemaView.scss';
 import { EditableView } from '../../EditableView';
-import { emptyFunction } from '../../../../Utils';
-import { action, computed } from 'mobx';
+import './CollectionSchemaView.scss';
 
 export interface SchemaColumnHeaderProps {
     columnKeys: string[];
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index ea2ebed7a..3d1fa0ee2 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -36,12 +36,13 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
         e.stopPropagation();
 
         setupMoveUpEvents(
-            this, e,
-            (e) => this.props.startDrag(e, this.props.Document),
+            this,
+            e,
+            e => this.props.startDrag(e, this.props.Document),
             emptyFunction,
-            (e) => this.props.selectRow(e, this.props.Document, this.props.rowIndex)
-        )
-    }
+            e => this.props.selectRow(e, this.props.Document, this.props.rowIndex)
+        );
+    };
 
     onPointerEnter = (e: any) => {
         if (!this.props.dragging) return;
@@ -54,7 +55,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
         let dragIsRow: boolean = true;
         DragManager.docsBeingDragged.forEach(doc => {
             dragIsRow = this.props.selectedRows.has(doc);
-        })
+        });
         if (this._ref && dragIsRow) {
             const rect = this._ref.getBoundingClientRect();
             const y = e.clientY - rect.top; //y position within the element.
@@ -82,17 +83,35 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
 
     render() {
         return (
-            <div className="schema-row" style={this.isSelected() ? { backgroundColor: Colors.LIGHT_BLUE, opacity: this.props.dragging ? 0.5 : 1} : {}} onPointerDown={this.onRowPointerDown} onPointerEnter={this.onPointerEnter} onPointerLeave={this.onPointerLeave} ref={(row: HTMLDivElement | null) => (this._ref = row)}>
-                <div className="row-menu" style={{width: this.props.rowMenuWidth}}>
-                    <div className="row-button" onPointerDown={undoBatch((e) => {e.stopPropagation(); this.props.removeDocument?.(this.props.Document)})}>
+            <div
+                className="schema-row"
+                style={this.isSelected() ? { backgroundColor: Colors.LIGHT_BLUE, opacity: this.props.dragging ? 0.5 : 1 } : {}}
+                onPointerDown={this.onRowPointerDown}
+                onPointerEnter={this.onPointerEnter}
+                onPointerLeave={this.onPointerLeave}
+                ref={(row: HTMLDivElement | null) => (this._ref = row)}>
+                <div className="row-menu" style={{ width: this.props.rowMenuWidth }}>
+                    <div
+                        className="row-button"
+                        onPointerDown={undoBatch(e => {
+                            e.stopPropagation();
+                            this.props.removeDocument?.(this.props.Document);
+                        })}>
                         <FontAwesomeIcon icon="times" />
                     </div>
-                    <div className="row-button" onPointerDown={(e) => {e.stopPropagation(); this.props.addDocTab(this.props.Document, 'add:right')}}>
+                    <div
+                        className="row-button"
+                        onPointerDown={e => {
+                            e.stopPropagation();
+                            this.props.addDocTab(this.props.Document, 'add:right');
+                        }}>
                         <FontAwesomeIcon icon="external-link-alt" />
                     </div>
                 </div>
                 <div className="row-cells">
-                    {this.props.columnKeys.map((key, index) => (<SchemaTableCell Document={this.props.Document} fieldKey={key} columnWidth={this.props.columnWidths[index]} />))}
+                    {this.props.columnKeys.map((key, index) => (
+                        <SchemaTableCell Document={this.props.Document} fieldKey={key} columnWidth={this.props.columnWidths[index]} />
+                    ))}
                 </div>
             </div>
         );
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 1eb5e0e01..7e2fa1f6f 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -1,7 +1,6 @@
 import React = require('react');
 import { observer } from 'mobx-react';
 import { Doc, Field } from '../../../../fields/Doc';
-import { StrCast } from '../../../../fields/Types';
 import './CollectionSchemaView.scss';
 
 export interface SchemaTableCellProps {
-- 
cgit v1.2.3-70-g09d2


From 330752fa253b61136b78ce7147e09e9d6004f833 Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Thu, 18 Aug 2022 14:08:31 -0400
Subject: added external drop and column resize

---
 .../collectionSchema/CollectionSchemaView.scss     |  32 ++++++-
 .../collectionSchema/CollectionSchemaView.tsx      | 105 ++++++++++++++++++---
 .../collectionSchema/SchemaColumnHeader.tsx        |   8 +-
 .../collections/collectionSchema/SchemaRowBox.tsx  |   6 +-
 4 files changed, 133 insertions(+), 18 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaRowBox.tsx')

diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
index 83164a82a..1d0ab459d 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
@@ -11,11 +11,12 @@
         .schema-row {
             display: flex;
             flex-direction: row;
+            max-height: 70px;
+            overflow: auto;
 
             .schema-column-header,
             .schema-table-cell,
             .row-menu {
-                min-width: 50px;
                 border: 1px solid $medium-gray;
                 padding: 5px;
                 overflow: hidden;
@@ -31,6 +32,34 @@
                 flex-direction: row;
                 justify-content: space-between;
                 align-items: center;
+                padding: 0;
+
+                .schema-column-title {
+                    flex-grow: 2;
+                    margin: 5px;
+                }
+
+                .schema-header-menu {
+                    margin: 5px;
+                }
+
+                .schema-column-resizer {
+                    height: 100%;
+                    width: 3px;
+                    cursor: ew-resize;
+
+                    &:hover {
+                        background-color: $light-blue;
+                    }
+                }
+
+                .schema-column-resizer.right {
+                    align-self: flex-end;
+                }
+
+                .schema-column-resizer.left {
+                    align-self: flex-start;
+                }
             }
         }
 
@@ -41,6 +70,7 @@
                 display: flex;
                 flex-direction: row;
                 justify-content: center;
+                min-width: 50px;
             }
 
             .row-cells {
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 4d96d5f7e..a09d2722c 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -2,25 +2,25 @@ import React = require('react');
 import { action, computed, observable, ObservableSet } from 'mobx';
 import { observer } from 'mobx-react';
 import { Doc, DocListCast } from '../../../../fields/Doc';
+import { Id } from '../../../../fields/FieldSymbols';
 import { List } from '../../../../fields/List';
+import { RichTextField } from '../../../../fields/RichTextField';
 import { listSpec } from '../../../../fields/Schema';
 import { Cast, StrCast } from '../../../../fields/Types';
+import { ImageField } from '../../../../fields/URLField';
+import { emptyFunction, returnEmptyString, setupMoveUpEvents } from '../../../../Utils';
+import { Docs, DocUtils } from '../../../documents/Documents';
 import { DragManager } from '../../../util/DragManager';
-import { CollectionSubView } from '../CollectionSubView';
-import './CollectionSchemaView.scss';
-import { SchemaColumnHeader } from './SchemaColumnHeader';
-import { SchemaRowBox } from './SchemaRowBox';
 import { SelectionManager } from '../../../util/SelectionManager';
 import { undoBatch } from '../../../util/UndoManager';
-import { EditableView } from '../../EditableView';
-import { returnEmptyString } from '../../../../Utils';
-import { Docs, DocUtils } from '../../../documents/Documents';
-import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox';
 import { ContextMenu } from '../../ContextMenu';
 import { ContextMenuProps } from '../../ContextMenuItem';
-import { Id } from '../../../../fields/FieldSymbols';
-import { RichTextField } from '../../../../fields/RichTextField';
-import { ImageField } from '../../../../fields/URLField';
+import { EditableView } from '../../EditableView';
+import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox';
+import { CollectionSubView } from '../CollectionSubView';
+import './CollectionSchemaView.scss';
+import { SchemaColumnHeader } from './SchemaColumnHeader';
+import { SchemaRowBox } from './SchemaRowBox';
 
 export enum ColumnType {
     Number,
@@ -38,16 +38,18 @@ export class CollectionSchemaView extends CollectionSubView() {
     private _lastSelectedRow: number | undefined;
     private _selectedDocSortedArray: Doc[] = [];
     private _closestDropIndex: number = 0;
+    private _minColWidth: number = 120;
 
     @observable _rowMenuWidth: number = 100;
     @observable _selectedDocs: ObservableSet = new ObservableSet<SchemaRowBox>();
     @observable _isDragging: boolean = false;
+    @observable _displayColumnWidths: number[] | undefined;
 
     @computed get columnKeys() {
         return Cast(this.layoutDoc.columnKeys, listSpec('string'), defaultColumnKeys);
     }
 
-    @computed get columnWidths() {
+    @computed get storedColumnWidths() {
         return Cast(
             this.layoutDoc.columnWidths,
             listSpec('number'),
@@ -55,6 +57,10 @@ export class CollectionSchemaView extends CollectionSubView() {
         );
     }
 
+    @computed get displayColumnWidths() {
+        return this._displayColumnWidths ?? this.storedColumnWidths;
+    }
+
     @undoBatch
     @action
     changeColumnKey = (index: number, newKey: string) => {
@@ -80,6 +86,51 @@ export class CollectionSchemaView extends CollectionSubView() {
         this.layoutDoc.columnKeys = new List<string>(currKeys);
     };
 
+    @action
+    startResize = (e: any, index: number, left: boolean) => {
+        this._displayColumnWidths = this.storedColumnWidths;
+        setupMoveUpEvents(this, e, (e, delta) => this.resizeColumn(e, index, left), this.finishResize, emptyFunction);
+    };
+
+    @action
+    resizeColumn = (e: PointerEvent, index: number, left: boolean) => {
+        if (this._displayColumnWidths) {
+            let shrinking;
+            let growing;
+
+            let change = e.movementX;
+
+            if (left && index !== 0) {
+                growing = change < 0 ? index : index - 1;
+                shrinking = change < 0 ? index - 1 : index;
+            } else if (!left && index !== this.columnKeys.length - 1) {
+                growing = change > 0 ? index : index + 1;
+                shrinking = change > 0 ? index + 1 : index;
+            }
+
+            if (shrinking === undefined || growing === undefined) return true;
+
+            change = Math.abs(change);
+            if (this._displayColumnWidths[shrinking] - change < this._minColWidth) {
+                change = this._displayColumnWidths[shrinking] - this._minColWidth;
+            }
+
+            this._displayColumnWidths[shrinking] -= change;
+            this._displayColumnWidths[growing] += change;
+
+            return false;
+        }
+        return true;
+    };
+
+    // @undoBatch
+    @action
+    finishResize = () => {
+        console.log('finished');
+        this.layoutDoc.columnWidths = new List<number>(this._displayColumnWidths);
+        this._displayColumnWidths = undefined;
+    };
+
     @action
     selectRow = (e: React.PointerEvent, doc: Doc, index: number) => {
         const ctrl = e.ctrlKey || e.metaKey;
@@ -135,6 +186,21 @@ export class CollectionSchemaView extends CollectionSubView() {
         return false;
     };
 
+    @action
+    onExternalDrop = async (e: React.DragEvent): Promise<void> => {
+        console.log('hello');
+        super.onExternalDrop(
+            e,
+            {},
+            undoBatch(
+                action(docus => {
+                    this._isDragging = false;
+                    docus.map((doc: Doc) => this.addDocument(doc));
+                })
+            )
+        );
+    };
+
     @action
     startDrag = (e: React.PointerEvent, doc: Doc) => {
         if (!this._selectedDocs.has(doc)) {
@@ -251,11 +317,20 @@ export class CollectionSchemaView extends CollectionSubView() {
                     this._ref = ele;
                     this.createDashEventsTarget(ele);
                 }}
-                onPointerDown={() => this._selectedDocs.clear()}>
+                onPointerDown={() => this._selectedDocs.clear()}
+                onDrop={this.onExternalDrop.bind(this)}>
                 <div className="schema-table">
                     <div className="schema-header-row">
                         {this.columnKeys.map((key, index) => (
-                            <SchemaColumnHeader columnIndex={index} columnKeys={this.columnKeys} columnWidths={this.columnWidths} changeColumnKey={this.changeColumnKey} addColumn={this.addColumn} removeColumn={this.removeColumn} />
+                            <SchemaColumnHeader
+                                columnIndex={index}
+                                columnKeys={this.columnKeys}
+                                columnWidths={this.displayColumnWidths}
+                                changeColumnKey={this.changeColumnKey}
+                                addColumn={this.addColumn}
+                                removeColumn={this.removeColumn}
+                                resizeColumn={this.startResize}
+                            />
                         ))}
                     </div>
                     <div className="schema-table-content">
@@ -267,7 +342,7 @@ export class CollectionSchemaView extends CollectionSubView() {
                                 ContainingCollectionView={this.props.CollectionView}
                                 rowIndex={index}
                                 columnKeys={this.columnKeys}
-                                columnWidths={this.columnWidths}
+                                columnWidths={this.displayColumnWidths}
                                 rowMenuWidth={this._rowMenuWidth}
                                 selectedRows={this._selectedDocs}
                                 selectRow={this.selectRow}
diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
index f93a3d13d..bee76bb24 100644
--- a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
@@ -12,6 +12,7 @@ export interface SchemaColumnHeaderProps {
     changeColumnKey: (index: number, newKey: string) => boolean;
     addColumn: (index: number) => void;
     removeColumn: (index: number) => void;
+    resizeColumn: (e: any, index: number, left: boolean) => void;
 }
 
 @observer
@@ -23,7 +24,10 @@ export class SchemaColumnHeader extends React.Component<SchemaColumnHeaderProps>
     render() {
         return (
             <div className="schema-column-header" style={{ width: this.props.columnWidths[this.props.columnIndex] }}>
-                <EditableView SetValue={(newKey: string) => this.props.changeColumnKey(this.props.columnIndex, newKey)} GetValue={() => this.fieldKey} contents={this.fieldKey} />
+                <div className="schema-column-resizer left" onPointerDown={e => this.props.resizeColumn(e, this.props.columnIndex, true)}></div>
+                <div className="schema-column-title">
+                    <EditableView SetValue={(newKey: string) => this.props.changeColumnKey(this.props.columnIndex, newKey)} GetValue={() => this.fieldKey} contents={this.fieldKey} />
+                </div>
 
                 <div className="schema-header-menu">
                     <div
@@ -41,6 +45,8 @@ export class SchemaColumnHeader extends React.Component<SchemaColumnHeaderProps>
                         <FontAwesomeIcon icon="trash" />
                     </div>
                 </div>
+
+                <div className="schema-column-resizer right" onPointerDown={e => this.props.resizeColumn(e, this.props.columnIndex, false)}></div>
             </div>
         );
     }
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 3d1fa0ee2..661056553 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -6,7 +6,7 @@ import { Doc } from '../../../../fields/Doc';
 import { undoBatch } from '../../../util/UndoManager';
 import { ViewBoxBaseComponent } from '../../DocComponent';
 import { Colors } from '../../global/globalEnums';
-import { FieldViewProps } from '../../nodes/FieldView';
+import { FieldView, FieldViewProps } from '../../nodes/FieldView';
 import './CollectionSchemaView.scss';
 import { SchemaTableCell } from './SchemaTableCell';
 import { emptyFunction, setupMoveUpEvents } from '../../../../Utils';
@@ -26,6 +26,10 @@ export interface SchemaRowBoxProps extends FieldViewProps {
 
 @observer
 export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
+    public static LayoutString(fieldKey: string) {
+        return FieldView.LayoutString(SchemaRowBox, fieldKey);
+    }
+
     private _ref: HTMLDivElement | null = null;
 
     isSelected = () => this.props.selectedRows.has(this.props.Document);
-- 
cgit v1.2.3-70-g09d2


From 5425b61d62beef22d068e259ae3e2003f08e0c05 Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Mon, 24 Oct 2022 15:06:47 -0400
Subject: switched drag element to show rows

---
 .../collectionSchema/CollectionSchemaView.scss     | 98 +++++++++++-----------
 .../collectionSchema/CollectionSchemaView.tsx      | 34 ++++----
 .../collections/collectionSchema/SchemaRowBox.tsx  | 14 ++--
 3 files changed, 73 insertions(+), 73 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaRowBox.tsx')

diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
index 1d0ab459d..4d7e8c39f 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
@@ -7,22 +7,6 @@
     .schema-table {
         background-color: $white;
 
-        .schema-header-row,
-        .schema-row {
-            display: flex;
-            flex-direction: row;
-            max-height: 70px;
-            overflow: auto;
-
-            .schema-column-header,
-            .schema-table-cell,
-            .row-menu {
-                border: 1px solid $medium-gray;
-                padding: 5px;
-                overflow: hidden;
-            }
-        }
-
         .schema-header-row {
             justify-content: flex-end;
 
@@ -63,44 +47,60 @@
             }
         }
 
-        .schema-row {
-            justify-content: flex-end;
-
-            .row-menu {
-                display: flex;
-                flex-direction: row;
-                justify-content: center;
-                min-width: 50px;
-            }
-
-            .row-cells {
-                display: flex;
-                flex-direction: row;
-                justify-content: flex-end;
-            }
-        }
-
         .schema-header-menu {
             display: flex;
             flex-direction: row;
         }
+    }
+}
 
-        .row-button,
-        .schema-header-button {
-            width: 20px;
-            height: 20px;
-            border-radius: 100%;
-            background-color: $dark-gray;
-            color: white;
-            margin: 3px;
-            cursor: pointer;
-            display: flex;
-            align-items: center;
-            justify-content: center;
+.schema-header-row,
+.schema-row {
+    display: flex;
+    flex-direction: row;
+    max-height: 70px;
+    overflow: auto;
+
+    .schema-column-header,
+    .schema-table-cell,
+    .row-menu {
+        border: 1px solid $medium-gray;
+        padding: 5px;
+        overflow: hidden;
+    }
+}
 
-            svg {
-                width: 12px;
-            }
-        }
+.schema-row {
+    justify-content: flex-end;
+
+    .row-menu {
+        display: flex;
+        flex-direction: row;
+        justify-content: center;
+        min-width: 50px;
+    }
+
+    .row-cells {
+        display: flex;
+        flex-direction: row;
+        justify-content: flex-end;
+    }
+}
+
+.schema-row-button,
+.schema-header-button {
+    width: 20px;
+    height: 20px;
+    border-radius: 100%;
+    background-color: $dark-gray;
+    color: white;
+    margin: 3px;
+    cursor: pointer;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+
+    svg {
+        width: 12px;
     }
 }
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 69a49598d..84a69d4b9 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -1,5 +1,5 @@
 import React = require('react');
-import { action, computed, observable, ObservableSet } from 'mobx';
+import { action, computed, observable, ObservableMap, ObservableSet } from 'mobx';
 import { observer } from 'mobx-react';
 import { Doc, DocListCast } from '../../../../fields/Doc';
 import { Id } from '../../../../fields/FieldSymbols';
@@ -41,7 +41,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     private _minColWidth: number = 120;
 
     @observable _rowMenuWidth: number = 100;
-    @observable _selectedDocs: ObservableSet = new ObservableSet<SchemaRowBox>();
+    @observable _selectedDocs: ObservableMap = new ObservableMap<SchemaRowBox, HTMLDivElement>();
     @observable _isDragging: boolean = false;
     @observable _displayColumnWidths: number[] | undefined;
 
@@ -149,7 +149,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     };
 
     @action
-    selectRow = (e: React.PointerEvent, doc: Doc, index: number) => {
+    selectRow = (e: React.PointerEvent, doc: Doc, ref: HTMLDivElement, index: number) => {
         const ctrl = e.ctrlKey || e.metaKey;
         const shift = e.shiftKey;
         if (shift && this._lastSelectedRow !== undefined) {
@@ -157,19 +157,19 @@ export class CollectionSchemaView extends CollectionSubView() {
             const endRow = Math.max(this._lastSelectedRow, index);
             for (let i = startRow; i <= endRow; i++) {
                 const currDoc: Doc = this.childDocs[i];
-                if (!this._selectedDocs.has(currDoc)) this._selectedDocs.add(currDoc);
+                if (!this._selectedDocs.has(currDoc)) this._selectedDocs.set(currDoc, ref);
             }
             this._lastSelectedRow = endRow;
         } else if (ctrl) {
             if (!this._selectedDocs.has(doc)) {
-                this._selectedDocs.add(doc);
+                this._selectedDocs.set(doc, ref);
                 this._lastSelectedRow = index;
             } else {
                 this._selectedDocs.delete(doc);
             }
         } else {
             this._selectedDocs.clear();
-            this._selectedDocs.add(doc);
+            this._selectedDocs.set(doc, ref);
             this._lastSelectedRow = index;
         }
 
@@ -219,25 +219,25 @@ export class CollectionSchemaView extends CollectionSubView() {
     };
 
     @action
-    startDrag = (e: React.PointerEvent, doc: Doc) => {
+    startDrag = (e: React.PointerEvent, doc: Doc, ref: HTMLDivElement, index: number) => {
         if (!this._selectedDocs.has(doc)) {
             this._selectedDocs.clear();
-            this._selectedDocs.add(doc);
-            this._lastSelectedRow = this.childDocs.indexOf(doc);
+            this._selectedDocs.set(doc, ref);
+            this._lastSelectedRow = index;
             SelectionManager.SelectSchemaViewDoc(doc);
         }
         this._isDragging = true;
         this._selectedDocSortedArray = this.sortedSelectedDocs();
         const dragData = new DragManager.DocumentDragData(this._selectedDocSortedArray, 'move');
         dragData.moveDocument = this.props.moveDocument;
-        const dragItem: HTMLElement[] = [];
-        const dragDiv = document.createElement('div');
-        dragDiv.className = 'presItem-multiDrag';
-        dragDiv.innerText = 'Move ' + this._selectedDocs.size + '  row' + (this._selectedDocs.size > 1 ? 's' : '');
-        dragDiv.style.position = 'absolute';
-        dragDiv.style.top = e.clientY + 'px';
-        dragDiv.style.left = e.clientX - 50 + 'px';
-        dragItem.push(dragDiv);
+        const dragItem: HTMLElement[] = Array.from(this._selectedDocs.values());
+        // const dragDiv = document.createElement('div');
+        // dragDiv.className = 'presItem-multiDrag';
+        // dragDiv.innerText = 'Move ' + this._selectedDocs.size + '  row' + (this._selectedDocs.size > 1 ? 's' : '');
+        // dragDiv.style.position = 'absolute';
+        // dragDiv.style.top = e.clientY + 'px';
+        // dragDiv.style.left = e.clientX - 50 + 'px';
+        // dragItem.push(dragDiv);
 
         DragManager.StartDocumentDrag(
             dragItem.map(ele => ele),
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 661056553..66cc3a47a 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -17,9 +17,9 @@ export interface SchemaRowBoxProps extends FieldViewProps {
     columnKeys: string[];
     columnWidths: number[];
     rowMenuWidth: number;
-    selectedRows: ObservableSet<Doc>;
-    selectRow: (e: any, doc: Doc, index: number) => void;
-    startDrag: (e: any, doc: Doc) => boolean;
+    selectedRows: ObservableMap<Doc, HTMLDivElement>;
+    selectRow: (e: any, doc: Doc, ref: HTMLDivElement, index: number) => void;
+    startDrag: (e: any, doc: Doc, ref: HTMLDivElement, index: number) => boolean;
     dragging: boolean;
     dropIndex: (index: number) => void;
 }
@@ -42,9 +42,9 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
         setupMoveUpEvents(
             this,
             e,
-            e => this.props.startDrag(e, this.props.Document),
+            e => this.props.startDrag(e, this.props.Document, this._ref!, this.props.rowIndex),
             emptyFunction,
-            e => this.props.selectRow(e, this.props.Document, this.props.rowIndex)
+            e => this.props.selectRow(e, this.props.Document, this._ref!, this.props.rowIndex)
         );
     };
 
@@ -96,7 +96,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
                 ref={(row: HTMLDivElement | null) => (this._ref = row)}>
                 <div className="row-menu" style={{ width: this.props.rowMenuWidth }}>
                     <div
-                        className="row-button"
+                        className="schema-row-button"
                         onPointerDown={undoBatch(e => {
                             e.stopPropagation();
                             this.props.removeDocument?.(this.props.Document);
@@ -104,7 +104,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
                         <FontAwesomeIcon icon="times" />
                     </div>
                     <div
-                        className="row-button"
+                        className="schema-row-button"
                         onPointerDown={e => {
                             e.stopPropagation();
                             this.props.addDocTab(this.props.Document, 'add:right');
-- 
cgit v1.2.3-70-g09d2


From 213a92ba3aa39d144754029fde32b9d69b0f51cf Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Mon, 7 Nov 2022 12:57:44 -0500
Subject: basic key selection menu created

---
 .../collectionSchema/CollectionSchemaView.scss     |   8 ++
 .../collectionSchema/CollectionSchemaView.tsx      | 150 +++++++++++++++------
 .../collectionSchema/SchemaColumnHeader.tsx        | 105 +++++++++++++--
 .../collections/collectionSchema/SchemaRowBox.tsx  |  12 +-
 4 files changed, 223 insertions(+), 52 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaRowBox.tsx')

diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
index 4d7e8c39f..0631cd21d 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
@@ -44,6 +44,13 @@
                 .schema-column-resizer.left {
                     align-self: flex-start;
                 }
+
+                .schema-column-menu {
+                    background: $light-gray;
+                    width: inherit;
+                    position: absolute;
+                    top: 35px;
+                }
             }
         }
 
@@ -72,6 +79,7 @@
 
 .schema-row {
     justify-content: flex-end;
+    background: white;
 
     .row-menu {
         display: flex;
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 84a69d4b9..7516b95b8 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -1,7 +1,7 @@
 import React = require('react');
-import { action, computed, observable, ObservableMap, ObservableSet } from 'mobx';
+import { action, computed, observable, ObservableMap, ObservableSet, untracked } from 'mobx';
 import { observer } from 'mobx-react';
-import { Doc, DocListCast } from '../../../../fields/Doc';
+import { Doc, DocListCast, StrListCast } from '../../../../fields/Doc';
 import { Id } from '../../../../fields/FieldSymbols';
 import { List } from '../../../../fields/List';
 import { RichTextField } from '../../../../fields/RichTextField';
@@ -41,10 +41,26 @@ export class CollectionSchemaView extends CollectionSubView() {
     private _minColWidth: number = 120;
 
     @observable _rowMenuWidth: number = 100;
-    @observable _selectedDocs: ObservableMap = new ObservableMap<SchemaRowBox, HTMLDivElement>();
+    @observable _selectedDocs: ObservableSet = new ObservableSet<Doc>();
+    @observable _rowEles: ObservableMap = new ObservableMap<Doc, HTMLDivElement>();
     @observable _isDragging: boolean = false;
     @observable _displayColumnWidths: number[] | undefined;
 
+    get documentKeys() {
+        const docs = this.childDocs;
+        const keys: { [key: string]: boolean } = {};
+        // bcz: ugh.  this is untracked since otherwise a large collection of documents will blast the server for all their fields.
+        //  then as each document's fields come back, we update the documents _proxies.  Each time we do this, the whole schema will be
+        //  invalidated and re-rendered.   This workaround will inquire all of the document fields before the options button is clicked.
+        //  then by the time the options button is clicked, all of the fields should be in place.  If a new field is added while this menu
+        //  is displayed (unlikely) it won't show up until something else changes.
+        //TODO Types
+        untracked(() => docs.map(doc => Doc.GetAllPrototypes(doc).map(proto => Object.keys(proto).forEach(key => (keys[key] = false)))));
+
+        // this.columns.forEach(key => (keys[key.heading] = true));
+        return Array.from(Object.keys(keys));
+    }
+
     @computed get columnKeys() {
         return Cast(this.layoutDoc.columnKeys, listSpec('string'), defaultColumnKeys);
     }
@@ -64,6 +80,10 @@ export class CollectionSchemaView extends CollectionSubView() {
     @undoBatch
     @action
     changeColumnKey = (index: number, newKey: string) => {
+        if (!this.documentKeys.includes(newKey)) {
+            this.addNewKey(newKey);
+        }
+
         let currKeys = this.columnKeys;
         currKeys[index] = newKey;
         this.layoutDoc.columnKeys = new List<string>(currKeys);
@@ -72,10 +92,10 @@ export class CollectionSchemaView extends CollectionSubView() {
 
     @undoBatch
     @action
-    addColumn = (index: number) => {
-        let currKeys = this.columnKeys;
-        currKeys.splice(index, 0, 'title');
-        this.layoutDoc.columnKeys = new List<string>(currKeys);
+    addColumn = (index: number, key: string) => {
+        if (!this.documentKeys.includes(key)) {
+            this.addNewKey(key);
+        }
 
         const newColWidth = this._minColWidth;
         let currWidths = this.storedColumnWidths;
@@ -83,17 +103,22 @@ export class CollectionSchemaView extends CollectionSubView() {
             const proportion = w / (this.props.PanelWidth() - this._rowMenuWidth);
             return proportion * (this.props.PanelWidth() - this._rowMenuWidth - newColWidth);
         });
-        currWidths.splice(index, 0, newColWidth);
+        currWidths.splice(index + 1, 0, newColWidth);
         this.layoutDoc.columnWidths = new List<number>(currWidths);
+
+        let currKeys = this.columnKeys;
+        currKeys.splice(index + 1, 0, key);
+        this.layoutDoc.columnKeys = new List<string>(currKeys);
+    };
+
+    @action
+    addNewKey = (key: string) => {
+        this.childDocs.forEach(doc => (doc[key] = key + ' default val'));
     };
 
     @undoBatch
     @action
     removeColumn = (index: number) => {
-        let currKeys = this.columnKeys;
-        currKeys.splice(index, 1);
-        this.layoutDoc.columnKeys = new List<string>(currKeys);
-
         let currWidths = this.storedColumnWidths;
         const removedColWidth = currWidths[index];
         currWidths = currWidths.map(w => {
@@ -102,6 +127,10 @@ export class CollectionSchemaView extends CollectionSubView() {
         });
         currWidths.splice(index, 1);
         this.layoutDoc.columnWidths = new List<number>(currWidths);
+
+        let currKeys = this.columnKeys;
+        currKeys.splice(index, 1);
+        this.layoutDoc.columnKeys = new List<string>(currKeys);
     };
 
     @action
@@ -143,11 +172,55 @@ export class CollectionSchemaView extends CollectionSubView() {
 
     @action
     finishResize = () => {
-        console.log('finished');
         this.layoutDoc.columnWidths = new List<number>(this._displayColumnWidths);
         this._displayColumnWidths = undefined;
     };
 
+    @undoBatch
+    @action
+    swapColumns = (index1: number, index2: number) => {
+        console.log(index1, index2);
+        const tempKey = this.columnKeys[index1];
+        const tempWidth = this.storedColumnWidths[index1];
+
+        let currKeys = this.columnKeys;
+        currKeys[index1] = currKeys[index2];
+        currKeys[index2] = tempKey;
+        this.layoutDoc.columnKeys = new List<string>(currKeys);
+
+        let currWidths = this.storedColumnWidths;
+        currWidths[index1] = currWidths[index2];
+        currWidths[index2] = tempWidth;
+        this.layoutDoc.columnWidths = new List<number>(currWidths);
+    };
+
+    @action
+    dragColumn = (e: any, index: number) => {
+        console.log(index);
+        e.stopPropagation();
+        e.preventDefault();
+        const rect = e.target.getBoundingClientRect();
+        if (e.clientX < rect.x) {
+            console.log('left', e.clientX, rect.x);
+            if (index < 1) return true;
+            this.swapColumns(index - 1, index);
+            return true;
+        }
+        if (e.clientX > rect.x + rect.width) {
+            console.log('right', e.clientX, rect.x + rect.width);
+            if (index === this.columnKeys.length) return true;
+            console.log(index);
+            this.swapColumns(index, index + 1);
+            return true;
+        }
+        return false;
+    };
+
+    @action
+    addRowRef = (doc: Doc, ref: HTMLDivElement) => {
+        this._rowEles.set(doc, ref);
+    };
+
     @action
     selectRow = (e: React.PointerEvent, doc: Doc, ref: HTMLDivElement, index: number) => {
         const ctrl = e.ctrlKey || e.metaKey;
@@ -157,19 +230,19 @@ export class CollectionSchemaView extends CollectionSubView() {
             const endRow = Math.max(this._lastSelectedRow, index);
             for (let i = startRow; i <= endRow; i++) {
                 const currDoc: Doc = this.childDocs[i];
-                if (!this._selectedDocs.has(currDoc)) this._selectedDocs.set(currDoc, ref);
+                if (!this._selectedDocs.has(currDoc)) this._selectedDocs.add(currDoc);
             }
             this._lastSelectedRow = endRow;
         } else if (ctrl) {
             if (!this._selectedDocs.has(doc)) {
-                this._selectedDocs.set(doc, ref);
+                this._selectedDocs.add(doc);
                 this._lastSelectedRow = index;
             } else {
                 this._selectedDocs.delete(doc);
             }
         } else {
             this._selectedDocs.clear();
-            this._selectedDocs.set(doc, ref);
+            this._selectedDocs.add(doc);
             this._lastSelectedRow = index;
         }
 
@@ -205,7 +278,6 @@ export class CollectionSchemaView extends CollectionSubView() {
 
     @action
     onExternalDrop = async (e: React.DragEvent): Promise<void> => {
-        console.log('hello');
         super.onExternalDrop(
             e,
             {},
@@ -222,7 +294,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     startDrag = (e: React.PointerEvent, doc: Doc, ref: HTMLDivElement, index: number) => {
         if (!this._selectedDocs.has(doc)) {
             this._selectedDocs.clear();
-            this._selectedDocs.set(doc, ref);
+            this._selectedDocs.add(doc);
             this._lastSelectedRow = index;
             SelectionManager.SelectSchemaViewDoc(doc);
         }
@@ -230,14 +302,7 @@ export class CollectionSchemaView extends CollectionSubView() {
         this._selectedDocSortedArray = this.sortedSelectedDocs();
         const dragData = new DragManager.DocumentDragData(this._selectedDocSortedArray, 'move');
         dragData.moveDocument = this.props.moveDocument;
-        const dragItem: HTMLElement[] = Array.from(this._selectedDocs.values());
-        // const dragDiv = document.createElement('div');
-        // dragDiv.className = 'presItem-multiDrag';
-        // dragDiv.innerText = 'Move ' + this._selectedDocs.size + '  row' + (this._selectedDocs.size > 1 ? 's' : '');
-        // dragDiv.style.position = 'absolute';
-        // dragDiv.style.top = e.clientY + 'px';
-        // dragDiv.style.left = e.clientX - 50 + 'px';
-        // dragItem.push(dragDiv);
+        const dragItem: HTMLElement[] = Array.from(this._selectedDocs.values()).map((doc: Doc) => this._rowEles.get(doc));
 
         DragManager.StartDocumentDrag(
             dragItem.map(ele => ele),
@@ -334,21 +399,27 @@ export class CollectionSchemaView extends CollectionSubView() {
                     this._ref = ele;
                     this.createDashEventsTarget(ele);
                 }}
-                onPointerDown={() => this._selectedDocs.clear()}
+                onPointerDown={action(() => {
+                    this._selectedDocs.clear();
+                })}
                 onDrop={this.onExternalDrop.bind(this)}>
                 <div className="schema-table">
                     <div className="schema-header-row">
-                        {this.columnKeys.map((key, index) => (
-                            <SchemaColumnHeader
-                                columnIndex={index}
-                                columnKeys={this.columnKeys}
-                                columnWidths={this.displayColumnWidths}
-                                changeColumnKey={this.changeColumnKey}
-                                addColumn={this.addColumn}
-                                removeColumn={this.removeColumn}
-                                resizeColumn={this.startResize}
-                            />
-                        ))}
+                        {this.columnKeys.map((key, index) => {
+                            return (
+                                <SchemaColumnHeader
+                                    columnIndex={index}
+                                    columnKeys={this.columnKeys}
+                                    columnWidths={this.displayColumnWidths}
+                                    possibleKeys={this.documentKeys}
+                                    changeColumnKey={this.changeColumnKey}
+                                    addColumn={this.addColumn}
+                                    removeColumn={this.removeColumn}
+                                    resizeColumn={this.startResize}
+                                    dragColumn={this.dragColumn}
+                                />
+                            );
+                        })}
                     </div>
                     <div className="schema-table-content">
                         {this.childDocs.map((doc: Doc, index: number) => (
@@ -361,11 +432,12 @@ export class CollectionSchemaView extends CollectionSubView() {
                                 columnKeys={this.columnKeys}
                                 columnWidths={this.displayColumnWidths}
                                 rowMenuWidth={this._rowMenuWidth}
-                                selectedRows={this._selectedDocs}
+                                selectedDocs={this._selectedDocs}
                                 selectRow={this.selectRow}
                                 startDrag={this.startDrag}
                                 dragging={this._isDragging}
                                 dropIndex={this.setDropIndex}
+                                addRowRef={this.addRowRef}
                             />
                         ))}
                     </div>
diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
index bee76bb24..a6140bafd 100644
--- a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
@@ -1,39 +1,124 @@
 import React = require('react');
-import { computed } from 'mobx';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { action, computed, observable } from 'mobx';
 import { observer } from 'mobx-react';
-import { EditableView } from '../../EditableView';
+import { emptyFunction, setupMoveUpEvents } from '../../../../Utils';
 import './CollectionSchemaView.scss';
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 
 export interface SchemaColumnHeaderProps {
     columnKeys: string[];
     columnWidths: number[];
     columnIndex: number;
+    possibleKeys: string[];
     changeColumnKey: (index: number, newKey: string) => boolean;
-    addColumn: (index: number) => void;
+    addColumn: (index: number, key: string) => void;
     removeColumn: (index: number) => void;
     resizeColumn: (e: any, index: number, left: boolean) => void;
+    dragColumn: (e: any, index: number) => boolean;
 }
 
 @observer
 export class SchemaColumnHeader extends React.Component<SchemaColumnHeaderProps> {
+    @observable _menuVisible: boolean = false;
+    @observable _menuValue: string = '';
+    @observable _menuOptions: string[] = [];
+    private _makeNewColumn = false;
+
     @computed get fieldKey() {
         return this.props.columnKeys[this.props.columnIndex];
     }
 
+    @computed get renderColumnMenu() {
+        return (
+            <div className="schema-column-menu">
+                <input type="text" value={this._menuValue} onKeyDown={this.onSearchKeyDown} onChange={this.updateKeySearch} onPointerDown={e => e.stopPropagation()} />
+                {this._menuOptions.map(key => (
+                    <div
+                        onPointerDown={e => {
+                            e.stopPropagation();
+                            this.setKey(key);
+                        }}>
+                        {key}
+                    </div>
+                ))}
+                <div
+                    onPointerDown={e => {
+                        e.stopPropagation();
+                        this.setKey(this._menuValue);
+                    }}>
+                    + new field
+                </div>
+            </div>
+        );
+    }
+
+    onSearchKeyDown = (e: React.KeyboardEvent) => {
+        switch (e.key) {
+            case 'Enter':
+                this.setKey(this._menuOptions.length > 0 ? this._menuOptions[0] : this._menuValue);
+                break;
+            case 'Escape':
+                this.toggleColumnMenu();
+                break;
+        }
+    };
+
+    @action
+    setKey = (key: string) => {
+        if (this._makeNewColumn) {
+            this.props.addColumn(this.props.columnIndex, key);
+        } else {
+            this.props.changeColumnKey(this.props.columnIndex, key);
+        }
+        this.toggleColumnMenu();
+    };
+
+    @action
+    updateKeySearch = (e: React.ChangeEvent<HTMLInputElement>) => {
+        this._menuValue = e.target.value;
+        this._menuOptions = this.props.possibleKeys.filter(value => value.toLowerCase().includes(this._menuValue.toLowerCase()));
+    };
+
+    @action
+    onPointerDown = (e: React.PointerEvent) => {
+        e.stopPropagation();
+
+        setupMoveUpEvents(this, e, e => this.props.dragColumn(e, this.props.columnIndex), emptyFunction, emptyFunction);
+    };
+
+    @action
+    toggleColumnMenu = (newCol?: boolean) => {
+        this._makeNewColumn = false;
+        if (this._menuVisible) {
+            this._menuVisible = false;
+        } else {
+            this._menuVisible = true;
+            this._menuValue = this.fieldKey;
+            this._menuOptions = this.props.possibleKeys;
+            if (newCol) {
+                this._makeNewColumn = true;
+            }
+        }
+    };
+
     render() {
         return (
-            <div className="schema-column-header" style={{ width: this.props.columnWidths[this.props.columnIndex] }}>
+            <div className="schema-column-header" style={{ width: this.props.columnWidths[this.props.columnIndex] }} onPointerDown={this.onPointerDown}>
                 <div className="schema-column-resizer left" onPointerDown={e => this.props.resizeColumn(e, this.props.columnIndex, true)}></div>
-                <div className="schema-column-title">
-                    <EditableView SetValue={(newKey: string) => this.props.changeColumnKey(this.props.columnIndex, newKey)} GetValue={() => this.fieldKey} contents={this.fieldKey} />
-                </div>
+                <div className="schema-column-title">{this.fieldKey}</div>
 
                 <div className="schema-header-menu">
                     <div
                         className="schema-header-button"
                         onPointerDown={e => {
-                            this.props.addColumn(this.props.columnIndex + 1);
+                            this.toggleColumnMenu();
+                        }}>
+                        <FontAwesomeIcon icon="pencil-alt" />
+                    </div>
+                    <div
+                        className="schema-header-button"
+                        onPointerDown={e => {
+                            this.toggleColumnMenu(true);
                         }}>
                         <FontAwesomeIcon icon="plus" />
                     </div>
@@ -47,6 +132,8 @@ export class SchemaColumnHeader extends React.Component<SchemaColumnHeaderProps>
                 </div>
 
                 <div className="schema-column-resizer right" onPointerDown={e => this.props.resizeColumn(e, this.props.columnIndex, false)}></div>
+
+                {this._menuVisible && this.renderColumnMenu}
             </div>
         );
     }
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 66cc3a47a..bfce61952 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -17,11 +17,12 @@ export interface SchemaRowBoxProps extends FieldViewProps {
     columnKeys: string[];
     columnWidths: number[];
     rowMenuWidth: number;
-    selectedRows: ObservableMap<Doc, HTMLDivElement>;
+    selectedDocs: ObservableSet<Doc>;
     selectRow: (e: any, doc: Doc, ref: HTMLDivElement, index: number) => void;
     startDrag: (e: any, doc: Doc, ref: HTMLDivElement, index: number) => boolean;
     dragging: boolean;
     dropIndex: (index: number) => void;
+    addRowRef: (doc: Doc, ref: HTMLDivElement) => void;
 }
 
 @observer
@@ -32,7 +33,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
 
     private _ref: HTMLDivElement | null = null;
 
-    isSelected = () => this.props.selectedRows.has(this.props.Document);
+    isSelected = () => this.props.selectedDocs.has(this.props.Document);
     bounds = () => this._ref?.getBoundingClientRect();
 
     @action
@@ -58,7 +59,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
         if (!this.props.dragging) return;
         let dragIsRow: boolean = true;
         DragManager.docsBeingDragged.forEach(doc => {
-            dragIsRow = this.props.selectedRows.has(doc);
+            dragIsRow = this.props.selectedDocs.has(doc);
         });
         if (this._ref && dragIsRow) {
             const rect = this._ref.getBoundingClientRect();
@@ -93,7 +94,10 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
                 onPointerDown={this.onRowPointerDown}
                 onPointerEnter={this.onPointerEnter}
                 onPointerLeave={this.onPointerLeave}
-                ref={(row: HTMLDivElement | null) => (this._ref = row)}>
+                ref={(row: HTMLDivElement | null) => {
+                    row && this.props.addRowRef(this.props.Document, row);
+                    this._ref = row;
+                }}>
                 <div className="row-menu" style={{ width: this.props.rowMenuWidth }}>
                     <div
                         className="schema-row-button"
-- 
cgit v1.2.3-70-g09d2


From 73d3c63658c4bdf3268ea81a02eb96566869b855 Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Mon, 21 Nov 2022 12:38:37 -0500
Subject: column deletion and new key menu fixes

---
 .../collectionSchema/CollectionSchemaView.scss     | 13 +++-
 .../collectionSchema/CollectionSchemaView.tsx      | 73 +++++++++++++---------
 .../collectionSchema/SchemaColumnHeader.tsx        | 31 +++++----
 .../collections/collectionSchema/SchemaRowBox.tsx  |  2 +-
 4 files changed, 74 insertions(+), 45 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaRowBox.tsx')

diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
index 99f49eb0e..4fa5d80e2 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
@@ -78,6 +78,15 @@
                         align-items: flex-start;
                     }
 
+                    .schema-new-key-options {
+                        margin: 10px;
+                        .schema-key-warning {
+                            color: red;
+                            font-weight: normal;
+                            align-self: center;
+                        }
+                    }
+
                     .schema-key-list {
                         width: 100%;
                         max-height: 300px;
@@ -85,7 +94,7 @@
                     }
 
                     .schema-key-type-option {
-                        margin: 2px 10px;
+                        margin: 2px 0px;
 
                         input {
                             margin-right: 5px;
@@ -93,7 +102,7 @@
                     }
 
                     .schema-key-default-val {
-                        margin: 5px 10px;
+                        margin: 5px 0;
                     }
 
                     .schema-column-menu-button {
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 24008a21d..f7c68c803 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -1,5 +1,5 @@
 import React = require('react');
-import { action, computed, observable, ObservableMap, ObservableSet, untracked } from 'mobx';
+import { action, computed, observable, ObservableMap, ObservableSet, trace, untracked } from 'mobx';
 import { observer } from 'mobx-react';
 import { Doc, DocListCast, StrListCast } from '../../../../fields/Doc';
 import { Id } from '../../../../fields/FieldSymbols';
@@ -66,11 +66,22 @@ export class CollectionSchemaView extends CollectionSubView() {
     }
 
     @computed get storedColumnWidths() {
-        return Cast(
+        let widths = Cast(
             this.layoutDoc.columnWidths,
             listSpec('number'),
             this.columnKeys.map(() => (this.props.PanelWidth() - this._rowMenuWidth) / this.columnKeys.length)
         );
+
+        const totalWidth = widths.reduce((sum, width) => sum + width, 0);
+        if (totalWidth !== this.props.PanelWidth() - this._rowMenuWidth) {
+            widths = widths.map(w => {
+                const proportion = w / totalWidth;
+                return proportion * (this.props.PanelWidth() - this._rowMenuWidth);
+            });
+            // this.layoutDoc.columnWidths = new List<number>(widths);
+        }
+
+        return widths;
     }
 
     @computed get displayColumnWidths() {
@@ -84,7 +95,7 @@ export class CollectionSchemaView extends CollectionSubView() {
             this.addNewKey(newKey, defaultVal);
         }
 
-        let currKeys = this.columnKeys;
+        let currKeys = [...this.columnKeys];
         currKeys[index] = newKey;
         this.layoutDoc.columnKeys = new List<string>(currKeys);
     };
@@ -96,7 +107,7 @@ export class CollectionSchemaView extends CollectionSubView() {
             this.addNewKey(key, defaultVal);
         }
 
-        let currWidths = this.storedColumnWidths;
+        let currWidths = [...this.storedColumnWidths];
         const newColWidth = this.props.PanelWidth() / (currWidths.length + 1);
         currWidths = currWidths.map(w => {
             const proportion = w / (this.props.PanelWidth() - this._rowMenuWidth);
@@ -105,21 +116,21 @@ export class CollectionSchemaView extends CollectionSubView() {
         currWidths.splice(index + 1, 0, newColWidth);
         this.layoutDoc.columnWidths = new List<number>(currWidths);
 
-        let currKeys = this.columnKeys;
+        let currKeys = [...this.columnKeys];
         currKeys.splice(index + 1, 0, key);
         this.layoutDoc.columnKeys = new List<string>(currKeys);
     };
 
     @action
     addNewKey = (key: string, defaultVal: any) => {
-        console.log(defaultVal);
         this.childDocs.forEach(doc => (doc[key] = defaultVal));
     };
 
     @undoBatch
     @action
     removeColumn = (index: number) => {
-        let currWidths = this.storedColumnWidths;
+        if (this.columnKeys.length === 1) return;
+        let currWidths = [...this.storedColumnWidths];
         const removedColWidth = currWidths[index];
         currWidths = currWidths.map(w => {
             const proportion = w / (this.props.PanelWidth() - this._rowMenuWidth - removedColWidth);
@@ -128,9 +139,11 @@ export class CollectionSchemaView extends CollectionSubView() {
         currWidths.splice(index, 1);
         this.layoutDoc.columnWidths = new List<number>(currWidths);
 
-        let currKeys = this.columnKeys;
+        let currKeys = [...this.columnKeys];
         currKeys.splice(index, 1);
         this.layoutDoc.columnKeys = new List<string>(currKeys);
+        console.log([...this.storedColumnWidths]);
+        console.log([...this.columnKeys]);
     };
 
     @action
@@ -179,7 +192,6 @@ export class CollectionSchemaView extends CollectionSubView() {
     @undoBatch
     @action
     swapColumns = (index1: number, index2: number) => {
-        console.log(index1, index2);
         const tempKey = this.columnKeys[index1];
         const tempWidth = this.storedColumnWidths[index1];
 
@@ -194,27 +206,23 @@ export class CollectionSchemaView extends CollectionSubView() {
         this.layoutDoc.columnWidths = new List<number>(currWidths);
     };
 
-    @action
-    dragColumn = (e: any, index: number) => {
-        console.log(index);
-        e.stopPropagation();
-        e.preventDefault();
-        const rect = e.target.getBoundingClientRect();
-        if (e.clientX < rect.x) {
-            console.log('left', e.clientX, rect.x);
-            if (index < 1) return true;
-            this.swapColumns(index - 1, index);
-            return true;
-        }
-        if (e.clientX > rect.x + rect.width) {
-            console.log('right', e.clientX, rect.x + rect.width);
-            if (index === this.columnKeys.length) return true;
-            console.log(index);
-            this.swapColumns(index, index + 1);
-            return true;
-        }
-        return false;
-    };
+    // @action
+    // dragColumn = (e: any, index: number) => {
+    //     e.stopPropagation();
+    //     e.preventDefault();
+    //     const rect = e.target.getBoundingClientRect();
+    //     if (e.clientX < rect.x) {
+    //         if (index < 1) return true;
+    //         this.swapColumns(index - 1, index);
+    //         return true;
+    //     }
+    //     if (e.clientX > rect.x + rect.width) {
+    //         if (index === this.columnKeys.length) return true;
+    //         this.swapColumns(index, index + 1);
+    //         return true;
+    //     }
+    //     return false;
+    // };
 
     @action
     addRowRef = (doc: Doc, ref: HTMLDivElement) => {
@@ -405,9 +413,11 @@ export class CollectionSchemaView extends CollectionSubView() {
                 onDrop={this.onExternalDrop.bind(this)}>
                 <div className="schema-table">
                     <div className="schema-header-row">
+                        <div className="row-menu" style={{ width: this._rowMenuWidth }}></div>
                         {this.columnKeys.map((key, index) => {
                             return (
                                 <SchemaColumnHeader
+                                    key={index}
                                     columnIndex={index}
                                     columnKeys={this.columnKeys}
                                     columnWidths={this.displayColumnWidths}
@@ -416,7 +426,7 @@ export class CollectionSchemaView extends CollectionSubView() {
                                     addColumn={this.addColumn}
                                     removeColumn={this.removeColumn}
                                     resizeColumn={this.startResize}
-                                    dragColumn={this.dragColumn}
+                                    // dragColumn={this.dragColumn}
                                 />
                             );
                         })}
@@ -425,6 +435,7 @@ export class CollectionSchemaView extends CollectionSubView() {
                         {this.childDocs.map((doc: Doc, index: number) => (
                             <SchemaRowBox
                                 {...this.props}
+                                key={index}
                                 Document={doc}
                                 ContainingCollectionDoc={this.props.CollectionView?.props.Document}
                                 ContainingCollectionView={this.props.CollectionView}
diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
index b9e25a473..a6a5f66ab 100644
--- a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
@@ -15,7 +15,7 @@ export interface SchemaColumnHeaderProps {
     addColumn: (index: number, key: string, defaultVal?: any) => void;
     removeColumn: (index: number) => void;
     resizeColumn: (e: any, index: number, left: boolean) => void;
-    dragColumn: (e: any, index: number) => boolean;
+    // dragColumn: (e: any, index: number) => boolean;
 }
 
 @observer
@@ -24,6 +24,7 @@ export class SchemaColumnHeader extends React.Component<SchemaColumnHeaderProps>
     @observable _makeNewField: boolean = false;
     @observable _newFieldType: ColumnType = ColumnType.Number;
     @observable _newFieldDefault: any = 0;
+    @observable _newFieldWarning: string = '';
     @observable _menuValue: string = '';
     @observable _menuOptions: string[] = [];
     private _makeNewColumn = false;
@@ -94,11 +95,17 @@ export class SchemaColumnHeader extends React.Component<SchemaColumnHeaderProps>
                             string
                         </div>
                         <div className="schema-key-default-val">value: {this.fieldDefaultInput}</div>
+                        <div className="schema-key-warning">{this._newFieldWarning}</div>
                         <div
                             className="schema-column-menu-button"
                             onPointerDown={action(e => {
-                                this.setKey(this._menuValue, this._newFieldDefault);
-                                this._makeNewField = false;
+                                if (this.props.possibleKeys.includes(this._menuValue)) {
+                                    this._newFieldWarning = 'Field already exists';
+                                } else if (this._menuValue.length === 0) {
+                                    this._newFieldWarning = 'Field cannot be an empty string';
+                                } else {
+                                    this.setKey(this._menuValue, this._newFieldDefault);
+                                }
                             })}>
                             done
                         </div>
@@ -134,7 +141,7 @@ export class SchemaColumnHeader extends React.Component<SchemaColumnHeaderProps>
     onSearchKeyDown = (e: React.KeyboardEvent) => {
         switch (e.key) {
             case 'Enter':
-                this.setKey(this._menuOptions.length > 0 ? this._menuOptions[0] : this._menuValue);
+                this.setKey(this._menuOptions.length > 0 && this._menuValue.length > 0 ? this._menuOptions[0] : this._menuValue);
                 break;
             case 'Escape':
                 this.toggleColumnMenu();
@@ -158,12 +165,12 @@ export class SchemaColumnHeader extends React.Component<SchemaColumnHeaderProps>
         this._menuOptions = this.props.possibleKeys.filter(value => value.toLowerCase().includes(this._menuValue.toLowerCase()));
     };
 
-    @action
-    onPointerDown = (e: React.PointerEvent) => {
-        e.stopPropagation();
+    // @action
+    // onPointerDown = (e: React.PointerEvent) => {
+    //     e.stopPropagation();
 
-        setupMoveUpEvents(this, e, e => this.props.dragColumn(e, this.props.columnIndex), emptyFunction, emptyFunction);
-    };
+    //     setupMoveUpEvents(this, e, e => this.props.dragColumn(e, this.props.columnIndex), emptyFunction, emptyFunction);
+    // };
 
     @action
     toggleColumnMenu = (newCol?: boolean) => {
@@ -172,9 +179,11 @@ export class SchemaColumnHeader extends React.Component<SchemaColumnHeaderProps>
             this._menuVisible = false;
         } else {
             this._menuVisible = true;
-            this._menuValue = this.fieldKey;
+            this._menuValue = '';
             this._menuOptions = this.props.possibleKeys;
             this._makeNewField = false;
+            this._newFieldWarning = '';
+            this._makeNewField = false;
             if (newCol) {
                 this._makeNewColumn = true;
             }
@@ -183,7 +192,7 @@ export class SchemaColumnHeader extends React.Component<SchemaColumnHeaderProps>
 
     render() {
         return (
-            <div className="schema-column-header" style={{ width: this.props.columnWidths[this.props.columnIndex] }} onPointerDown={this.onPointerDown}>
+            <div className="schema-column-header" style={{ width: this.props.columnWidths[this.props.columnIndex] }}>
                 <div className="schema-column-resizer left" onPointerDown={e => this.props.resizeColumn(e, this.props.columnIndex, true)}></div>
                 <div className="schema-column-title">{this.fieldKey}</div>
 
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index bfce61952..5c1f32565 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -118,7 +118,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
                 </div>
                 <div className="row-cells">
                     {this.props.columnKeys.map((key, index) => (
-                        <SchemaTableCell Document={this.props.Document} fieldKey={key} columnWidth={this.props.columnWidths[index]} />
+                        <SchemaTableCell key={key} Document={this.props.Document} fieldKey={key} columnWidth={this.props.columnWidths[index]} />
                     ))}
                 </div>
             </div>
-- 
cgit v1.2.3-70-g09d2


From 9d2af1180f0dd5af5ab86b922cd8b0cdfcf4ea09 Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Sat, 28 Jan 2023 22:38:41 -0500
Subject: checkpoint: schemarow as documentview functioning

---
 package-lock.json                                  |   39 -
 src/client/documents/Documents.ts                  |    4 +
 .../collectionSchema/CollectionSchemaView.scss     |    6 +
 .../collectionSchema/CollectionSchemaView.tsx      |  129 +-
 .../collections/collectionSchema/SchemaRowBox.tsx  |   80 +-
 .../OldCollectionSchemaCells.tsx                   | 1366 +++++++++----------
 .../OldCollectionSchemaMovableColumn.tsx           |  250 ++--
 .../OldCollectionSchemaMovableRow.tsx              |  274 ++--
 .../OldCollectionSchemaView.tsx                    | 1298 +++++++++---------
 .../old_collectionSchema/OldSchemaTable.tsx        | 1388 ++++++++++----------
 src/client/views/nodes/DocumentContentsView.tsx    |    2 +
 11 files changed, 2451 insertions(+), 2385 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaRowBox.tsx')

diff --git a/package-lock.json b/package-lock.json
index 26e7a41d7..7f93ef3c8 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -5303,16 +5303,6 @@
             "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=",
             "dev": true
         },
-        "d": {
-            "version": "1.0.1",
-            "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz",
-            "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==",
-            "dev": true,
-            "requires": {
-                "es5-ext": "^0.10.50",
-                "type": "^1.0.1"
-            }
-        },
         "d3-array": {
             "version": "2.12.1",
             "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz",
@@ -6480,28 +6470,6 @@
                 "is-symbol": "^1.0.2"
             }
         },
-        "es5-ext": {
-            "version": "0.10.62",
-            "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz",
-            "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==",
-            "dev": true,
-            "requires": {
-                "es6-iterator": "^2.0.3",
-                "es6-symbol": "^3.1.3",
-                "next-tick": "^1.1.0"
-            }
-        },
-        "es6-iterator": {
-            "version": "2.0.3",
-            "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz",
-            "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==",
-            "dev": true,
-            "requires": {
-                "d": "1",
-                "es5-ext": "^0.10.35",
-                "es6-symbol": "^3.1.1"
-            }
-        },
         "es6-promise": {
             "version": "3.2.1",
             "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.2.1.tgz",
@@ -6513,7 +6481,6 @@
             "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==",
             "dev": true,
             "requires": {
-                "d": "^1.0.1",
                 "ext": "^1.1.2"
             }
         },
@@ -21699,12 +21666,6 @@
             "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
             "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q="
         },
-        "type": {
-            "version": "1.2.0",
-            "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz",
-            "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==",
-            "dev": true
-        },
         "type-check": {
             "version": "0.3.2",
             "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 1fd07d61d..58e318879 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -1150,6 +1150,10 @@ export namespace Docs {
             return InstanceFromProto(Prototypes.get(DocumentType.DATAVIZ), new CsvField(url), { title: 'Data Viz', ...options });
         }
 
+        export function SchemaRowDocument(options?: DocumentOptions) {
+            return InstanceFromProto(Prototypes.get(DocumentType.SCHEMAROW), undefined, { ...(options || {}) });
+        }
+
         export function DockDocument(documents: Array<Doc>, config: string, options: DocumentOptions, id?: string) {
             return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { freezeChildren: 'remove|add', ...options, viewType: CollectionViewType.Docking, _viewType: CollectionViewType.Docking, dockingConfig: config }, id);
         }
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
index 4fa5d80e2..e0d0101a2 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
@@ -126,10 +126,16 @@
     }
 }
 
+.schema-row-wrapper {
+    max-height: 70px;
+    overflow: hidden;
+}
+
 .schema-header-row,
 .schema-row {
     display: flex;
     flex-direction: row;
+    height: 100%;
     max-height: 70px;
     overflow: auto;
 
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index f7c68c803..c9f934aec 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -1,14 +1,14 @@
 import React = require('react');
 import { action, computed, observable, ObservableMap, ObservableSet, trace, untracked } from 'mobx';
 import { observer } from 'mobx-react';
-import { Doc, DocListCast, StrListCast } from '../../../../fields/Doc';
+import { DataSym, Doc, DocListCast, Opt, StrListCast } from '../../../../fields/Doc';
 import { Id } from '../../../../fields/FieldSymbols';
 import { List } from '../../../../fields/List';
 import { RichTextField } from '../../../../fields/RichTextField';
 import { listSpec } from '../../../../fields/Schema';
-import { Cast, StrCast } from '../../../../fields/Types';
+import { BoolCast, Cast, StrCast } from '../../../../fields/Types';
 import { ImageField } from '../../../../fields/URLField';
-import { emptyFunction, returnEmptyString, setupMoveUpEvents } from '../../../../Utils';
+import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, setupMoveUpEvents, smoothScroll, Utils } from '../../../../Utils';
 import { Docs, DocUtils } from '../../../documents/Documents';
 import { DragManager } from '../../../util/DragManager';
 import { SelectionManager } from '../../../util/SelectionManager';
@@ -21,6 +21,9 @@ import { CollectionSubView } from '../CollectionSubView';
 import './CollectionSchemaView.scss';
 import { SchemaColumnHeader } from './SchemaColumnHeader';
 import { SchemaRowBox } from './SchemaRowBox';
+import { DocFocusOptions, DocumentView, ViewAdjustment } from '../../nodes/DocumentView';
+import { DefaultStyleProvider } from '../../StyleProvider';
+import { Transform } from '../../../util/Transform';
 
 export enum ColumnType {
     Number,
@@ -40,7 +43,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     private _closestDropIndex: number = 0;
     private _minColWidth: number = 150;
 
-    @observable _rowMenuWidth: number = 100;
+    public static _rowMenuWidth: number = 100;
     @observable _selectedDocs: ObservableSet = new ObservableSet<Doc>();
     @observable _rowEles: ObservableMap = new ObservableMap<Doc, HTMLDivElement>();
     @observable _isDragging: boolean = false;
@@ -69,16 +72,15 @@ export class CollectionSchemaView extends CollectionSubView() {
         let widths = Cast(
             this.layoutDoc.columnWidths,
             listSpec('number'),
-            this.columnKeys.map(() => (this.props.PanelWidth() - this._rowMenuWidth) / this.columnKeys.length)
+            this.columnKeys.map(() => (this.props.PanelWidth() - CollectionSchemaView._rowMenuWidth) / this.columnKeys.length)
         );
 
         const totalWidth = widths.reduce((sum, width) => sum + width, 0);
-        if (totalWidth !== this.props.PanelWidth() - this._rowMenuWidth) {
+        if (totalWidth !== this.props.PanelWidth() - CollectionSchemaView._rowMenuWidth) {
             widths = widths.map(w => {
                 const proportion = w / totalWidth;
-                return proportion * (this.props.PanelWidth() - this._rowMenuWidth);
+                return proportion * (this.props.PanelWidth() - CollectionSchemaView._rowMenuWidth);
             });
-            // this.layoutDoc.columnWidths = new List<number>(widths);
         }
 
         return widths;
@@ -110,8 +112,8 @@ export class CollectionSchemaView extends CollectionSubView() {
         let currWidths = [...this.storedColumnWidths];
         const newColWidth = this.props.PanelWidth() / (currWidths.length + 1);
         currWidths = currWidths.map(w => {
-            const proportion = w / (this.props.PanelWidth() - this._rowMenuWidth);
-            return proportion * (this.props.PanelWidth() - this._rowMenuWidth - newColWidth);
+            const proportion = w / (this.props.PanelWidth() - CollectionSchemaView._rowMenuWidth);
+            return proportion * (this.props.PanelWidth() - CollectionSchemaView._rowMenuWidth - newColWidth);
         });
         currWidths.splice(index + 1, 0, newColWidth);
         this.layoutDoc.columnWidths = new List<number>(currWidths);
@@ -133,8 +135,8 @@ export class CollectionSchemaView extends CollectionSubView() {
         let currWidths = [...this.storedColumnWidths];
         const removedColWidth = currWidths[index];
         currWidths = currWidths.map(w => {
-            const proportion = w / (this.props.PanelWidth() - this._rowMenuWidth - removedColWidth);
-            return proportion * (this.props.PanelWidth() - this._rowMenuWidth);
+            const proportion = w / (this.props.PanelWidth() - CollectionSchemaView._rowMenuWidth - removedColWidth);
+            return proportion * (this.props.PanelWidth() - CollectionSchemaView._rowMenuWidth);
         });
         currWidths.splice(index, 1);
         this.layoutDoc.columnWidths = new List<number>(currWidths);
@@ -142,8 +144,6 @@ export class CollectionSchemaView extends CollectionSubView() {
         let currKeys = [...this.columnKeys];
         currKeys.splice(index, 1);
         this.layoutDoc.columnKeys = new List<string>(currKeys);
-        console.log([...this.storedColumnWidths]);
-        console.log([...this.columnKeys]);
     };
 
     @action
@@ -399,6 +399,34 @@ export class CollectionSchemaView extends CollectionSubView() {
         ContextMenu.Instance.displayMenu(x, y, undefined, true);
     };
 
+    focusDocument = (doc: Doc, options: DocFocusOptions) => {
+        Doc.BrushDoc(doc);
+
+        let focusSpeed = 0;
+        const found = this._mainCont && Array.from(this._mainCont.getElementsByClassName('documentView-node')).find((node: any) => node.id === doc[Id]);
+        if (found) {
+            const top = found.getBoundingClientRect().top;
+            const localTop = this.props.ScreenToLocalTransform().transformPoint(0, top);
+            if (Math.floor(localTop[1]) !== 0) {
+                smoothScroll((focusSpeed = options.zoomTime ?? 500), this._mainCont!, localTop[1] + this._mainCont!.scrollTop, options.easeFunc);
+            }
+        }
+        const endFocus = async (moved: boolean) => options?.afterFocus?.(moved) ?? ViewAdjustment.doNothing;
+        this.props.focus(this.rootDoc, {
+            ...options,
+            afterFocus: (didFocus: boolean) => new Promise<ViewAdjustment>(res => setTimeout(async () => res(await endFocus(didFocus)), focusSpeed)),
+        });
+    };
+
+    isChildContentActive = () =>
+        this.props.isDocumentActive?.() && (this.props.childDocumentsActive?.() || BoolCast(this.rootDoc.childDocumentsActive)) ? true : this.props.childDocumentsActive?.() === false || this.rootDoc.childDocumentsActive === false ? false : undefined;
+
+    getDocTransform(doc: Doc, dref?: DocumentView) {
+        const { scale, translateX, translateY } = Utils.GetScreenTransform(dref?.ContentDiv || undefined);
+        // the document view may center its contents and if so, will prepend that onto the screenToLocalTansform.  so we have to subtract that off
+        return new Transform(-translateX + (dref?.centeringX || 0), -translateY + (dref?.centeringY || 0), 1).scale(this.props.ScreenToLocalTransform().Scale);
+    }
+
     render() {
         return (
             <div
@@ -413,7 +441,7 @@ export class CollectionSchemaView extends CollectionSubView() {
                 onDrop={this.onExternalDrop.bind(this)}>
                 <div className="schema-table">
                     <div className="schema-header-row">
-                        <div className="row-menu" style={{ width: this._rowMenuWidth }}></div>
+                        <div className="row-menu" style={{ width: CollectionSchemaView._rowMenuWidth }}></div>
                         {this.columnKeys.map((key, index) => {
                             return (
                                 <SchemaColumnHeader
@@ -432,25 +460,58 @@ export class CollectionSchemaView extends CollectionSubView() {
                         })}
                     </div>
                     <div className="schema-table-content">
-                        {this.childDocs.map((doc: Doc, index: number) => (
-                            <SchemaRowBox
-                                {...this.props}
-                                key={index}
-                                Document={doc}
-                                ContainingCollectionDoc={this.props.CollectionView?.props.Document}
-                                ContainingCollectionView={this.props.CollectionView}
-                                rowIndex={index}
-                                columnKeys={this.columnKeys}
-                                columnWidths={this.displayColumnWidths}
-                                rowMenuWidth={this._rowMenuWidth}
-                                selectedDocs={this._selectedDocs}
-                                selectRow={this.selectRow}
-                                startDrag={this.startDrag}
-                                dragging={this._isDragging}
-                                dropIndex={this.setDropIndex}
-                                addRowRef={this.addRowRef}
-                            />
-                        ))}
+                        {this.childDocs.map((doc: Doc, index: number) => {
+                            const dataDoc = !doc.isTemplateDoc && !doc.isTemplateForField && !doc.PARAMS ? undefined : this.props.DataDoc;
+                            let dref: Opt<DocumentView>;
+
+                            return (
+                                <div className="schema-row-wrapper">
+                                    <DocumentView
+                                        {...this.props}
+                                        ref={r => (dref = r || undefined)}
+                                        LayoutTemplate={this.props.childLayoutTemplate}
+                                        LayoutTemplateString={SchemaRowBox.LayoutString(this.props.fieldKey)}
+                                        renderDepth={this.props.renderDepth + 1}
+                                        Document={doc}
+                                        DataDoc={dataDoc}
+                                        ContainingCollectionView={this.props.CollectionView}
+                                        ContainingCollectionDoc={this.Document}
+                                        PanelWidth={this.props.PanelWidth}
+                                        PanelHeight={() => 70}
+                                        styleProvider={DefaultStyleProvider}
+                                        focus={this.focusDocument}
+                                        docFilters={this.childDocFilters}
+                                        docRangeFilters={this.childDocRangeFilters}
+                                        searchFilterDocs={this.searchFilterDocs}
+                                        rootSelected={this.rootSelected}
+                                        ScreenToLocalTransform={() => this.getDocTransform(doc, dref)}
+                                        bringToFront={emptyFunction}
+                                        isContentActive={this.isChildContentActive}
+                                        hideDecorations={true}
+                                        hideTitle={true}
+                                        hideDocumentButtonBar={true}
+                                    />
+                                </div>
+                            );
+
+                            // <SchemaRowBox
+                            //     {...this.props}
+                            //     key={index}
+                            //     Document={doc}
+                            //     ContainingCollectionDoc={this.props.CollectionView?.props.Document}
+                            //     ContainingCollectionView={this.props.CollectionView}
+                            //     rowIndex={index}
+                            //     columnKeys={this.columnKeys}
+                            //     columnWidths={this.displayColumnWidths}
+                            //     rowMenuWidth={CollectionSchemaView._rowMenuWidth}
+                            //     selectedDocs={this._selectedDocs}
+                            //     selectRow={this.selectRow}
+                            //     startDrag={this.startDrag}
+                            //     dragging={this._isDragging}
+                            //     dropIndex={this.setDropIndex}
+                            //     addRowRef={this.addRowRef}
+                            // />
+                        })}
                     </div>
                 </div>
                 <EditableView GetValue={returnEmptyString} SetValue={this.addNewTextDoc} placeholder={"Type ':' for commands"} contents={'+ New Node'} menuCallback={this.menuCallback} />
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 5c1f32565..f790e9dbf 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -1,8 +1,8 @@
 import React = require('react');
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, ObservableMap, ObservableSet } from 'mobx';
+import { action, computed, ObservableMap, ObservableSet } from 'mobx';
 import { observer } from 'mobx-react';
-import { Doc } from '../../../../fields/Doc';
+import { Doc, StrListCast } from '../../../../fields/Doc';
 import { undoBatch } from '../../../util/UndoManager';
 import { ViewBoxBaseComponent } from '../../DocComponent';
 import { Colors } from '../../global/globalEnums';
@@ -11,6 +11,10 @@ import './CollectionSchemaView.scss';
 import { SchemaTableCell } from './SchemaTableCell';
 import { emptyFunction, setupMoveUpEvents } from '../../../../Utils';
 import { DragManager } from '../../../util/DragManager';
+import { OpenWhere } from '../../nodes/DocumentView';
+import { Cast } from '../../../../fields/Types';
+import { listSpec } from '../../../../fields/Schema';
+import { CollectionSchemaView } from './CollectionSchemaView';
 
 export interface SchemaRowBoxProps extends FieldViewProps {
     rowIndex: number;
@@ -26,40 +30,61 @@ export interface SchemaRowBoxProps extends FieldViewProps {
 }
 
 @observer
-export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
+export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
     public static LayoutString(fieldKey: string) {
         return FieldView.LayoutString(SchemaRowBox, fieldKey);
     }
 
     private _ref: HTMLDivElement | null = null;
 
-    isSelected = () => this.props.selectedDocs.has(this.props.Document);
     bounds = () => this._ref?.getBoundingClientRect();
 
+    @computed get columnKeys() {
+        return StrListCast(this.props.ContainingCollectionDoc?.columnKeys);
+    }
+
+    @computed get storedColumnWidths() {
+        let widths = Cast(
+            this.props.ContainingCollectionDoc?.columnWidths,
+            listSpec('number'),
+            this.columnKeys.map(() => (this.props.PanelWidth() - CollectionSchemaView._rowMenuWidth) / this.columnKeys.length)
+        );
+
+        const totalWidth = widths.reduce((sum, width) => sum + width, 0);
+        if (totalWidth !== this.props.PanelWidth() - CollectionSchemaView._rowMenuWidth) {
+            widths = widths.map(w => {
+                const proportion = w / totalWidth;
+                return proportion * (this.props.PanelWidth() - CollectionSchemaView._rowMenuWidth);
+            });
+        }
+
+        return widths;
+    }
+
     @action
     onRowPointerDown = (e: React.PointerEvent) => {
         e.stopPropagation();
 
-        setupMoveUpEvents(
-            this,
-            e,
-            e => this.props.startDrag(e, this.props.Document, this._ref!, this.props.rowIndex),
-            emptyFunction,
-            e => this.props.selectRow(e, this.props.Document, this._ref!, this.props.rowIndex)
-        );
+        // setupMoveUpEvents(
+        //     this,
+        //     e,
+        //     e => this.props.startDrag(e, this.props.Document, this._ref!, this.props.rowIndex),
+        //     emptyFunction,
+        //     e => this.props.selectRow(e, this.props.Document, this._ref!, this.props.rowIndex)
+        // );
     };
 
     onPointerEnter = (e: any) => {
-        if (!this.props.dragging) return;
+        // if (!this.props.dragging) return;
         document.removeEventListener('pointermove', this.onPointerMove);
         document.addEventListener('pointermove', this.onPointerMove);
     };
 
     onPointerMove = (e: any) => {
-        if (!this.props.dragging) return;
+        // if (!this.props.dragging) return;
         let dragIsRow: boolean = true;
         DragManager.docsBeingDragged.forEach(doc => {
-            dragIsRow = this.props.selectedDocs.has(doc);
+            // dragIsRow = this.props.selectedDocs.has(doc);
         });
         if (this._ref && dragIsRow) {
             const rect = this._ref.getBoundingClientRect();
@@ -69,11 +94,11 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
             if (y <= halfLine) {
                 this._ref.style.borderTop = `solid 2px ${Colors.MEDIUM_BLUE}`;
                 this._ref.style.borderBottom = '0px';
-                this.props.dropIndex(this.props.rowIndex);
+                // this.props.dropIndex(this.props.rowIndex);
             } else if (y > halfLine) {
                 this._ref.style.borderTop = '0px';
                 this._ref.style.borderBottom = `solid 2px ${Colors.MEDIUM_BLUE}`;
-                this.props.dropIndex(this.props.rowIndex + 1);
+                // this.props.dropIndex(this.props.rowIndex + 1);
             }
         }
     };
@@ -90,15 +115,22 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
         return (
             <div
                 className="schema-row"
-                style={this.isSelected() ? { backgroundColor: Colors.LIGHT_BLUE, opacity: this.props.dragging ? 0.5 : 1 } : {}}
-                onPointerDown={this.onRowPointerDown}
-                onPointerEnter={this.onPointerEnter}
+                style={this.props.isSelected() ? { backgroundColor: Colors.LIGHT_BLUE } : {}}
+                // style={this.isSelected() ? { backgroundColor: Colors.LIGHT_BLUE, opacity: this.props.dragging ? 0.5 : 1 } : {}}
+                // onPointerDown={this.onRowPointerDown}
+                // onPointerEnter={this.onPointerEnter}
                 onPointerLeave={this.onPointerLeave}
                 ref={(row: HTMLDivElement | null) => {
-                    row && this.props.addRowRef(this.props.Document, row);
+                    // row && this.props.addRowRef(this.props.Document, row);
                     this._ref = row;
                 }}>
-                <div className="row-menu" style={{ width: this.props.rowMenuWidth }}>
+                <div
+                    className="row-menu"
+                    style={
+                        {
+                            /* width: this.props.rowMenuWidth */
+                        }
+                    }>
                     <div
                         className="schema-row-button"
                         onPointerDown={undoBatch(e => {
@@ -111,14 +143,14 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
                         className="schema-row-button"
                         onPointerDown={e => {
                             e.stopPropagation();
-                            this.props.addDocTab(this.props.Document, 'add:right');
+                            this.props.addDocTab(this.props.Document, OpenWhere.addRight);
                         }}>
                         <FontAwesomeIcon icon="external-link-alt" />
                     </div>
                 </div>
                 <div className="row-cells">
-                    {this.props.columnKeys.map((key, index) => (
-                        <SchemaTableCell key={key} Document={this.props.Document} fieldKey={key} columnWidth={this.props.columnWidths[index]} />
+                    {this.columnKeys.map((key, index) => (
+                        <SchemaTableCell key={key} Document={this.props.Document} fieldKey={key} columnWidth={this.storedColumnWidths[index]} />
                     ))}
                 </div>
             </div>
diff --git a/src/client/views/collections/old_collectionSchema/OldCollectionSchemaCells.tsx b/src/client/views/collections/old_collectionSchema/OldCollectionSchemaCells.tsx
index 97a6c5c18..5953f85ad 100644
--- a/src/client/views/collections/old_collectionSchema/OldCollectionSchemaCells.tsx
+++ b/src/client/views/collections/old_collectionSchema/OldCollectionSchemaCells.tsx
@@ -1,683 +1,683 @@
-import React = require('react');
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, computed, observable } from 'mobx';
-import { observer } from 'mobx-react';
-import { extname } from 'path';
-import DatePicker from 'react-datepicker';
-import { CellInfo } from 'react-table';
-import { DateField } from '../../../../fields/DateField';
-import { Doc, DocListCast, Field, Opt } from '../../../../fields/Doc';
-import { Id } from '../../../../fields/FieldSymbols';
-import { List } from '../../../../fields/List';
-import { SchemaHeaderField } from '../../../../fields/SchemaHeaderField';
-import { ComputedField } from '../../../../fields/ScriptField';
-import { BoolCast, Cast, DateCast, FieldValue, StrCast } from '../../../../fields/Types';
-import { ImageField } from '../../../../fields/URLField';
-import { emptyFunction, Utils } from '../../../../Utils';
-import { Docs } from '../../../documents/Documents';
-import { DocumentType } from '../../../documents/DocumentTypes';
-import { DocumentManager } from '../../../util/DocumentManager';
-import { DragManager } from '../../../util/DragManager';
-import { KeyCodes } from '../../../util/KeyCodes';
-import { CompileScript } from '../../../util/Scripting';
-import { SearchUtil } from '../../../util/SearchUtil';
-import { SnappingManager } from '../../../util/SnappingManager';
-import { undoBatch } from '../../../util/UndoManager';
-import '../../../views/DocumentDecorations.scss';
-import { EditableView } from '../../EditableView';
-import { MAX_ROW_HEIGHT } from '../../global/globalCssVariables.scss';
-import { DocumentIconContainer } from '../../nodes/DocumentIcon';
-import { OverlayView } from '../../OverlayView';
-import { CollectionView } from '../CollectionView';
-import './CollectionSchemaView.scss';
-import { OpenWhere } from '../../nodes/DocumentView';
-import { PinProps } from '../../nodes/trails';
-
-// intialize cell properties
-export interface CellProps {
-    row: number;
-    col: number;
-    rowProps: CellInfo;
-    // currently unused
-    CollectionView: Opt<CollectionView>;
-    // currently unused
-    ContainingCollection: Opt<CollectionView>;
-    Document: Doc;
-    // column name
-    fieldKey: string;
-    // currently unused
-    renderDepth: number;
-    // called when a button is pressed on the node itself
-    addDocTab: (document: Doc, where: OpenWhere) => boolean;
-    pinToPres: (document: Doc, pinProps: PinProps) => void;
-    moveDocument?: (document: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => boolean;
-    isFocused: boolean;
-    changeFocusedCellByIndex: (row: number, col: number) => void;
-    // set whether the cell is in the isEditing mode
-    setIsEditing: (isEditing: boolean) => void;
-    isEditable: boolean;
-    setPreviewDoc: (doc: Doc) => void;
-    setComputed: (script: string, doc: Doc, field: string, row: number, col: number) => boolean;
-    getField: (row: number, col?: number) => void;
-    // currnetly unused
-    showDoc: (doc: Doc | undefined, dataDoc?: any, screenX?: number, screenY?: number) => void;
-}
-
-@observer
-export class CollectionSchemaCell extends React.Component<CellProps> {
-    // return a field key that is corrected for whether it COMMENT
-    public static resolvedFieldKey(column: string, rowDoc: Doc) {
-        const fieldKey = column;
-        if (fieldKey.startsWith('*')) {
-            const rootKey = fieldKey.substring(1);
-            const allKeys = [...Array.from(Object.keys(rowDoc)), ...Array.from(Object.keys(Doc.GetProto(rowDoc)))];
-            const matchedKeys = allKeys.filter(key => key.includes(rootKey));
-            if (matchedKeys.length) return matchedKeys[0];
-        }
-        return fieldKey;
-    }
-    @observable protected _isEditing: boolean = false;
-    protected _focusRef = React.createRef<HTMLDivElement>();
-    protected _rowDoc = this.props.rowProps.original;
-    // Gets the serialized data in proto form of the base proto that this document's proto inherits from
-    protected _rowDataDoc = Doc.GetProto(this.props.rowProps.original);
-    // methods for dragging and dropping
-    protected _dropDisposer?: DragManager.DragDropDisposer;
-    @observable contents: string = '';
-
-    componentDidMount() {
-        document.addEventListener('keydown', this.onKeyDown);
-    }
-    componentWillUnmount() {
-        document.removeEventListener('keydown', this.onKeyDown);
-    }
-
-    @action
-    onKeyDown = (e: KeyboardEvent): void => {
-        // If a cell is editable and clicked, hitting enter shoudl allow the user to edit it
-        if (this.props.isFocused && this.props.isEditable && e.keyCode === KeyCodes.ENTER) {
-            document.removeEventListener('keydown', this.onKeyDown);
-            this._isEditing = true;
-            this.props.setIsEditing(true);
-        }
-    };
-
-    @action
-    isEditingCallback = (isEditing: boolean): void => {
-        // a general method that takes a boolean that determines whether the cell should be in
-        // is-editing mode
-        // remove the event listener if it's there
-        document.removeEventListener('keydown', this.onKeyDown);
-        // it's not already in is-editing mode, re-add the event listener
-        isEditing && document.addEventListener('keydown', this.onKeyDown);
-        this._isEditing = isEditing;
-        this.props.setIsEditing(isEditing);
-        this.props.changeFocusedCellByIndex(this.props.row, this.props.col);
-    };
-
-    @action
-    onPointerDown = async (e: React.PointerEvent): Promise<void> => {
-        // pan to the cell
-        this.onItemDown(e);
-        // focus on it
-        this.props.changeFocusedCellByIndex(this.props.row, this.props.col);
-        this.props.setPreviewDoc(this.props.rowProps.original);
-
-        let url: string;
-        if ((url = StrCast(this.props.rowProps.row.href))) {
-            // opens up the the doc in a new window, blurring the old one
-            try {
-                new URL(url);
-                const temp = window.open(url)!;
-                temp.blur();
-                window.focus();
-            } catch {}
-        }
-
-        const doc = Cast(this._rowDoc[this.renderFieldKey], Doc, null);
-        doc && this.props.setPreviewDoc(doc);
-    };
-
-    @undoBatch
-    applyToDoc = (doc: Doc, row: number, col: number, run: (args?: { [name: string]: any }) => any) => {
-        // apply a specified change to the cell
-        const res = run({ this: doc, $r: row, $c: col, $: (r: number = 0, c: number = 0) => this.props.getField(r + row, c + col) });
-        if (!res.success) return false;
-        // change what is rendered to this new changed cell content
-        doc[this.renderFieldKey] = res.result;
-        return true;
-        // return whether the change was successful
-    };
-
-    private drop = (e: Event, de: DragManager.DropEvent) => {
-        // if the drag has data at its completion
-        if (de.complete.docDragData) {
-            // if only one doc was dragged
-            if (de.complete.docDragData.draggedDocuments.length === 1) {
-                // update the renderFieldKey
-                this._rowDataDoc[this.renderFieldKey] = de.complete.docDragData.draggedDocuments[0];
-            } else {
-                // create schema document reflecting the new column arrangement
-                const coll = Docs.Create.SchemaDocument([new SchemaHeaderField('title', '#f1efeb')], de.complete.docDragData.draggedDocuments, {});
-                this._rowDataDoc[this.renderFieldKey] = coll;
-            }
-            e.stopPropagation();
-        }
-    };
-
-    protected dropRef = (ele: HTMLElement | null) => {
-        // if the drop disposer is not undefined, run its function
-        this._dropDisposer?.();
-        // if ele is not null, give ele a non-undefined drop disposer
-        ele && (this._dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this)));
-    };
-
-    returnHighlights(contents: string, positions?: number[]) {
-        if (positions) {
-            const results = [];
-            StrCast(this.props.Document._searchString);
-            const length = StrCast(this.props.Document._searchString).length;
-            const color = contents ? 'black' : 'grey';
-
-            results.push(
-                <span key="-1" style={{ color }}>
-                    {contents?.slice(0, positions[0])}
-                </span>
-            );
-            positions.forEach((num, cur) => {
-                results.push(
-                    <span key={'start' + cur} style={{ backgroundColor: '#FFFF00', color }}>
-                        {contents?.slice(num, num + length)}
-                    </span>
-                );
-                let end = 0;
-                cur === positions.length - 1 ? (end = contents.length) : (end = positions[cur + 1]);
-                results.push(
-                    <span key={'end' + cur} style={{ color }}>
-                        {contents?.slice(num + length, end)}
-                    </span>
-                );
-            });
-            return results;
-        }
-        return <span style={{ color: contents ? 'black' : 'grey' }}>{contents ? contents?.valueOf() : 'undefined'}</span>;
-    }
-
-    @computed get renderFieldKey() {
-        // gets the resolved field key of this cell
-        return CollectionSchemaCell.resolvedFieldKey(this.props.rowProps.column.id!, this.props.rowProps.original);
-    }
-
-    onItemDown = async (e: React.PointerEvent) => {
-        // if the document is a document used to change UI for search results in schema view
-        if (this.props.Document._searchDoc) {
-            const aliasdoc = await SearchUtil.GetAliasesOfDocument(this._rowDataDoc);
-            const targetContext = aliasdoc.length <= 0 ? undefined : Cast(aliasdoc[0].context, Doc, null);
-            // Jump to the this document
-            DocumentManager.Instance.jumpToDocument(this._rowDoc, { willPan: true }, emptyFunction, targetContext ? [targetContext] : [], () => this.props.setPreviewDoc(this._rowDoc));
-        }
-    };
-
-    renderCellWithType(type: string | undefined) {
-        const dragRef: React.RefObject<HTMLDivElement> = React.createRef();
-
-        // the column
-        const fieldKey = this.renderFieldKey;
-        // the exact cell
-        const field = this._rowDoc[fieldKey];
-
-        const onPointerEnter = (e: React.PointerEvent): void => {
-            // e.buttons === 1 means the left moue pointer is down
-            if (e.buttons === 1 && SnappingManager.GetIsDragging() && (type === 'document' || type === undefined)) {
-                dragRef.current!.className = 'collectionSchemaView-cellContainer doc-drag-over';
-            }
-        };
-        const onPointerLeave = (e: React.PointerEvent): void => {
-            // change the class name to indicate that the cell is no longer being dragged
-            dragRef.current!.className = 'collectionSchemaView-cellContainer';
-        };
-
-        let contents = Field.toString(field as Field);
-        // display 2 hyphens instead of a blank box for empty cells
-        contents = contents === '' ? '--' : contents;
-
-        // classname reflects the tatus of the cell
-        let className = 'collectionSchemaView-cellWrapper';
-        if (this._isEditing) className += ' editing';
-        if (this.props.isFocused && this.props.isEditable) className += ' focused';
-        if (this.props.isFocused && !this.props.isEditable) className += ' inactive';
-
-        const positions = [];
-        if (StrCast(this.props.Document._searchString).toLowerCase() !== '') {
-            // term is ...promise pending... if the field is a Promise, otherwise it is the cell's contents
-            let term = field instanceof Promise ? '...promise pending...' : contents.toLowerCase();
-            const search = StrCast(this.props.Document._searchString).toLowerCase();
-            let start = term.indexOf(search);
-            let tally = 0;
-            // if search is found in term
-            if (start !== -1) {
-                positions.push(start);
-            }
-            // if search is found in term, continue finding all instances of search in term
-            while (start < contents?.length && start !== -1) {
-                term = term.slice(start + search.length + 1);
-                tally += start + search.length + 1;
-                start = term.indexOf(search);
-                positions.push(tally + start);
-            }
-            // remove the last position
-            if (positions.length > 1) {
-                positions.pop();
-            }
-        }
-        const placeholder = type === 'number' ? '0' : contents === '' ? '--' : 'undefined';
-        return (
-            <div
-                className="collectionSchemaView-cellContainer"
-                style={{ cursor: field instanceof Doc ? 'grab' : 'auto' }}
-                ref={dragRef}
-                onPointerDown={this.onPointerDown}
-                onClick={action(e => (this._isEditing = true))}
-                onPointerEnter={onPointerEnter}
-                onPointerLeave={onPointerLeave}>
-                <div className={className} ref={this._focusRef} tabIndex={-1}>
-                    <div className="collectionSchemaView-cellContents" ref={type === undefined || type === 'document' ? this.dropRef : null}>
-                        {!this.props.Document._searchDoc ? (
-                            <EditableView
-                                editing={this._isEditing}
-                                isEditingCallback={this.isEditingCallback}
-                                display={'inline'}
-                                contents={contents}
-                                height={'auto'}
-                                maxHeight={Number(MAX_ROW_HEIGHT)}
-                                placeholder={placeholder}
-                                GetValue={() => {
-                                    const cfield = ComputedField.WithoutComputed(() => FieldValue(field));
-                                    const cscript = cfield instanceof ComputedField ? cfield.script.originalScript : undefined;
-                                    const cfinalScript = cscript?.split('return')[cscript.split('return').length - 1];
-                                    return cscript ? (cfinalScript?.endsWith(';') ? `:=${cfinalScript?.substring(0, cfinalScript.length - 2)}` : cfinalScript) : Field.IsField(cfield) ? Field.toScriptString(cfield) : '';
-                                }}
-                                SetValue={action((value: string) => {
-                                    // sets what is displayed after the user makes an input
-                                    let retVal = false;
-                                    if (value.startsWith(':=') || value.startsWith('=:=')) {
-                                        // decides how to compute a value when given either of the above strings
-                                        const script = value.substring(value.startsWith('=:=') ? 3 : 2);
-                                        retVal = this.props.setComputed(script, value.startsWith(':=') ? this._rowDataDoc : this._rowDoc, this.renderFieldKey, this.props.row, this.props.col);
-                                    } else {
-                                        // check if the input is a number
-                                        let inputIsNum = true;
-                                        for (const s of value) {
-                                            if (isNaN(parseInt(s)) && !(s === '.') && !(s === ',')) {
-                                                inputIsNum = false;
-                                            }
-                                        }
-                                        // check if the input is a boolean
-                                        const inputIsBool: boolean = value === 'false' || value === 'true';
-                                        // what to do in the case
-                                        if (!inputIsNum && !inputIsBool && !value.startsWith('=')) {
-                                            // if it's not a number, it's a string, and should be processed as such
-                                            // strips the string of quotes when it is edited to prevent quotes form being added to the text automatically
-                                            // after each edit
-                                            let valueSansQuotes = value;
-                                            if (this._isEditing) {
-                                                const vsqLength = valueSansQuotes.length;
-                                                // get rid of outer quotes
-                                                valueSansQuotes = valueSansQuotes.substring(value.startsWith('"') ? 1 : 0, valueSansQuotes.charAt(vsqLength - 1) === '"' ? vsqLength - 1 : vsqLength);
-                                            }
-                                            let inputAsString = '"';
-                                            // escape any quotes in the string
-                                            for (const i of valueSansQuotes) {
-                                                if (i === '"') {
-                                                    inputAsString += '\\"';
-                                                } else {
-                                                    inputAsString += i;
-                                                }
-                                            }
-                                            // add a closing quote
-                                            inputAsString += '"';
-                                            //two options here: we can strip off outer quotes or we can figure out what's going on with the script
-                                            const script = CompileScript(inputAsString, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: 'number', $c: 'number', $: 'any' } });
-                                            const changeMade = inputAsString.length !== value.length || inputAsString.length - 2 !== value.length;
-                                            // change it if a change is made, otherwise, just compile using the old cell conetnts
-                                            script.compiled && (retVal = this.applyToDoc(changeMade ? this._rowDoc : this._rowDataDoc, this.props.row, this.props.col, script.run));
-                                            // handle numbers and expressions
-                                        } else if (inputIsNum || value.startsWith('=')) {
-                                            //TODO: make accept numbers
-                                            const inputscript = value.substring(value.startsWith('=') ? 1 : 0);
-                                            // if commas are not stripped, the parser only considers the numbers after the last comma
-                                            let inputSansCommas = '';
-                                            for (const s of inputscript) {
-                                                if (!(s === ',')) {
-                                                    inputSansCommas += s;
-                                                }
-                                            }
-                                            const script = CompileScript(inputSansCommas, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: 'number', $c: 'number', $: 'any' } });
-                                            const changeMade = value.length - 2 !== value.length;
-                                            script.compiled && (retVal = this.applyToDoc(changeMade ? this._rowDoc : this._rowDataDoc, this.props.row, this.props.col, script.run));
-                                            // handle booleans
-                                        } else if (inputIsBool) {
-                                            const script = CompileScript(value, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: 'number', $c: 'number', $: 'any' } });
-                                            const changeMade = value.length - 2 !== value.length;
-                                            script.compiled && (retVal = this.applyToDoc(changeMade ? this._rowDoc : this._rowDataDoc, this.props.row, this.props.col, script.run));
-                                        }
-                                    }
-                                    if (retVal) {
-                                        this._isEditing = false; // need to set this here. otherwise, the assignment of the field will invalidate & cause render() to be called with the wrong value for 'editing'
-                                        this.props.setIsEditing(false);
-                                    }
-                                    return retVal;
-                                })}
-                                OnFillDown={async (value: string) => {
-                                    // computes all of the value preceded by :=
-                                    const script = CompileScript(value, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: 'number', $c: 'number', $: 'any' } });
-                                    script.compiled &&
-                                        DocListCast(this.props.Document[this.props.fieldKey]).forEach((doc, i) =>
-                                            value.startsWith(':=') ? this.props.setComputed(value.substring(2), Doc.GetProto(doc), this.renderFieldKey, i, this.props.col) : this.applyToDoc(Doc.GetProto(doc), i, this.props.col, script.run)
-                                        );
-                                }}
-                            />
-                        ) : (
-                            this.returnHighlights(contents, positions)
-                        )}
-                    </div>
-                </div>
-            </div>
-        );
-    }
-
-    render() {
-        return this.renderCellWithType(undefined);
-    }
-}
-
-@observer
-export class CollectionSchemaNumberCell extends CollectionSchemaCell {
-    render() {
-        return this.renderCellWithType('number');
-    }
-}
-
-@observer
-export class CollectionSchemaBooleanCell extends CollectionSchemaCell {
-    render() {
-        return this.renderCellWithType('boolean');
-    }
-}
-
-@observer
-export class CollectionSchemaStringCell extends CollectionSchemaCell {
-    render() {
-        return this.renderCellWithType('string');
-    }
-}
-
-@observer
-export class CollectionSchemaDateCell extends CollectionSchemaCell {
-    @computed get _date(): Opt<DateField> {
-        // if the cell is a date field, cast then contents to a date. Otherrwwise, make the contents undefined.
-        return this._rowDoc[this.renderFieldKey] instanceof DateField ? DateCast(this._rowDoc[this.renderFieldKey]) : undefined;
-    }
-
-    @action
-    handleChange = (date: any) => {
-        // const script = CompileScript(date.toString(), { requiredType: "Date", addReturn: true, params: { this: Doc.name } });
-        // if (script.compiled) {
-        //     this.applyToDoc(this._document, this.props.row, this.props.col, script.run);
-        // } else {
-        // ^ DateCast is always undefined for some reason, but that is what the field should be set to
-        this._rowDoc[this.renderFieldKey] = new DateField(date as Date);
-        //}
-    };
-
-    render() {
-        return !this.props.isFocused ? (
-            <span onPointerDown={this.onPointerDown}>{this._date ? Field.toString(this._date as Field) : '--'}</span>
-        ) : (
-            <DatePicker selected={this._date?.date || new Date()} onSelect={date => this.handleChange(date)} onChange={date => this.handleChange(date)} />
-        );
-    }
-}
-
-@observer
-export class CollectionSchemaDocCell extends CollectionSchemaCell {
-    _overlayDisposer?: () => void;
-
-    @computed get _doc() {
-        return FieldValue(Cast(this._rowDoc[this.renderFieldKey], Doc));
-    }
-
-    @action
-    onSetValue = (value: string) => {
-        this._doc && (Doc.GetProto(this._doc).title = value);
-
-        const script = CompileScript(value, {
-            addReturn: true,
-            typecheck: true,
-            transformer: DocumentIconContainer.getTransformer(),
-        });
-        // compile the script
-        const results = script.compiled && script.run();
-        // if the script was compiled and run
-        if (results && results.success) {
-            this._rowDoc[this.renderFieldKey] = results.result;
-            return true;
-        }
-        return false;
-    };
-
-    componentWillUnmount() {
-        this.onBlur();
-    }
-
-    onBlur = () => {
-        this._overlayDisposer?.();
-    };
-    onFocus = () => {
-        this.onBlur();
-        this._overlayDisposer = OverlayView.Instance.addElement(<DocumentIconContainer />, { x: 0, y: 0 });
-    };
-
-    @action
-    isEditingCallback = (isEditing: boolean): void => {
-        // the isEditingCallback from a general CollectionSchemaCell
-        document.removeEventListener('keydown', this.onKeyDown);
-        isEditing && document.addEventListener('keydown', this.onKeyDown);
-        this._isEditing = isEditing;
-        this.props.setIsEditing(isEditing);
-        this.props.changeFocusedCellByIndex(this.props.row, this.props.col);
-    };
-
-    render() {
-        // if there's a doc, render it
-        return !this._doc ? (
-            this.renderCellWithType('document')
-        ) : (
-            <div className="collectionSchemaView-cellWrapper" ref={this._focusRef} tabIndex={-1} onPointerDown={this.onPointerDown}>
-                <div className="collectionSchemaView-cellContents-document" style={{ padding: '5.9px' }} ref={this.dropRef} onFocus={this.onFocus} onBlur={this.onBlur}>
-                    <EditableView
-                        editing={this._isEditing}
-                        isEditingCallback={this.isEditingCallback}
-                        display={'inline'}
-                        contents={this._doc.title || '--'}
-                        height={'auto'}
-                        maxHeight={Number(MAX_ROW_HEIGHT)}
-                        GetValue={() => StrCast(this._doc?.title)}
-                        SetValue={action((value: string) => {
-                            this.onSetValue(value);
-                            return true;
-                        })}
-                    />
-                </div>
-                <div onClick={() => this._doc && this.props.addDocTab(this._doc, OpenWhere.addRight)} className="collectionSchemaView-cellContents-docButton">
-                    <FontAwesomeIcon icon="external-link-alt" size="lg" />
-                </div>
-            </div>
-        );
-    }
-}
-
-@observer
-export class CollectionSchemaImageCell extends CollectionSchemaCell {
-    choosePath(url: URL) {
-        if (url.protocol === 'data') return url.href; // if the url ises the data protocol, just return the href
-        if (url.href.indexOf(window.location.origin) === -1) return Utils.CorsProxy(url.href); // otherwise, put it through the cors proxy erver
-        if (!/\.(png|jpg|jpeg|gif|webp)$/.test(url.href.toLowerCase())) return url.href; //Why is this here — good question
-
-        const ext = extname(url.href);
-        return url.href.replace(ext, '_o' + ext);
-    }
-
-    render() {
-        const field = Cast(this._rowDoc[this.renderFieldKey], ImageField, null); // retrieve the primary image URL that is being rendered from the data doc
-        const alts = DocListCast(this._rowDoc[this.renderFieldKey + '-alternates']); // retrieve alternate documents that may be rendered as alternate images
-        const altpaths = alts
-            .map(doc => Cast(doc[Doc.LayoutFieldKey(doc)], ImageField, null)?.url)
-            .filter(url => url)
-            .map(url => this.choosePath(url)); // access the primary layout data of the alternate documents
-        const paths = field ? [this.choosePath(field.url), ...altpaths] : altpaths;
-        // If there is a path, follow it; otherwise, follow a link to a default image icon
-        const url = paths.length ? paths : [Utils.CorsProxy('http://www.cs.brown.edu/~bcz/noImage.png')];
-
-        const aspect = Doc.NativeAspect(this._rowDoc); // aspect ratio
-        let width = Math.min(75, this.props.rowProps.width); // get a with that is no smaller than 75px
-        const height = Math.min(75, width / aspect); // get a height either proportional to that or 75 px
-        width = height * aspect; // increase the width of the image if necessary to maintain proportionality
-
-        const reference = React.createRef<HTMLDivElement>();
-        return (
-            <div className="collectionSchemaView-cellWrapper" ref={this._focusRef} tabIndex={-1} onPointerDown={this.onPointerDown}>
-                <div className="collectionSchemaView-cellContents" key={this._rowDoc[Id]} ref={reference}>
-                    <img src={url[0]} width={paths.length ? width : '20px'} height={paths.length ? height : '20px'} />
-                </div>
-            </div>
-        );
-    }
-}
-
-@observer
-export class CollectionSchemaListCell extends CollectionSchemaCell {
-    _overlayDisposer?: () => void;
-
-    @computed get _field() {
-        return this._rowDoc[this.renderFieldKey];
-    }
-    @computed get _optionsList() {
-        return this._field as List<any>;
-    }
-    @observable private _opened = false; // whether the list is opened
-    @observable private _text = 'select an item';
-    @observable private _selectedNum = 0; // the index of the list item selected
-
-    @action
-    onSetValue = (value: string) => {
-        // change if it's a document
-        this._optionsList[this._selectedNum] = this._text = value;
-
-        (this._field as List<any>).splice(this._selectedNum, 1, value);
-    };
-
-    @action
-    onSelected = (element: string, index: number) => {
-        // if an item is selected, the private variables should update to reflect this
-        this._text = element;
-        this._selectedNum = index;
-    };
-
-    onFocus = () => {
-        this._overlayDisposer?.();
-        this._overlayDisposer = OverlayView.Instance.addElement(<DocumentIconContainer />, { x: 0, y: 0 });
-    };
-
-    render() {
-        const link = false;
-        const reference = React.createRef<HTMLDivElement>();
-
-        // if the list is not opened, don't display it; otherwise, do.
-        if (this._optionsList?.length) {
-            const options = !this._opened ? null : (
-                <div>
-                    {this._optionsList.map((element, index) => {
-                        const val = Field.toString(element);
-                        return (
-                            <div className="collectionSchemaView-dropdownOption" key={index} style={{ padding: '6px' }} onPointerDown={e => this.onSelected(StrCast(element), index)}>
-                                {val}
-                            </div>
-                        );
-                    })}
-                </div>
-            );
-
-            const plainText = <div style={{ padding: '5.9px' }}>{this._text}</div>;
-            const textarea = (
-                <div className="collectionSchemaView-cellContents" key={this._rowDoc[Id]} style={{ padding: '5.9px' }} ref={this.dropRef}>
-                    <EditableView
-                        editing={this._isEditing}
-                        isEditingCallback={this.isEditingCallback}
-                        display={'inline'}
-                        contents={this._text}
-                        height={'auto'}
-                        maxHeight={Number(MAX_ROW_HEIGHT)}
-                        GetValue={() => this._text}
-                        SetValue={action((value: string) => {
-                            // add special for params
-                            this.onSetValue(value);
-                            return true;
-                        })}
-                    />
-                </div>
-            );
-
-            //☰
-            return (
-                <div className="collectionSchemaView-cellWrapper" ref={this._focusRef} tabIndex={-1} onPointerDown={this.onPointerDown}>
-                    <div className="collectionSchemaView-cellContents" key={this._rowDoc[Id]} ref={reference}>
-                        <div className="collectionSchemaView-dropDownWrapper">
-                            <button type="button" className="collectionSchemaView-dropdownButton" style={{ right: 'length', position: 'relative' }} onClick={action(e => (this._opened = !this._opened))}>
-                                <FontAwesomeIcon icon={this._opened ? 'caret-up' : 'caret-down'} size="sm" />
-                            </button>
-                            <div className="collectionSchemaView-dropdownText"> {link ? plainText : textarea} </div>
-                        </div>
-                        {options}
-                    </div>
-                </div>
-            );
-        }
-        return this.renderCellWithType('list');
-    }
-}
-
-@observer
-export class CollectionSchemaCheckboxCell extends CollectionSchemaCell {
-    @computed get _isChecked() {
-        return BoolCast(this._rowDoc[this.renderFieldKey]);
-    }
-
-    render() {
-        const reference = React.createRef<HTMLDivElement>();
-        return (
-            <div className="collectionSchemaView-cellWrapper" ref={this._focusRef} tabIndex={-1} onPointerDown={this.onPointerDown}>
-                <input type="checkbox" checked={this._isChecked} onChange={e => (this._rowDoc[this.renderFieldKey] = e.target.checked)} />
-            </div>
-        );
-    }
-}
-
-@observer
-export class CollectionSchemaButtons extends CollectionSchemaCell {
-    // the navigation buttons for schema view when it is used for search.
-    render() {
-        return !this.props.Document._searchDoc || ![DocumentType.PDF, DocumentType.RTF].includes(StrCast(this._rowDoc.type) as DocumentType) ? (
-            <></>
-        ) : (
-            <div style={{ paddingTop: 8, paddingLeft: 3 }}>
-                <button style={{ padding: 2, left: 77 }} onClick={() => Doc.SearchMatchNext(this._rowDoc, true)}>
-                    <FontAwesomeIcon icon="arrow-up" size="sm" />
-                </button>
-                <button style={{ padding: 2 }} onClick={() => Doc.SearchMatchNext(this._rowDoc, false)}>
-                    <FontAwesomeIcon icon="arrow-down" size="sm" />
-                </button>
-            </div>
-        );
-    }
-}
+// import React = require('react');
+// import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+// import { action, computed, observable } from 'mobx';
+// import { observer } from 'mobx-react';
+// import { extname } from 'path';
+// import DatePicker from 'react-datepicker';
+// import { CellInfo } from 'react-table';
+// import { DateField } from '../../../../fields/DateField';
+// import { Doc, DocListCast, Field, Opt } from '../../../../fields/Doc';
+// import { Id } from '../../../../fields/FieldSymbols';
+// import { List } from '../../../../fields/List';
+// import { SchemaHeaderField } from '../../../../fields/SchemaHeaderField';
+// import { ComputedField } from '../../../../fields/ScriptField';
+// import { BoolCast, Cast, DateCast, FieldValue, StrCast } from '../../../../fields/Types';
+// import { ImageField } from '../../../../fields/URLField';
+// import { emptyFunction, Utils } from '../../../../Utils';
+// import { Docs } from '../../../documents/Documents';
+// import { DocumentType } from '../../../documents/DocumentTypes';
+// import { DocumentManager } from '../../../util/DocumentManager';
+// import { DragManager } from '../../../util/DragManager';
+// import { KeyCodes } from '../../../util/KeyCodes';
+// import { CompileScript } from '../../../util/Scripting';
+// import { SearchUtil } from '../../../util/SearchUtil';
+// import { SnappingManager } from '../../../util/SnappingManager';
+// import { undoBatch } from '../../../util/UndoManager';
+// import '../../../views/DocumentDecorations.scss';
+// import { EditableView } from '../../EditableView';
+// import { MAX_ROW_HEIGHT } from '../../global/globalCssVariables.scss';
+// import { DocumentIconContainer } from '../../nodes/DocumentIcon';
+// import { OverlayView } from '../../OverlayView';
+// import { CollectionView } from '../CollectionView';
+// import './CollectionSchemaView.scss';
+// import { OpenWhere } from '../../nodes/DocumentView';
+// import { PinProps } from '../../nodes/trails';
+
+// // intialize cell properties
+// export interface CellProps {
+//     row: number;
+//     col: number;
+//     rowProps: CellInfo;
+//     // currently unused
+//     CollectionView: Opt<CollectionView>;
+//     // currently unused
+//     ContainingCollection: Opt<CollectionView>;
+//     Document: Doc;
+//     // column name
+//     fieldKey: string;
+//     // currently unused
+//     renderDepth: number;
+//     // called when a button is pressed on the node itself
+//     addDocTab: (document: Doc, where: OpenWhere) => boolean;
+//     pinToPres: (document: Doc, pinProps: PinProps) => void;
+//     moveDocument?: (document: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => boolean;
+//     isFocused: boolean;
+//     changeFocusedCellByIndex: (row: number, col: number) => void;
+//     // set whether the cell is in the isEditing mode
+//     setIsEditing: (isEditing: boolean) => void;
+//     isEditable: boolean;
+//     setPreviewDoc: (doc: Doc) => void;
+//     setComputed: (script: string, doc: Doc, field: string, row: number, col: number) => boolean;
+//     getField: (row: number, col?: number) => void;
+//     // currnetly unused
+//     showDoc: (doc: Doc | undefined, dataDoc?: any, screenX?: number, screenY?: number) => void;
+// }
+
+// @observer
+// export class CollectionSchemaCell extends React.Component<CellProps> {
+//     // return a field key that is corrected for whether it COMMENT
+//     public static resolvedFieldKey(column: string, rowDoc: Doc) {
+//         const fieldKey = column;
+//         if (fieldKey.startsWith('*')) {
+//             const rootKey = fieldKey.substring(1);
+//             const allKeys = [...Array.from(Object.keys(rowDoc)), ...Array.from(Object.keys(Doc.GetProto(rowDoc)))];
+//             const matchedKeys = allKeys.filter(key => key.includes(rootKey));
+//             if (matchedKeys.length) return matchedKeys[0];
+//         }
+//         return fieldKey;
+//     }
+//     @observable protected _isEditing: boolean = false;
+//     protected _focusRef = React.createRef<HTMLDivElement>();
+//     protected _rowDoc = this.props.rowProps.original;
+//     // Gets the serialized data in proto form of the base proto that this document's proto inherits from
+//     protected _rowDataDoc = Doc.GetProto(this.props.rowProps.original);
+//     // methods for dragging and dropping
+//     protected _dropDisposer?: DragManager.DragDropDisposer;
+//     @observable contents: string = '';
+
+//     componentDidMount() {
+//         document.addEventListener('keydown', this.onKeyDown);
+//     }
+//     componentWillUnmount() {
+//         document.removeEventListener('keydown', this.onKeyDown);
+//     }
+
+//     @action
+//     onKeyDown = (e: KeyboardEvent): void => {
+//         // If a cell is editable and clicked, hitting enter shoudl allow the user to edit it
+//         if (this.props.isFocused && this.props.isEditable && e.keyCode === KeyCodes.ENTER) {
+//             document.removeEventListener('keydown', this.onKeyDown);
+//             this._isEditing = true;
+//             this.props.setIsEditing(true);
+//         }
+//     };
+
+//     @action
+//     isEditingCallback = (isEditing: boolean): void => {
+//         // a general method that takes a boolean that determines whether the cell should be in
+//         // is-editing mode
+//         // remove the event listener if it's there
+//         document.removeEventListener('keydown', this.onKeyDown);
+//         // it's not already in is-editing mode, re-add the event listener
+//         isEditing && document.addEventListener('keydown', this.onKeyDown);
+//         this._isEditing = isEditing;
+//         this.props.setIsEditing(isEditing);
+//         this.props.changeFocusedCellByIndex(this.props.row, this.props.col);
+//     };
+
+//     @action
+//     onPointerDown = async (e: React.PointerEvent): Promise<void> => {
+//         // pan to the cell
+//         this.onItemDown(e);
+//         // focus on it
+//         this.props.changeFocusedCellByIndex(this.props.row, this.props.col);
+//         this.props.setPreviewDoc(this.props.rowProps.original);
+
+//         let url: string;
+//         if ((url = StrCast(this.props.rowProps.row.href))) {
+//             // opens up the the doc in a new window, blurring the old one
+//             try {
+//                 new URL(url);
+//                 const temp = window.open(url)!;
+//                 temp.blur();
+//                 window.focus();
+//             } catch {}
+//         }
+
+//         const doc = Cast(this._rowDoc[this.renderFieldKey], Doc, null);
+//         doc && this.props.setPreviewDoc(doc);
+//     };
+
+//     @undoBatch
+//     applyToDoc = (doc: Doc, row: number, col: number, run: (args?: { [name: string]: any }) => any) => {
+//         // apply a specified change to the cell
+//         const res = run({ this: doc, $r: row, $c: col, $: (r: number = 0, c: number = 0) => this.props.getField(r + row, c + col) });
+//         if (!res.success) return false;
+//         // change what is rendered to this new changed cell content
+//         doc[this.renderFieldKey] = res.result;
+//         return true;
+//         // return whether the change was successful
+//     };
+
+//     private drop = (e: Event, de: DragManager.DropEvent) => {
+//         // if the drag has data at its completion
+//         if (de.complete.docDragData) {
+//             // if only one doc was dragged
+//             if (de.complete.docDragData.draggedDocuments.length === 1) {
+//                 // update the renderFieldKey
+//                 this._rowDataDoc[this.renderFieldKey] = de.complete.docDragData.draggedDocuments[0];
+//             } else {
+//                 // create schema document reflecting the new column arrangement
+//                 const coll = Docs.Create.SchemaDocument([new SchemaHeaderField('title', '#f1efeb')], de.complete.docDragData.draggedDocuments, {});
+//                 this._rowDataDoc[this.renderFieldKey] = coll;
+//             }
+//             e.stopPropagation();
+//         }
+//     };
+
+//     protected dropRef = (ele: HTMLElement | null) => {
+//         // if the drop disposer is not undefined, run its function
+//         this._dropDisposer?.();
+//         // if ele is not null, give ele a non-undefined drop disposer
+//         ele && (this._dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this)));
+//     };
+
+//     returnHighlights(contents: string, positions?: number[]) {
+//         if (positions) {
+//             const results = [];
+//             StrCast(this.props.Document._searchString);
+//             const length = StrCast(this.props.Document._searchString).length;
+//             const color = contents ? 'black' : 'grey';
+
+//             results.push(
+//                 <span key="-1" style={{ color }}>
+//                     {contents?.slice(0, positions[0])}
+//                 </span>
+//             );
+//             positions.forEach((num, cur) => {
+//                 results.push(
+//                     <span key={'start' + cur} style={{ backgroundColor: '#FFFF00', color }}>
+//                         {contents?.slice(num, num + length)}
+//                     </span>
+//                 );
+//                 let end = 0;
+//                 cur === positions.length - 1 ? (end = contents.length) : (end = positions[cur + 1]);
+//                 results.push(
+//                     <span key={'end' + cur} style={{ color }}>
+//                         {contents?.slice(num + length, end)}
+//                     </span>
+//                 );
+//             });
+//             return results;
+//         }
+//         return <span style={{ color: contents ? 'black' : 'grey' }}>{contents ? contents?.valueOf() : 'undefined'}</span>;
+//     }
+
+//     @computed get renderFieldKey() {
+//         // gets the resolved field key of this cell
+//         return CollectionSchemaCell.resolvedFieldKey(this.props.rowProps.column.id!, this.props.rowProps.original);
+//     }
+
+//     onItemDown = async (e: React.PointerEvent) => {
+//         // if the document is a document used to change UI for search results in schema view
+//         if (this.props.Document._searchDoc) {
+//             const aliasdoc = await SearchUtil.GetAliasesOfDocument(this._rowDataDoc);
+//             const targetContext = aliasdoc.length <= 0 ? undefined : Cast(aliasdoc[0].context, Doc, null);
+//             // Jump to the this document
+//             DocumentManager.Instance.jumpToDocument(this._rowDoc, { willPan: true }, emptyFunction, targetContext ? [targetContext] : [], () => this.props.setPreviewDoc(this._rowDoc));
+//         }
+//     };
+
+//     renderCellWithType(type: string | undefined) {
+//         const dragRef: React.RefObject<HTMLDivElement> = React.createRef();
+
+//         // the column
+//         const fieldKey = this.renderFieldKey;
+//         // the exact cell
+//         const field = this._rowDoc[fieldKey];
+
+//         const onPointerEnter = (e: React.PointerEvent): void => {
+//             // e.buttons === 1 means the left moue pointer is down
+//             if (e.buttons === 1 && SnappingManager.GetIsDragging() && (type === 'document' || type === undefined)) {
+//                 dragRef.current!.className = 'collectionSchemaView-cellContainer doc-drag-over';
+//             }
+//         };
+//         const onPointerLeave = (e: React.PointerEvent): void => {
+//             // change the class name to indicate that the cell is no longer being dragged
+//             dragRef.current!.className = 'collectionSchemaView-cellContainer';
+//         };
+
+//         let contents = Field.toString(field as Field);
+//         // display 2 hyphens instead of a blank box for empty cells
+//         contents = contents === '' ? '--' : contents;
+
+//         // classname reflects the tatus of the cell
+//         let className = 'collectionSchemaView-cellWrapper';
+//         if (this._isEditing) className += ' editing';
+//         if (this.props.isFocused && this.props.isEditable) className += ' focused';
+//         if (this.props.isFocused && !this.props.isEditable) className += ' inactive';
+
+//         const positions = [];
+//         if (StrCast(this.props.Document._searchString).toLowerCase() !== '') {
+//             // term is ...promise pending... if the field is a Promise, otherwise it is the cell's contents
+//             let term = field instanceof Promise ? '...promise pending...' : contents.toLowerCase();
+//             const search = StrCast(this.props.Document._searchString).toLowerCase();
+//             let start = term.indexOf(search);
+//             let tally = 0;
+//             // if search is found in term
+//             if (start !== -1) {
+//                 positions.push(start);
+//             }
+//             // if search is found in term, continue finding all instances of search in term
+//             while (start < contents?.length && start !== -1) {
+//                 term = term.slice(start + search.length + 1);
+//                 tally += start + search.length + 1;
+//                 start = term.indexOf(search);
+//                 positions.push(tally + start);
+//             }
+//             // remove the last position
+//             if (positions.length > 1) {
+//                 positions.pop();
+//             }
+//         }
+//         const placeholder = type === 'number' ? '0' : contents === '' ? '--' : 'undefined';
+//         return (
+//             <div
+//                 className="collectionSchemaView-cellContainer"
+//                 style={{ cursor: field instanceof Doc ? 'grab' : 'auto' }}
+//                 ref={dragRef}
+//                 onPointerDown={this.onPointerDown}
+//                 onClick={action(e => (this._isEditing = true))}
+//                 onPointerEnter={onPointerEnter}
+//                 onPointerLeave={onPointerLeave}>
+//                 <div className={className} ref={this._focusRef} tabIndex={-1}>
+//                     <div className="collectionSchemaView-cellContents" ref={type === undefined || type === 'document' ? this.dropRef : null}>
+//                         {!this.props.Document._searchDoc ? (
+//                             <EditableView
+//                                 editing={this._isEditing}
+//                                 isEditingCallback={this.isEditingCallback}
+//                                 display={'inline'}
+//                                 contents={contents}
+//                                 height={'auto'}
+//                                 maxHeight={Number(MAX_ROW_HEIGHT)}
+//                                 placeholder={placeholder}
+//                                 GetValue={() => {
+//                                     const cfield = ComputedField.WithoutComputed(() => FieldValue(field));
+//                                     const cscript = cfield instanceof ComputedField ? cfield.script.originalScript : undefined;
+//                                     const cfinalScript = cscript?.split('return')[cscript.split('return').length - 1];
+//                                     return cscript ? (cfinalScript?.endsWith(';') ? `:=${cfinalScript?.substring(0, cfinalScript.length - 2)}` : cfinalScript) : Field.IsField(cfield) ? Field.toScriptString(cfield) : '';
+//                                 }}
+//                                 SetValue={action((value: string) => {
+//                                     // sets what is displayed after the user makes an input
+//                                     let retVal = false;
+//                                     if (value.startsWith(':=') || value.startsWith('=:=')) {
+//                                         // decides how to compute a value when given either of the above strings
+//                                         const script = value.substring(value.startsWith('=:=') ? 3 : 2);
+//                                         retVal = this.props.setComputed(script, value.startsWith(':=') ? this._rowDataDoc : this._rowDoc, this.renderFieldKey, this.props.row, this.props.col);
+//                                     } else {
+//                                         // check if the input is a number
+//                                         let inputIsNum = true;
+//                                         for (const s of value) {
+//                                             if (isNaN(parseInt(s)) && !(s === '.') && !(s === ',')) {
+//                                                 inputIsNum = false;
+//                                             }
+//                                         }
+//                                         // check if the input is a boolean
+//                                         const inputIsBool: boolean = value === 'false' || value === 'true';
+//                                         // what to do in the case
+//                                         if (!inputIsNum && !inputIsBool && !value.startsWith('=')) {
+//                                             // if it's not a number, it's a string, and should be processed as such
+//                                             // strips the string of quotes when it is edited to prevent quotes form being added to the text automatically
+//                                             // after each edit
+//                                             let valueSansQuotes = value;
+//                                             if (this._isEditing) {
+//                                                 const vsqLength = valueSansQuotes.length;
+//                                                 // get rid of outer quotes
+//                                                 valueSansQuotes = valueSansQuotes.substring(value.startsWith('"') ? 1 : 0, valueSansQuotes.charAt(vsqLength - 1) === '"' ? vsqLength - 1 : vsqLength);
+//                                             }
+//                                             let inputAsString = '"';
+//                                             // escape any quotes in the string
+//                                             for (const i of valueSansQuotes) {
+//                                                 if (i === '"') {
+//                                                     inputAsString += '\\"';
+//                                                 } else {
+//                                                     inputAsString += i;
+//                                                 }
+//                                             }
+//                                             // add a closing quote
+//                                             inputAsString += '"';
+//                                             //two options here: we can strip off outer quotes or we can figure out what's going on with the script
+//                                             const script = CompileScript(inputAsString, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: 'number', $c: 'number', $: 'any' } });
+//                                             const changeMade = inputAsString.length !== value.length || inputAsString.length - 2 !== value.length;
+//                                             // change it if a change is made, otherwise, just compile using the old cell conetnts
+//                                             script.compiled && (retVal = this.applyToDoc(changeMade ? this._rowDoc : this._rowDataDoc, this.props.row, this.props.col, script.run));
+//                                             // handle numbers and expressions
+//                                         } else if (inputIsNum || value.startsWith('=')) {
+//                                             //TODO: make accept numbers
+//                                             const inputscript = value.substring(value.startsWith('=') ? 1 : 0);
+//                                             // if commas are not stripped, the parser only considers the numbers after the last comma
+//                                             let inputSansCommas = '';
+//                                             for (const s of inputscript) {
+//                                                 if (!(s === ',')) {
+//                                                     inputSansCommas += s;
+//                                                 }
+//                                             }
+//                                             const script = CompileScript(inputSansCommas, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: 'number', $c: 'number', $: 'any' } });
+//                                             const changeMade = value.length - 2 !== value.length;
+//                                             script.compiled && (retVal = this.applyToDoc(changeMade ? this._rowDoc : this._rowDataDoc, this.props.row, this.props.col, script.run));
+//                                             // handle booleans
+//                                         } else if (inputIsBool) {
+//                                             const script = CompileScript(value, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: 'number', $c: 'number', $: 'any' } });
+//                                             const changeMade = value.length - 2 !== value.length;
+//                                             script.compiled && (retVal = this.applyToDoc(changeMade ? this._rowDoc : this._rowDataDoc, this.props.row, this.props.col, script.run));
+//                                         }
+//                                     }
+//                                     if (retVal) {
+//                                         this._isEditing = false; // need to set this here. otherwise, the assignment of the field will invalidate & cause render() to be called with the wrong value for 'editing'
+//                                         this.props.setIsEditing(false);
+//                                     }
+//                                     return retVal;
+//                                 })}
+//                                 OnFillDown={async (value: string) => {
+//                                     // computes all of the value preceded by :=
+//                                     const script = CompileScript(value, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: 'number', $c: 'number', $: 'any' } });
+//                                     script.compiled &&
+//                                         DocListCast(this.props.Document[this.props.fieldKey]).forEach((doc, i) =>
+//                                             value.startsWith(':=') ? this.props.setComputed(value.substring(2), Doc.GetProto(doc), this.renderFieldKey, i, this.props.col) : this.applyToDoc(Doc.GetProto(doc), i, this.props.col, script.run)
+//                                         );
+//                                 }}
+//                             />
+//                         ) : (
+//                             this.returnHighlights(contents, positions)
+//                         )}
+//                     </div>
+//                 </div>
+//             </div>
+//         );
+//     }
+
+//     render() {
+//         return this.renderCellWithType(undefined);
+//     }
+// }
+
+// @observer
+// export class CollectionSchemaNumberCell extends CollectionSchemaCell {
+//     render() {
+//         return this.renderCellWithType('number');
+//     }
+// }
+
+// @observer
+// export class CollectionSchemaBooleanCell extends CollectionSchemaCell {
+//     render() {
+//         return this.renderCellWithType('boolean');
+//     }
+// }
+
+// @observer
+// export class CollectionSchemaStringCell extends CollectionSchemaCell {
+//     render() {
+//         return this.renderCellWithType('string');
+//     }
+// }
+
+// @observer
+// export class CollectionSchemaDateCell extends CollectionSchemaCell {
+//     @computed get _date(): Opt<DateField> {
+//         // if the cell is a date field, cast then contents to a date. Otherrwwise, make the contents undefined.
+//         return this._rowDoc[this.renderFieldKey] instanceof DateField ? DateCast(this._rowDoc[this.renderFieldKey]) : undefined;
+//     }
+
+//     @action
+//     handleChange = (date: any) => {
+//         // const script = CompileScript(date.toString(), { requiredType: "Date", addReturn: true, params: { this: Doc.name } });
+//         // if (script.compiled) {
+//         //     this.applyToDoc(this._document, this.props.row, this.props.col, script.run);
+//         // } else {
+//         // ^ DateCast is always undefined for some reason, but that is what the field should be set to
+//         this._rowDoc[this.renderFieldKey] = new DateField(date as Date);
+//         //}
+//     };
+
+//     render() {
+//         return !this.props.isFocused ? (
+//             <span onPointerDown={this.onPointerDown}>{this._date ? Field.toString(this._date as Field) : '--'}</span>
+//         ) : (
+//             <DatePicker selected={this._date?.date || new Date()} onSelect={date => this.handleChange(date)} onChange={date => this.handleChange(date)} />
+//         );
+//     }
+// }
+
+// @observer
+// export class CollectionSchemaDocCell extends CollectionSchemaCell {
+//     _overlayDisposer?: () => void;
+
+//     @computed get _doc() {
+//         return FieldValue(Cast(this._rowDoc[this.renderFieldKey], Doc));
+//     }
+
+//     @action
+//     onSetValue = (value: string) => {
+//         this._doc && (Doc.GetProto(this._doc).title = value);
+
+//         const script = CompileScript(value, {
+//             addReturn: true,
+//             typecheck: true,
+//             transformer: DocumentIconContainer.getTransformer(),
+//         });
+//         // compile the script
+//         const results = script.compiled && script.run();
+//         // if the script was compiled and run
+//         if (results && results.success) {
+//             this._rowDoc[this.renderFieldKey] = results.result;
+//             return true;
+//         }
+//         return false;
+//     };
+
+//     componentWillUnmount() {
+//         this.onBlur();
+//     }
+
+//     onBlur = () => {
+//         this._overlayDisposer?.();
+//     };
+//     onFocus = () => {
+//         this.onBlur();
+//         this._overlayDisposer = OverlayView.Instance.addElement(<DocumentIconContainer />, { x: 0, y: 0 });
+//     };
+
+//     @action
+//     isEditingCallback = (isEditing: boolean): void => {
+//         // the isEditingCallback from a general CollectionSchemaCell
+//         document.removeEventListener('keydown', this.onKeyDown);
+//         isEditing && document.addEventListener('keydown', this.onKeyDown);
+//         this._isEditing = isEditing;
+//         this.props.setIsEditing(isEditing);
+//         this.props.changeFocusedCellByIndex(this.props.row, this.props.col);
+//     };
+
+//     render() {
+//         // if there's a doc, render it
+//         return !this._doc ? (
+//             this.renderCellWithType('document')
+//         ) : (
+//             <div className="collectionSchemaView-cellWrapper" ref={this._focusRef} tabIndex={-1} onPointerDown={this.onPointerDown}>
+//                 <div className="collectionSchemaView-cellContents-document" style={{ padding: '5.9px' }} ref={this.dropRef} onFocus={this.onFocus} onBlur={this.onBlur}>
+//                     <EditableView
+//                         editing={this._isEditing}
+//                         isEditingCallback={this.isEditingCallback}
+//                         display={'inline'}
+//                         contents={this._doc.title || '--'}
+//                         height={'auto'}
+//                         maxHeight={Number(MAX_ROW_HEIGHT)}
+//                         GetValue={() => StrCast(this._doc?.title)}
+//                         SetValue={action((value: string) => {
+//                             this.onSetValue(value);
+//                             return true;
+//                         })}
+//                     />
+//                 </div>
+//                 <div onClick={() => this._doc && this.props.addDocTab(this._doc, OpenWhere.addRight)} className="collectionSchemaView-cellContents-docButton">
+//                     <FontAwesomeIcon icon="external-link-alt" size="lg" />
+//                 </div>
+//             </div>
+//         );
+//     }
+// }
+
+// @observer
+// export class CollectionSchemaImageCell extends CollectionSchemaCell {
+//     choosePath(url: URL) {
+//         if (url.protocol === 'data') return url.href; // if the url ises the data protocol, just return the href
+//         if (url.href.indexOf(window.location.origin) === -1) return Utils.CorsProxy(url.href); // otherwise, put it through the cors proxy erver
+//         if (!/\.(png|jpg|jpeg|gif|webp)$/.test(url.href.toLowerCase())) return url.href; //Why is this here — good question
+
+//         const ext = extname(url.href);
+//         return url.href.replace(ext, '_o' + ext);
+//     }
+
+//     render() {
+//         const field = Cast(this._rowDoc[this.renderFieldKey], ImageField, null); // retrieve the primary image URL that is being rendered from the data doc
+//         const alts = DocListCast(this._rowDoc[this.renderFieldKey + '-alternates']); // retrieve alternate documents that may be rendered as alternate images
+//         const altpaths = alts
+//             .map(doc => Cast(doc[Doc.LayoutFieldKey(doc)], ImageField, null)?.url)
+//             .filter(url => url)
+//             .map(url => this.choosePath(url)); // access the primary layout data of the alternate documents
+//         const paths = field ? [this.choosePath(field.url), ...altpaths] : altpaths;
+//         // If there is a path, follow it; otherwise, follow a link to a default image icon
+//         const url = paths.length ? paths : [Utils.CorsProxy('http://www.cs.brown.edu/~bcz/noImage.png')];
+
+//         const aspect = Doc.NativeAspect(this._rowDoc); // aspect ratio
+//         let width = Math.min(75, this.props.rowProps.width); // get a with that is no smaller than 75px
+//         const height = Math.min(75, width / aspect); // get a height either proportional to that or 75 px
+//         width = height * aspect; // increase the width of the image if necessary to maintain proportionality
+
+//         const reference = React.createRef<HTMLDivElement>();
+//         return (
+//             <div className="collectionSchemaView-cellWrapper" ref={this._focusRef} tabIndex={-1} onPointerDown={this.onPointerDown}>
+//                 <div className="collectionSchemaView-cellContents" key={this._rowDoc[Id]} ref={reference}>
+//                     <img src={url[0]} width={paths.length ? width : '20px'} height={paths.length ? height : '20px'} />
+//                 </div>
+//             </div>
+//         );
+//     }
+// }
+
+// @observer
+// export class CollectionSchemaListCell extends CollectionSchemaCell {
+//     _overlayDisposer?: () => void;
+
+//     @computed get _field() {
+//         return this._rowDoc[this.renderFieldKey];
+//     }
+//     @computed get _optionsList() {
+//         return this._field as List<any>;
+//     }
+//     @observable private _opened = false; // whether the list is opened
+//     @observable private _text = 'select an item';
+//     @observable private _selectedNum = 0; // the index of the list item selected
+
+//     @action
+//     onSetValue = (value: string) => {
+//         // change if it's a document
+//         this._optionsList[this._selectedNum] = this._text = value;
+
+//         (this._field as List<any>).splice(this._selectedNum, 1, value);
+//     };
+
+//     @action
+//     onSelected = (element: string, index: number) => {
+//         // if an item is selected, the private variables should update to reflect this
+//         this._text = element;
+//         this._selectedNum = index;
+//     };
+
+//     onFocus = () => {
+//         this._overlayDisposer?.();
+//         this._overlayDisposer = OverlayView.Instance.addElement(<DocumentIconContainer />, { x: 0, y: 0 });
+//     };
+
+//     render() {
+//         const link = false;
+//         const reference = React.createRef<HTMLDivElement>();
+
+//         // if the list is not opened, don't display it; otherwise, do.
+//         if (this._optionsList?.length) {
+//             const options = !this._opened ? null : (
+//                 <div>
+//                     {this._optionsList.map((element, index) => {
+//                         const val = Field.toString(element);
+//                         return (
+//                             <div className="collectionSchemaView-dropdownOption" key={index} style={{ padding: '6px' }} onPointerDown={e => this.onSelected(StrCast(element), index)}>
+//                                 {val}
+//                             </div>
+//                         );
+//                     })}
+//                 </div>
+//             );
+
+//             const plainText = <div style={{ padding: '5.9px' }}>{this._text}</div>;
+//             const textarea = (
+//                 <div className="collectionSchemaView-cellContents" key={this._rowDoc[Id]} style={{ padding: '5.9px' }} ref={this.dropRef}>
+//                     <EditableView
+//                         editing={this._isEditing}
+//                         isEditingCallback={this.isEditingCallback}
+//                         display={'inline'}
+//                         contents={this._text}
+//                         height={'auto'}
+//                         maxHeight={Number(MAX_ROW_HEIGHT)}
+//                         GetValue={() => this._text}
+//                         SetValue={action((value: string) => {
+//                             // add special for params
+//                             this.onSetValue(value);
+//                             return true;
+//                         })}
+//                     />
+//                 </div>
+//             );
+
+//             //☰
+//             return (
+//                 <div className="collectionSchemaView-cellWrapper" ref={this._focusRef} tabIndex={-1} onPointerDown={this.onPointerDown}>
+//                     <div className="collectionSchemaView-cellContents" key={this._rowDoc[Id]} ref={reference}>
+//                         <div className="collectionSchemaView-dropDownWrapper">
+//                             <button type="button" className="collectionSchemaView-dropdownButton" style={{ right: 'length', position: 'relative' }} onClick={action(e => (this._opened = !this._opened))}>
+//                                 <FontAwesomeIcon icon={this._opened ? 'caret-up' : 'caret-down'} size="sm" />
+//                             </button>
+//                             <div className="collectionSchemaView-dropdownText"> {link ? plainText : textarea} </div>
+//                         </div>
+//                         {options}
+//                     </div>
+//                 </div>
+//             );
+//         }
+//         return this.renderCellWithType('list');
+//     }
+// }
+
+// @observer
+// export class CollectionSchemaCheckboxCell extends CollectionSchemaCell {
+//     @computed get _isChecked() {
+//         return BoolCast(this._rowDoc[this.renderFieldKey]);
+//     }
+
+//     render() {
+//         const reference = React.createRef<HTMLDivElement>();
+//         return (
+//             <div className="collectionSchemaView-cellWrapper" ref={this._focusRef} tabIndex={-1} onPointerDown={this.onPointerDown}>
+//                 <input type="checkbox" checked={this._isChecked} onChange={e => (this._rowDoc[this.renderFieldKey] = e.target.checked)} />
+//             </div>
+//         );
+//     }
+// }
+
+// @observer
+// export class CollectionSchemaButtons extends CollectionSchemaCell {
+//     // the navigation buttons for schema view when it is used for search.
+//     render() {
+//         return !this.props.Document._searchDoc || ![DocumentType.PDF, DocumentType.RTF].includes(StrCast(this._rowDoc.type) as DocumentType) ? (
+//             <></>
+//         ) : (
+//             <div style={{ paddingTop: 8, paddingLeft: 3 }}>
+//                 <button style={{ padding: 2, left: 77 }} onClick={() => Doc.SearchMatchNext(this._rowDoc, true)}>
+//                     <FontAwesomeIcon icon="arrow-up" size="sm" />
+//                 </button>
+//                 <button style={{ padding: 2 }} onClick={() => Doc.SearchMatchNext(this._rowDoc, false)}>
+//                     <FontAwesomeIcon icon="arrow-down" size="sm" />
+//                 </button>
+//             </div>
+//         );
+//     }
+// }
diff --git a/src/client/views/collections/old_collectionSchema/OldCollectionSchemaMovableColumn.tsx b/src/client/views/collections/old_collectionSchema/OldCollectionSchemaMovableColumn.tsx
index 28d2e6ab1..c2182ae0c 100644
--- a/src/client/views/collections/old_collectionSchema/OldCollectionSchemaMovableColumn.tsx
+++ b/src/client/views/collections/old_collectionSchema/OldCollectionSchemaMovableColumn.tsx
@@ -1,138 +1,138 @@
-import React = require('react');
-import { action } from 'mobx';
-import { SchemaHeaderField } from '../../../../fields/SchemaHeaderField';
-import { DragManager } from '../../../util/DragManager';
-import { SnappingManager } from '../../../util/SnappingManager';
-import { Transform } from '../../../util/Transform';
-import './CollectionSchemaView.scss';
+// import React = require('react');
+// import { action } from 'mobx';
+// import { SchemaHeaderField } from '../../../../fields/SchemaHeaderField';
+// import { DragManager } from '../../../util/DragManager';
+// import { SnappingManager } from '../../../util/SnappingManager';
+// import { Transform } from '../../../util/Transform';
+// import './CollectionSchemaView.scss';
 
-export interface MovableColumnProps {
-    columnRenderer: React.ReactNode;
-    columnValue: SchemaHeaderField;
-    allColumns: SchemaHeaderField[];
-    reorderColumns: (toMove: SchemaHeaderField, relativeTo: SchemaHeaderField, before: boolean, columns: SchemaHeaderField[]) => void;
-    ScreenToLocalTransform: () => Transform;
-}
-export class MovableColumn extends React.Component<MovableColumnProps> {
-    // The header of the column
-    private _header?: React.RefObject<HTMLDivElement> = React.createRef();
-    // The container of the function that is responsible for moving the column over to a new plac
-    private _colDropDisposer?: DragManager.DragDropDisposer;
-    // initial column position
-    private _startDragPosition: { x: number; y: number } = { x: 0, y: 0 };
-    // sensitivity to being dragged, in pixels
-    private _sensitivity: number = 16;
-    // Column reference ID
-    private _dragRef: React.RefObject<HTMLDivElement> = React.createRef();
+// export interface MovableColumnProps {
+//     columnRenderer: React.ReactNode;
+//     columnValue: SchemaHeaderField;
+//     allColumns: SchemaHeaderField[];
+//     reorderColumns: (toMove: SchemaHeaderField, relativeTo: SchemaHeaderField, before: boolean, columns: SchemaHeaderField[]) => void;
+//     ScreenToLocalTransform: () => Transform;
+// }
+// export class MovableColumn extends React.Component<MovableColumnProps> {
+//     // The header of the column
+//     private _header?: React.RefObject<HTMLDivElement> = React.createRef();
+//     // The container of the function that is responsible for moving the column over to a new plac
+//     private _colDropDisposer?: DragManager.DragDropDisposer;
+//     // initial column position
+//     private _startDragPosition: { x: number; y: number } = { x: 0, y: 0 };
+//     // sensitivity to being dragged, in pixels
+//     private _sensitivity: number = 16;
+//     // Column reference ID
+//     private _dragRef: React.RefObject<HTMLDivElement> = React.createRef();
 
-    onPointerEnter = (e: React.PointerEvent): void => {
-        // if the column is left-clicked and it is being dragged
-        if (e.buttons === 1 && SnappingManager.GetIsDragging()) {
-            this._header!.current!.className = 'collectionSchema-col-wrapper';
-            document.addEventListener('pointermove', this.onDragMove, true);
-        }
-    };
+//     onPointerEnter = (e: React.PointerEvent): void => {
+//         // if the column is left-clicked and it is being dragged
+//         if (e.buttons === 1 && SnappingManager.GetIsDragging()) {
+//             this._header!.current!.className = 'collectionSchema-col-wrapper';
+//             document.addEventListener('pointermove', this.onDragMove, true);
+//         }
+//     };
 
-    onPointerLeave = (e: React.PointerEvent): void => {
-        this._header!.current!.className = 'collectionSchema-col-wrapper';
-        document.removeEventListener('pointermove', this.onDragMove, true);
-        !e.buttons && document.removeEventListener('pointermove', this.onPointerMove);
-    };
+//     onPointerLeave = (e: React.PointerEvent): void => {
+//         this._header!.current!.className = 'collectionSchema-col-wrapper';
+//         document.removeEventListener('pointermove', this.onDragMove, true);
+//         !e.buttons && document.removeEventListener('pointermove', this.onPointerMove);
+//     };
 
-    onDragMove = (e: PointerEvent): void => {
-        // only take into account the horizonal direction when a column is dragged
-        const x = this.props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY);
-        const rect = this._header!.current!.getBoundingClientRect();
-        // Now store the point at the top center of the column when it was in its original position
-        const bounds = this.props.ScreenToLocalTransform().transformPoint(rect.left + (rect.right - rect.left) / 2, rect.top);
-        // to be compared with its new horizontal position
-        const before = x[0] < bounds[0];
-        this._header!.current!.className = 'collectionSchema-col-wrapper';
-        if (before) this._header!.current!.className += ' col-before';
-        if (!before) this._header!.current!.className += ' col-after';
-        e.stopPropagation();
-    };
+//     onDragMove = (e: PointerEvent): void => {
+//         // only take into account the horizonal direction when a column is dragged
+//         const x = this.props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY);
+//         const rect = this._header!.current!.getBoundingClientRect();
+//         // Now store the point at the top center of the column when it was in its original position
+//         const bounds = this.props.ScreenToLocalTransform().transformPoint(rect.left + (rect.right - rect.left) / 2, rect.top);
+//         // to be compared with its new horizontal position
+//         const before = x[0] < bounds[0];
+//         this._header!.current!.className = 'collectionSchema-col-wrapper';
+//         if (before) this._header!.current!.className += ' col-before';
+//         if (!before) this._header!.current!.className += ' col-after';
+//         e.stopPropagation();
+//     };
 
-    createColDropTarget = (ele: HTMLDivElement) => {
-        this._colDropDisposer?.();
-        if (ele) {
-            this._colDropDisposer = DragManager.MakeDropTarget(ele, this.colDrop.bind(this));
-        }
-    };
+//     createColDropTarget = (ele: HTMLDivElement) => {
+//         this._colDropDisposer?.();
+//         if (ele) {
+//             this._colDropDisposer = DragManager.MakeDropTarget(ele, this.colDrop.bind(this));
+//         }
+//     };
 
-    colDrop = (e: Event, de: DragManager.DropEvent) => {
-        document.removeEventListener('pointermove', this.onDragMove, true);
-        // we only care about whether the column is shifted to the side
-        const x = this.props.ScreenToLocalTransform().transformPoint(de.x, de.y);
-        // get the dimensions of the smallest rectangle that bounds the header
-        const rect = this._header!.current!.getBoundingClientRect();
-        const bounds = this.props.ScreenToLocalTransform().transformPoint(rect.left + (rect.right - rect.left) / 2, rect.top);
-        // get whether the column was dragged before or after where it is now
-        const before = x[0] < bounds[0];
-        const colDragData = de.complete.columnDragData;
-        // if there is colDragData, which happen when the drag is complete, reorder the columns according to the established variables
-        if (colDragData) {
-            e.stopPropagation();
-            this.props.reorderColumns(colDragData.colKey, this.props.columnValue, before, this.props.allColumns);
-            return true;
-        }
-        return false;
-    };
+//     colDrop = (e: Event, de: DragManager.DropEvent) => {
+//         document.removeEventListener('pointermove', this.onDragMove, true);
+//         // we only care about whether the column is shifted to the side
+//         const x = this.props.ScreenToLocalTransform().transformPoint(de.x, de.y);
+//         // get the dimensions of the smallest rectangle that bounds the header
+//         const rect = this._header!.current!.getBoundingClientRect();
+//         const bounds = this.props.ScreenToLocalTransform().transformPoint(rect.left + (rect.right - rect.left) / 2, rect.top);
+//         // get whether the column was dragged before or after where it is now
+//         const before = x[0] < bounds[0];
+//         const colDragData = de.complete.columnDragData;
+//         // if there is colDragData, which happen when the drag is complete, reorder the columns according to the established variables
+//         if (colDragData) {
+//             e.stopPropagation();
+//             this.props.reorderColumns(colDragData.colKey, this.props.columnValue, before, this.props.allColumns);
+//             return true;
+//         }
+//         return false;
+//     };
 
-    onPointerMove = (e: PointerEvent) => {
-        const onRowMove = (e: PointerEvent) => {
-            e.stopPropagation();
-            e.preventDefault();
+//     onPointerMove = (e: PointerEvent) => {
+//         const onRowMove = (e: PointerEvent) => {
+//             e.stopPropagation();
+//             e.preventDefault();
 
-            document.removeEventListener('pointermove', onRowMove);
-            document.removeEventListener('pointerup', onRowUp);
-            const dragData = new DragManager.ColumnDragData(this.props.columnValue);
-            DragManager.StartColumnDrag(this._dragRef.current!, dragData, e.x, e.y);
-        };
-        const onRowUp = (): void => {
-            document.removeEventListener('pointermove', onRowMove);
-            document.removeEventListener('pointerup', onRowUp);
-        };
-        // if the left mouse button is the one being held
-        if (e.buttons === 1) {
-            const [dx, dy] = this.props.ScreenToLocalTransform().transformDirection(e.clientX - this._startDragPosition.x, e.clientY - this._startDragPosition.y);
-            // If the movemnt of the drag exceeds the sensitivity value
-            if (Math.abs(dx) + Math.abs(dy) > this._sensitivity) {
-                document.removeEventListener('pointermove', this.onPointerMove);
-                e.stopPropagation();
+//             document.removeEventListener('pointermove', onRowMove);
+//             document.removeEventListener('pointerup', onRowUp);
+//             const dragData = new DragManager.ColumnDragData(this.props.columnValue);
+//             DragManager.StartColumnDrag(this._dragRef.current!, dragData, e.x, e.y);
+//         };
+//         const onRowUp = (): void => {
+//             document.removeEventListener('pointermove', onRowMove);
+//             document.removeEventListener('pointerup', onRowUp);
+//         };
+//         // if the left mouse button is the one being held
+//         if (e.buttons === 1) {
+//             const [dx, dy] = this.props.ScreenToLocalTransform().transformDirection(e.clientX - this._startDragPosition.x, e.clientY - this._startDragPosition.y);
+//             // If the movemnt of the drag exceeds the sensitivity value
+//             if (Math.abs(dx) + Math.abs(dy) > this._sensitivity) {
+//                 document.removeEventListener('pointermove', this.onPointerMove);
+//                 e.stopPropagation();
 
-                document.addEventListener('pointermove', onRowMove);
-                document.addEventListener('pointerup', onRowUp);
-            }
-        }
-    };
+//                 document.addEventListener('pointermove', onRowMove);
+//                 document.addEventListener('pointerup', onRowUp);
+//             }
+//         }
+//     };
 
-    onPointerUp = (e: React.PointerEvent) => {
-        document.removeEventListener('pointermove', this.onPointerMove);
-    };
+//     onPointerUp = (e: React.PointerEvent) => {
+//         document.removeEventListener('pointermove', this.onPointerMove);
+//     };
 
-    @action
-    onPointerDown = (e: React.PointerEvent, ref: React.RefObject<HTMLDivElement>) => {
-        this._dragRef = ref;
-        const [dx, dy] = this.props.ScreenToLocalTransform().transformDirection(e.clientX, e.clientY);
-        // If the cell thing dragged is not being edited
-        if (!(e.target as any)?.tagName.includes('INPUT')) {
-            this._startDragPosition = { x: dx, y: dy };
-            document.addEventListener('pointermove', this.onPointerMove);
-        }
-    };
+//     @action
+//     onPointerDown = (e: React.PointerEvent, ref: React.RefObject<HTMLDivElement>) => {
+//         this._dragRef = ref;
+//         const [dx, dy] = this.props.ScreenToLocalTransform().transformDirection(e.clientX, e.clientY);
+//         // If the cell thing dragged is not being edited
+//         if (!(e.target as any)?.tagName.includes('INPUT')) {
+//             this._startDragPosition = { x: dx, y: dy };
+//             document.addEventListener('pointermove', this.onPointerMove);
+//         }
+//     };
 
-    render() {
-        const reference = React.createRef<HTMLDivElement>();
+//     render() {
+//         const reference = React.createRef<HTMLDivElement>();
 
-        return (
-            <div className="collectionSchema-col" ref={this.createColDropTarget}>
-                <div className="collectionSchema-col-wrapper" ref={this._header} onPointerEnter={this.onPointerEnter} onPointerLeave={this.onPointerLeave}>
-                    <div className="col-dragger" ref={reference} onPointerDown={e => this.onPointerDown(e, reference)} onPointerUp={this.onPointerUp}>
-                        {this.props.columnRenderer}
-                    </div>
-                </div>
-            </div>
-        );
-    }
-}
+//         return (
+//             <div className="collectionSchema-col" ref={this.createColDropTarget}>
+//                 <div className="collectionSchema-col-wrapper" ref={this._header} onPointerEnter={this.onPointerEnter} onPointerLeave={this.onPointerLeave}>
+//                     <div className="col-dragger" ref={reference} onPointerDown={e => this.onPointerDown(e, reference)} onPointerUp={this.onPointerUp}>
+//                         {this.props.columnRenderer}
+//                     </div>
+//                 </div>
+//             </div>
+//         );
+//     }
+// }
diff --git a/src/client/views/collections/old_collectionSchema/OldCollectionSchemaMovableRow.tsx b/src/client/views/collections/old_collectionSchema/OldCollectionSchemaMovableRow.tsx
index 3cb2df7d3..2b39df201 100644
--- a/src/client/views/collections/old_collectionSchema/OldCollectionSchemaMovableRow.tsx
+++ b/src/client/views/collections/old_collectionSchema/OldCollectionSchemaMovableRow.tsx
@@ -1,152 +1,152 @@
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action } from 'mobx';
-import * as React from 'react';
-import { ReactTableDefaults, RowInfo } from 'react-table';
-import { Doc } from '../../../../fields/Doc';
-import { Cast, FieldValue, StrCast } from '../../../../fields/Types';
-import { DocumentManager } from '../../../util/DocumentManager';
-import { DragManager, dropActionType, SetupDrag } from '../../../util/DragManager';
-import { SnappingManager } from '../../../util/SnappingManager';
-import { Transform } from '../../../util/Transform';
-import { undoBatch } from '../../../util/UndoManager';
-import { ContextMenu } from '../../ContextMenu';
-import { OpenWhere } from '../../nodes/DocumentView';
-import './CollectionSchemaView.scss';
+// import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+// import { action } from 'mobx';
+// import * as React from 'react';
+// import { ReactTableDefaults, RowInfo } from 'react-table';
+// import { Doc } from '../../../../fields/Doc';
+// import { Cast, FieldValue, StrCast } from '../../../../fields/Types';
+// import { DocumentManager } from '../../../util/DocumentManager';
+// import { DragManager, dropActionType, SetupDrag } from '../../../util/DragManager';
+// import { SnappingManager } from '../../../util/SnappingManager';
+// import { Transform } from '../../../util/Transform';
+// import { undoBatch } from '../../../util/UndoManager';
+// import { ContextMenu } from '../../ContextMenu';
+// import { OpenWhere } from '../../nodes/DocumentView';
+// import './CollectionSchemaView.scss';
 
-export interface MovableRowProps {
-    rowInfo: RowInfo;
-    ScreenToLocalTransform: () => Transform;
-    addDoc: (doc: Doc | Doc[], relativeTo?: Doc, before?: boolean) => boolean;
-    removeDoc: (doc: Doc | Doc[]) => boolean;
-    rowFocused: boolean;
-    textWrapRow: (doc: Doc) => void;
-    rowWrapped: boolean;
-    dropAction: string;
-    addDocTab: any;
-}
+// export interface MovableRowProps {
+//     rowInfo: RowInfo;
+//     ScreenToLocalTransform: () => Transform;
+//     addDoc: (doc: Doc | Doc[], relativeTo?: Doc, before?: boolean) => boolean;
+//     removeDoc: (doc: Doc | Doc[]) => boolean;
+//     rowFocused: boolean;
+//     textWrapRow: (doc: Doc) => void;
+//     rowWrapped: boolean;
+//     dropAction: string;
+//     addDocTab: any;
+// }
 
-export class MovableRow extends React.Component<React.PropsWithChildren<MovableRowProps>> {
-    private _header?: React.RefObject<HTMLDivElement> = React.createRef();
-    private _rowDropDisposer?: DragManager.DragDropDisposer;
+// export class MovableRow extends React.Component<React.PropsWithChildren<MovableRowProps>> {
+//     private _header?: React.RefObject<HTMLDivElement> = React.createRef();
+//     private _rowDropDisposer?: DragManager.DragDropDisposer;
 
-    // Event listeners are only necessary when the user is hovering over the table
-    // Create one when the mouse starts hovering...
-    onPointerEnter = (e: React.PointerEvent): void => {
-        if (e.buttons === 1 && SnappingManager.GetIsDragging()) {
-            this._header!.current!.className = 'collectionSchema-row-wrapper';
-            document.addEventListener('pointermove', this.onDragMove, true);
-        }
-    };
-    // ... and delete it when the mouse leaves
-    onPointerLeave = (e: React.PointerEvent): void => {
-        this._header!.current!.className = 'collectionSchema-row-wrapper';
-        document.removeEventListener('pointermove', this.onDragMove, true);
-    };
-    // The method for the event listener, reorders columns when dragged to their new locations.
-    onDragMove = (e: PointerEvent): void => {
-        const x = this.props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY);
-        const rect = this._header!.current!.getBoundingClientRect();
-        const bounds = this.props.ScreenToLocalTransform().transformPoint(rect.left, rect.top + rect.height / 2);
-        const before = x[1] < bounds[1];
-        this._header!.current!.className = 'collectionSchema-row-wrapper';
-        if (before) this._header!.current!.className += ' row-above';
-        if (!before) this._header!.current!.className += ' row-below';
-        e.stopPropagation();
-    };
-    componentWillUnmount() {
-        this._rowDropDisposer?.();
-    }
-    //
-    createRowDropTarget = (ele: HTMLDivElement) => {
-        this._rowDropDisposer?.();
-        if (ele) {
-            this._rowDropDisposer = DragManager.MakeDropTarget(ele, this.rowDrop.bind(this));
-        }
-    };
-    // Controls what hppens when a row is dragged and dropped
-    rowDrop = (e: Event, de: DragManager.DropEvent) => {
-        this.onPointerLeave(e as any);
-        const rowDoc = FieldValue(Cast(this.props.rowInfo.original, Doc));
-        if (!rowDoc) return false;
+//     // Event listeners are only necessary when the user is hovering over the table
+//     // Create one when the mouse starts hovering...
+//     onPointerEnter = (e: React.PointerEvent): void => {
+//         if (e.buttons === 1 && SnappingManager.GetIsDragging()) {
+//             this._header!.current!.className = 'collectionSchema-row-wrapper';
+//             document.addEventListener('pointermove', this.onDragMove, true);
+//         }
+//     };
+//     // ... and delete it when the mouse leaves
+//     onPointerLeave = (e: React.PointerEvent): void => {
+//         this._header!.current!.className = 'collectionSchema-row-wrapper';
+//         document.removeEventListener('pointermove', this.onDragMove, true);
+//     };
+//     // The method for the event listener, reorders columns when dragged to their new locations.
+//     onDragMove = (e: PointerEvent): void => {
+//         const x = this.props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY);
+//         const rect = this._header!.current!.getBoundingClientRect();
+//         const bounds = this.props.ScreenToLocalTransform().transformPoint(rect.left, rect.top + rect.height / 2);
+//         const before = x[1] < bounds[1];
+//         this._header!.current!.className = 'collectionSchema-row-wrapper';
+//         if (before) this._header!.current!.className += ' row-above';
+//         if (!before) this._header!.current!.className += ' row-below';
+//         e.stopPropagation();
+//     };
+//     componentWillUnmount() {
+//         this._rowDropDisposer?.();
+//     }
+//     //
+//     createRowDropTarget = (ele: HTMLDivElement) => {
+//         this._rowDropDisposer?.();
+//         if (ele) {
+//             this._rowDropDisposer = DragManager.MakeDropTarget(ele, this.rowDrop.bind(this));
+//         }
+//     };
+//     // Controls what hppens when a row is dragged and dropped
+//     rowDrop = (e: Event, de: DragManager.DropEvent) => {
+//         this.onPointerLeave(e as any);
+//         const rowDoc = FieldValue(Cast(this.props.rowInfo.original, Doc));
+//         if (!rowDoc) return false;
 
-        const x = this.props.ScreenToLocalTransform().transformPoint(de.x, de.y);
-        const rect = this._header!.current!.getBoundingClientRect();
-        const bounds = this.props.ScreenToLocalTransform().transformPoint(rect.left, rect.top + rect.height / 2);
-        const before = x[1] < bounds[1];
+//         const x = this.props.ScreenToLocalTransform().transformPoint(de.x, de.y);
+//         const rect = this._header!.current!.getBoundingClientRect();
+//         const bounds = this.props.ScreenToLocalTransform().transformPoint(rect.left, rect.top + rect.height / 2);
+//         const before = x[1] < bounds[1];
 
-        const docDragData = de.complete.docDragData;
-        if (docDragData) {
-            e.stopPropagation();
-            if (docDragData.draggedDocuments[0] === rowDoc) return true;
-            const addDocument = (doc: Doc | Doc[]) => this.props.addDoc(doc, rowDoc, before);
-            const movedDocs = docDragData.draggedDocuments;
-            return docDragData.dropAction || docDragData.userDropAction
-                ? docDragData.droppedDocuments.reduce((added: boolean, d) => this.props.addDoc(d, rowDoc, before) || added, false)
-                : docDragData.moveDocument
-                ? movedDocs.reduce((added: boolean, d) => docDragData.moveDocument?.(d, rowDoc, addDocument) || added, false)
-                : docDragData.droppedDocuments.reduce((added: boolean, d) => this.props.addDoc(d, rowDoc, before), false);
-        }
-        return false;
-    };
+//         const docDragData = de.complete.docDragData;
+//         if (docDragData) {
+//             e.stopPropagation();
+//             if (docDragData.draggedDocuments[0] === rowDoc) return true;
+//             const addDocument = (doc: Doc | Doc[]) => this.props.addDoc(doc, rowDoc, before);
+//             const movedDocs = docDragData.draggedDocuments;
+//             return docDragData.dropAction || docDragData.userDropAction
+//                 ? docDragData.droppedDocuments.reduce((added: boolean, d) => this.props.addDoc(d, rowDoc, before) || added, false)
+//                 : docDragData.moveDocument
+//                 ? movedDocs.reduce((added: boolean, d) => docDragData.moveDocument?.(d, rowDoc, addDocument) || added, false)
+//                 : docDragData.droppedDocuments.reduce((added: boolean, d) => this.props.addDoc(d, rowDoc, before), false);
+//         }
+//         return false;
+//     };
 
-    onRowContextMenu = (e: React.MouseEvent): void => {
-        const description = this.props.rowWrapped ? 'Unwrap text on row' : 'Text wrap row';
-        ContextMenu.Instance.addItem({ description: description, event: () => this.props.textWrapRow(this.props.rowInfo.original), icon: 'file-pdf' });
-    };
+//     onRowContextMenu = (e: React.MouseEvent): void => {
+//         const description = this.props.rowWrapped ? 'Unwrap text on row' : 'Text wrap row';
+//         ContextMenu.Instance.addItem({ description: description, event: () => this.props.textWrapRow(this.props.rowInfo.original), icon: 'file-pdf' });
+//     };
 
-    @undoBatch
-    @action
-    move: DragManager.MoveFunction = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDoc) => {
-        const targetView = targetCollection && DocumentManager.Instance.getDocumentView(targetCollection);
-        return doc !== targetCollection && doc !== targetView?.props.ContainingCollectionDoc && this.props.removeDoc(doc) && addDoc(doc);
-    };
+//     @undoBatch
+//     @action
+//     move: DragManager.MoveFunction = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDoc) => {
+//         const targetView = targetCollection && DocumentManager.Instance.getDocumentView(targetCollection);
+//         return doc !== targetCollection && doc !== targetView?.props.ContainingCollectionDoc && this.props.removeDoc(doc) && addDoc(doc);
+//     };
 
-    @action
-    onKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
-        console.log('yes');
-        if (e.key === 'Backspace' || e.key === 'Delete') {
-            undoBatch(() => this.props.removeDoc(this.props.rowInfo.original));
-        }
-    };
+//     @action
+//     onKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
+//         console.log('yes');
+//         if (e.key === 'Backspace' || e.key === 'Delete') {
+//             undoBatch(() => this.props.removeDoc(this.props.rowInfo.original));
+//         }
+//     };
 
-    render() {
-        const { children = null, rowInfo } = this.props;
+//     render() {
+//         const { children = null, rowInfo } = this.props;
 
-        if (!rowInfo) {
-            return <ReactTableDefaults.TrComponent>{children}</ReactTableDefaults.TrComponent>;
-        }
+//         if (!rowInfo) {
+//             return <ReactTableDefaults.TrComponent>{children}</ReactTableDefaults.TrComponent>;
+//         }
 
-        const { original } = rowInfo;
-        const doc = FieldValue(Cast(original, Doc));
+//         const { original } = rowInfo;
+//         const doc = FieldValue(Cast(original, Doc));
 
-        if (!doc) return null;
+//         if (!doc) return null;
 
-        const reference = React.createRef<HTMLDivElement>();
-        const onItemDown = SetupDrag(reference, () => doc, this.move, StrCast(this.props.dropAction) as dropActionType);
+//         const reference = React.createRef<HTMLDivElement>();
+//         const onItemDown = SetupDrag(reference, () => doc, this.move, StrCast(this.props.dropAction) as dropActionType);
 
-        let className = 'collectionSchema-row';
-        if (this.props.rowFocused) className += ' row-focused';
-        if (this.props.rowWrapped) className += ' row-wrapped';
+//         let className = 'collectionSchema-row';
+//         if (this.props.rowFocused) className += ' row-focused';
+//         if (this.props.rowWrapped) className += ' row-wrapped';
 
-        return (
-            <div className={className} onKeyPress={this.onKeyDown} ref={this.createRowDropTarget} onContextMenu={this.onRowContextMenu}>
-                <div className="collectionSchema-row-wrapper" onKeyPress={this.onKeyDown} ref={this._header} onPointerEnter={this.onPointerEnter} onPointerLeave={this.onPointerLeave}>
-                    <ReactTableDefaults.TrComponent onKeyPress={this.onKeyDown}>
-                        <div className="row-dragger">
-                            <div className="row-option" onClick={undoBatch(() => this.props.removeDoc(this.props.rowInfo.original))}>
-                                <FontAwesomeIcon icon="trash" size="sm" />
-                            </div>
-                            <div className="row-option" style={{ cursor: 'grab' }} ref={reference} onPointerDown={onItemDown}>
-                                <FontAwesomeIcon icon="grip-vertical" size="sm" />
-                            </div>
-                            <div className="row-option" onClick={() => this.props.addDocTab(this.props.rowInfo.original, OpenWhere.addRight)}>
-                                <FontAwesomeIcon icon="external-link-alt" size="sm" />
-                            </div>
-                        </div>
-                        {children}
-                    </ReactTableDefaults.TrComponent>
-                </div>
-            </div>
-        );
-    }
-}
+//         return (
+//             <div className={className} onKeyPress={this.onKeyDown} ref={this.createRowDropTarget} onContextMenu={this.onRowContextMenu}>
+//                 <div className="collectionSchema-row-wrapper" onKeyPress={this.onKeyDown} ref={this._header} onPointerEnter={this.onPointerEnter} onPointerLeave={this.onPointerLeave}>
+//                     <ReactTableDefaults.TrComponent onKeyPress={this.onKeyDown}>
+//                         <div className="row-dragger">
+//                             <div className="row-option" onClick={undoBatch(() => this.props.removeDoc(this.props.rowInfo.original))}>
+//                                 <FontAwesomeIcon icon="trash" size="sm" />
+//                             </div>
+//                             <div className="row-option" style={{ cursor: 'grab' }} ref={reference} onPointerDown={onItemDown}>
+//                                 <FontAwesomeIcon icon="grip-vertical" size="sm" />
+//                             </div>
+//                             <div className="row-option" onClick={() => this.props.addDocTab(this.props.rowInfo.original, OpenWhere.addRight)}>
+//                                 <FontAwesomeIcon icon="external-link-alt" size="sm" />
+//                             </div>
+//                         </div>
+//                         {children}
+//                     </ReactTableDefaults.TrComponent>
+//                 </div>
+//             </div>
+//         );
+//     }
+// }
diff --git a/src/client/views/collections/old_collectionSchema/OldCollectionSchemaView.tsx b/src/client/views/collections/old_collectionSchema/OldCollectionSchemaView.tsx
index 260db4b88..f3f09cbf0 100644
--- a/src/client/views/collections/old_collectionSchema/OldCollectionSchemaView.tsx
+++ b/src/client/views/collections/old_collectionSchema/OldCollectionSchemaView.tsx
@@ -1,649 +1,649 @@
-import React = require('react');
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, computed, observable, untracked } from 'mobx';
-import { observer } from 'mobx-react';
-import Measure from 'react-measure';
-// import { Resize } from 'react-table';
-import { Doc, Opt } from '../../../../fields/Doc';
-import { List } from '../../../../fields/List';
-import { listSpec } from '../../../../fields/Schema';
-import { PastelSchemaPalette, SchemaHeaderField } from '../../../../fields/SchemaHeaderField';
-import { Cast, NumCast } from '../../../../fields/Types';
-import { TraceMobx } from '../../../../fields/util';
-import { emptyFunction, returnEmptyDoclist, returnFalse, returnTrue, setupMoveUpEvents } from '../../../../Utils';
-import { DocUtils } from '../../../documents/Documents';
-import { SelectionManager } from '../../../util/SelectionManager';
-import { SnappingManager } from '../../../util/SnappingManager';
-import { Transform } from '../../../util/Transform';
-import { undoBatch } from '../../../util/UndoManager';
-import { ContextMenu } from '../../ContextMenu';
-import { ContextMenuProps } from '../../ContextMenuItem';
-import { COLLECTION_BORDER_WIDTH, SCHEMA_DIVIDER_WIDTH } from '../../global/globalCssVariables.scss';
-import { DocumentView } from '../../nodes/DocumentView';
-import { DefaultStyleProvider } from '../../StyleProvider';
-import { CollectionSubView } from '../CollectionSubView';
-import './CollectionSchemaView.scss';
-// import { SchemaTable } from './SchemaTable';
-// bcz: need to add drag and drop of rows and columns.  This seems like it might work for rows: https://codesandbox.io/s/l94mn1q657
-
-export enum ColumnType {
-    Any,
-    Number,
-    String,
-    Boolean,
-    Doc,
-    Image,
-    List,
-    Date,
-}
-// this map should be used for keys that should have a const type of value
-const columnTypes: Map<string, ColumnType> = new Map([
-    ['title', ColumnType.String],
-    ['x', ColumnType.Number],
-    ['y', ColumnType.Number],
-    ['_width', ColumnType.Number],
-    ['_height', ColumnType.Number],
-    ['_nativeWidth', ColumnType.Number],
-    ['_nativeHeight', ColumnType.Number],
-    ['isPrototype', ColumnType.Boolean],
-    ['_curPage', ColumnType.Number],
-    ['_currentTimecode', ColumnType.Number],
-    ['zIndex', ColumnType.Number],
-]);
-
-@observer
-export class CollectionSchemaView extends CollectionSubView() {
-    private _previewCont?: HTMLDivElement;
-
-    @observable _previewDoc: Doc | undefined = undefined;
-    @observable _focusedTable: Doc = this.props.Document;
-    @observable _col: any = '';
-    @observable _menuWidth = 0;
-    @observable _headerOpen = false;
-    @observable _headerIsEditing = false;
-    @observable _menuHeight = 0;
-    @observable _pointerX = 0;
-    @observable _pointerY = 0;
-    @observable _openTypes: boolean = false;
-
-    @computed get previewWidth() {
-        return () => NumCast(this.props.Document.schemaPreviewWidth);
-    }
-    @computed get previewHeight() {
-        return () => this.props.PanelHeight() - 2 * this.borderWidth;
-    }
-    @computed get tableWidth() {
-        return this.props.PanelWidth() - 2 * this.borderWidth - Number(SCHEMA_DIVIDER_WIDTH) - this.previewWidth();
-    }
-    @computed get borderWidth() {
-        return Number(COLLECTION_BORDER_WIDTH);
-    }
-    @computed get scale() {
-        return this.props.ScreenToLocalTransform().Scale;
-    }
-    @computed get columns() {
-        return Cast(this.props.Document._schemaHeaders, listSpec(SchemaHeaderField), []);
-    }
-    set columns(columns: SchemaHeaderField[]) {
-        this.props.Document._schemaHeaders = new List<SchemaHeaderField>(columns);
-    }
-
-    @computed get menuCoordinates() {
-        let searchx = 0;
-        let searchy = 0;
-        if (this.props.Document._searchDoc) {
-            const el = document.getElementsByClassName('collectionSchemaView-searchContainer')[0];
-            if (el !== undefined) {
-                const rect = el.getBoundingClientRect();
-                searchx = rect.x;
-                searchy = rect.y;
-            }
-        }
-        const x = Math.max(0, Math.min(document.body.clientWidth - this._menuWidth, this._pointerX)) - searchx;
-        const y = Math.max(0, Math.min(document.body.clientHeight - this._menuHeight, this._pointerY)) - searchy;
-        return this.props.ScreenToLocalTransform().transformPoint(x, y);
-    }
-
-    get documentKeys() {
-        const docs = this.childDocs;
-        const keys: { [key: string]: boolean } = {};
-        // bcz: ugh.  this is untracked since otherwise a large collection of documents will blast the server for all their fields.
-        //  then as each document's fields come back, we update the documents _proxies.  Each time we do this, the whole schema will be
-        //  invalidated and re-rendered.   This workaround will inquire all of the document fields before the options button is clicked.
-        //  then by the time the options button is clicked, all of the fields should be in place.  If a new field is added while this menu
-        //  is displayed (unlikely) it won't show up until something else changes.
-        //TODO Types
-        untracked(() => docs.map(doc => Doc.GetAllPrototypes(doc).map(proto => Object.keys(proto).forEach(key => (keys[key] = false)))));
-
-        this.columns.forEach(key => (keys[key.heading] = true));
-        return Array.from(Object.keys(keys));
-    }
-
-    @action setHeaderIsEditing = (isEditing: boolean) => (this._headerIsEditing = isEditing);
-
-    @undoBatch
-    setColumnType = action((columnField: SchemaHeaderField, type: ColumnType): void => {
-        this._openTypes = false;
-        if (columnTypes.get(columnField.heading)) return;
-
-        const columns = this.columns;
-        const index = columns.indexOf(columnField);
-        if (index > -1) {
-            columnField.setType(NumCast(type));
-            columns[index] = columnField;
-            this.columns = columns;
-        }
-    });
-
-    @undoBatch
-    setColumnColor = (columnField: SchemaHeaderField, color: string): void => {
-        const columns = this.columns;
-        const index = columns.indexOf(columnField);
-        if (index > -1) {
-            columnField.setColor(color);
-            columns[index] = columnField;
-            this.columns = columns; // need to set the columns to trigger rerender
-        }
-    };
-
-    @undoBatch
-    @action
-    setColumnSort = (columnField: SchemaHeaderField, descending: boolean | undefined) => {
-        const columns = this.columns;
-        columns.forEach(col => col.setDesc(undefined));
-
-        const index = columns.findIndex(c => c.heading === columnField.heading);
-        const column = columns[index];
-        column.setDesc(descending);
-        columns[index] = column;
-        this.columns = columns;
-    };
-
-    renderTypes = (col: any) => {
-        if (columnTypes.get(col.heading)) return null;
-
-        const type = col.type;
-
-        const anyType = (
-            <div className={'columnMenu-option' + (type === ColumnType.Any ? ' active' : '')} onClick={() => this.setColumnType(col, ColumnType.Any)}>
-                <FontAwesomeIcon icon={'align-justify'} size="sm" />
-                Any
-            </div>
-        );
-
-        const numType = (
-            <div className={'columnMenu-option' + (type === ColumnType.Number ? ' active' : '')} onClick={() => this.setColumnType(col, ColumnType.Number)}>
-                <FontAwesomeIcon icon={'hashtag'} size="sm" />
-                Number
-            </div>
-        );
-
-        const textType = (
-            <div className={'columnMenu-option' + (type === ColumnType.String ? ' active' : '')} onClick={() => this.setColumnType(col, ColumnType.String)}>
-                <FontAwesomeIcon icon={'font'} size="sm" />
-                Text
-            </div>
-        );
-
-        const boolType = (
-            <div className={'columnMenu-option' + (type === ColumnType.Boolean ? ' active' : '')} onClick={() => this.setColumnType(col, ColumnType.Boolean)}>
-                <FontAwesomeIcon icon={'check-square'} size="sm" />
-                Checkbox
-            </div>
-        );
-
-        const listType = (
-            <div className={'columnMenu-option' + (type === ColumnType.List ? ' active' : '')} onClick={() => this.setColumnType(col, ColumnType.List)}>
-                <FontAwesomeIcon icon={'list-ul'} size="sm" />
-                List
-            </div>
-        );
-
-        const docType = (
-            <div className={'columnMenu-option' + (type === ColumnType.Doc ? ' active' : '')} onClick={() => this.setColumnType(col, ColumnType.Doc)}>
-                <FontAwesomeIcon icon={'file'} size="sm" />
-                Document
-            </div>
-        );
-
-        const imageType = (
-            <div className={'columnMenu-option' + (type === ColumnType.Image ? ' active' : '')} onClick={() => this.setColumnType(col, ColumnType.Image)}>
-                <FontAwesomeIcon icon={'image'} size="sm" />
-                Image
-            </div>
-        );
-
-        const dateType = (
-            <div className={'columnMenu-option' + (type === ColumnType.Date ? ' active' : '')} onClick={() => this.setColumnType(col, ColumnType.Date)}>
-                <FontAwesomeIcon icon={'calendar'} size="sm" />
-                Date
-            </div>
-        );
-
-        const allColumnTypes = (
-            <div className="columnMenu-types">
-                {anyType}
-                {numType}
-                {textType}
-                {boolType}
-                {listType}
-                {docType}
-                {imageType}
-                {dateType}
-            </div>
-        );
-
-        const justColType =
-            type === ColumnType.Any
-                ? anyType
-                : type === ColumnType.Number
-                ? numType
-                : type === ColumnType.String
-                ? textType
-                : type === ColumnType.Boolean
-                ? boolType
-                : type === ColumnType.List
-                ? listType
-                : type === ColumnType.Doc
-                ? docType
-                : type === ColumnType.Date
-                ? dateType
-                : imageType;
-
-        return (
-            <div className="collectionSchema-headerMenu-group" onClick={action(() => (this._openTypes = !this._openTypes))}>
-                <div>
-                    <label style={{ cursor: 'pointer' }}>Column type:</label>
-                    <FontAwesomeIcon icon={'caret-down'} size="lg" style={{ float: 'right', transform: `rotate(${this._openTypes ? '180deg' : 0})`, transition: '0.2s all ease' }} />
-                </div>
-                {this._openTypes ? allColumnTypes : justColType}
-            </div>
-        );
-    };
-
-    renderSorting = (col: any) => {
-        const sort = col.desc;
-        return (
-            <div className="collectionSchema-headerMenu-group">
-                <label>Sort by:</label>
-                <div className="columnMenu-sort">
-                    <div className={'columnMenu-option' + (sort === true ? ' active' : '')} onClick={() => this.setColumnSort(col, true)}>
-                        <FontAwesomeIcon icon="sort-amount-down" size="sm" />
-                        Sort descending
-                    </div>
-                    <div className={'columnMenu-option' + (sort === false ? ' active' : '')} onClick={() => this.setColumnSort(col, false)}>
-                        <FontAwesomeIcon icon="sort-amount-up" size="sm" />
-                        Sort ascending
-                    </div>
-                    <div className="columnMenu-option" onClick={() => this.setColumnSort(col, undefined)}>
-                        <FontAwesomeIcon icon="times" size="sm" />
-                        Clear sorting
-                    </div>
-                </div>
-            </div>
-        );
-    };
-
-    renderColors = (col: any) => {
-        const selected = col.color;
-
-        const pink = PastelSchemaPalette.get('pink2');
-        const purple = PastelSchemaPalette.get('purple2');
-        const blue = PastelSchemaPalette.get('bluegreen1');
-        const yellow = PastelSchemaPalette.get('yellow4');
-        const red = PastelSchemaPalette.get('red2');
-        const gray = '#f1efeb';
-
-        return (
-            <div className="collectionSchema-headerMenu-group">
-                <label>Color:</label>
-                <div className="columnMenu-colors">
-                    <div className={'columnMenu-colorPicker' + (selected === pink ? ' active' : '')} style={{ backgroundColor: pink }} onClick={() => this.setColumnColor(col, pink!)}></div>
-                    <div className={'columnMenu-colorPicker' + (selected === purple ? ' active' : '')} style={{ backgroundColor: purple }} onClick={() => this.setColumnColor(col, purple!)}></div>
-                    <div className={'columnMenu-colorPicker' + (selected === blue ? ' active' : '')} style={{ backgroundColor: blue }} onClick={() => this.setColumnColor(col, blue!)}></div>
-                    <div className={'columnMenu-colorPicker' + (selected === yellow ? ' active' : '')} style={{ backgroundColor: yellow }} onClick={() => this.setColumnColor(col, yellow!)}></div>
-                    <div className={'columnMenu-colorPicker' + (selected === red ? ' active' : '')} style={{ backgroundColor: red }} onClick={() => this.setColumnColor(col, red!)}></div>
-                    <div className={'columnMenu-colorPicker' + (selected === gray ? ' active' : '')} style={{ backgroundColor: gray }} onClick={() => this.setColumnColor(col, gray)}></div>
-                </div>
-            </div>
-        );
-    };
-
-    @undoBatch
-    @action
-    changeColumns = (oldKey: string, newKey: string, addNew: boolean, filter?: string) => {
-        const columns = this.columns;
-        if (columns === undefined) {
-            this.columns = new List<SchemaHeaderField>([new SchemaHeaderField(newKey, 'f1efeb')]);
-        } else {
-            if (addNew) {
-                columns.push(new SchemaHeaderField(newKey, 'f1efeb'));
-                this.columns = columns;
-            } else {
-                const index = columns.map(c => c.heading).indexOf(oldKey);
-                if (index > -1) {
-                    const column = columns[index];
-                    column.setHeading(newKey);
-                    columns[index] = column;
-                    this.columns = columns;
-                    if (filter) {
-                        Doc.setDocFilter(this.props.Document, newKey, filter, 'match');
-                    } else {
-                        this.props.Document._docFilters = undefined;
-                    }
-                }
-            }
-        }
-    };
-
-    @action
-    openHeader = (col: any, screenx: number, screeny: number) => {
-        this._col = col;
-        this._headerOpen = true;
-        this._pointerX = screenx;
-        this._pointerY = screeny;
-    };
-
-    @action
-    closeHeader = () => {
-        this._headerOpen = false;
-    };
-
-    @undoBatch
-    @action
-    deleteColumn = (key: string) => {
-        const columns = this.columns;
-        if (columns === undefined) {
-            this.columns = new List<SchemaHeaderField>([]);
-        } else {
-            const index = columns.map(c => c.heading).indexOf(key);
-            if (index > -1) {
-                columns.splice(index, 1);
-                this.columns = columns;
-            }
-        }
-        this.closeHeader();
-    };
-
-    getPreviewTransform = (): Transform => {
-        return this.props.ScreenToLocalTransform().translate(-this.borderWidth - NumCast(COLLECTION_BORDER_WIDTH) - this.tableWidth, -this.borderWidth);
-    };
-
-    @action
-    onHeaderClick = (e: React.PointerEvent) => {
-        e.stopPropagation();
-    };
-
-    @action
-    onWheel(e: React.WheelEvent) {
-        const scale = this.props.ScreenToLocalTransform().Scale;
-        this.props.isContentActive(true) && e.stopPropagation();
-    }
-
-    @computed get renderMenuContent() {
-        TraceMobx();
-        return (
-            <div className="collectionSchema-header-menuOptions">
-                {this.renderTypes(this._col)}
-                {this.renderColors(this._col)}
-                <div className="collectionSchema-headerMenu-group">
-                    <button
-                        onClick={() => {
-                            this.deleteColumn(this._col.heading);
-                        }}>
-                        Hide Column
-                    </button>
-                </div>
-            </div>
-        );
-    }
-
-    private createTarget = (ele: HTMLDivElement) => {
-        this._previewCont = ele;
-        super.CreateDropTarget(ele);
-    };
-
-    isFocused = (doc: Doc, outsideReaction: boolean): boolean => this.props.isSelected(outsideReaction) && doc === this._focusedTable;
-
-    @action setFocused = (doc: Doc) => (this._focusedTable = doc);
-
-    @action setPreviewDoc = (doc: Opt<Doc>) => {
-        SelectionManager.SelectSchemaViewDoc(doc);
-        this._previewDoc = doc;
-    };
-
-    //toggles preview side-panel of schema
-    @action
-    toggleExpander = () => {
-        this.props.Document.schemaPreviewWidth = this.previewWidth() === 0 ? Math.min(this.tableWidth / 3, 200) : 0;
-    };
-
-    onDividerDown = (e: React.PointerEvent) => {
-        setupMoveUpEvents(this, e, this.onDividerMove, emptyFunction, this.toggleExpander);
-    };
-    @action
-    onDividerMove = (e: PointerEvent, down: number[], delta: number[]) => {
-        const nativeWidth = this._previewCont!.getBoundingClientRect();
-        const minWidth = 40;
-        const maxWidth = 1000;
-        const movedWidth = this.props.ScreenToLocalTransform().transformDirection(nativeWidth.right - e.clientX, 0)[0];
-        const width = movedWidth < minWidth ? minWidth : movedWidth > maxWidth ? maxWidth : movedWidth;
-        this.props.Document.schemaPreviewWidth = width;
-        return false;
-    };
-
-    onPointerDown = (e: React.PointerEvent): void => {
-        if (e.button === 0 && !e.altKey && !e.ctrlKey && !e.metaKey) {
-            if (this.props.isSelected(true)) e.stopPropagation();
-            else this.props.select(false);
-        }
-    };
-
-    @computed
-    get previewDocument(): Doc | undefined {
-        return this._previewDoc;
-    }
-
-    @computed
-    get dividerDragger() {
-        return this.previewWidth() === 0 ? null : (
-            <div className="collectionSchemaView-dividerDragger" onPointerDown={this.onDividerDown}>
-                <div className="collectionSchemaView-dividerDragger" />
-            </div>
-        );
-    }
-
-    @computed
-    get previewPanel() {
-        return (
-            <div ref={this.createTarget} style={{ width: `${this.previewWidth()}px` }}>
-                {!this.previewDocument ? null : (
-                    <DocumentView
-                        Document={this.previewDocument}
-                        DataDoc={undefined}
-                        fitContentsToBox={returnTrue}
-                        dontCenter={'y'}
-                        focus={DocUtils.DefaultFocus}
-                        renderDepth={this.props.renderDepth}
-                        rootSelected={this.rootSelected}
-                        PanelWidth={this.previewWidth}
-                        PanelHeight={this.previewHeight}
-                        isContentActive={returnTrue}
-                        isDocumentActive={returnFalse}
-                        ScreenToLocalTransform={this.getPreviewTransform}
-                        docFilters={this.childDocFilters}
-                        docRangeFilters={this.childDocRangeFilters}
-                        searchFilterDocs={this.searchFilterDocs}
-                        styleProvider={DefaultStyleProvider}
-                        docViewPath={returnEmptyDoclist}
-                        ContainingCollectionDoc={this.props.CollectionView?.props.Document}
-                        ContainingCollectionView={this.props.CollectionView}
-                        moveDocument={this.props.moveDocument}
-                        addDocument={this.props.addDocument}
-                        removeDocument={this.props.removeDocument}
-                        whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
-                        addDocTab={this.props.addDocTab}
-                        pinToPres={this.props.pinToPres}
-                        bringToFront={returnFalse}
-                    />
-                )}
-            </div>
-        );
-    }
-
-    @computed
-    get schemaTable() {
-        return (
-            <SchemaTable
-                Document={this.props.Document}
-                PanelHeight={this.props.PanelHeight}
-                PanelWidth={this.props.PanelWidth}
-                childDocs={this.childDocs}
-                CollectionView={this.props.CollectionView}
-                ContainingCollectionView={this.props.ContainingCollectionView}
-                ContainingCollectionDoc={this.props.ContainingCollectionDoc}
-                fieldKey={this.props.fieldKey}
-                renderDepth={this.props.renderDepth}
-                moveDocument={this.props.moveDocument}
-                ScreenToLocalTransform={this.props.ScreenToLocalTransform}
-                active={this.props.isContentActive}
-                onDrop={this.onExternalDrop}
-                addDocTab={this.props.addDocTab}
-                pinToPres={this.props.pinToPres}
-                isSelected={this.props.isSelected}
-                isFocused={this.isFocused}
-                setFocused={this.setFocused}
-                setPreviewDoc={this.setPreviewDoc}
-                deleteDocument={this.props.removeDocument}
-                addDocument={this.props.addDocument}
-                dataDoc={this.props.DataDoc}
-                columns={this.columns}
-                documentKeys={this.documentKeys}
-                headerIsEditing={this._headerIsEditing}
-                openHeader={this.openHeader}
-                onClick={this.onTableClick}
-                onPointerDown={emptyFunction}
-                onResizedChange={this.onResizedChange}
-                setColumns={this.setColumns}
-                reorderColumns={this.reorderColumns}
-                changeColumns={this.changeColumns}
-                setHeaderIsEditing={this.setHeaderIsEditing}
-                changeColumnSort={this.setColumnSort}
-            />
-        );
-    }
-
-    @computed
-    public get schemaToolbar() {
-        return (
-            <div className="collectionSchemaView-toolbar">
-                <div className="collectionSchemaView-toolbar-item">
-                    <div id="preview-schema-checkbox-div">
-                        <input type="checkbox" key={'Show Preview'} checked={this.previewWidth() !== 0} onChange={this.toggleExpander} />
-                        Show Preview
-                    </div>
-                </div>
-            </div>
-        );
-    }
-
-    onSpecificMenu = (e: React.MouseEvent) => {
-        if ((e.target as any)?.className?.includes?.('collectionSchemaView-cell') || e.target instanceof HTMLSpanElement) {
-            const cm = ContextMenu.Instance;
-            const options = cm.findByDescription('Options...');
-            const optionItems: ContextMenuProps[] = options && 'subitems' in options ? options.subitems : [];
-            optionItems.push({ description: 'remove', event: () => this._previewDoc && this.props.removeDocument?.(this._previewDoc), icon: 'trash' });
-            !options && cm.addItem({ description: 'Options...', subitems: optionItems, icon: 'compass' });
-            cm.displayMenu(e.clientX, e.clientY);
-            (e.nativeEvent as any).SchemaHandled = true; // not sure why this is needed, but if you right-click quickly on a cell, the Document/Collection contextMenu handlers still fire without this.
-            e.stopPropagation();
-        }
-    };
-
-    @action
-    onTableClick = (e: React.MouseEvent): void => {
-        if (!(e.target as any)?.className?.includes?.('collectionSchemaView-cell') && !(e.target instanceof HTMLSpanElement)) {
-            this.setPreviewDoc(undefined);
-        } else {
-            e.stopPropagation();
-        }
-        this.setFocused(this.props.Document);
-        this.closeHeader();
-    };
-
-    onResizedChange = (newResized: Resize[], event: any) => {
-        const columns = this.columns;
-        newResized.forEach(resized => {
-            const index = columns.findIndex(c => c.heading === resized.id);
-            const column = columns[index];
-            column.setWidth(resized.value);
-            columns[index] = column;
-        });
-        this.columns = columns;
-    };
-
-    @action
-    setColumns = (columns: SchemaHeaderField[]) => (this.columns = columns);
-
-    @undoBatch
-    reorderColumns = (toMove: SchemaHeaderField, relativeTo: SchemaHeaderField, before: boolean, columnsValues: SchemaHeaderField[]) => {
-        const columns = [...columnsValues];
-        const oldIndex = columns.indexOf(toMove);
-        const relIndex = columns.indexOf(relativeTo);
-        const newIndex = oldIndex > relIndex && !before ? relIndex + 1 : oldIndex < relIndex && before ? relIndex - 1 : relIndex;
-
-        if (oldIndex === newIndex) return;
-
-        columns.splice(newIndex, 0, columns.splice(oldIndex, 1)[0]);
-        this.columns = columns;
-    };
-
-    onZoomMenu = (e: React.WheelEvent) => this.props.isContentActive(true) && e.stopPropagation();
-
-    render() {
-        TraceMobx();
-        if (!this.props.isContentActive()) setTimeout(() => this.closeHeader(), 0);
-        const menuContent = this.renderMenuContent;
-        const menu = (
-            <div className="collectionSchema-header-menu" onWheel={e => this.onZoomMenu(e)} onPointerDown={e => this.onHeaderClick(e)} style={{ transform: `translate(${this.menuCoordinates[0]}px, ${this.menuCoordinates[1]}px)` }}>
-                <Measure
-                    offset
-                    onResize={action((r: any) => {
-                        const dim = this.props.ScreenToLocalTransform().inverse().transformDirection(r.offset.width, r.offset.height);
-                        this._menuWidth = dim[0];
-                        this._menuHeight = dim[1];
-                    })}>
-                    {({ measureRef }) => <div ref={measureRef}> {menuContent} </div>}
-                </Measure>
-            </div>
-        );
-        return (
-            <div
-                className={'collectionSchemaView' + (this.props.Document._searchDoc ? '-searchContainer' : '-container')}
-                style={{
-                    overflow: this.props.scrollOverflow === true ? 'scroll' : undefined,
-                    backgroundColor: 'white',
-                    pointerEvents: this.props.Document._searchDoc !== undefined && !this.props.isContentActive() && !SnappingManager.GetIsDragging() ? 'none' : undefined,
-                    width: this.props.PanelWidth() || '100%',
-                    height: this.props.PanelHeight() || '100%',
-                    position: 'relative',
-                }}>
-                <div
-                    className="collectionSchemaView-tableContainer"
-                    style={{ width: `calc(100% - ${this.previewWidth()}px)` }}
-                    onContextMenu={this.onSpecificMenu}
-                    onPointerDown={this.onPointerDown}
-                    onWheel={e => this.props.isContentActive(true) && e.stopPropagation()}
-                    onDrop={e => this.onExternalDrop(e, {})}
-                    ref={this.createTarget}>
-                    {this.schemaTable}
-                </div>
-                {this.dividerDragger}
-                {!this.previewWidth() ? null : this.previewPanel}
-                {this._headerOpen && this.props.isContentActive() ? menu : null}
-            </div>
-        );
-        TraceMobx();
-        return <div>HELLO</div>;
-    }
-}
+// import React = require('react');
+// import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+// import { action, computed, observable, untracked } from 'mobx';
+// import { observer } from 'mobx-react';
+// import Measure from 'react-measure';
+// // import { Resize } from 'react-table';
+// import { Doc, Opt } from '../../../../fields/Doc';
+// import { List } from '../../../../fields/List';
+// import { listSpec } from '../../../../fields/Schema';
+// import { PastelSchemaPalette, SchemaHeaderField } from '../../../../fields/SchemaHeaderField';
+// import { Cast, NumCast } from '../../../../fields/Types';
+// import { TraceMobx } from '../../../../fields/util';
+// import { emptyFunction, returnEmptyDoclist, returnFalse, returnTrue, setupMoveUpEvents } from '../../../../Utils';
+// import { DocUtils } from '../../../documents/Documents';
+// import { SelectionManager } from '../../../util/SelectionManager';
+// import { SnappingManager } from '../../../util/SnappingManager';
+// import { Transform } from '../../../util/Transform';
+// import { undoBatch } from '../../../util/UndoManager';
+// import { ContextMenu } from '../../ContextMenu';
+// import { ContextMenuProps } from '../../ContextMenuItem';
+// import { COLLECTION_BORDER_WIDTH, SCHEMA_DIVIDER_WIDTH } from '../../global/globalCssVariables.scss';
+// import { DocumentView } from '../../nodes/DocumentView';
+// import { DefaultStyleProvider } from '../../StyleProvider';
+// import { CollectionSubView } from '../CollectionSubView';
+// import './CollectionSchemaView.scss';
+// // import { SchemaTable } from './SchemaTable';
+// // bcz: need to add drag and drop of rows and columns.  This seems like it might work for rows: https://codesandbox.io/s/l94mn1q657
+
+// export enum ColumnType {
+//     Any,
+//     Number,
+//     String,
+//     Boolean,
+//     Doc,
+//     Image,
+//     List,
+//     Date,
+// }
+// // this map should be used for keys that should have a const type of value
+// const columnTypes: Map<string, ColumnType> = new Map([
+//     ['title', ColumnType.String],
+//     ['x', ColumnType.Number],
+//     ['y', ColumnType.Number],
+//     ['_width', ColumnType.Number],
+//     ['_height', ColumnType.Number],
+//     ['_nativeWidth', ColumnType.Number],
+//     ['_nativeHeight', ColumnType.Number],
+//     ['isPrototype', ColumnType.Boolean],
+//     ['_curPage', ColumnType.Number],
+//     ['_currentTimecode', ColumnType.Number],
+//     ['zIndex', ColumnType.Number],
+// ]);
+
+// @observer
+// export class CollectionSchemaView extends CollectionSubView() {
+//     private _previewCont?: HTMLDivElement;
+
+//     @observable _previewDoc: Doc | undefined = undefined;
+//     @observable _focusedTable: Doc = this.props.Document;
+//     @observable _col: any = '';
+//     @observable _menuWidth = 0;
+//     @observable _headerOpen = false;
+//     @observable _headerIsEditing = false;
+//     @observable _menuHeight = 0;
+//     @observable _pointerX = 0;
+//     @observable _pointerY = 0;
+//     @observable _openTypes: boolean = false;
+
+//     @computed get previewWidth() {
+//         return () => NumCast(this.props.Document.schemaPreviewWidth);
+//     }
+//     @computed get previewHeight() {
+//         return () => this.props.PanelHeight() - 2 * this.borderWidth;
+//     }
+//     @computed get tableWidth() {
+//         return this.props.PanelWidth() - 2 * this.borderWidth - Number(SCHEMA_DIVIDER_WIDTH) - this.previewWidth();
+//     }
+//     @computed get borderWidth() {
+//         return Number(COLLECTION_BORDER_WIDTH);
+//     }
+//     @computed get scale() {
+//         return this.props.ScreenToLocalTransform().Scale;
+//     }
+//     @computed get columns() {
+//         return Cast(this.props.Document._schemaHeaders, listSpec(SchemaHeaderField), []);
+//     }
+//     set columns(columns: SchemaHeaderField[]) {
+//         this.props.Document._schemaHeaders = new List<SchemaHeaderField>(columns);
+//     }
+
+//     @computed get menuCoordinates() {
+//         let searchx = 0;
+//         let searchy = 0;
+//         if (this.props.Document._searchDoc) {
+//             const el = document.getElementsByClassName('collectionSchemaView-searchContainer')[0];
+//             if (el !== undefined) {
+//                 const rect = el.getBoundingClientRect();
+//                 searchx = rect.x;
+//                 searchy = rect.y;
+//             }
+//         }
+//         const x = Math.max(0, Math.min(document.body.clientWidth - this._menuWidth, this._pointerX)) - searchx;
+//         const y = Math.max(0, Math.min(document.body.clientHeight - this._menuHeight, this._pointerY)) - searchy;
+//         return this.props.ScreenToLocalTransform().transformPoint(x, y);
+//     }
+
+//     get documentKeys() {
+//         const docs = this.childDocs;
+//         const keys: { [key: string]: boolean } = {};
+//         // bcz: ugh.  this is untracked since otherwise a large collection of documents will blast the server for all their fields.
+//         //  then as each document's fields come back, we update the documents _proxies.  Each time we do this, the whole schema will be
+//         //  invalidated and re-rendered.   This workaround will inquire all of the document fields before the options button is clicked.
+//         //  then by the time the options button is clicked, all of the fields should be in place.  If a new field is added while this menu
+//         //  is displayed (unlikely) it won't show up until something else changes.
+//         //TODO Types
+//         untracked(() => docs.map(doc => Doc.GetAllPrototypes(doc).map(proto => Object.keys(proto).forEach(key => (keys[key] = false)))));
+
+//         this.columns.forEach(key => (keys[key.heading] = true));
+//         return Array.from(Object.keys(keys));
+//     }
+
+//     @action setHeaderIsEditing = (isEditing: boolean) => (this._headerIsEditing = isEditing);
+
+//     @undoBatch
+//     setColumnType = action((columnField: SchemaHeaderField, type: ColumnType): void => {
+//         this._openTypes = false;
+//         if (columnTypes.get(columnField.heading)) return;
+
+//         const columns = this.columns;
+//         const index = columns.indexOf(columnField);
+//         if (index > -1) {
+//             columnField.setType(NumCast(type));
+//             columns[index] = columnField;
+//             this.columns = columns;
+//         }
+//     });
+
+//     @undoBatch
+//     setColumnColor = (columnField: SchemaHeaderField, color: string): void => {
+//         const columns = this.columns;
+//         const index = columns.indexOf(columnField);
+//         if (index > -1) {
+//             columnField.setColor(color);
+//             columns[index] = columnField;
+//             this.columns = columns; // need to set the columns to trigger rerender
+//         }
+//     };
+
+//     @undoBatch
+//     @action
+//     setColumnSort = (columnField: SchemaHeaderField, descending: boolean | undefined) => {
+//         const columns = this.columns;
+//         columns.forEach(col => col.setDesc(undefined));
+
+//         const index = columns.findIndex(c => c.heading === columnField.heading);
+//         const column = columns[index];
+//         column.setDesc(descending);
+//         columns[index] = column;
+//         this.columns = columns;
+//     };
+
+//     renderTypes = (col: any) => {
+//         if (columnTypes.get(col.heading)) return null;
+
+//         const type = col.type;
+
+//         const anyType = (
+//             <div className={'columnMenu-option' + (type === ColumnType.Any ? ' active' : '')} onClick={() => this.setColumnType(col, ColumnType.Any)}>
+//                 <FontAwesomeIcon icon={'align-justify'} size="sm" />
+//                 Any
+//             </div>
+//         );
+
+//         const numType = (
+//             <div className={'columnMenu-option' + (type === ColumnType.Number ? ' active' : '')} onClick={() => this.setColumnType(col, ColumnType.Number)}>
+//                 <FontAwesomeIcon icon={'hashtag'} size="sm" />
+//                 Number
+//             </div>
+//         );
+
+//         const textType = (
+//             <div className={'columnMenu-option' + (type === ColumnType.String ? ' active' : '')} onClick={() => this.setColumnType(col, ColumnType.String)}>
+//                 <FontAwesomeIcon icon={'font'} size="sm" />
+//                 Text
+//             </div>
+//         );
+
+//         const boolType = (
+//             <div className={'columnMenu-option' + (type === ColumnType.Boolean ? ' active' : '')} onClick={() => this.setColumnType(col, ColumnType.Boolean)}>
+//                 <FontAwesomeIcon icon={'check-square'} size="sm" />
+//                 Checkbox
+//             </div>
+//         );
+
+//         const listType = (
+//             <div className={'columnMenu-option' + (type === ColumnType.List ? ' active' : '')} onClick={() => this.setColumnType(col, ColumnType.List)}>
+//                 <FontAwesomeIcon icon={'list-ul'} size="sm" />
+//                 List
+//             </div>
+//         );
+
+//         const docType = (
+//             <div className={'columnMenu-option' + (type === ColumnType.Doc ? ' active' : '')} onClick={() => this.setColumnType(col, ColumnType.Doc)}>
+//                 <FontAwesomeIcon icon={'file'} size="sm" />
+//                 Document
+//             </div>
+//         );
+
+//         const imageType = (
+//             <div className={'columnMenu-option' + (type === ColumnType.Image ? ' active' : '')} onClick={() => this.setColumnType(col, ColumnType.Image)}>
+//                 <FontAwesomeIcon icon={'image'} size="sm" />
+//                 Image
+//             </div>
+//         );
+
+//         const dateType = (
+//             <div className={'columnMenu-option' + (type === ColumnType.Date ? ' active' : '')} onClick={() => this.setColumnType(col, ColumnType.Date)}>
+//                 <FontAwesomeIcon icon={'calendar'} size="sm" />
+//                 Date
+//             </div>
+//         );
+
+//         const allColumnTypes = (
+//             <div className="columnMenu-types">
+//                 {anyType}
+//                 {numType}
+//                 {textType}
+//                 {boolType}
+//                 {listType}
+//                 {docType}
+//                 {imageType}
+//                 {dateType}
+//             </div>
+//         );
+
+//         const justColType =
+//             type === ColumnType.Any
+//                 ? anyType
+//                 : type === ColumnType.Number
+//                 ? numType
+//                 : type === ColumnType.String
+//                 ? textType
+//                 : type === ColumnType.Boolean
+//                 ? boolType
+//                 : type === ColumnType.List
+//                 ? listType
+//                 : type === ColumnType.Doc
+//                 ? docType
+//                 : type === ColumnType.Date
+//                 ? dateType
+//                 : imageType;
+
+//         return (
+//             <div className="collectionSchema-headerMenu-group" onClick={action(() => (this._openTypes = !this._openTypes))}>
+//                 <div>
+//                     <label style={{ cursor: 'pointer' }}>Column type:</label>
+//                     <FontAwesomeIcon icon={'caret-down'} size="lg" style={{ float: 'right', transform: `rotate(${this._openTypes ? '180deg' : 0})`, transition: '0.2s all ease' }} />
+//                 </div>
+//                 {this._openTypes ? allColumnTypes : justColType}
+//             </div>
+//         );
+//     };
+
+//     renderSorting = (col: any) => {
+//         const sort = col.desc;
+//         return (
+//             <div className="collectionSchema-headerMenu-group">
+//                 <label>Sort by:</label>
+//                 <div className="columnMenu-sort">
+//                     <div className={'columnMenu-option' + (sort === true ? ' active' : '')} onClick={() => this.setColumnSort(col, true)}>
+//                         <FontAwesomeIcon icon="sort-amount-down" size="sm" />
+//                         Sort descending
+//                     </div>
+//                     <div className={'columnMenu-option' + (sort === false ? ' active' : '')} onClick={() => this.setColumnSort(col, false)}>
+//                         <FontAwesomeIcon icon="sort-amount-up" size="sm" />
+//                         Sort ascending
+//                     </div>
+//                     <div className="columnMenu-option" onClick={() => this.setColumnSort(col, undefined)}>
+//                         <FontAwesomeIcon icon="times" size="sm" />
+//                         Clear sorting
+//                     </div>
+//                 </div>
+//             </div>
+//         );
+//     };
+
+//     renderColors = (col: any) => {
+//         const selected = col.color;
+
+//         const pink = PastelSchemaPalette.get('pink2');
+//         const purple = PastelSchemaPalette.get('purple2');
+//         const blue = PastelSchemaPalette.get('bluegreen1');
+//         const yellow = PastelSchemaPalette.get('yellow4');
+//         const red = PastelSchemaPalette.get('red2');
+//         const gray = '#f1efeb';
+
+//         return (
+//             <div className="collectionSchema-headerMenu-group">
+//                 <label>Color:</label>
+//                 <div className="columnMenu-colors">
+//                     <div className={'columnMenu-colorPicker' + (selected === pink ? ' active' : '')} style={{ backgroundColor: pink }} onClick={() => this.setColumnColor(col, pink!)}></div>
+//                     <div className={'columnMenu-colorPicker' + (selected === purple ? ' active' : '')} style={{ backgroundColor: purple }} onClick={() => this.setColumnColor(col, purple!)}></div>
+//                     <div className={'columnMenu-colorPicker' + (selected === blue ? ' active' : '')} style={{ backgroundColor: blue }} onClick={() => this.setColumnColor(col, blue!)}></div>
+//                     <div className={'columnMenu-colorPicker' + (selected === yellow ? ' active' : '')} style={{ backgroundColor: yellow }} onClick={() => this.setColumnColor(col, yellow!)}></div>
+//                     <div className={'columnMenu-colorPicker' + (selected === red ? ' active' : '')} style={{ backgroundColor: red }} onClick={() => this.setColumnColor(col, red!)}></div>
+//                     <div className={'columnMenu-colorPicker' + (selected === gray ? ' active' : '')} style={{ backgroundColor: gray }} onClick={() => this.setColumnColor(col, gray)}></div>
+//                 </div>
+//             </div>
+//         );
+//     };
+
+//     @undoBatch
+//     @action
+//     changeColumns = (oldKey: string, newKey: string, addNew: boolean, filter?: string) => {
+//         const columns = this.columns;
+//         if (columns === undefined) {
+//             this.columns = new List<SchemaHeaderField>([new SchemaHeaderField(newKey, 'f1efeb')]);
+//         } else {
+//             if (addNew) {
+//                 columns.push(new SchemaHeaderField(newKey, 'f1efeb'));
+//                 this.columns = columns;
+//             } else {
+//                 const index = columns.map(c => c.heading).indexOf(oldKey);
+//                 if (index > -1) {
+//                     const column = columns[index];
+//                     column.setHeading(newKey);
+//                     columns[index] = column;
+//                     this.columns = columns;
+//                     if (filter) {
+//                         Doc.setDocFilter(this.props.Document, newKey, filter, 'match');
+//                     } else {
+//                         this.props.Document._docFilters = undefined;
+//                     }
+//                 }
+//             }
+//         }
+//     };
+
+//     @action
+//     openHeader = (col: any, screenx: number, screeny: number) => {
+//         this._col = col;
+//         this._headerOpen = true;
+//         this._pointerX = screenx;
+//         this._pointerY = screeny;
+//     };
+
+//     @action
+//     closeHeader = () => {
+//         this._headerOpen = false;
+//     };
+
+//     @undoBatch
+//     @action
+//     deleteColumn = (key: string) => {
+//         const columns = this.columns;
+//         if (columns === undefined) {
+//             this.columns = new List<SchemaHeaderField>([]);
+//         } else {
+//             const index = columns.map(c => c.heading).indexOf(key);
+//             if (index > -1) {
+//                 columns.splice(index, 1);
+//                 this.columns = columns;
+//             }
+//         }
+//         this.closeHeader();
+//     };
+
+//     getPreviewTransform = (): Transform => {
+//         return this.props.ScreenToLocalTransform().translate(-this.borderWidth - NumCast(COLLECTION_BORDER_WIDTH) - this.tableWidth, -this.borderWidth);
+//     };
+
+//     @action
+//     onHeaderClick = (e: React.PointerEvent) => {
+//         e.stopPropagation();
+//     };
+
+//     @action
+//     onWheel(e: React.WheelEvent) {
+//         const scale = this.props.ScreenToLocalTransform().Scale;
+//         this.props.isContentActive(true) && e.stopPropagation();
+//     }
+
+//     @computed get renderMenuContent() {
+//         TraceMobx();
+//         return (
+//             <div className="collectionSchema-header-menuOptions">
+//                 {this.renderTypes(this._col)}
+//                 {this.renderColors(this._col)}
+//                 <div className="collectionSchema-headerMenu-group">
+//                     <button
+//                         onClick={() => {
+//                             this.deleteColumn(this._col.heading);
+//                         }}>
+//                         Hide Column
+//                     </button>
+//                 </div>
+//             </div>
+//         );
+//     }
+
+//     private createTarget = (ele: HTMLDivElement) => {
+//         this._previewCont = ele;
+//         super.CreateDropTarget(ele);
+//     };
+
+//     isFocused = (doc: Doc, outsideReaction: boolean): boolean => this.props.isSelected(outsideReaction) && doc === this._focusedTable;
+
+//     @action setFocused = (doc: Doc) => (this._focusedTable = doc);
+
+//     @action setPreviewDoc = (doc: Opt<Doc>) => {
+//         SelectionManager.SelectSchemaViewDoc(doc);
+//         this._previewDoc = doc;
+//     };
+
+//     //toggles preview side-panel of schema
+//     @action
+//     toggleExpander = () => {
+//         this.props.Document.schemaPreviewWidth = this.previewWidth() === 0 ? Math.min(this.tableWidth / 3, 200) : 0;
+//     };
+
+//     onDividerDown = (e: React.PointerEvent) => {
+//         setupMoveUpEvents(this, e, this.onDividerMove, emptyFunction, this.toggleExpander);
+//     };
+//     @action
+//     onDividerMove = (e: PointerEvent, down: number[], delta: number[]) => {
+//         const nativeWidth = this._previewCont!.getBoundingClientRect();
+//         const minWidth = 40;
+//         const maxWidth = 1000;
+//         const movedWidth = this.props.ScreenToLocalTransform().transformDirection(nativeWidth.right - e.clientX, 0)[0];
+//         const width = movedWidth < minWidth ? minWidth : movedWidth > maxWidth ? maxWidth : movedWidth;
+//         this.props.Document.schemaPreviewWidth = width;
+//         return false;
+//     };
+
+//     onPointerDown = (e: React.PointerEvent): void => {
+//         if (e.button === 0 && !e.altKey && !e.ctrlKey && !e.metaKey) {
+//             if (this.props.isSelected(true)) e.stopPropagation();
+//             else this.props.select(false);
+//         }
+//     };
+
+//     @computed
+//     get previewDocument(): Doc | undefined {
+//         return this._previewDoc;
+//     }
+
+//     @computed
+//     get dividerDragger() {
+//         return this.previewWidth() === 0 ? null : (
+//             <div className="collectionSchemaView-dividerDragger" onPointerDown={this.onDividerDown}>
+//                 <div className="collectionSchemaView-dividerDragger" />
+//             </div>
+//         );
+//     }
+
+//     @computed
+//     get previewPanel() {
+//         return (
+//             <div ref={this.createTarget} style={{ width: `${this.previewWidth()}px` }}>
+//                 {!this.previewDocument ? null : (
+//                     <DocumentView
+//                         Document={this.previewDocument}
+//                         DataDoc={undefined}
+//                         fitContentsToBox={returnTrue}
+//                         dontCenter={'y'}
+//                         focus={DocUtils.DefaultFocus}
+//                         renderDepth={this.props.renderDepth}
+//                         rootSelected={this.rootSelected}
+//                         PanelWidth={this.previewWidth}
+//                         PanelHeight={this.previewHeight}
+//                         isContentActive={returnTrue}
+//                         isDocumentActive={returnFalse}
+//                         ScreenToLocalTransform={this.getPreviewTransform}
+//                         docFilters={this.childDocFilters}
+//                         docRangeFilters={this.childDocRangeFilters}
+//                         searchFilterDocs={this.searchFilterDocs}
+//                         styleProvider={DefaultStyleProvider}
+//                         docViewPath={returnEmptyDoclist}
+//                         ContainingCollectionDoc={this.props.CollectionView?.props.Document}
+//                         ContainingCollectionView={this.props.CollectionView}
+//                         moveDocument={this.props.moveDocument}
+//                         addDocument={this.props.addDocument}
+//                         removeDocument={this.props.removeDocument}
+//                         whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
+//                         addDocTab={this.props.addDocTab}
+//                         pinToPres={this.props.pinToPres}
+//                         bringToFront={returnFalse}
+//                     />
+//                 )}
+//             </div>
+//         );
+//     }
+
+//     @computed
+//     get schemaTable() {
+//         return (
+//             <SchemaTable
+//                 Document={this.props.Document}
+//                 PanelHeight={this.props.PanelHeight}
+//                 PanelWidth={this.props.PanelWidth}
+//                 childDocs={this.childDocs}
+//                 CollectionView={this.props.CollectionView}
+//                 ContainingCollectionView={this.props.ContainingCollectionView}
+//                 ContainingCollectionDoc={this.props.ContainingCollectionDoc}
+//                 fieldKey={this.props.fieldKey}
+//                 renderDepth={this.props.renderDepth}
+//                 moveDocument={this.props.moveDocument}
+//                 ScreenToLocalTransform={this.props.ScreenToLocalTransform}
+//                 active={this.props.isContentActive}
+//                 onDrop={this.onExternalDrop}
+//                 addDocTab={this.props.addDocTab}
+//                 pinToPres={this.props.pinToPres}
+//                 isSelected={this.props.isSelected}
+//                 isFocused={this.isFocused}
+//                 setFocused={this.setFocused}
+//                 setPreviewDoc={this.setPreviewDoc}
+//                 deleteDocument={this.props.removeDocument}
+//                 addDocument={this.props.addDocument}
+//                 dataDoc={this.props.DataDoc}
+//                 columns={this.columns}
+//                 documentKeys={this.documentKeys}
+//                 headerIsEditing={this._headerIsEditing}
+//                 openHeader={this.openHeader}
+//                 onClick={this.onTableClick}
+//                 onPointerDown={emptyFunction}
+//                 onResizedChange={this.onResizedChange}
+//                 setColumns={this.setColumns}
+//                 reorderColumns={this.reorderColumns}
+//                 changeColumns={this.changeColumns}
+//                 setHeaderIsEditing={this.setHeaderIsEditing}
+//                 changeColumnSort={this.setColumnSort}
+//             />
+//         );
+//     }
+
+//     @computed
+//     public get schemaToolbar() {
+//         return (
+//             <div className="collectionSchemaView-toolbar">
+//                 <div className="collectionSchemaView-toolbar-item">
+//                     <div id="preview-schema-checkbox-div">
+//                         <input type="checkbox" key={'Show Preview'} checked={this.previewWidth() !== 0} onChange={this.toggleExpander} />
+//                         Show Preview
+//                     </div>
+//                 </div>
+//             </div>
+//         );
+//     }
+
+//     onSpecificMenu = (e: React.MouseEvent) => {
+//         if ((e.target as any)?.className?.includes?.('collectionSchemaView-cell') || e.target instanceof HTMLSpanElement) {
+//             const cm = ContextMenu.Instance;
+//             const options = cm.findByDescription('Options...');
+//             const optionItems: ContextMenuProps[] = options && 'subitems' in options ? options.subitems : [];
+//             optionItems.push({ description: 'remove', event: () => this._previewDoc && this.props.removeDocument?.(this._previewDoc), icon: 'trash' });
+//             !options && cm.addItem({ description: 'Options...', subitems: optionItems, icon: 'compass' });
+//             cm.displayMenu(e.clientX, e.clientY);
+//             (e.nativeEvent as any).SchemaHandled = true; // not sure why this is needed, but if you right-click quickly on a cell, the Document/Collection contextMenu handlers still fire without this.
+//             e.stopPropagation();
+//         }
+//     };
+
+//     @action
+//     onTableClick = (e: React.MouseEvent): void => {
+//         if (!(e.target as any)?.className?.includes?.('collectionSchemaView-cell') && !(e.target instanceof HTMLSpanElement)) {
+//             this.setPreviewDoc(undefined);
+//         } else {
+//             e.stopPropagation();
+//         }
+//         this.setFocused(this.props.Document);
+//         this.closeHeader();
+//     };
+
+//     onResizedChange = (newResized: Resize[], event: any) => {
+//         const columns = this.columns;
+//         newResized.forEach(resized => {
+//             const index = columns.findIndex(c => c.heading === resized.id);
+//             const column = columns[index];
+//             column.setWidth(resized.value);
+//             columns[index] = column;
+//         });
+//         this.columns = columns;
+//     };
+
+//     @action
+//     setColumns = (columns: SchemaHeaderField[]) => (this.columns = columns);
+
+//     @undoBatch
+//     reorderColumns = (toMove: SchemaHeaderField, relativeTo: SchemaHeaderField, before: boolean, columnsValues: SchemaHeaderField[]) => {
+//         const columns = [...columnsValues];
+//         const oldIndex = columns.indexOf(toMove);
+//         const relIndex = columns.indexOf(relativeTo);
+//         const newIndex = oldIndex > relIndex && !before ? relIndex + 1 : oldIndex < relIndex && before ? relIndex - 1 : relIndex;
+
+//         if (oldIndex === newIndex) return;
+
+//         columns.splice(newIndex, 0, columns.splice(oldIndex, 1)[0]);
+//         this.columns = columns;
+//     };
+
+//     onZoomMenu = (e: React.WheelEvent) => this.props.isContentActive(true) && e.stopPropagation();
+
+//     render() {
+//         TraceMobx();
+//         if (!this.props.isContentActive()) setTimeout(() => this.closeHeader(), 0);
+//         const menuContent = this.renderMenuContent;
+//         const menu = (
+//             <div className="collectionSchema-header-menu" onWheel={e => this.onZoomMenu(e)} onPointerDown={e => this.onHeaderClick(e)} style={{ transform: `translate(${this.menuCoordinates[0]}px, ${this.menuCoordinates[1]}px)` }}>
+//                 <Measure
+//                     offset
+//                     onResize={action((r: any) => {
+//                         const dim = this.props.ScreenToLocalTransform().inverse().transformDirection(r.offset.width, r.offset.height);
+//                         this._menuWidth = dim[0];
+//                         this._menuHeight = dim[1];
+//                     })}>
+//                     {({ measureRef }) => <div ref={measureRef}> {menuContent} </div>}
+//                 </Measure>
+//             </div>
+//         );
+//         return (
+//             <div
+//                 className={'collectionSchemaView' + (this.props.Document._searchDoc ? '-searchContainer' : '-container')}
+//                 style={{
+//                     overflow: this.props.scrollOverflow === true ? 'scroll' : undefined,
+//                     backgroundColor: 'white',
+//                     pointerEvents: this.props.Document._searchDoc !== undefined && !this.props.isContentActive() && !SnappingManager.GetIsDragging() ? 'none' : undefined,
+//                     width: this.props.PanelWidth() || '100%',
+//                     height: this.props.PanelHeight() || '100%',
+//                     position: 'relative',
+//                 }}>
+//                 <div
+//                     className="collectionSchemaView-tableContainer"
+//                     style={{ width: `calc(100% - ${this.previewWidth()}px)` }}
+//                     onContextMenu={this.onSpecificMenu}
+//                     onPointerDown={this.onPointerDown}
+//                     onWheel={e => this.props.isContentActive(true) && e.stopPropagation()}
+//                     onDrop={e => this.onExternalDrop(e, {})}
+//                     ref={this.createTarget}>
+//                     {this.schemaTable}
+//                 </div>
+//                 {this.dividerDragger}
+//                 {!this.previewWidth() ? null : this.previewPanel}
+//                 {this._headerOpen && this.props.isContentActive() ? menu : null}
+//             </div>
+//         );
+//         TraceMobx();
+//         return <div>HELLO</div>;
+//     }
+// }
diff --git a/src/client/views/collections/old_collectionSchema/OldSchemaTable.tsx b/src/client/views/collections/old_collectionSchema/OldSchemaTable.tsx
index 1b4fcf0a4..bc33f3be5 100644
--- a/src/client/views/collections/old_collectionSchema/OldSchemaTable.tsx
+++ b/src/client/views/collections/old_collectionSchema/OldSchemaTable.tsx
@@ -1,694 +1,694 @@
-import { IconProp } from '@fortawesome/fontawesome-svg-core';
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, computed, observable } from 'mobx';
-import { observer } from 'mobx-react';
-import * as React from 'react';
-import ReactTable, { CellInfo, Column, ComponentPropsGetterR, Resize, SortingRule } from 'react-table';
-import { DateField } from '../../../../fields/DateField';
-import { AclPrivate, AclReadonly, DataSym, Doc, DocListCast, Field, Opt } from '../../../../fields/Doc';
-import { Id } from '../../../../fields/FieldSymbols';
-import { List } from '../../../../fields/List';
-import { listSpec } from '../../../../fields/Schema';
-import { SchemaHeaderField } from '../../../../fields/SchemaHeaderField';
-import { ComputedField } from '../../../../fields/ScriptField';
-import { Cast, FieldValue, NumCast, StrCast } from '../../../../fields/Types';
-import { ImageField } from '../../../../fields/URLField';
-import { GetEffectiveAcl } from '../../../../fields/util';
-import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue } from '../../../../Utils';
-import { Docs, DocumentOptions, DocUtils } from '../../../documents/Documents';
-import { DocumentType } from '../../../documents/DocumentTypes';
-import { CompileScript, Transformer, ts } from '../../../util/Scripting';
-import { Transform } from '../../../util/Transform';
-import { undoBatch } from '../../../util/UndoManager';
-import '../../../views/DocumentDecorations.scss';
-import { ContextMenu } from '../../ContextMenu';
-import { COLLECTION_BORDER_WIDTH, SCHEMA_DIVIDER_WIDTH } from '../../global/globalCssVariables.scss';
-import { DocumentView, OpenWhere } from '../../nodes/DocumentView';
-import { PinProps } from '../../nodes/trails';
-import { DefaultStyleProvider } from '../../StyleProvider';
-import { CollectionView } from '../CollectionView';
-import {
-    CellProps,
-    CollectionSchemaButtons,
-    CollectionSchemaCell,
-    CollectionSchemaCheckboxCell,
-    CollectionSchemaDateCell,
-    CollectionSchemaDocCell,
-    CollectionSchemaImageCell,
-    CollectionSchemaListCell,
-    CollectionSchemaNumberCell,
-    CollectionSchemaStringCell,
-} from './CollectionSchemaCells';
-import { CollectionSchemaAddColumnHeader, KeysDropdown } from './CollectionSchemaHeaders';
-import { MovableColumn } from './OldCollectionSchemaMovableColumn';
-import { MovableRow } from './CollectionSchemaMovableRow';
-import './CollectionSchemaView.scss';
-
-enum ColumnType {
-    Any,
-    Number,
-    String,
-    Boolean,
-    Doc,
-    Image,
-    List,
-    Date,
-}
-
-// this map should be used for keys that should have a const type of value
-const columnTypes: Map<string, ColumnType> = new Map([
-    ['title', ColumnType.String],
-    ['x', ColumnType.Number],
-    ['y', ColumnType.Number],
-    ['_width', ColumnType.Number],
-    ['_height', ColumnType.Number],
-    ['_nativeWidth', ColumnType.Number],
-    ['_nativeHeight', ColumnType.Number],
-    ['isPrototype', ColumnType.Boolean],
-    ['_curPage', ColumnType.Number],
-    ['_currentTimecode', ColumnType.Number],
-    ['zIndex', ColumnType.Number],
-]);
-
-export interface SchemaTableProps {
-    Document: Doc; // child doc
-    dataDoc?: Doc;
-    PanelHeight: () => number;
-    PanelWidth: () => number;
-    childDocs?: Doc[];
-    CollectionView: Opt<CollectionView>;
-    ContainingCollectionView: Opt<CollectionView>;
-    ContainingCollectionDoc: Opt<Doc>;
-    fieldKey: string;
-    renderDepth: number;
-    deleteDocument?: (document: Doc | Doc[]) => boolean;
-    addDocument?: (document: Doc | Doc[]) => boolean;
-    moveDocument?: (document: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => boolean;
-    ScreenToLocalTransform: () => Transform;
-    active: (outsideReaction: boolean | undefined) => boolean | undefined;
-    onDrop: (e: React.DragEvent<Element>, options: DocumentOptions, completed?: (() => void) | undefined) => void;
-    addDocTab: (document: Doc, where: OpenWhere) => boolean;
-    pinToPres: (document: Doc, pinProps: PinProps) => void;
-    isSelected: (outsideReaction?: boolean) => boolean;
-    isFocused: (document: Doc, outsideReaction: boolean) => boolean;
-    setFocused: (document: Doc) => void;
-    setPreviewDoc: (document: Opt<Doc>) => void;
-    columns: SchemaHeaderField[];
-    documentKeys: any[];
-    headerIsEditing: boolean;
-    openHeader: (column: any, screenx: number, screeny: number) => void;
-    onClick: (e: React.MouseEvent) => void;
-    onPointerDown: (e: React.PointerEvent) => void;
-    onResizedChange: (newResized: Resize[], event: any) => void;
-    setColumns: (columns: SchemaHeaderField[]) => void;
-    reorderColumns: (toMove: SchemaHeaderField, relativeTo: SchemaHeaderField, before: boolean, columnsValues: SchemaHeaderField[]) => void;
-    changeColumns: (oldKey: string, newKey: string, addNew: boolean) => void;
-    setHeaderIsEditing: (isEditing: boolean) => void;
-    changeColumnSort: (columnField: SchemaHeaderField, descending: boolean | undefined) => void;
-}
-
-@observer
-export class SchemaTable extends React.Component<SchemaTableProps> {
-    @observable _cellIsEditing: boolean = false;
-    @observable _focusedCell: { row: number; col: number } = { row: 0, col: 0 };
-    @observable _openCollections: Set<number> = new Set();
-
-    @observable _showDoc: Doc | undefined;
-    @observable _showDataDoc: any = '';
-    @observable _showDocPos: number[] = [];
-
-    @observable _showTitleDropdown: boolean = false;
-
-    @computed get previewWidth() {
-        return () => NumCast(this.props.Document.schemaPreviewWidth);
-    }
-    @computed get previewHeight() {
-        return () => this.props.PanelHeight() - 2 * this.borderWidth;
-    }
-    @computed get tableWidth() {
-        return this.props.PanelWidth() - 2 * this.borderWidth - Number(SCHEMA_DIVIDER_WIDTH) - this.previewWidth();
-    }
-
-    @computed get childDocs() {
-        if (this.props.childDocs) return this.props.childDocs;
-
-        const doc = this.props.dataDoc ? this.props.dataDoc : this.props.Document;
-        return DocListCast(doc[this.props.fieldKey]);
-    }
-    set childDocs(docs: Doc[]) {
-        const doc = this.props.dataDoc ? this.props.dataDoc : this.props.Document;
-        doc[this.props.fieldKey] = new List<Doc>(docs);
-    }
-
-    @computed get textWrappedRows() {
-        return Cast(this.props.Document.textwrappedSchemaRows, listSpec('string'), []);
-    }
-    set textWrappedRows(textWrappedRows: string[]) {
-        this.props.Document.textwrappedSchemaRows = new List<string>(textWrappedRows);
-    }
-
-    @computed get resized(): { id: string; value: number }[] {
-        return this.props.columns.reduce((resized, shf) => {
-            shf.width > -1 && resized.push({ id: shf.heading, value: shf.width });
-            return resized;
-        }, [] as { id: string; value: number }[]);
-    }
-    @computed get sorted(): SortingRule[] {
-        return this.props.columns.reduce((sorted, shf) => {
-            shf.desc !== undefined && sorted.push({ id: shf.heading, desc: shf.desc });
-            return sorted;
-        }, [] as SortingRule[]);
-    }
-
-    @action
-    changeSorting = (col: any) => {
-        this.props.changeColumnSort(col, col.desc === true ? false : col.desc === false ? undefined : true);
-    };
-
-    @action
-    changeTitleMode = () => (this._showTitleDropdown = !this._showTitleDropdown);
-
-    @computed get borderWidth() {
-        return Number(COLLECTION_BORDER_WIDTH);
-    }
-    @computed get tableColumns(): Column<Doc>[] {
-        const possibleKeys = this.props.documentKeys.filter(key => this.props.columns.findIndex(existingKey => existingKey.heading.toUpperCase() === key.toUpperCase()) === -1);
-        const columns: Column<Doc>[] = [];
-        const tableIsFocused = this.props.isFocused(this.props.Document, false);
-        const focusedRow = this._focusedCell.row;
-        const focusedCol = this._focusedCell.col;
-        const isEditable = !this.props.headerIsEditing;
-
-        columns.push({
-            expander: true,
-            Header: '',
-            width: 58,
-            Expander: rowInfo => {
-                return rowInfo.original.type !== DocumentType.COL ? null : (
-                    <div className="collectionSchemaView-expander" onClick={action(() => this._openCollections[rowInfo.isExpanded ? 'delete' : 'add'](rowInfo.viewIndex))}>
-                        <FontAwesomeIcon icon={rowInfo.isExpanded ? 'caret-down' : 'caret-right'} size="lg" />
-                    </div>
-                );
-            },
-        });
-        columns.push(
-            ...this.props.columns.map(col => {
-                const icon: IconProp =
-                    this.getColumnType(col) === ColumnType.Number
-                        ? 'hashtag'
-                        : this.getColumnType(col) === ColumnType.String
-                        ? 'font'
-                        : this.getColumnType(col) === ColumnType.Boolean
-                        ? 'check-square'
-                        : this.getColumnType(col) === ColumnType.Doc
-                        ? 'file'
-                        : this.getColumnType(col) === ColumnType.Image
-                        ? 'image'
-                        : this.getColumnType(col) === ColumnType.List
-                        ? 'list-ul'
-                        : this.getColumnType(col) === ColumnType.Date
-                        ? 'calendar'
-                        : 'align-justify';
-
-                const keysDropdown = (
-                    <KeysDropdown
-                        keyValue={col.heading}
-                        possibleKeys={possibleKeys}
-                        existingKeys={this.props.columns.map(c => c.heading)}
-                        canAddNew={true}
-                        addNew={false}
-                        onSelect={this.props.changeColumns}
-                        setIsEditing={this.props.setHeaderIsEditing}
-                        docs={this.props.childDocs}
-                        Document={this.props.Document}
-                        dataDoc={this.props.dataDoc}
-                        fieldKey={this.props.fieldKey}
-                        ContainingCollectionDoc={this.props.ContainingCollectionDoc}
-                        ContainingCollectionView={this.props.ContainingCollectionView}
-                        active={this.props.active}
-                        openHeader={this.props.openHeader}
-                        icon={icon}
-                        col={col}
-                        // try commenting this out
-                        width={'100%'}
-                    />
-                );
-
-                const sortIcon = col.desc === undefined ? 'caret-right' : col.desc === true ? 'caret-down' : 'caret-up';
-                const header = (
-                    <div className="collectionSchemaView-menuOptions-wrapper" style={{ background: col.color, padding: '2px', display: 'flex', cursor: 'default', height: '100%' }}>
-                        {keysDropdown}
-                        <div onClick={e => this.changeSorting(col)} style={{ width: 21, padding: 1, display: 'inline', zIndex: 1, background: 'inherit', cursor: 'pointer' }}>
-                            <FontAwesomeIcon icon={sortIcon} size="lg" />
-                        </div>
-                        {/* {this.props.Document._chromeHidden || this.props.addDocument == returnFalse ? undefined : <div className="collectionSchemaView-addRow" onClick={this.createRow}>+ new</div>} */}
-                    </div>
-                );
-
-                return {
-                    Header: <MovableColumn columnRenderer={header} columnValue={col} allColumns={this.props.columns} reorderColumns={this.props.reorderColumns} ScreenToLocalTransform={this.props.ScreenToLocalTransform} />,
-                    accessor: (doc: Doc) => (doc ? Field.toString(doc[col.heading] as Field) : 0),
-                    id: col.heading,
-                    Cell: (rowProps: CellInfo) => {
-                        const rowIndex = rowProps.index;
-                        const columnIndex = this.props.columns.map(c => c.heading).indexOf(rowProps.column.id!);
-                        const isFocused = focusedRow === rowIndex && focusedCol === columnIndex && tableIsFocused;
-
-                        const props: CellProps = {
-                            row: rowIndex,
-                            col: columnIndex,
-                            rowProps: rowProps,
-                            isFocused: isFocused,
-                            changeFocusedCellByIndex: this.changeFocusedCellByIndex,
-                            CollectionView: this.props.CollectionView,
-                            ContainingCollection: this.props.ContainingCollectionView,
-                            Document: this.props.Document,
-                            fieldKey: this.props.fieldKey,
-                            renderDepth: this.props.renderDepth,
-                            addDocTab: this.props.addDocTab,
-                            pinToPres: this.props.pinToPres,
-                            moveDocument: this.props.moveDocument,
-                            setIsEditing: this.setCellIsEditing,
-                            isEditable: isEditable,
-                            setPreviewDoc: this.props.setPreviewDoc,
-                            setComputed: this.setComputed,
-                            getField: this.getField,
-                            showDoc: this.showDoc,
-                        };
-
-                        switch (this.getColumnType(col, rowProps.original, rowProps.column.id)) {
-                            case ColumnType.Number:
-                                return <CollectionSchemaNumberCell {...props} />;
-                            case ColumnType.String:
-                                return <CollectionSchemaStringCell {...props} />;
-                            case ColumnType.Boolean:
-                                return <CollectionSchemaCheckboxCell {...props} />;
-                            case ColumnType.Doc:
-                                return <CollectionSchemaDocCell {...props} />;
-                            case ColumnType.Image:
-                                return <CollectionSchemaImageCell {...props} />;
-                            case ColumnType.List:
-                                return <CollectionSchemaListCell {...props} />;
-                            case ColumnType.Date:
-                                return <CollectionSchemaDateCell {...props} />;
-                            default:
-                                return <CollectionSchemaCell {...props} />;
-                        }
-                    },
-                    minWidth: 200,
-                };
-            })
-        );
-        columns.push({
-            Header: <CollectionSchemaAddColumnHeader createColumn={this.createColumn} />,
-            accessor: (doc: Doc) => 0,
-            id: 'add',
-            Cell: (rowProps: CellInfo) => {
-                const rowIndex = rowProps.index;
-                const columnIndex = this.props.columns.map(c => c.heading).indexOf(rowProps.column.id!);
-                const isFocused = focusedRow === rowIndex && focusedCol === columnIndex && tableIsFocused;
-                return (
-                    <CollectionSchemaButtons
-                        {...{
-                            row: rowProps.index,
-                            col: columnIndex,
-                            rowProps: rowProps,
-                            isFocused: isFocused,
-                            changeFocusedCellByIndex: this.changeFocusedCellByIndex,
-                            CollectionView: this.props.CollectionView,
-                            ContainingCollection: this.props.ContainingCollectionView,
-                            Document: this.props.Document,
-                            fieldKey: this.props.fieldKey,
-                            renderDepth: this.props.renderDepth,
-                            addDocTab: this.props.addDocTab,
-                            pinToPres: this.props.pinToPres,
-                            moveDocument: this.props.moveDocument,
-                            setIsEditing: this.setCellIsEditing,
-                            isEditable: isEditable,
-                            setPreviewDoc: this.props.setPreviewDoc,
-                            setComputed: this.setComputed,
-                            getField: this.getField,
-                            showDoc: this.showDoc,
-                        }}
-                    />
-                );
-            },
-            width: 28,
-            resizable: false,
-        });
-        return columns;
-    }
-
-    constructor(props: SchemaTableProps) {
-        super(props);
-        if (this.props.Document._schemaHeaders === undefined) {
-            this.props.Document._schemaHeaders = new List<SchemaHeaderField>([
-                new SchemaHeaderField('title', '#f1efeb'),
-                new SchemaHeaderField('author', '#f1efeb'),
-                new SchemaHeaderField('*lastModified', '#f1efeb', ColumnType.Date),
-                new SchemaHeaderField('text', '#f1efeb', ColumnType.String),
-                new SchemaHeaderField('type', '#f1efeb'),
-                new SchemaHeaderField('context', '#f1efeb', ColumnType.Doc),
-            ]);
-        }
-    }
-
-    componentDidMount() {
-        document.addEventListener('keydown', this.onKeyDown);
-    }
-
-    componentWillUnmount() {
-        document.removeEventListener('keydown', this.onKeyDown);
-    }
-
-    tableAddDoc = (doc: Doc, relativeTo?: Doc, before?: boolean) => {
-        const tableDoc = this.props.Document[DataSym];
-        const effectiveAcl = GetEffectiveAcl(tableDoc);
-
-        if (effectiveAcl !== AclPrivate && effectiveAcl !== AclReadonly) {
-            doc.context = this.props.Document;
-            tableDoc[this.props.fieldKey + '-lastModified'] = new DateField(new Date(Date.now()));
-            return Doc.AddDocToList(this.props.Document, this.props.fieldKey, doc, relativeTo, before);
-        }
-        return false;
-    };
-
-    private getTrProps: ComponentPropsGetterR = (state, rowInfo) => {
-        return !rowInfo
-            ? {}
-            : {
-                  ScreenToLocalTransform: this.props.ScreenToLocalTransform,
-                  addDoc: this.tableAddDoc,
-                  removeDoc: this.props.deleteDocument,
-                  rowInfo,
-                  rowFocused: !this.props.headerIsEditing && rowInfo.index === this._focusedCell.row && this.props.isFocused(this.props.Document, true),
-                  textWrapRow: this.toggleTextWrapRow,
-                  rowWrapped: this.textWrappedRows.findIndex(id => rowInfo.original[Id] === id) > -1,
-                  dropAction: StrCast(this.props.Document.childDropAction),
-                  addDocTab: this.props.addDocTab,
-              };
-    };
-
-    private getTdProps: ComponentPropsGetterR = (state, rowInfo, column, instance) => {
-        if (!rowInfo || column) return {};
-
-        const row = rowInfo.index;
-        //@ts-ignore
-        const col = this.columns.map(c => c.heading).indexOf(column!.id);
-        const isFocused = this._focusedCell.row === row && this._focusedCell.col === col && this.props.isFocused(this.props.Document, true);
-        // TODO: editing border doesn't work :(
-        return {
-            style: { border: !this.props.headerIsEditing && isFocused ? '2px solid rgb(255, 160, 160)' : '1px solid #f1efeb' },
-        };
-    };
-
-    @action setCellIsEditing = (isEditing: boolean) => (this._cellIsEditing = isEditing);
-
-    @action
-    onKeyDown = (e: KeyboardEvent): void => {
-        if (!this._cellIsEditing && !this.props.headerIsEditing && this.props.isFocused(this.props.Document, true)) {
-            // && this.props.isSelected(true)) {
-            const direction = e.key === 'Tab' ? 'tab' : e.which === 39 ? 'right' : e.which === 37 ? 'left' : e.which === 38 ? 'up' : e.which === 40 ? 'down' : '';
-            this._focusedCell = this.changeFocusedCellByDirection(direction, this._focusedCell.row, this._focusedCell.col);
-
-            if (direction) {
-                const pdoc = FieldValue(this.childDocs[this._focusedCell.row]);
-                pdoc && this.props.setPreviewDoc(pdoc);
-                e.stopPropagation();
-            }
-        } else if (e.keyCode === 27) {
-            this.props.setPreviewDoc(undefined);
-            e.stopPropagation(); // stopPropagation for left/right arrows
-        }
-    };
-
-    changeFocusedCellByDirection = (direction: string, curRow: number, curCol: number) => {
-        switch (direction) {
-            case 'tab':
-                return { row: curRow + 1 === this.childDocs.length ? 0 : curRow + 1, col: curCol + 1 === this.props.columns.length ? 0 : curCol + 1 };
-            case 'right':
-                return { row: curRow, col: curCol + 1 === this.props.columns.length ? curCol : curCol + 1 };
-            case 'left':
-                return { row: curRow, col: curCol === 0 ? curCol : curCol - 1 };
-            case 'up':
-                return { row: curRow === 0 ? curRow : curRow - 1, col: curCol };
-            case 'down':
-                return { row: curRow + 1 === this.childDocs.length ? curRow : curRow + 1, col: curCol };
-        }
-        return this._focusedCell;
-    };
-
-    @action
-    changeFocusedCellByIndex = (row: number, col: number): void => {
-        if (this._focusedCell.row !== row || this._focusedCell.col !== col) {
-            this._focusedCell = { row: row, col: col };
-        }
-        this.props.setFocused(this.props.Document);
-    };
-
-    @undoBatch
-    createRow = action(() => {
-        this.props.addDocument?.(Docs.Create.TextDocument('', { title: '', _width: 100, _height: 30 }));
-        this._focusedCell = { row: this.childDocs.length, col: this._focusedCell.col };
-    });
-
-    @undoBatch
-    @action
-    createColumn = () => {
-        const newFieldName = (index: number) => `New field${index ? ` (${index})` : ''}`;
-        for (let index = 0; index < 100; index++) {
-            if (this.props.columns.findIndex(col => col.heading === newFieldName(index)) === -1) {
-                this.props.columns.push(new SchemaHeaderField(newFieldName(index), '#f1efeb'));
-                break;
-            }
-        }
-    };
-
-    @action
-    getColumnType = (column: SchemaHeaderField, doc?: Doc, field?: string): ColumnType => {
-        if (doc && field && column.type === ColumnType.Any) {
-            const val = doc[CollectionSchemaCell.resolvedFieldKey(field, doc)];
-            if (val instanceof ImageField) return ColumnType.Image;
-            if (val instanceof Doc) return ColumnType.Doc;
-            if (val instanceof DateField) return ColumnType.Date;
-            if (val instanceof List) return ColumnType.List;
-        }
-        if (column.type && column.type !== 0) {
-            return column.type;
-        }
-        if (columnTypes.get(column.heading)) {
-            return (column.type = columnTypes.get(column.heading)!);
-        }
-        return (column.type = ColumnType.Any);
-    };
-
-    @undoBatch
-    @action
-    toggleTextwrap = async () => {
-        const textwrappedRows = Cast(this.props.Document.textwrappedSchemaRows, listSpec('string'), []);
-        if (textwrappedRows.length) {
-            this.props.Document.textwrappedSchemaRows = new List<string>([]);
-        } else {
-            const docs = DocListCast(this.props.Document[this.props.fieldKey]);
-            const allRows = docs instanceof Doc ? [docs[Id]] : docs.map(doc => doc[Id]);
-            this.props.Document.textwrappedSchemaRows = new List<string>(allRows);
-        }
-    };
-
-    @action
-    toggleTextWrapRow = (doc: Doc): void => {
-        const textWrapped = this.textWrappedRows;
-        const index = textWrapped.findIndex(id => doc[Id] === id);
-
-        index > -1 ? textWrapped.splice(index, 1) : textWrapped.push(doc[Id]);
-
-        this.textWrappedRows = textWrapped;
-    };
-
-    @computed
-    get reactTable() {
-        const children = this.childDocs;
-        const hasCollectionChild = children.reduce((found, doc) => found || doc.type === DocumentType.COL, false);
-        const expanded: { [name: string]: any } = {};
-        Array.from(this._openCollections.keys()).map(col => (expanded[col.toString()] = true));
-        const rerender = [...this.textWrappedRows]; // TODO: get component to rerender on text wrap change without needign to console.log :((((
-
-        return (
-            <ReactTable
-                style={{ position: 'relative' }}
-                data={children}
-                page={0}
-                pageSize={children.length}
-                showPagination={false}
-                columns={this.tableColumns}
-                getTrProps={this.getTrProps}
-                getTdProps={this.getTdProps}
-                sortable={false}
-                TrComponent={MovableRow}
-                sorted={this.sorted}
-                expanded={expanded}
-                resized={this.resized}
-                onResizedChange={this.props.onResizedChange}
-                // if it has a child, render another table with the children
-                SubComponent={
-                    !hasCollectionChild
-                        ? undefined
-                        : row =>
-                              row.original.type !== DocumentType.COL ? null : (
-                                  <div style={{ paddingLeft: 57 + 'px' }} className="reactTable-sub">
-                                      <SchemaTable {...this.props} Document={row.original} dataDoc={undefined} childDocs={undefined} />
-                                  </div>
-                              )
-                }
-            />
-        );
-    }
-
-    onContextMenu = (e: React.MouseEvent): void => {
-        ContextMenu.Instance.addItem({ description: 'Toggle text wrapping', event: this.toggleTextwrap, icon: 'table' });
-    };
-
-    getField = (row: number, col?: number) => {
-        const docs = this.childDocs;
-
-        row = row % docs.length;
-        while (row < 0) row += docs.length;
-        const columns = this.props.columns;
-        const doc = docs[row];
-        if (col === undefined) {
-            return doc;
-        }
-        if (col >= 0 && col < columns.length) {
-            const column = this.props.columns[col].heading;
-            return doc[column];
-        }
-        return undefined;
-    };
-
-    createTransformer = (row: number, col: number): Transformer => {
-        const self = this;
-        const captures: { [name: string]: Field } = {};
-
-        const transformer: ts.TransformerFactory<ts.SourceFile> = context => {
-            return root => {
-                function visit(node: ts.Node) {
-                    node = ts.visitEachChild(node, visit, context);
-                    if (ts.isIdentifier(node)) {
-                        const isntPropAccess = !ts.isPropertyAccessExpression(node.parent) || node.parent.expression === node;
-                        const isntPropAssign = !ts.isPropertyAssignment(node.parent) || node.parent.name !== node;
-                        if (isntPropAccess && isntPropAssign) {
-                            if (node.text === '$r') {
-                                return ts.createNumericLiteral(row.toString());
-                            } else if (node.text === '$c') {
-                                return ts.createNumericLiteral(col.toString());
-                            } else if (node.text === '$') {
-                                if (ts.isCallExpression(node.parent)) {
-                                    // captures.doc = self.props.Document;
-                                    // captures.key = self.props.fieldKey;
-                                }
-                            }
-                        }
-                    }
-
-                    return node;
-                }
-                return ts.visitNode(root, visit);
-            };
-        };
-
-        // const getVars = () => {
-        //     return { capturedVariables: captures };
-        // };
-
-        return { transformer /*getVars*/ };
-    };
-
-    setComputed = (script: string, doc: Doc, field: string, row: number, col: number): boolean => {
-        script = `const $ = (row:number, col?:number) => {
-                const rval = (doc as any)[key][row + ${row}];
-                return col === undefined ? rval : rval[(doc as any)._schemaHeaders[col + ${col}].heading];
-            }
-            return ${script}`;
-        const compiled = CompileScript(script, { params: { this: Doc.name }, capturedVariables: { doc: this.props.Document, key: this.props.fieldKey }, typecheck: false, transformer: this.createTransformer(row, col) });
-        if (compiled.compiled) {
-            doc[field] = new ComputedField(compiled);
-            return true;
-        }
-        return false;
-    };
-
-    @action
-    showDoc = (doc: Doc | undefined, dataDoc?: Doc, screenX?: number, screenY?: number) => {
-        this._showDoc = doc;
-        if (dataDoc && screenX && screenY) {
-            this._showDocPos = this.props.ScreenToLocalTransform().transformPoint(screenX, screenY);
-        }
-    };
-
-    onOpenClick = () => {
-        this._showDoc && this.props.addDocTab(this._showDoc, OpenWhere.addRight);
-    };
-
-    getPreviewTransform = (): Transform => {
-        return this.props.ScreenToLocalTransform().translate(-this.borderWidth - 4 - this.tableWidth, -this.borderWidth);
-    };
-
-    render() {
-        const preview = '';
-        return (
-            <div
-                className="collectionSchemaView-table"
-                onPointerDown={this.props.onPointerDown}
-                onClick={this.props.onClick}
-                onWheel={e => this.props.active(true) && e.stopPropagation()}
-                onDrop={e => this.props.onDrop(e, {})}
-                onContextMenu={this.onContextMenu}>
-                {this.reactTable}
-                {this.props.Document._chromeHidden || this.props.addDocument === returnFalse ? undefined : (
-                    <div className="collectionSchemaView-addRow" onClick={this.createRow}>
-                        + new
-                    </div>
-                )}
-                {!this._showDoc ? null : (
-                    <div
-                        className="collectionSchemaView-documentPreview"
-                        ref="overlay"
-                        style={{
-                            position: 'absolute',
-                            width: 150,
-                            height: 150,
-                            background: 'dimgray',
-                            display: 'block',
-                            top: 0,
-                            left: 0,
-                            transform: `translate(${this._showDocPos[0]}px, ${this._showDocPos[1] - 180}px)`,
-                        }}>
-                        <DocumentView
-                            Document={this._showDoc}
-                            DataDoc={this._showDataDoc}
-                            styleProvider={DefaultStyleProvider}
-                            docViewPath={returnEmptyDoclist}
-                            focus={DocUtils.DefaultFocus}
-                            renderDepth={this.props.renderDepth}
-                            rootSelected={returnFalse}
-                            isContentActive={returnTrue}
-                            isDocumentActive={returnFalse}
-                            PanelWidth={() => 150}
-                            PanelHeight={() => 150}
-                            ScreenToLocalTransform={this.getPreviewTransform}
-                            docFilters={returnEmptyFilter}
-                            docRangeFilters={returnEmptyFilter}
-                            searchFilterDocs={returnEmptyDoclist}
-                            ContainingCollectionDoc={this.props.CollectionView?.props.Document}
-                            ContainingCollectionView={this.props.CollectionView}
-                            moveDocument={this.props.moveDocument}
-                            whenChildContentsActiveChanged={emptyFunction}
-                            addDocTab={this.props.addDocTab}
-                            pinToPres={this.props.pinToPres}
-                            bringToFront={returnFalse}></DocumentView>
-                    </div>
-                )}
-            </div>
-        );
-    }
-}
+// import { IconProp } from '@fortawesome/fontawesome-svg-core';
+// import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+// import { action, computed, observable } from 'mobx';
+// import { observer } from 'mobx-react';
+// import * as React from 'react';
+// import ReactTable, { CellInfo, Column, ComponentPropsGetterR, Resize, SortingRule } from 'react-table';
+// import { DateField } from '../../../../fields/DateField';
+// import { AclPrivate, AclReadonly, DataSym, Doc, DocListCast, Field, Opt } from '../../../../fields/Doc';
+// import { Id } from '../../../../fields/FieldSymbols';
+// import { List } from '../../../../fields/List';
+// import { listSpec } from '../../../../fields/Schema';
+// import { SchemaHeaderField } from '../../../../fields/SchemaHeaderField';
+// import { ComputedField } from '../../../../fields/ScriptField';
+// import { Cast, FieldValue, NumCast, StrCast } from '../../../../fields/Types';
+// import { ImageField } from '../../../../fields/URLField';
+// import { GetEffectiveAcl } from '../../../../fields/util';
+// import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue } from '../../../../Utils';
+// import { Docs, DocumentOptions, DocUtils } from '../../../documents/Documents';
+// import { DocumentType } from '../../../documents/DocumentTypes';
+// import { CompileScript, Transformer, ts } from '../../../util/Scripting';
+// import { Transform } from '../../../util/Transform';
+// import { undoBatch } from '../../../util/UndoManager';
+// import '../../../views/DocumentDecorations.scss';
+// import { ContextMenu } from '../../ContextMenu';
+// import { COLLECTION_BORDER_WIDTH, SCHEMA_DIVIDER_WIDTH } from '../../global/globalCssVariables.scss';
+// import { DocumentView, OpenWhere } from '../../nodes/DocumentView';
+// import { PinProps } from '../../nodes/trails';
+// import { DefaultStyleProvider } from '../../StyleProvider';
+// import { CollectionView } from '../CollectionView';
+// import {
+//     CellProps,
+//     CollectionSchemaButtons,
+//     CollectionSchemaCell,
+//     CollectionSchemaCheckboxCell,
+//     CollectionSchemaDateCell,
+//     CollectionSchemaDocCell,
+//     CollectionSchemaImageCell,
+//     CollectionSchemaListCell,
+//     CollectionSchemaNumberCell,
+//     CollectionSchemaStringCell,
+// } from './CollectionSchemaCells';
+// import { CollectionSchemaAddColumnHeader, KeysDropdown } from './CollectionSchemaHeaders';
+// import { MovableColumn } from './OldCollectionSchemaMovableColumn';
+// import { MovableRow } from './CollectionSchemaMovableRow';
+// import './CollectionSchemaView.scss';
+
+// enum ColumnType {
+//     Any,
+//     Number,
+//     String,
+//     Boolean,
+//     Doc,
+//     Image,
+//     List,
+//     Date,
+// }
+
+// // this map should be used for keys that should have a const type of value
+// const columnTypes: Map<string, ColumnType> = new Map([
+//     ['title', ColumnType.String],
+//     ['x', ColumnType.Number],
+//     ['y', ColumnType.Number],
+//     ['_width', ColumnType.Number],
+//     ['_height', ColumnType.Number],
+//     ['_nativeWidth', ColumnType.Number],
+//     ['_nativeHeight', ColumnType.Number],
+//     ['isPrototype', ColumnType.Boolean],
+//     ['_curPage', ColumnType.Number],
+//     ['_currentTimecode', ColumnType.Number],
+//     ['zIndex', ColumnType.Number],
+// ]);
+
+// export interface SchemaTableProps {
+//     Document: Doc; // child doc
+//     dataDoc?: Doc;
+//     PanelHeight: () => number;
+//     PanelWidth: () => number;
+//     childDocs?: Doc[];
+//     CollectionView: Opt<CollectionView>;
+//     ContainingCollectionView: Opt<CollectionView>;
+//     ContainingCollectionDoc: Opt<Doc>;
+//     fieldKey: string;
+//     renderDepth: number;
+//     deleteDocument?: (document: Doc | Doc[]) => boolean;
+//     addDocument?: (document: Doc | Doc[]) => boolean;
+//     moveDocument?: (document: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => boolean;
+//     ScreenToLocalTransform: () => Transform;
+//     active: (outsideReaction: boolean | undefined) => boolean | undefined;
+//     onDrop: (e: React.DragEvent<Element>, options: DocumentOptions, completed?: (() => void) | undefined) => void;
+//     addDocTab: (document: Doc, where: OpenWhere) => boolean;
+//     pinToPres: (document: Doc, pinProps: PinProps) => void;
+//     isSelected: (outsideReaction?: boolean) => boolean;
+//     isFocused: (document: Doc, outsideReaction: boolean) => boolean;
+//     setFocused: (document: Doc) => void;
+//     setPreviewDoc: (document: Opt<Doc>) => void;
+//     columns: SchemaHeaderField[];
+//     documentKeys: any[];
+//     headerIsEditing: boolean;
+//     openHeader: (column: any, screenx: number, screeny: number) => void;
+//     onClick: (e: React.MouseEvent) => void;
+//     onPointerDown: (e: React.PointerEvent) => void;
+//     onResizedChange: (newResized: Resize[], event: any) => void;
+//     setColumns: (columns: SchemaHeaderField[]) => void;
+//     reorderColumns: (toMove: SchemaHeaderField, relativeTo: SchemaHeaderField, before: boolean, columnsValues: SchemaHeaderField[]) => void;
+//     changeColumns: (oldKey: string, newKey: string, addNew: boolean) => void;
+//     setHeaderIsEditing: (isEditing: boolean) => void;
+//     changeColumnSort: (columnField: SchemaHeaderField, descending: boolean | undefined) => void;
+// }
+
+// @observer
+// export class SchemaTable extends React.Component<SchemaTableProps> {
+//     @observable _cellIsEditing: boolean = false;
+//     @observable _focusedCell: { row: number; col: number } = { row: 0, col: 0 };
+//     @observable _openCollections: Set<number> = new Set();
+
+//     @observable _showDoc: Doc | undefined;
+//     @observable _showDataDoc: any = '';
+//     @observable _showDocPos: number[] = [];
+
+//     @observable _showTitleDropdown: boolean = false;
+
+//     @computed get previewWidth() {
+//         return () => NumCast(this.props.Document.schemaPreviewWidth);
+//     }
+//     @computed get previewHeight() {
+//         return () => this.props.PanelHeight() - 2 * this.borderWidth;
+//     }
+//     @computed get tableWidth() {
+//         return this.props.PanelWidth() - 2 * this.borderWidth - Number(SCHEMA_DIVIDER_WIDTH) - this.previewWidth();
+//     }
+
+//     @computed get childDocs() {
+//         if (this.props.childDocs) return this.props.childDocs;
+
+//         const doc = this.props.dataDoc ? this.props.dataDoc : this.props.Document;
+//         return DocListCast(doc[this.props.fieldKey]);
+//     }
+//     set childDocs(docs: Doc[]) {
+//         const doc = this.props.dataDoc ? this.props.dataDoc : this.props.Document;
+//         doc[this.props.fieldKey] = new List<Doc>(docs);
+//     }
+
+//     @computed get textWrappedRows() {
+//         return Cast(this.props.Document.textwrappedSchemaRows, listSpec('string'), []);
+//     }
+//     set textWrappedRows(textWrappedRows: string[]) {
+//         this.props.Document.textwrappedSchemaRows = new List<string>(textWrappedRows);
+//     }
+
+//     @computed get resized(): { id: string; value: number }[] {
+//         return this.props.columns.reduce((resized, shf) => {
+//             shf.width > -1 && resized.push({ id: shf.heading, value: shf.width });
+//             return resized;
+//         }, [] as { id: string; value: number }[]);
+//     }
+//     @computed get sorted(): SortingRule[] {
+//         return this.props.columns.reduce((sorted, shf) => {
+//             shf.desc !== undefined && sorted.push({ id: shf.heading, desc: shf.desc });
+//             return sorted;
+//         }, [] as SortingRule[]);
+//     }
+
+//     @action
+//     changeSorting = (col: any) => {
+//         this.props.changeColumnSort(col, col.desc === true ? false : col.desc === false ? undefined : true);
+//     };
+
+//     @action
+//     changeTitleMode = () => (this._showTitleDropdown = !this._showTitleDropdown);
+
+//     @computed get borderWidth() {
+//         return Number(COLLECTION_BORDER_WIDTH);
+//     }
+//     @computed get tableColumns(): Column<Doc>[] {
+//         const possibleKeys = this.props.documentKeys.filter(key => this.props.columns.findIndex(existingKey => existingKey.heading.toUpperCase() === key.toUpperCase()) === -1);
+//         const columns: Column<Doc>[] = [];
+//         const tableIsFocused = this.props.isFocused(this.props.Document, false);
+//         const focusedRow = this._focusedCell.row;
+//         const focusedCol = this._focusedCell.col;
+//         const isEditable = !this.props.headerIsEditing;
+
+//         columns.push({
+//             expander: true,
+//             Header: '',
+//             width: 58,
+//             Expander: rowInfo => {
+//                 return rowInfo.original.type !== DocumentType.COL ? null : (
+//                     <div className="collectionSchemaView-expander" onClick={action(() => this._openCollections[rowInfo.isExpanded ? 'delete' : 'add'](rowInfo.viewIndex))}>
+//                         <FontAwesomeIcon icon={rowInfo.isExpanded ? 'caret-down' : 'caret-right'} size="lg" />
+//                     </div>
+//                 );
+//             },
+//         });
+//         columns.push(
+//             ...this.props.columns.map(col => {
+//                 const icon: IconProp =
+//                     this.getColumnType(col) === ColumnType.Number
+//                         ? 'hashtag'
+//                         : this.getColumnType(col) === ColumnType.String
+//                         ? 'font'
+//                         : this.getColumnType(col) === ColumnType.Boolean
+//                         ? 'check-square'
+//                         : this.getColumnType(col) === ColumnType.Doc
+//                         ? 'file'
+//                         : this.getColumnType(col) === ColumnType.Image
+//                         ? 'image'
+//                         : this.getColumnType(col) === ColumnType.List
+//                         ? 'list-ul'
+//                         : this.getColumnType(col) === ColumnType.Date
+//                         ? 'calendar'
+//                         : 'align-justify';
+
+//                 const keysDropdown = (
+//                     <KeysDropdown
+//                         keyValue={col.heading}
+//                         possibleKeys={possibleKeys}
+//                         existingKeys={this.props.columns.map(c => c.heading)}
+//                         canAddNew={true}
+//                         addNew={false}
+//                         onSelect={this.props.changeColumns}
+//                         setIsEditing={this.props.setHeaderIsEditing}
+//                         docs={this.props.childDocs}
+//                         Document={this.props.Document}
+//                         dataDoc={this.props.dataDoc}
+//                         fieldKey={this.props.fieldKey}
+//                         ContainingCollectionDoc={this.props.ContainingCollectionDoc}
+//                         ContainingCollectionView={this.props.ContainingCollectionView}
+//                         active={this.props.active}
+//                         openHeader={this.props.openHeader}
+//                         icon={icon}
+//                         col={col}
+//                         // try commenting this out
+//                         width={'100%'}
+//                     />
+//                 );
+
+//                 const sortIcon = col.desc === undefined ? 'caret-right' : col.desc === true ? 'caret-down' : 'caret-up';
+//                 const header = (
+//                     <div className="collectionSchemaView-menuOptions-wrapper" style={{ background: col.color, padding: '2px', display: 'flex', cursor: 'default', height: '100%' }}>
+//                         {keysDropdown}
+//                         <div onClick={e => this.changeSorting(col)} style={{ width: 21, padding: 1, display: 'inline', zIndex: 1, background: 'inherit', cursor: 'pointer' }}>
+//                             <FontAwesomeIcon icon={sortIcon} size="lg" />
+//                         </div>
+//                         {/* {this.props.Document._chromeHidden || this.props.addDocument == returnFalse ? undefined : <div className="collectionSchemaView-addRow" onClick={this.createRow}>+ new</div>} */}
+//                     </div>
+//                 );
+
+//                 return {
+//                     Header: <MovableColumn columnRenderer={header} columnValue={col} allColumns={this.props.columns} reorderColumns={this.props.reorderColumns} ScreenToLocalTransform={this.props.ScreenToLocalTransform} />,
+//                     accessor: (doc: Doc) => (doc ? Field.toString(doc[col.heading] as Field) : 0),
+//                     id: col.heading,
+//                     Cell: (rowProps: CellInfo) => {
+//                         const rowIndex = rowProps.index;
+//                         const columnIndex = this.props.columns.map(c => c.heading).indexOf(rowProps.column.id!);
+//                         const isFocused = focusedRow === rowIndex && focusedCol === columnIndex && tableIsFocused;
+
+//                         const props: CellProps = {
+//                             row: rowIndex,
+//                             col: columnIndex,
+//                             rowProps: rowProps,
+//                             isFocused: isFocused,
+//                             changeFocusedCellByIndex: this.changeFocusedCellByIndex,
+//                             CollectionView: this.props.CollectionView,
+//                             ContainingCollection: this.props.ContainingCollectionView,
+//                             Document: this.props.Document,
+//                             fieldKey: this.props.fieldKey,
+//                             renderDepth: this.props.renderDepth,
+//                             addDocTab: this.props.addDocTab,
+//                             pinToPres: this.props.pinToPres,
+//                             moveDocument: this.props.moveDocument,
+//                             setIsEditing: this.setCellIsEditing,
+//                             isEditable: isEditable,
+//                             setPreviewDoc: this.props.setPreviewDoc,
+//                             setComputed: this.setComputed,
+//                             getField: this.getField,
+//                             showDoc: this.showDoc,
+//                         };
+
+//                         switch (this.getColumnType(col, rowProps.original, rowProps.column.id)) {
+//                             case ColumnType.Number:
+//                                 return <CollectionSchemaNumberCell {...props} />;
+//                             case ColumnType.String:
+//                                 return <CollectionSchemaStringCell {...props} />;
+//                             case ColumnType.Boolean:
+//                                 return <CollectionSchemaCheckboxCell {...props} />;
+//                             case ColumnType.Doc:
+//                                 return <CollectionSchemaDocCell {...props} />;
+//                             case ColumnType.Image:
+//                                 return <CollectionSchemaImageCell {...props} />;
+//                             case ColumnType.List:
+//                                 return <CollectionSchemaListCell {...props} />;
+//                             case ColumnType.Date:
+//                                 return <CollectionSchemaDateCell {...props} />;
+//                             default:
+//                                 return <CollectionSchemaCell {...props} />;
+//                         }
+//                     },
+//                     minWidth: 200,
+//                 };
+//             })
+//         );
+//         columns.push({
+//             Header: <CollectionSchemaAddColumnHeader createColumn={this.createColumn} />,
+//             accessor: (doc: Doc) => 0,
+//             id: 'add',
+//             Cell: (rowProps: CellInfo) => {
+//                 const rowIndex = rowProps.index;
+//                 const columnIndex = this.props.columns.map(c => c.heading).indexOf(rowProps.column.id!);
+//                 const isFocused = focusedRow === rowIndex && focusedCol === columnIndex && tableIsFocused;
+//                 return (
+//                     <CollectionSchemaButtons
+//                         {...{
+//                             row: rowProps.index,
+//                             col: columnIndex,
+//                             rowProps: rowProps,
+//                             isFocused: isFocused,
+//                             changeFocusedCellByIndex: this.changeFocusedCellByIndex,
+//                             CollectionView: this.props.CollectionView,
+//                             ContainingCollection: this.props.ContainingCollectionView,
+//                             Document: this.props.Document,
+//                             fieldKey: this.props.fieldKey,
+//                             renderDepth: this.props.renderDepth,
+//                             addDocTab: this.props.addDocTab,
+//                             pinToPres: this.props.pinToPres,
+//                             moveDocument: this.props.moveDocument,
+//                             setIsEditing: this.setCellIsEditing,
+//                             isEditable: isEditable,
+//                             setPreviewDoc: this.props.setPreviewDoc,
+//                             setComputed: this.setComputed,
+//                             getField: this.getField,
+//                             showDoc: this.showDoc,
+//                         }}
+//                     />
+//                 );
+//             },
+//             width: 28,
+//             resizable: false,
+//         });
+//         return columns;
+//     }
+
+//     constructor(props: SchemaTableProps) {
+//         super(props);
+//         if (this.props.Document._schemaHeaders === undefined) {
+//             this.props.Document._schemaHeaders = new List<SchemaHeaderField>([
+//                 new SchemaHeaderField('title', '#f1efeb'),
+//                 new SchemaHeaderField('author', '#f1efeb'),
+//                 new SchemaHeaderField('*lastModified', '#f1efeb', ColumnType.Date),
+//                 new SchemaHeaderField('text', '#f1efeb', ColumnType.String),
+//                 new SchemaHeaderField('type', '#f1efeb'),
+//                 new SchemaHeaderField('context', '#f1efeb', ColumnType.Doc),
+//             ]);
+//         }
+//     }
+
+//     componentDidMount() {
+//         document.addEventListener('keydown', this.onKeyDown);
+//     }
+
+//     componentWillUnmount() {
+//         document.removeEventListener('keydown', this.onKeyDown);
+//     }
+
+//     tableAddDoc = (doc: Doc, relativeTo?: Doc, before?: boolean) => {
+//         const tableDoc = this.props.Document[DataSym];
+//         const effectiveAcl = GetEffectiveAcl(tableDoc);
+
+//         if (effectiveAcl !== AclPrivate && effectiveAcl !== AclReadonly) {
+//             doc.context = this.props.Document;
+//             tableDoc[this.props.fieldKey + '-lastModified'] = new DateField(new Date(Date.now()));
+//             return Doc.AddDocToList(this.props.Document, this.props.fieldKey, doc, relativeTo, before);
+//         }
+//         return false;
+//     };
+
+//     private getTrProps: ComponentPropsGetterR = (state, rowInfo) => {
+//         return !rowInfo
+//             ? {}
+//             : {
+//                   ScreenToLocalTransform: this.props.ScreenToLocalTransform,
+//                   addDoc: this.tableAddDoc,
+//                   removeDoc: this.props.deleteDocument,
+//                   rowInfo,
+//                   rowFocused: !this.props.headerIsEditing && rowInfo.index === this._focusedCell.row && this.props.isFocused(this.props.Document, true),
+//                   textWrapRow: this.toggleTextWrapRow,
+//                   rowWrapped: this.textWrappedRows.findIndex(id => rowInfo.original[Id] === id) > -1,
+//                   dropAction: StrCast(this.props.Document.childDropAction),
+//                   addDocTab: this.props.addDocTab,
+//               };
+//     };
+
+//     private getTdProps: ComponentPropsGetterR = (state, rowInfo, column, instance) => {
+//         if (!rowInfo || column) return {};
+
+//         const row = rowInfo.index;
+//         //@ts-ignore
+//         const col = this.columns.map(c => c.heading).indexOf(column!.id);
+//         const isFocused = this._focusedCell.row === row && this._focusedCell.col === col && this.props.isFocused(this.props.Document, true);
+//         // TODO: editing border doesn't work :(
+//         return {
+//             style: { border: !this.props.headerIsEditing && isFocused ? '2px solid rgb(255, 160, 160)' : '1px solid #f1efeb' },
+//         };
+//     };
+
+//     @action setCellIsEditing = (isEditing: boolean) => (this._cellIsEditing = isEditing);
+
+//     @action
+//     onKeyDown = (e: KeyboardEvent): void => {
+//         if (!this._cellIsEditing && !this.props.headerIsEditing && this.props.isFocused(this.props.Document, true)) {
+//             // && this.props.isSelected(true)) {
+//             const direction = e.key === 'Tab' ? 'tab' : e.which === 39 ? 'right' : e.which === 37 ? 'left' : e.which === 38 ? 'up' : e.which === 40 ? 'down' : '';
+//             this._focusedCell = this.changeFocusedCellByDirection(direction, this._focusedCell.row, this._focusedCell.col);
+
+//             if (direction) {
+//                 const pdoc = FieldValue(this.childDocs[this._focusedCell.row]);
+//                 pdoc && this.props.setPreviewDoc(pdoc);
+//                 e.stopPropagation();
+//             }
+//         } else if (e.keyCode === 27) {
+//             this.props.setPreviewDoc(undefined);
+//             e.stopPropagation(); // stopPropagation for left/right arrows
+//         }
+//     };
+
+//     changeFocusedCellByDirection = (direction: string, curRow: number, curCol: number) => {
+//         switch (direction) {
+//             case 'tab':
+//                 return { row: curRow + 1 === this.childDocs.length ? 0 : curRow + 1, col: curCol + 1 === this.props.columns.length ? 0 : curCol + 1 };
+//             case 'right':
+//                 return { row: curRow, col: curCol + 1 === this.props.columns.length ? curCol : curCol + 1 };
+//             case 'left':
+//                 return { row: curRow, col: curCol === 0 ? curCol : curCol - 1 };
+//             case 'up':
+//                 return { row: curRow === 0 ? curRow : curRow - 1, col: curCol };
+//             case 'down':
+//                 return { row: curRow + 1 === this.childDocs.length ? curRow : curRow + 1, col: curCol };
+//         }
+//         return this._focusedCell;
+//     };
+
+//     @action
+//     changeFocusedCellByIndex = (row: number, col: number): void => {
+//         if (this._focusedCell.row !== row || this._focusedCell.col !== col) {
+//             this._focusedCell = { row: row, col: col };
+//         }
+//         this.props.setFocused(this.props.Document);
+//     };
+
+//     @undoBatch
+//     createRow = action(() => {
+//         this.props.addDocument?.(Docs.Create.TextDocument('', { title: '', _width: 100, _height: 30 }));
+//         this._focusedCell = { row: this.childDocs.length, col: this._focusedCell.col };
+//     });
+
+//     @undoBatch
+//     @action
+//     createColumn = () => {
+//         const newFieldName = (index: number) => `New field${index ? ` (${index})` : ''}`;
+//         for (let index = 0; index < 100; index++) {
+//             if (this.props.columns.findIndex(col => col.heading === newFieldName(index)) === -1) {
+//                 this.props.columns.push(new SchemaHeaderField(newFieldName(index), '#f1efeb'));
+//                 break;
+//             }
+//         }
+//     };
+
+//     @action
+//     getColumnType = (column: SchemaHeaderField, doc?: Doc, field?: string): ColumnType => {
+//         if (doc && field && column.type === ColumnType.Any) {
+//             const val = doc[CollectionSchemaCell.resolvedFieldKey(field, doc)];
+//             if (val instanceof ImageField) return ColumnType.Image;
+//             if (val instanceof Doc) return ColumnType.Doc;
+//             if (val instanceof DateField) return ColumnType.Date;
+//             if (val instanceof List) return ColumnType.List;
+//         }
+//         if (column.type && column.type !== 0) {
+//             return column.type;
+//         }
+//         if (columnTypes.get(column.heading)) {
+//             return (column.type = columnTypes.get(column.heading)!);
+//         }
+//         return (column.type = ColumnType.Any);
+//     };
+
+//     @undoBatch
+//     @action
+//     toggleTextwrap = async () => {
+//         const textwrappedRows = Cast(this.props.Document.textwrappedSchemaRows, listSpec('string'), []);
+//         if (textwrappedRows.length) {
+//             this.props.Document.textwrappedSchemaRows = new List<string>([]);
+//         } else {
+//             const docs = DocListCast(this.props.Document[this.props.fieldKey]);
+//             const allRows = docs instanceof Doc ? [docs[Id]] : docs.map(doc => doc[Id]);
+//             this.props.Document.textwrappedSchemaRows = new List<string>(allRows);
+//         }
+//     };
+
+//     @action
+//     toggleTextWrapRow = (doc: Doc): void => {
+//         const textWrapped = this.textWrappedRows;
+//         const index = textWrapped.findIndex(id => doc[Id] === id);
+
+//         index > -1 ? textWrapped.splice(index, 1) : textWrapped.push(doc[Id]);
+
+//         this.textWrappedRows = textWrapped;
+//     };
+
+//     @computed
+//     get reactTable() {
+//         const children = this.childDocs;
+//         const hasCollectionChild = children.reduce((found, doc) => found || doc.type === DocumentType.COL, false);
+//         const expanded: { [name: string]: any } = {};
+//         Array.from(this._openCollections.keys()).map(col => (expanded[col.toString()] = true));
+//         const rerender = [...this.textWrappedRows]; // TODO: get component to rerender on text wrap change without needign to console.log :((((
+
+//         return (
+//             <ReactTable
+//                 style={{ position: 'relative' }}
+//                 data={children}
+//                 page={0}
+//                 pageSize={children.length}
+//                 showPagination={false}
+//                 columns={this.tableColumns}
+//                 getTrProps={this.getTrProps}
+//                 getTdProps={this.getTdProps}
+//                 sortable={false}
+//                 TrComponent={MovableRow}
+//                 sorted={this.sorted}
+//                 expanded={expanded}
+//                 resized={this.resized}
+//                 onResizedChange={this.props.onResizedChange}
+//                 // if it has a child, render another table with the children
+//                 SubComponent={
+//                     !hasCollectionChild
+//                         ? undefined
+//                         : row =>
+//                               row.original.type !== DocumentType.COL ? null : (
+//                                   <div style={{ paddingLeft: 57 + 'px' }} className="reactTable-sub">
+//                                       <SchemaTable {...this.props} Document={row.original} dataDoc={undefined} childDocs={undefined} />
+//                                   </div>
+//                               )
+//                 }
+//             />
+//         );
+//     }
+
+//     onContextMenu = (e: React.MouseEvent): void => {
+//         ContextMenu.Instance.addItem({ description: 'Toggle text wrapping', event: this.toggleTextwrap, icon: 'table' });
+//     };
+
+//     getField = (row: number, col?: number) => {
+//         const docs = this.childDocs;
+
+//         row = row % docs.length;
+//         while (row < 0) row += docs.length;
+//         const columns = this.props.columns;
+//         const doc = docs[row];
+//         if (col === undefined) {
+//             return doc;
+//         }
+//         if (col >= 0 && col < columns.length) {
+//             const column = this.props.columns[col].heading;
+//             return doc[column];
+//         }
+//         return undefined;
+//     };
+
+//     createTransformer = (row: number, col: number): Transformer => {
+//         const self = this;
+//         const captures: { [name: string]: Field } = {};
+
+//         const transformer: ts.TransformerFactory<ts.SourceFile> = context => {
+//             return root => {
+//                 function visit(node: ts.Node) {
+//                     node = ts.visitEachChild(node, visit, context);
+//                     if (ts.isIdentifier(node)) {
+//                         const isntPropAccess = !ts.isPropertyAccessExpression(node.parent) || node.parent.expression === node;
+//                         const isntPropAssign = !ts.isPropertyAssignment(node.parent) || node.parent.name !== node;
+//                         if (isntPropAccess && isntPropAssign) {
+//                             if (node.text === '$r') {
+//                                 return ts.createNumericLiteral(row.toString());
+//                             } else if (node.text === '$c') {
+//                                 return ts.createNumericLiteral(col.toString());
+//                             } else if (node.text === '$') {
+//                                 if (ts.isCallExpression(node.parent)) {
+//                                     // captures.doc = self.props.Document;
+//                                     // captures.key = self.props.fieldKey;
+//                                 }
+//                             }
+//                         }
+//                     }
+
+//                     return node;
+//                 }
+//                 return ts.visitNode(root, visit);
+//             };
+//         };
+
+//         // const getVars = () => {
+//         //     return { capturedVariables: captures };
+//         // };
+
+//         return { transformer /*getVars*/ };
+//     };
+
+//     setComputed = (script: string, doc: Doc, field: string, row: number, col: number): boolean => {
+//         script = `const $ = (row:number, col?:number) => {
+//                 const rval = (doc as any)[key][row + ${row}];
+//                 return col === undefined ? rval : rval[(doc as any)._schemaHeaders[col + ${col}].heading];
+//             }
+//             return ${script}`;
+//         const compiled = CompileScript(script, { params: { this: Doc.name }, capturedVariables: { doc: this.props.Document, key: this.props.fieldKey }, typecheck: false, transformer: this.createTransformer(row, col) });
+//         if (compiled.compiled) {
+//             doc[field] = new ComputedField(compiled);
+//             return true;
+//         }
+//         return false;
+//     };
+
+//     @action
+//     showDoc = (doc: Doc | undefined, dataDoc?: Doc, screenX?: number, screenY?: number) => {
+//         this._showDoc = doc;
+//         if (dataDoc && screenX && screenY) {
+//             this._showDocPos = this.props.ScreenToLocalTransform().transformPoint(screenX, screenY);
+//         }
+//     };
+
+//     onOpenClick = () => {
+//         this._showDoc && this.props.addDocTab(this._showDoc, OpenWhere.addRight);
+//     };
+
+//     getPreviewTransform = (): Transform => {
+//         return this.props.ScreenToLocalTransform().translate(-this.borderWidth - 4 - this.tableWidth, -this.borderWidth);
+//     };
+
+//     render() {
+//         const preview = '';
+//         return (
+//             <div
+//                 className="collectionSchemaView-table"
+//                 onPointerDown={this.props.onPointerDown}
+//                 onClick={this.props.onClick}
+//                 onWheel={e => this.props.active(true) && e.stopPropagation()}
+//                 onDrop={e => this.props.onDrop(e, {})}
+//                 onContextMenu={this.onContextMenu}>
+//                 {this.reactTable}
+//                 {this.props.Document._chromeHidden || this.props.addDocument === returnFalse ? undefined : (
+//                     <div className="collectionSchemaView-addRow" onClick={this.createRow}>
+//                         + new
+//                     </div>
+//                 )}
+//                 {!this._showDoc ? null : (
+//                     <div
+//                         className="collectionSchemaView-documentPreview"
+//                         ref="overlay"
+//                         style={{
+//                             position: 'absolute',
+//                             width: 150,
+//                             height: 150,
+//                             background: 'dimgray',
+//                             display: 'block',
+//                             top: 0,
+//                             left: 0,
+//                             transform: `translate(${this._showDocPos[0]}px, ${this._showDocPos[1] - 180}px)`,
+//                         }}>
+//                         <DocumentView
+//                             Document={this._showDoc}
+//                             DataDoc={this._showDataDoc}
+//                             styleProvider={DefaultStyleProvider}
+//                             docViewPath={returnEmptyDoclist}
+//                             focus={DocUtils.DefaultFocus}
+//                             renderDepth={this.props.renderDepth}
+//                             rootSelected={returnFalse}
+//                             isContentActive={returnTrue}
+//                             isDocumentActive={returnFalse}
+//                             PanelWidth={() => 150}
+//                             PanelHeight={() => 150}
+//                             ScreenToLocalTransform={this.getPreviewTransform}
+//                             docFilters={returnEmptyFilter}
+//                             docRangeFilters={returnEmptyFilter}
+//                             searchFilterDocs={returnEmptyDoclist}
+//                             ContainingCollectionDoc={this.props.CollectionView?.props.Document}
+//                             ContainingCollectionView={this.props.CollectionView}
+//                             moveDocument={this.props.moveDocument}
+//                             whenChildContentsActiveChanged={emptyFunction}
+//                             addDocTab={this.props.addDocTab}
+//                             pinToPres={this.props.pinToPres}
+//                             bringToFront={returnFalse}></DocumentView>
+//                     </div>
+//                 )}
+//             </div>
+//         );
+//     }
+// }
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index 569579996..459554ebe 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -44,6 +44,7 @@ import { WebBox } from './WebBox';
 import React = require('react');
 import XRegExp = require('xregexp');
 import { LoadingBox } from './LoadingBox';
+import { SchemaRowBox } from '../collections/collectionSchema/SchemaRowBox';
 
 const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this?
 
@@ -268,6 +269,7 @@ export class DocumentContentsView extends React.Component<
                     HTMLtag,
                     ComparisonBox,
                     LoadingBox,
+                    SchemaRowBox,
                 }}
                 bindings={bindings}
                 jsx={layoutFrame}
-- 
cgit v1.2.3-70-g09d2


From 6c58ca9d473103624be82c6f2da90f22bafd7b98 Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Sat, 28 Jan 2023 23:27:17 -0500
Subject: version without schemarow as documentview

---
 src/client/documents/DocumentTypes.ts              |  1 -
 src/client/documents/Documents.ts                  | 11 ---
 .../collectionSchema/CollectionSchemaView.scss     |  6 --
 .../collectionSchema/CollectionSchemaView.tsx      | 94 ++++++----------------
 .../collectionSchema/SchemaColumnHeader.tsx        |  2 +-
 .../collections/collectionSchema/SchemaRowBox.tsx  | 88 +++++++-------------
 src/client/views/nodes/DocumentContentsView.tsx    |  2 -
 7 files changed, 53 insertions(+), 151 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaRowBox.tsx')

diff --git a/src/client/documents/DocumentTypes.ts b/src/client/documents/DocumentTypes.ts
index b910b26b0..d99cd2dac 100644
--- a/src/client/documents/DocumentTypes.ts
+++ b/src/client/documents/DocumentTypes.ts
@@ -40,7 +40,6 @@ export enum DocumentType {
     SEARCHITEM = 'searchitem',
     COMPARISON = 'comparison',
     GROUP = 'group',
-    SCHEMAROW = 'schemarow',
 
     LINKDB = 'linkdb', // database of links  ??? why do we have this
     SCRIPTDB = 'scriptdb', // database of scripts
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index f6104d655..7de1221cc 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -26,7 +26,6 @@ import { ScriptingGlobals } from '../util/ScriptingGlobals';
 import { undoBatch, UndoManager } from '../util/UndoManager';
 import { CollectionDockingView } from '../views/collections/CollectionDockingView';
 import { DimUnit } from '../views/collections/collectionMulticolumn/CollectionMulticolumnView';
-import { SchemaRowBox } from '../views/collections/collectionSchema/SchemaRowBox';
 import { CollectionView } from '../views/collections/CollectionView';
 import { ContextMenu } from '../views/ContextMenu';
 import { ContextMenuProps } from '../views/ContextMenuItem';
@@ -650,12 +649,6 @@ export namespace Docs {
                     options: { _fitWidth: true, nativeDimModifiable: true, links: '@links(self)' },
                 },
             ],
-            [
-                DocumentType.SCHEMAROW,
-                {
-                    layout: { view: SchemaRowBox, dataField: defaultDataKey },
-                },
-            ],
             [
                 DocumentType.LOADING,
                 {
@@ -1148,10 +1141,6 @@ export namespace Docs {
             return InstanceFromProto(Prototypes.get(DocumentType.DATAVIZ), new CsvField(url), { title: 'Data Viz', ...options });
         }
 
-        export function SchemaRowDocument(options?: DocumentOptions) {
-            return InstanceFromProto(Prototypes.get(DocumentType.SCHEMAROW), undefined, { ...(options || {}) });
-        }
-
         export function DockDocument(documents: Array<Doc>, config: string, options: DocumentOptions, id?: string) {
             return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { freezeChildren: 'remove|add', ...options, viewType: CollectionViewType.Docking, _viewType: CollectionViewType.Docking, dockingConfig: config }, id);
         }
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
index e0d0101a2..4fa5d80e2 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
@@ -126,16 +126,10 @@
     }
 }
 
-.schema-row-wrapper {
-    max-height: 70px;
-    overflow: hidden;
-}
-
 .schema-header-row,
 .schema-row {
     display: flex;
     flex-direction: row;
-    height: 100%;
     max-height: 70px;
     overflow: auto;
 
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index c9f934aec..29b22c0d5 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -1,29 +1,28 @@
 import React = require('react');
-import { action, computed, observable, ObservableMap, ObservableSet, trace, untracked } from 'mobx';
+import { action, computed, observable, ObservableMap, ObservableSet, untracked } from 'mobx';
 import { observer } from 'mobx-react';
-import { DataSym, Doc, DocListCast, Opt, StrListCast } from '../../../../fields/Doc';
+import { Doc, DocListCast, Opt } from '../../../../fields/Doc';
 import { Id } from '../../../../fields/FieldSymbols';
 import { List } from '../../../../fields/List';
 import { RichTextField } from '../../../../fields/RichTextField';
 import { listSpec } from '../../../../fields/Schema';
 import { BoolCast, Cast, StrCast } from '../../../../fields/Types';
 import { ImageField } from '../../../../fields/URLField';
-import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, setupMoveUpEvents, smoothScroll, Utils } from '../../../../Utils';
+import { emptyFunction, returnEmptyString, setupMoveUpEvents, Utils } from '../../../../Utils';
 import { Docs, DocUtils } from '../../../documents/Documents';
 import { DragManager } from '../../../util/DragManager';
 import { SelectionManager } from '../../../util/SelectionManager';
+import { Transform } from '../../../util/Transform';
 import { undoBatch } from '../../../util/UndoManager';
 import { ContextMenu } from '../../ContextMenu';
 import { ContextMenuProps } from '../../ContextMenuItem';
 import { EditableView } from '../../EditableView';
+import { DocumentView } from '../../nodes/DocumentView';
 import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox';
 import { CollectionSubView } from '../CollectionSubView';
 import './CollectionSchemaView.scss';
 import { SchemaColumnHeader } from './SchemaColumnHeader';
 import { SchemaRowBox } from './SchemaRowBox';
-import { DocFocusOptions, DocumentView, ViewAdjustment } from '../../nodes/DocumentView';
-import { DefaultStyleProvider } from '../../StyleProvider';
-import { Transform } from '../../../util/Transform';
 
 export enum ColumnType {
     Number,
@@ -33,7 +32,7 @@ export enum ColumnType {
     Image,
 }
 
-const defaultColumnKeys: string[] = ['title', 'type', 'author', 'text', 'data', 'tags'];
+const defaultColumnKeys: string[] = ['title', 'type', 'author', 'text', 'data', 'creationDate'];
 
 @observer
 export class CollectionSchemaView extends CollectionSubView() {
@@ -399,25 +398,6 @@ export class CollectionSchemaView extends CollectionSubView() {
         ContextMenu.Instance.displayMenu(x, y, undefined, true);
     };
 
-    focusDocument = (doc: Doc, options: DocFocusOptions) => {
-        Doc.BrushDoc(doc);
-
-        let focusSpeed = 0;
-        const found = this._mainCont && Array.from(this._mainCont.getElementsByClassName('documentView-node')).find((node: any) => node.id === doc[Id]);
-        if (found) {
-            const top = found.getBoundingClientRect().top;
-            const localTop = this.props.ScreenToLocalTransform().transformPoint(0, top);
-            if (Math.floor(localTop[1]) !== 0) {
-                smoothScroll((focusSpeed = options.zoomTime ?? 500), this._mainCont!, localTop[1] + this._mainCont!.scrollTop, options.easeFunc);
-            }
-        }
-        const endFocus = async (moved: boolean) => options?.afterFocus?.(moved) ?? ViewAdjustment.doNothing;
-        this.props.focus(this.rootDoc, {
-            ...options,
-            afterFocus: (didFocus: boolean) => new Promise<ViewAdjustment>(res => setTimeout(async () => res(await endFocus(didFocus)), focusSpeed)),
-        });
-    };
-
     isChildContentActive = () =>
         this.props.isDocumentActive?.() && (this.props.childDocumentsActive?.() || BoolCast(this.rootDoc.childDocumentsActive)) ? true : this.props.childDocumentsActive?.() === false || this.rootDoc.childDocumentsActive === false ? false : undefined;
 
@@ -465,52 +445,24 @@ export class CollectionSchemaView extends CollectionSubView() {
                             let dref: Opt<DocumentView>;
 
                             return (
-                                <div className="schema-row-wrapper">
-                                    <DocumentView
-                                        {...this.props}
-                                        ref={r => (dref = r || undefined)}
-                                        LayoutTemplate={this.props.childLayoutTemplate}
-                                        LayoutTemplateString={SchemaRowBox.LayoutString(this.props.fieldKey)}
-                                        renderDepth={this.props.renderDepth + 1}
-                                        Document={doc}
-                                        DataDoc={dataDoc}
-                                        ContainingCollectionView={this.props.CollectionView}
-                                        ContainingCollectionDoc={this.Document}
-                                        PanelWidth={this.props.PanelWidth}
-                                        PanelHeight={() => 70}
-                                        styleProvider={DefaultStyleProvider}
-                                        focus={this.focusDocument}
-                                        docFilters={this.childDocFilters}
-                                        docRangeFilters={this.childDocRangeFilters}
-                                        searchFilterDocs={this.searchFilterDocs}
-                                        rootSelected={this.rootSelected}
-                                        ScreenToLocalTransform={() => this.getDocTransform(doc, dref)}
-                                        bringToFront={emptyFunction}
-                                        isContentActive={this.isChildContentActive}
-                                        hideDecorations={true}
-                                        hideTitle={true}
-                                        hideDocumentButtonBar={true}
-                                    />
-                                </div>
+                                <SchemaRowBox
+                                    {...this.props}
+                                    key={index}
+                                    Document={doc}
+                                    ContainingCollectionDoc={this.props.CollectionView?.props.Document}
+                                    ContainingCollectionView={this.props.CollectionView}
+                                    rowIndex={index}
+                                    columnKeys={this.columnKeys}
+                                    columnWidths={this.displayColumnWidths}
+                                    rowMenuWidth={CollectionSchemaView._rowMenuWidth}
+                                    selectedDocs={this._selectedDocs}
+                                    selectRow={this.selectRow}
+                                    startDrag={this.startDrag}
+                                    dragging={this._isDragging}
+                                    dropIndex={this.setDropIndex}
+                                    addRowRef={this.addRowRef}
+                                />
                             );
-
-                            // <SchemaRowBox
-                            //     {...this.props}
-                            //     key={index}
-                            //     Document={doc}
-                            //     ContainingCollectionDoc={this.props.CollectionView?.props.Document}
-                            //     ContainingCollectionView={this.props.CollectionView}
-                            //     rowIndex={index}
-                            //     columnKeys={this.columnKeys}
-                            //     columnWidths={this.displayColumnWidths}
-                            //     rowMenuWidth={CollectionSchemaView._rowMenuWidth}
-                            //     selectedDocs={this._selectedDocs}
-                            //     selectRow={this.selectRow}
-                            //     startDrag={this.startDrag}
-                            //     dragging={this._isDragging}
-                            //     dropIndex={this.setDropIndex}
-                            //     addRowRef={this.addRowRef}
-                            // />
                         })}
                     </div>
                 </div>
diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
index a6a5f66ab..8e6d3d78a 100644
--- a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
@@ -40,7 +40,7 @@ export class SchemaColumnHeader extends React.Component<SchemaColumnHeaderProps>
             case ColumnType.Boolean:
                 return (
                     <>
-                        <input type="checkbox" name="" id="" value={this._newFieldDefault ?? false} onPointerDown={e => e.stopPropagation()} onChange={action(e => (this._newFieldDefault = e.target.value))} />
+                        <input type="checkbox" name="" id="" value={this._newFieldDefault} onPointerDown={e => e.stopPropagation()} onChange={action(e => (this._newFieldDefault = e.target.checked))} />
                         {this._newFieldDefault ? 'true' : 'false'}
                     </>
                 );
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index f790e9dbf..2cf0a1b79 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -1,20 +1,17 @@
 import React = require('react');
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, computed, ObservableMap, ObservableSet } from 'mobx';
+import { action, ObservableSet } from 'mobx';
 import { observer } from 'mobx-react';
-import { Doc, StrListCast } from '../../../../fields/Doc';
+import { Doc } from '../../../../fields/Doc';
+import { DragManager } from '../../../util/DragManager';
 import { undoBatch } from '../../../util/UndoManager';
 import { ViewBoxBaseComponent } from '../../DocComponent';
 import { Colors } from '../../global/globalEnums';
-import { FieldView, FieldViewProps } from '../../nodes/FieldView';
+import { OpenWhere } from '../../nodes/DocumentView';
+import { FieldViewProps } from '../../nodes/FieldView';
 import './CollectionSchemaView.scss';
 import { SchemaTableCell } from './SchemaTableCell';
-import { emptyFunction, setupMoveUpEvents } from '../../../../Utils';
-import { DragManager } from '../../../util/DragManager';
-import { OpenWhere } from '../../nodes/DocumentView';
-import { Cast } from '../../../../fields/Types';
-import { listSpec } from '../../../../fields/Schema';
-import { CollectionSchemaView } from './CollectionSchemaView';
+import { setupMoveUpEvents, emptyFunction } from '../../../../Utils';
 
 export interface SchemaRowBoxProps extends FieldViewProps {
     rowIndex: number;
@@ -30,61 +27,37 @@ export interface SchemaRowBoxProps extends FieldViewProps {
 }
 
 @observer
-export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
-    public static LayoutString(fieldKey: string) {
-        return FieldView.LayoutString(SchemaRowBox, fieldKey);
-    }
-
+export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
     private _ref: HTMLDivElement | null = null;
 
     bounds = () => this._ref?.getBoundingClientRect();
 
-    @computed get columnKeys() {
-        return StrListCast(this.props.ContainingCollectionDoc?.columnKeys);
-    }
-
-    @computed get storedColumnWidths() {
-        let widths = Cast(
-            this.props.ContainingCollectionDoc?.columnWidths,
-            listSpec('number'),
-            this.columnKeys.map(() => (this.props.PanelWidth() - CollectionSchemaView._rowMenuWidth) / this.columnKeys.length)
-        );
-
-        const totalWidth = widths.reduce((sum, width) => sum + width, 0);
-        if (totalWidth !== this.props.PanelWidth() - CollectionSchemaView._rowMenuWidth) {
-            widths = widths.map(w => {
-                const proportion = w / totalWidth;
-                return proportion * (this.props.PanelWidth() - CollectionSchemaView._rowMenuWidth);
-            });
-        }
-
-        return widths;
-    }
+    isSelected = () => this.props.selectedDocs.has(this.props.Document);
 
     @action
     onRowPointerDown = (e: React.PointerEvent) => {
         e.stopPropagation();
 
-        // setupMoveUpEvents(
-        //     this,
-        //     e,
-        //     e => this.props.startDrag(e, this.props.Document, this._ref!, this.props.rowIndex),
-        //     emptyFunction,
-        //     e => this.props.selectRow(e, this.props.Document, this._ref!, this.props.rowIndex)
-        // );
+        setupMoveUpEvents(
+            this,
+            e,
+            e => this.props.startDrag(e, this.props.Document, this._ref!, this.props.rowIndex),
+            emptyFunction,
+            e => this.props.selectRow(e, this.props.Document, this._ref!, this.props.rowIndex)
+        );
     };
 
     onPointerEnter = (e: any) => {
-        // if (!this.props.dragging) return;
+        if (!this.props.dragging) return;
         document.removeEventListener('pointermove', this.onPointerMove);
         document.addEventListener('pointermove', this.onPointerMove);
     };
 
     onPointerMove = (e: any) => {
-        // if (!this.props.dragging) return;
+        if (!this.props.dragging) return;
         let dragIsRow: boolean = true;
         DragManager.docsBeingDragged.forEach(doc => {
-            // dragIsRow = this.props.selectedDocs.has(doc);
+            dragIsRow = this.props.selectedDocs.has(doc);
         });
         if (this._ref && dragIsRow) {
             const rect = this._ref.getBoundingClientRect();
@@ -94,11 +67,11 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
             if (y <= halfLine) {
                 this._ref.style.borderTop = `solid 2px ${Colors.MEDIUM_BLUE}`;
                 this._ref.style.borderBottom = '0px';
-                // this.props.dropIndex(this.props.rowIndex);
+                this.props.dropIndex(this.props.rowIndex);
             } else if (y > halfLine) {
                 this._ref.style.borderTop = '0px';
                 this._ref.style.borderBottom = `solid 2px ${Colors.MEDIUM_BLUE}`;
-                // this.props.dropIndex(this.props.rowIndex + 1);
+                this.props.dropIndex(this.props.rowIndex + 1);
             }
         }
     };
@@ -115,22 +88,19 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
         return (
             <div
                 className="schema-row"
-                style={this.props.isSelected() ? { backgroundColor: Colors.LIGHT_BLUE } : {}}
-                // style={this.isSelected() ? { backgroundColor: Colors.LIGHT_BLUE, opacity: this.props.dragging ? 0.5 : 1 } : {}}
-                // onPointerDown={this.onRowPointerDown}
-                // onPointerEnter={this.onPointerEnter}
+                style={this.isSelected() ? { backgroundColor: Colors.LIGHT_BLUE, opacity: this.props.dragging ? 0.5 : 1 } : {}}
+                onPointerDown={this.onRowPointerDown}
+                onPointerEnter={this.onPointerEnter}
                 onPointerLeave={this.onPointerLeave}
                 ref={(row: HTMLDivElement | null) => {
-                    // row && this.props.addRowRef(this.props.Document, row);
+                    row && this.props.addRowRef(this.props.Document, row);
                     this._ref = row;
                 }}>
                 <div
                     className="row-menu"
-                    style={
-                        {
-                            /* width: this.props.rowMenuWidth */
-                        }
-                    }>
+                    style={{
+                        width: this.props.rowMenuWidth,
+                    }}>
                     <div
                         className="schema-row-button"
                         onPointerDown={undoBatch(e => {
@@ -149,8 +119,8 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
                     </div>
                 </div>
                 <div className="row-cells">
-                    {this.columnKeys.map((key, index) => (
-                        <SchemaTableCell key={key} Document={this.props.Document} fieldKey={key} columnWidth={this.storedColumnWidths[index]} />
+                    {this.props.columnKeys.map((key, index) => (
+                        <SchemaTableCell key={key} Document={this.props.Document} fieldKey={key} columnWidth={this.props.columnWidths[index]} />
                     ))}
                 </div>
             </div>
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index 459554ebe..569579996 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -44,7 +44,6 @@ import { WebBox } from './WebBox';
 import React = require('react');
 import XRegExp = require('xregexp');
 import { LoadingBox } from './LoadingBox';
-import { SchemaRowBox } from '../collections/collectionSchema/SchemaRowBox';
 
 const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this?
 
@@ -269,7 +268,6 @@ export class DocumentContentsView extends React.Component<
                     HTMLtag,
                     ComparisonBox,
                     LoadingBox,
-                    SchemaRowBox,
                 }}
                 bindings={bindings}
                 jsx={layoutFrame}
-- 
cgit v1.2.3-70-g09d2


From 222f659b8c291fafce2648e367392dd9f467cb25 Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Mon, 27 Feb 2023 17:00:49 -0500
Subject: rows are documentviews but clipped

---
 package-lock.json                                  |  39 +++++++
 .../collectionSchema/CollectionSchemaView.scss     |   6 ++
 .../collectionSchema/CollectionSchemaView.tsx      |  96 ++++++++++++-----
 .../collections/collectionSchema/SchemaRowBox.tsx  | 120 ++++++++++++---------
 .../collectionSchema/SchemaTableCell.tsx           |  12 ++-
 src/client/views/nodes/DocumentContentsView.tsx    |   2 +
 6 files changed, 195 insertions(+), 80 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaRowBox.tsx')

diff --git a/package-lock.json b/package-lock.json
index 3c2dccbf8..8806887df 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -5308,6 +5308,16 @@
             "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=",
             "dev": true
         },
+        "d": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz",
+            "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==",
+            "dev": true,
+            "requires": {
+                "es5-ext": "^0.10.50",
+                "type": "^1.0.1"
+            }
+        },
         "d3-array": {
             "version": "2.12.1",
             "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz",
@@ -6475,6 +6485,28 @@
                 "is-symbol": "^1.0.2"
             }
         },
+        "es5-ext": {
+            "version": "0.10.62",
+            "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz",
+            "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==",
+            "dev": true,
+            "requires": {
+                "es6-iterator": "^2.0.3",
+                "es6-symbol": "^3.1.3",
+                "next-tick": "^1.1.0"
+            }
+        },
+        "es6-iterator": {
+            "version": "2.0.3",
+            "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz",
+            "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==",
+            "dev": true,
+            "requires": {
+                "d": "1",
+                "es5-ext": "^0.10.35",
+                "es6-symbol": "^3.1.1"
+            }
+        },
         "es6-promise": {
             "version": "3.2.1",
             "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.2.1.tgz",
@@ -6486,6 +6518,7 @@
             "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==",
             "dev": true,
             "requires": {
+                "d": "^1.0.1",
                 "ext": "^1.1.2"
             }
         },
@@ -21371,6 +21404,12 @@
             "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
             "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q="
         },
+        "type": {
+            "version": "1.2.0",
+            "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz",
+            "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==",
+            "dev": true
+        },
         "type-check": {
             "version": "0.3.2",
             "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
index bd0fc11b3..46c2e2d1a 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
@@ -134,10 +134,16 @@
     }
 }
 
+.schema-row-wrapper {
+    max-height: 70px;
+    overflow: hidden;
+}
+
 .schema-header-row,
 .schema-row {
     display: flex;
     flex-direction: row;
+    height: 100%;
     max-height: 70px;
     overflow: auto;
 
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 64c39cf1a..46510b6fe 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -8,7 +8,7 @@ import { RichTextField } from '../../../../fields/RichTextField';
 import { listSpec } from '../../../../fields/Schema';
 import { BoolCast, Cast, NumCast, StrCast } from '../../../../fields/Types';
 import { ImageField } from '../../../../fields/URLField';
-import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, setupMoveUpEvents, Utils } from '../../../../Utils';
+import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, setupMoveUpEvents, smoothScroll, Utils } from '../../../../Utils';
 import { Docs, DocUtils } from '../../../documents/Documents';
 import { DragManager } from '../../../util/DragManager';
 import { SelectionManager } from '../../../util/SelectionManager';
@@ -17,7 +17,7 @@ import { undoBatch } from '../../../util/UndoManager';
 import { ContextMenu } from '../../ContextMenu';
 import { ContextMenuProps } from '../../ContextMenuItem';
 import { EditableView } from '../../EditableView';
-import { DocumentView } from '../../nodes/DocumentView';
+import { DocFocusOptions, DocumentView, ViewAdjustment } from '../../nodes/DocumentView';
 import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox';
 import { CollectionSubView } from '../CollectionSubView';
 import './CollectionSchemaView.scss';
@@ -41,9 +41,9 @@ export class CollectionSchemaView extends CollectionSubView() {
     private _lastSelectedRow: number | undefined;
     private _selectedDocSortedArray: Doc[] = [];
     private _closestDropIndex: number = 0;
-    private _minColWidth: number = 150;
     private _previewRef: HTMLDivElement | null = null;
 
+    public static _minColWidth: number = 150;
     public static _rowMenuWidth: number = 100;
     public static _previewDividerWidth: number = 4;
     @observable _selectedDocs: ObservableSet = new ObservableSet<Doc>();
@@ -110,6 +110,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     }
 
     componentDidMount() {
+        this.props.setContentView?.(this);
         document.addEventListener('keydown', this.onKeyDown);
     }
 
@@ -243,8 +244,8 @@ export class CollectionSchemaView extends CollectionSubView() {
             if (shrinking === undefined || growing === undefined) return true;
 
             change = Math.abs(change);
-            if (this._displayColumnWidths[shrinking] - change < this._minColWidth) {
-                change = this._displayColumnWidths[shrinking] - this._minColWidth;
+            if (this._displayColumnWidths[shrinking] - change < CollectionSchemaView._minColWidth) {
+                change = this._displayColumnWidths[shrinking] - CollectionSchemaView._minColWidth;
             }
 
             this._displayColumnWidths[shrinking] -= change;
@@ -481,7 +482,7 @@ export class CollectionSchemaView extends CollectionSubView() {
         !Doc.noviceMode && ContextMenu.Instance.addItem({ description: 'Containers ...', subitems: layoutItems, icon: 'eye' });
         ContextMenu.Instance.setDefaultItem('::', (name: string): void => {
             Doc.GetProto(this.props.Document)[name] = '';
-            const created = Docs.Create.TextDocument('', { title: name, _width: 250, _autoHeight: true });
+            const created = Docs.Create.TextDocument('', { title: name, _autoHeight: true });
             if (created) {
                 if (this.props.Document.isTemplateDoc) {
                     Doc.MakeMetadataFieldTemplate(created, this.props.Document);
@@ -492,9 +493,25 @@ export class CollectionSchemaView extends CollectionSubView() {
         ContextMenu.Instance.displayMenu(x, y, undefined, true);
     };
 
+    focusDocument = (doc: Doc, options: DocFocusOptions) => {
+        Doc.BrushDoc(doc);
+        let focusSpeed = 0;
+        const found = this._mainCont && Array.from(this._mainCont.getElementsByClassName('documentView-node')).find((node: any) => node.id === doc[Id]);
+        if (found) {
+            const top = found.getBoundingClientRect().top;
+            const localTop = this.props.ScreenToLocalTransform().transformPoint(0, top);
+            if (Math.floor(localTop[1]) !== 0) {
+                smoothScroll((focusSpeed = options.zoomTime ?? 500), this._mainCont!, localTop[1] + this._mainCont!.scrollTop, options.easeFunc);
+            }
+        }
+        const endFocus = async (moved: boolean) => options?.afterFocus?.(moved) ?? ViewAdjustment.doNothing;
+        this.props.focus(this.rootDoc, {
+            ...options,
+            afterFocus: (didFocus: boolean) => new Promise<ViewAdjustment>(res => setTimeout(async () => res(await endFocus(didFocus)), focusSpeed)),
+        });
+    };
     isChildContentActive = () =>
         this.props.isDocumentActive?.() && (this.props.childDocumentsActive?.() || BoolCast(this.rootDoc.childDocumentsActive)) ? true : this.props.childDocumentsActive?.() === false || this.rootDoc.childDocumentsActive === false ? false : undefined;
-
     getDocTransform(doc: Doc, dref?: DocumentView) {
         const { scale, translateX, translateY } = Utils.GetScreenTransform(dref?.ContentDiv || undefined);
         // the document view may center its contents and if so, will prepend that onto the screenToLocalTansform.  so we have to subtract that off
@@ -543,26 +560,55 @@ export class CollectionSchemaView extends CollectionSubView() {
                         {this.childDocs.map((doc: Doc, index: number) => {
                             const dataDoc = !doc.isTemplateDoc && !doc.isTemplateForField && !doc.PARAMS ? undefined : this.props.DataDoc;
                             let dref: Opt<DocumentView>;
-
                             return (
-                                <SchemaRowBox
-                                    {...this.props}
-                                    key={index}
-                                    Document={doc}
-                                    ContainingCollectionDoc={this.props.CollectionView?.props.Document}
-                                    ContainingCollectionView={this.props.CollectionView}
-                                    rowIndex={index}
-                                    columnKeys={this.columnKeys}
-                                    columnWidths={this.displayColumnWidths}
-                                    rowMenuWidth={CollectionSchemaView._rowMenuWidth}
-                                    selectedDocs={this._selectedDocs}
-                                    selectRow={this.selectRow}
-                                    startDrag={this.startDrag}
-                                    dragging={this._isDragging}
-                                    dropIndex={this.setDropIndex}
-                                    addRowRef={this.addRowRef}
-                                />
+                                <div className="schema-row-wrapper">
+                                    <DocumentView
+                                        {...this.props}
+                                        ref={r => (dref = r || undefined)}
+                                        LayoutTemplate={this.props.childLayoutTemplate}
+                                        LayoutTemplateString={SchemaRowBox.LayoutString(this.props.fieldKey)}
+                                        renderDepth={this.props.renderDepth + 1}
+                                        Document={doc}
+                                        DataDoc={dataDoc}
+                                        ContainingCollectionView={this.props.CollectionView}
+                                        ContainingCollectionDoc={this.Document}
+                                        PanelWidth={() => this.tableWidth}
+                                        PanelHeight={() => 70}
+                                        styleProvider={DefaultStyleProvider}
+                                        focus={this.focusDocument}
+                                        docFilters={this.childDocFilters}
+                                        docViewPath={this.props.docViewPath}
+                                        docRangeFilters={this.childDocRangeFilters}
+                                        searchFilterDocs={this.searchFilterDocs}
+                                        rootSelected={this.rootSelected}
+                                        ScreenToLocalTransform={() => this.getDocTransform(doc, dref)}
+                                        bringToFront={emptyFunction}
+                                        isContentActive={this.isChildContentActive}
+                                        hideDecorations={true}
+                                        hideTitle={true}
+                                        hideDocumentButtonBar={true}
+                                    />
+                                </div>
                             );
+                            // return (
+                            //     <SchemaRowBox
+                            //         {...this.props}
+                            //         key={index}
+                            //         Document={doc}
+                            //         ContainingCollectionDoc={this.props.CollectionView?.props.Document}
+                            //         ContainingCollectionView={this.props.CollectionView}
+                            //         rowIndex={index}
+                            //         columnKeys={this.columnKeys}
+                            //         columnWidths={this.displayColumnWidths}
+                            //         rowMenuWidth={CollectionSchemaView._rowMenuWidth}
+                            //         selectedDocs={this._selectedDocs}
+                            //         selectRow={this.selectRow}
+                            //         startDrag={this.startDrag}
+                            //         dragging={this._isDragging}
+                            //         dropIndex={this.setDropIndex}
+                            //         addRowRef={this.addRowRef}
+                            //     />
+                            // );
                         })}
                     </div>
                     <EditableView GetValue={returnEmptyString} SetValue={this.addNewTextDoc} placeholder={"Type ':' for commands"} contents={'+ New Node'} menuCallback={this.menuCallback} />
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 2cf0a1b79..0378fa67e 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -1,17 +1,17 @@
 import React = require('react');
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, ObservableSet } from 'mobx';
+import { computed, ObservableSet } from 'mobx';
 import { observer } from 'mobx-react';
 import { Doc } from '../../../../fields/Doc';
-import { DragManager } from '../../../util/DragManager';
 import { undoBatch } from '../../../util/UndoManager';
 import { ViewBoxBaseComponent } from '../../DocComponent';
-import { Colors } from '../../global/globalEnums';
 import { OpenWhere } from '../../nodes/DocumentView';
-import { FieldViewProps } from '../../nodes/FieldView';
+import { FieldView, FieldViewProps } from '../../nodes/FieldView';
+import { CollectionSchemaView } from './CollectionSchemaView';
 import './CollectionSchemaView.scss';
 import { SchemaTableCell } from './SchemaTableCell';
-import { setupMoveUpEvents, emptyFunction } from '../../../../Utils';
+import { Colors } from '../../global/globalEnums';
+import { DocCast, StrCast } from '../../../../fields/Types';
 
 export interface SchemaRowBoxProps extends FieldViewProps {
     rowIndex: number;
@@ -27,79 +27,93 @@ export interface SchemaRowBoxProps extends FieldViewProps {
 }
 
 @observer
-export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
+export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
+    public static LayoutString(fieldKey: string) {
+        return FieldView.LayoutString(SchemaRowBox, fieldKey);
+    }
+
     private _ref: HTMLDivElement | null = null;
 
     bounds = () => this._ref?.getBoundingClientRect();
 
-    isSelected = () => this.props.selectedDocs.has(this.props.Document);
+    @computed get schemaView() {
+        const vpath = this.props.docViewPath();
+        console.log(vpath[vpath.length - 2]);
+        return vpath.length > 1 ? (vpath[vpath.length - 2].ComponentView as CollectionSchemaView) : undefined;
+    }
 
-    @action
-    onRowPointerDown = (e: React.PointerEvent) => {
-        e.stopPropagation();
+    @computed get schemaDoc() {
+        return this.props.ContainingCollectionDoc!;
+    }
 
-        setupMoveUpEvents(
-            this,
-            e,
-            e => this.props.startDrag(e, this.props.Document, this._ref!, this.props.rowIndex),
-            emptyFunction,
-            e => this.props.selectRow(e, this.props.Document, this._ref!, this.props.rowIndex)
-        );
-    };
+    // isSelected = () => this.props.selectedDocs.has(this.props.Document);
 
-    onPointerEnter = (e: any) => {
-        if (!this.props.dragging) return;
-        document.removeEventListener('pointermove', this.onPointerMove);
-        document.addEventListener('pointermove', this.onPointerMove);
-    };
+    // @action
+    // onRowPointerDown = (e: React.PointerEvent) => {
+    //     e.stopPropagation();
 
-    onPointerMove = (e: any) => {
-        if (!this.props.dragging) return;
-        let dragIsRow: boolean = true;
-        DragManager.docsBeingDragged.forEach(doc => {
-            dragIsRow = this.props.selectedDocs.has(doc);
-        });
-        if (this._ref && dragIsRow) {
-            const rect = this._ref.getBoundingClientRect();
-            const y = e.clientY - rect.top; //y position within the element.
-            const height = this._ref.clientHeight;
-            const halfLine = height / 2;
-            if (y <= halfLine) {
-                this._ref.style.borderTop = `solid 2px ${Colors.MEDIUM_BLUE}`;
-                this._ref.style.borderBottom = '0px';
-                this.props.dropIndex(this.props.rowIndex);
-            } else if (y > halfLine) {
-                this._ref.style.borderTop = '0px';
-                this._ref.style.borderBottom = `solid 2px ${Colors.MEDIUM_BLUE}`;
-                this.props.dropIndex(this.props.rowIndex + 1);
-            }
-        }
-    };
+    //     setupMoveUpEvents(
+    //         this,
+    //         e,
+    //         e => this.props.startDrag(e, this.props.Document, this._ref!, this.props.rowIndex),
+    //         emptyFunction,
+    //         e => this.props.selectRow(e, this.props.Document, this._ref!, this.props.rowIndex)
+    //     );
+    // };
+
+    // onPointerEnter = (e: any) => {
+    //     if (!this.props.dragging) return;
+    //     document.removeEventListener('pointermove', this.onPointerMove);
+    //     document.addEventListener('pointermove', this.onPointerMove);
+    // };
+
+    // onPointerMove = (e: any) => {
+    //     if (!this.props.dragging) return;
+    //     let dragIsRow: boolean = true;
+    //     DragManager.docsBeingDragged.forEach(doc => {
+    //         dragIsRow = this.props.selectedDocs.has(doc);
+    //     });
+    //     if (this._ref && dragIsRow) {
+    //         const rect = this._ref.getBoundingClientRect();
+    //         const y = e.clientY - rect.top; //y position within the element.
+    //         const height = this._ref.clientHeight;
+    //         const halfLine = height / 2;
+    //         if (y <= halfLine) {
+    //             this._ref.style.borderTop = `solid 2px ${Colors.MEDIUM_BLUE}`;
+    //             this._ref.style.borderBottom = '0px';
+    //             this.props.dropIndex(this.props.rowIndex);
+    //         } else if (y > halfLine) {
+    //             this._ref.style.borderTop = '0px';
+    //             this._ref.style.borderBottom = `solid 2px ${Colors.MEDIUM_BLUE}`;
+    //             this.props.dropIndex(this.props.rowIndex + 1);
+    //         }
+    //     }
+    // };
 
     onPointerLeave = (e: any) => {
         if (this._ref) {
             this._ref.style.borderTop = '0px';
             this._ref.style.borderBottom = '0px';
         }
-        document.removeEventListener('pointermove', this.onPointerMove);
+        // document.removeEventListener('pointermove', this.onPointerMove);
     };
 
     render() {
         return (
             <div
                 className="schema-row"
-                style={this.isSelected() ? { backgroundColor: Colors.LIGHT_BLUE, opacity: this.props.dragging ? 0.5 : 1 } : {}}
-                onPointerDown={this.onRowPointerDown}
-                onPointerEnter={this.onPointerEnter}
+                style={this.props.isSelected() ? { backgroundColor: Colors.LIGHT_BLUE /*, opacity: this.props.dragging ? 0.5 : 1 */ } : {}}
+                // onPointerDown={this.onRowPointerDown}
+                // onPointerEnter={this.onPointerEnter}
                 onPointerLeave={this.onPointerLeave}
                 ref={(row: HTMLDivElement | null) => {
-                    row && this.props.addRowRef(this.props.Document, row);
+                    // row && this.props.addRowRef(this.props.Document, row);
                     this._ref = row;
                 }}>
                 <div
                     className="row-menu"
                     style={{
-                        width: this.props.rowMenuWidth,
+                        width: CollectionSchemaView._rowMenuWidth,
                     }}>
                     <div
                         className="schema-row-button"
@@ -119,8 +133,8 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
                     </div>
                 </div>
                 <div className="row-cells">
-                    {this.props.columnKeys.map((key, index) => (
-                        <SchemaTableCell key={key} Document={this.props.Document} fieldKey={key} columnWidth={this.props.columnWidths[index]} />
+                    {this.schemaView?.columnKeys?.map((key, index) => (
+                        <SchemaTableCell key={key} Document={this.props.Document} fieldKey={key} columnWidth={this.schemaView?.displayColumnWidths[index] ?? CollectionSchemaView._minColWidth} />
                     ))}
                 </div>
             </div>
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 5d9474173..e2f6d99f1 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -1,7 +1,14 @@
 import React = require('react');
 import { observer } from 'mobx-react';
-import { Doc, Field } from '../../../../fields/Doc';
+import { Doc, DocListCast, Field } from '../../../../fields/Doc';
 import './CollectionSchemaView.scss';
+import { type } from 'jquery';
+import { action } from 'mobx';
+import { ComputedField } from '../../../../fields/ScriptField';
+import { FieldValue } from '../../../../fields/Types';
+import { CompileScript } from '../../../util/Scripting';
+import { EditableView } from '../../EditableView';
+import { MAX_ROW_HEIGHT } from '../../global/globalCssVariables.scss';
 
 export interface SchemaTableCellProps {
     Document: Doc;
@@ -14,7 +21,8 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
     render() {
         return (
             <div className="schema-table-cell" style={{ width: this.props.columnWidth }}>
-                {Field.toString(this.props.Document[this.props.fieldKey] as Field)}
+                {/* {Field.toString(this.props.Document[this.props.fieldKey] as Field)} */}
+                <EditableView contents={Field.toString(this.props.Document[this.props.fieldKey] as Field)} GetValue={() => Field.toKeyValueString(this.props.Document, this.props.fieldKey)} SetValue={(value: string) => true} />
             </div>
         );
     }
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index 569579996..459554ebe 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -44,6 +44,7 @@ import { WebBox } from './WebBox';
 import React = require('react');
 import XRegExp = require('xregexp');
 import { LoadingBox } from './LoadingBox';
+import { SchemaRowBox } from '../collections/collectionSchema/SchemaRowBox';
 
 const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this?
 
@@ -268,6 +269,7 @@ export class DocumentContentsView extends React.Component<
                     HTMLtag,
                     ComparisonBox,
                     LoadingBox,
+                    SchemaRowBox,
                 }}
                 bindings={bindings}
                 jsx={layoutFrame}
-- 
cgit v1.2.3-70-g09d2


From d7d94fb4a9480a699eafa250a95821f7c584911d Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Tue, 28 Feb 2023 15:15:48 -0500
Subject: rows are documentviews (again)

---
 .../collections/collectionSchema/CollectionSchemaView.scss |  4 ++--
 .../collections/collectionSchema/CollectionSchemaView.tsx  | 14 ++++++++------
 .../views/collections/collectionSchema/SchemaRowBox.tsx    |  2 +-
 3 files changed, 11 insertions(+), 9 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaRowBox.tsx')

diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
index 46c2e2d1a..5c0b6d88b 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
@@ -135,7 +135,7 @@
 }
 
 .schema-row-wrapper {
-    max-height: 70px;
+    // max-height: 70px;
     overflow: hidden;
 }
 
@@ -144,7 +144,7 @@
     display: flex;
     flex-direction: row;
     height: 100%;
-    max-height: 70px;
+    // max-height: 70px;
     overflow: auto;
 
     .schema-column-header,
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 379676f41..bd9303997 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -33,7 +33,7 @@ export enum ColumnType {
     Image,
 }
 
-const defaultColumnKeys: string[] = ['title', 'type', 'author', 'text', 'data', 'creationDate'];
+const defaultColumnKeys: string[] = ['title', 'type', 'author', 'creationDate', 'links'];
 
 @observer
 export class CollectionSchemaView extends CollectionSubView() {
@@ -43,6 +43,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     private _closestDropIndex: number = 0;
     private _previewRef: HTMLDivElement | null = null;
 
+    public static _rowHeight: number = 50;
     public static _minColWidth: number = 150;
     public static _rowMenuWidth: number = 100;
     public static _previewDividerWidth: number = 4;
@@ -419,7 +420,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     @action
     addNewTextDoc = (value: string, shiftDown?: boolean, forceEmptyNote?: boolean) => {
         if (!value && !forceEmptyNote) return false;
-        const newDoc = Docs.Create.TextDocument(value, { title: value });
+        const newDoc = Docs.Create.TextDocument(value, { title: value, _autoHeight: true });
         FormattedTextBox.SelectOnLoad = newDoc[Id];
         FormattedTextBox.SelectOnLoadChar = forceEmptyNote ? '' : ' ';
         return this.props.addDocument?.(newDoc) || false;
@@ -534,7 +535,7 @@ export class CollectionSchemaView extends CollectionSubView() {
                         SelectionManager.SelectSchemaViewDoc(undefined);
                         this._previewDoc = undefined;
                     })}>
-                    <div className="schema-header-row">
+                    <div className="schema-header-row" style={{ height: CollectionSchemaView._rowHeight }}>
                         <div className="row-menu" style={{ width: CollectionSchemaView._rowMenuWidth }}></div>
                         {this.columnKeys.map((key, index) => {
                             return (
@@ -561,7 +562,7 @@ export class CollectionSchemaView extends CollectionSubView() {
                             const dataDoc = !doc.isTemplateDoc && !doc.isTemplateForField && !doc.PARAMS ? undefined : this.props.DataDoc;
                             let dref: Opt<DocumentView>;
                             return (
-                                <div className="schema-row-wrapper">
+                                <div className="schema-row-wrapper" style={{ maxHeight: CollectionSchemaView._rowHeight }}>
                                     <DocumentView
                                         {...this.props}
                                         ref={r => (dref = r || undefined)}
@@ -573,7 +574,7 @@ export class CollectionSchemaView extends CollectionSubView() {
                                         ContainingCollectionView={this.props.CollectionView}
                                         ContainingCollectionDoc={this.Document}
                                         PanelWidth={() => this.tableWidth}
-                                        PanelHeight={() => 70}
+                                        PanelHeight={() => CollectionSchemaView._rowHeight}
                                         styleProvider={DefaultStyleProvider}
                                         focus={this.focusDocument}
                                         docFilters={this.childDocFilters}
@@ -581,12 +582,13 @@ export class CollectionSchemaView extends CollectionSubView() {
                                         docRangeFilters={this.childDocRangeFilters}
                                         searchFilterDocs={this.searchFilterDocs}
                                         rootSelected={this.rootSelected}
-                                        ScreenToLocalTransform={() => this.getDocTransform(doc, dref)}
+                                        ScreenToLocalTransform={Transform.Identity}
                                         bringToFront={emptyFunction}
                                         isContentActive={this.isChildContentActive}
                                         hideDecorations={true}
                                         hideTitle={true}
                                         hideDocumentButtonBar={true}
+                                        fitWidth={returnTrue}
                                     />
                                 </div>
                             );
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 0378fa67e..e72ed3c4f 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -102,7 +102,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
         return (
             <div
                 className="schema-row"
-                style={this.props.isSelected() ? { backgroundColor: Colors.LIGHT_BLUE /*, opacity: this.props.dragging ? 0.5 : 1 */ } : {}}
+                style={this.props.isSelected() ? { height: CollectionSchemaView._rowHeight, backgroundColor: Colors.LIGHT_BLUE /*, opacity: this.props.dragging ? 0.5 : 1 */ } : { height: CollectionSchemaView._rowHeight }}
                 // onPointerDown={this.onRowPointerDown}
                 // onPointerEnter={this.onPointerEnter}
                 onPointerLeave={this.onPointerLeave}
-- 
cgit v1.2.3-70-g09d2


From df4781b27848731b329068b13da89a17d04ad1a9 Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Tue, 28 Feb 2023 17:13:11 -0500
Subject: selection working (except ctrl+click)

---
 .../collectionSchema/CollectionSchemaView.tsx      | 157 ++++++++++-----------
 .../collections/collectionSchema/SchemaRowBox.tsx  |  56 ++++----
 .../collectionSchema/SchemaTableCell.tsx           |   4 +-
 3 files changed, 102 insertions(+), 115 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaRowBox.tsx')

diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index bd9303997..22b8496aa 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -6,7 +6,7 @@ import { Id } from '../../../../fields/FieldSymbols';
 import { List } from '../../../../fields/List';
 import { RichTextField } from '../../../../fields/RichTextField';
 import { listSpec } from '../../../../fields/Schema';
-import { BoolCast, Cast, NumCast, StrCast } from '../../../../fields/Types';
+import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../../fields/Types';
 import { ImageField } from '../../../../fields/URLField';
 import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, setupMoveUpEvents, smoothScroll, Utils } from '../../../../Utils';
 import { Docs, DocUtils } from '../../../documents/Documents';
@@ -24,6 +24,7 @@ import './CollectionSchemaView.scss';
 import { SchemaColumnHeader } from './SchemaColumnHeader';
 import { SchemaRowBox } from './SchemaRowBox';
 import { DefaultStyleProvider } from '../../StyleProvider';
+import { DocumentManager } from '../../../util/DocumentManager';
 
 export enum ColumnType {
     Number,
@@ -38,7 +39,6 @@ const defaultColumnKeys: string[] = ['title', 'type', 'author', 'creationDate',
 @observer
 export class CollectionSchemaView extends CollectionSubView() {
     private _ref: HTMLDivElement | null = null;
-    private _lastSelectedRow: number | undefined;
     private _selectedDocSortedArray: Doc[] = [];
     private _closestDropIndex: number = 0;
     private _previewRef: HTMLDivElement | null = null;
@@ -47,11 +47,11 @@ export class CollectionSchemaView extends CollectionSubView() {
     public static _minColWidth: number = 150;
     public static _rowMenuWidth: number = 100;
     public static _previewDividerWidth: number = 4;
+    @observable _lastSelectedRow: number | undefined;
     @observable _selectedDocs: ObservableSet = new ObservableSet<Doc>();
     @observable _rowEles: ObservableMap = new ObservableMap<Doc, HTMLDivElement>();
     @observable _isDragging: boolean = false;
     @observable _displayColumnWidths: number[] | undefined;
-    @observable _previewDoc: Doc | undefined;
 
     get documentKeys() {
         const docs = this.childDocs;
@@ -110,6 +110,10 @@ export class CollectionSchemaView extends CollectionSubView() {
         return BoolCast(this.layoutDoc.sortDesc);
     }
 
+    rowIndex(doc: Doc) {
+        return this.childDocs.indexOf(doc);
+    }
+
     componentDidMount() {
         this.props.setContentView?.(this as DocComponentView);
         document.addEventListener('keydown', this.onKeyDown);
@@ -121,30 +125,32 @@ export class CollectionSchemaView extends CollectionSubView() {
 
     @action
     onKeyDown = (e: KeyboardEvent) => {
-        if (this._selectedDocs.size > 0) {
-            if (e.key == 'ArrowDown') {
-                const lastDoc = Array.from(this._selectedDocs.values()).lastElement();
-                const lastIndex = this.childDocs.indexOf(lastDoc);
-                if (lastIndex >= 0 && lastIndex < this.childDocs.length - 1) {
-                    this._selectedDocs.clear();
-                    const newDoc = this.childDocs[lastIndex + 1];
-                    this._selectedDocs.add(newDoc);
-                    SelectionManager.SelectSchemaViewDoc(newDoc);
-                    this._previewDoc = newDoc;
-                }
-            }
-            if (e.key == 'ArrowUp') {
-                const firstDoc = Array.from(this._selectedDocs.values())[0];
-                const firstIndex = this.childDocs.indexOf(firstDoc);
-                if (firstIndex > 0) {
-                    this._selectedDocs.clear();
-                    const newDoc = this.childDocs[firstIndex - 1];
-                    this._selectedDocs.add(newDoc);
-                    SelectionManager.SelectSchemaViewDoc(newDoc);
-                    this._previewDoc = newDoc;
-                }
-            }
-        }
+        // if (this._selectedDocs.size > 0) {
+        //     if (e.key == 'ArrowDown') {
+        //         const lastDoc = Array.from(this._selectedDocs.values()).lastElement();
+        //         const lastIndex = this.childDocs.indexOf(lastDoc);
+        //         if (lastIndex >= 0 && lastIndex < this.childDocs.length - 1) {
+        //             this._selectedDocs.clear();
+        //             const newDoc = this.childDocs[lastIndex + 1];
+        //             this._selectedDocs.add(newDoc);
+        //             const presDocView = DocumentManager.Instance.getDocumentView(this.rootDoc);
+        //         if (presDocView) SelectionManager.SelectView(presDocView, false);
+        //             SelectionManager.SelectSchemaViewDoc(newDoc);
+        //             this._previewDoc = newDoc;
+        //         }
+        //     }
+        //     if (e.key == 'ArrowUp') {
+        //         const firstDoc = Array.from(this._selectedDocs.values())[0];
+        //         const firstIndex = this.childDocs.indexOf(firstDoc);
+        //         if (firstIndex > 0) {
+        //             this._selectedDocs.clear();
+        //             const newDoc = this.childDocs[firstIndex - 1];
+        //             this._selectedDocs.add(newDoc);
+        //             SelectionManager.SelectSchemaViewDoc(newDoc);
+        //             this._previewDoc = newDoc;
+        //         }
+        //     }
+        // }
     };
 
     @undoBatch
@@ -304,40 +310,51 @@ export class CollectionSchemaView extends CollectionSubView() {
     };
 
     @action
-    selectRow = (e: React.PointerEvent, doc: Doc, ref: HTMLDivElement, index: number) => {
+    addDocToSelection = (doc: Doc, extendSelection: boolean, index: number) => {
+        this._selectedDocs.add(doc);
+        const rowDocView = DocumentManager.Instance.getDocumentView(doc);
+        if (rowDocView) SelectionManager.SelectView(rowDocView, extendSelection);
+        this._lastSelectedRow = index;
+    };
+
+    @action
+    removeDocFromSelection = (doc: Doc) => {
+        if (this._selectedDocs.has(doc)) this._selectedDocs.delete(doc);
+        const rowDocView = DocumentManager.Instance.getDocumentView(doc);
+        if (rowDocView) SelectionManager.DeselectView(rowDocView);
+    };
+
+    @action
+    clearSelection = () => {
+        this._selectedDocs.clear();
+        SelectionManager.DeselectAll();
+        this._lastSelectedRow = undefined;
+    };
+
+    @action
+    selectRow = (e: PointerEvent, doc: Doc, ref: HTMLDivElement, index: number) => {
+        e.stopPropagation();
+        if (index < 0) return;
         const ctrl = e.ctrlKey || e.metaKey;
         const shift = e.shiftKey;
         if (shift && this._lastSelectedRow !== undefined) {
             const startRow = Math.min(this._lastSelectedRow, index);
             const endRow = Math.max(this._lastSelectedRow, index);
             for (let i = startRow; i <= endRow; i++) {
-                const currDoc: Doc = this.childDocs[i];
-                if (!this._selectedDocs.has(currDoc)) this._selectedDocs.add(currDoc);
+                this.addDocToSelection(this.childDocs[i], true, i);
             }
-            this._lastSelectedRow = endRow;
+            this._lastSelectedRow = index;
         } else if (ctrl) {
             if (!this._selectedDocs.has(doc)) {
-                this._selectedDocs.add(doc);
-                this._lastSelectedRow = index;
+                console.log('add');
+                this.addDocToSelection(doc, true, index);
             } else {
-                this._selectedDocs.delete(doc);
+                console.log('remove');
+                this.removeDocFromSelection(doc);
             }
         } else {
-            this._selectedDocs.clear();
-            this._selectedDocs.add(doc);
-            this._lastSelectedRow = index;
-        }
-
-        if (this._lastSelectedRow && this._selectedDocs.size > 0) {
-            SelectionManager.SelectSchemaViewDoc(this.childDocs[this._lastSelectedRow]);
-        } else {
-            SelectionManager.SelectSchemaViewDoc(undefined);
-        }
-
-        if (this._selectedDocs.size == 1) {
-            this._previewDoc = Array.from(this._selectedDocs)[0];
-        } else {
-            this._previewDoc = undefined;
+            this.clearSelection();
+            this.addDocToSelection(doc, false, index);
         }
     };
 
@@ -381,10 +398,8 @@ export class CollectionSchemaView extends CollectionSubView() {
     @action
     startDrag = (e: React.PointerEvent, doc: Doc, ref: HTMLDivElement, index: number) => {
         if (!this._selectedDocs.has(doc)) {
-            this._selectedDocs.clear();
-            this._selectedDocs.add(doc);
-            this._lastSelectedRow = index;
-            SelectionManager.SelectSchemaViewDoc(doc);
+            this.clearSelection();
+            this.addDocToSelection(doc, false, index);
         }
         this._isDragging = true;
         this._selectedDocSortedArray = this.sortedSelectedDocs();
@@ -511,13 +526,9 @@ export class CollectionSchemaView extends CollectionSubView() {
             afterFocus: (didFocus: boolean) => new Promise<ViewAdjustment>(res => setTimeout(async () => res(await endFocus(didFocus)), focusSpeed)),
         });
     };
+
     isChildContentActive = () =>
         this.props.isDocumentActive?.() && (this.props.childDocumentsActive?.() || BoolCast(this.rootDoc.childDocumentsActive)) ? true : this.props.childDocumentsActive?.() === false || this.rootDoc.childDocumentsActive === false ? false : undefined;
-    getDocTransform(doc: Doc, dref?: DocumentView) {
-        const { scale, translateX, translateY } = Utils.GetScreenTransform(dref?.ContentDiv || undefined);
-        // the document view may center its contents and if so, will prepend that onto the screenToLocalTansform.  so we have to subtract that off
-        return new Transform(-translateX + (dref?.centeringX || 0), -translateY + (dref?.centeringY || 0), 1).scale(this.props.ScreenToLocalTransform().Scale);
-    }
 
     render() {
         return (
@@ -531,9 +542,7 @@ export class CollectionSchemaView extends CollectionSubView() {
                 <div
                     className="schema-table"
                     onPointerDown={action(() => {
-                        this._selectedDocs.clear();
-                        SelectionManager.SelectSchemaViewDoc(undefined);
-                        this._previewDoc = undefined;
+                        this.clearSelection();
                     })}>
                     <div className="schema-header-row" style={{ height: CollectionSchemaView._rowHeight }}>
                         <div className="row-menu" style={{ width: CollectionSchemaView._rowMenuWidth }}></div>
@@ -552,7 +561,6 @@ export class CollectionSchemaView extends CollectionSubView() {
                                     addColumn={this.addColumn}
                                     removeColumn={this.removeColumn}
                                     resizeColumn={this.startResize}
-                                    // dragColumn={this.dragColumn}
                                 />
                             );
                         })}
@@ -568,7 +576,6 @@ export class CollectionSchemaView extends CollectionSubView() {
                                         ref={r => (dref = r || undefined)}
                                         LayoutTemplate={this.props.childLayoutTemplate}
                                         LayoutTemplateString={SchemaRowBox.LayoutString(this.props.fieldKey)}
-                                        renderDepth={this.props.renderDepth + 1}
                                         Document={doc}
                                         DataDoc={dataDoc}
                                         ContainingCollectionView={this.props.CollectionView}
@@ -578,7 +585,6 @@ export class CollectionSchemaView extends CollectionSubView() {
                                         styleProvider={DefaultStyleProvider}
                                         focus={this.focusDocument}
                                         docFilters={this.childDocFilters}
-                                        docViewPath={this.props.docViewPath}
                                         docRangeFilters={this.childDocRangeFilters}
                                         searchFilterDocs={this.searchFilterDocs}
                                         rootSelected={this.rootSelected}
@@ -592,25 +598,6 @@ export class CollectionSchemaView extends CollectionSubView() {
                                     />
                                 </div>
                             );
-                            // return (
-                            //     <SchemaRowBox
-                            //         {...this.props}
-                            //         key={index}
-                            //         Document={doc}
-                            //         ContainingCollectionDoc={this.props.CollectionView?.props.Document}
-                            //         ContainingCollectionView={this.props.CollectionView}
-                            //         rowIndex={index}
-                            //         columnKeys={this.columnKeys}
-                            //         columnWidths={this.displayColumnWidths}
-                            //         rowMenuWidth={CollectionSchemaView._rowMenuWidth}
-                            //         selectedDocs={this._selectedDocs}
-                            //         selectRow={this.selectRow}
-                            //         startDrag={this.startDrag}
-                            //         dragging={this._isDragging}
-                            //         dropIndex={this.setDropIndex}
-                            //         addRowRef={this.addRowRef}
-                            //     />
-                            // );
                         })}
                     </div>
                     <EditableView GetValue={returnEmptyString} SetValue={this.addNewTextDoc} placeholder={"Type ':' for commands"} contents={'+ New Node'} menuCallback={this.menuCallback} />
@@ -618,9 +605,9 @@ export class CollectionSchemaView extends CollectionSubView() {
                 {this.previewWidth > 0 && <div className="schema-preview-divider" style={{ width: CollectionSchemaView._previewDividerWidth }} onPointerDown={this.onDividerDown}></div>}
                 {this.previewWidth > 0 && (
                     <div style={{ width: `${this.previewWidth}px` }} ref={ref => (this._previewRef = ref)}>
-                        {this._previewDoc && (
+                        {this._lastSelectedRow !== undefined && (
                             <DocumentView
-                                Document={this._previewDoc}
+                                Document={this.childDocs[this._lastSelectedRow]}
                                 DataDoc={undefined}
                                 fitContentsToBox={returnTrue}
                                 dontCenter={'y'}
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index e72ed3c4f..d67e6f2d7 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -1,6 +1,6 @@
 import React = require('react');
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { computed, ObservableSet } from 'mobx';
+import { action, computed, ObservableSet } from 'mobx';
 import { observer } from 'mobx-react';
 import { Doc } from '../../../../fields/Doc';
 import { undoBatch } from '../../../util/UndoManager';
@@ -12,19 +12,7 @@ import './CollectionSchemaView.scss';
 import { SchemaTableCell } from './SchemaTableCell';
 import { Colors } from '../../global/globalEnums';
 import { DocCast, StrCast } from '../../../../fields/Types';
-
-export interface SchemaRowBoxProps extends FieldViewProps {
-    rowIndex: number;
-    columnKeys: string[];
-    columnWidths: number[];
-    rowMenuWidth: number;
-    selectedDocs: ObservableSet<Doc>;
-    selectRow: (e: any, doc: Doc, ref: HTMLDivElement, index: number) => void;
-    startDrag: (e: any, doc: Doc, ref: HTMLDivElement, index: number) => boolean;
-    dragging: boolean;
-    dropIndex: (index: number) => void;
-    addRowRef: (doc: Doc, ref: HTMLDivElement) => void;
-}
+import { setupMoveUpEvents, emptyFunction } from '../../../../Utils';
 
 @observer
 export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
@@ -38,7 +26,6 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
 
     @computed get schemaView() {
         const vpath = this.props.docViewPath();
-        console.log(vpath[vpath.length - 2]);
         return vpath.length > 1 ? (vpath[vpath.length - 2].ComponentView as CollectionSchemaView) : undefined;
     }
 
@@ -46,20 +33,25 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
         return this.props.ContainingCollectionDoc!;
     }
 
+    @computed get rowIndex() {
+        return this.schemaView?.rowIndex(this.rootDoc) ?? -1;
+    }
+
     // isSelected = () => this.props.selectedDocs.has(this.props.Document);
 
-    // @action
-    // onRowPointerDown = (e: React.PointerEvent) => {
-    //     e.stopPropagation();
+    @action
+    onRowPointerDown = (e: React.PointerEvent) => {
+        e.stopPropagation();
 
-    //     setupMoveUpEvents(
-    //         this,
-    //         e,
-    //         e => this.props.startDrag(e, this.props.Document, this._ref!, this.props.rowIndex),
-    //         emptyFunction,
-    //         e => this.props.selectRow(e, this.props.Document, this._ref!, this.props.rowIndex)
-    //     );
-    // };
+        setupMoveUpEvents(
+            this,
+            e,
+            // e => this.schemaView?.startDrag(e, this.props.Document, this._ref!, this.props.rowIndex) ?? true,
+            returnTrue,
+            emptyFunction,
+            e => this.schemaView?.selectRow(e, this.props.Document, this._ref!, this.rowIndex)
+        );
+    };
 
     // onPointerEnter = (e: any) => {
     //     if (!this.props.dragging) return;
@@ -102,8 +94,12 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
         return (
             <div
                 className="schema-row"
-                style={this.props.isSelected() ? { height: CollectionSchemaView._rowHeight, backgroundColor: Colors.LIGHT_BLUE /*, opacity: this.props.dragging ? 0.5 : 1 */ } : { height: CollectionSchemaView._rowHeight }}
-                // onPointerDown={this.onRowPointerDown}
+                style={
+                    this.props.isSelected()
+                        ? { height: CollectionSchemaView._rowHeight, backgroundColor: Colors.LIGHT_BLUE, pointerEvents: this.schemaView?.props.isContentActive() ? 'all' : undefined /*, opacity: this.props.dragging ? 0.5 : 1 */ }
+                        : { height: CollectionSchemaView._rowHeight, pointerEvents: this.schemaView?.props.isContentActive() ? 'all' : undefined }
+                }
+                onPointerDown={this.onRowPointerDown}
                 // onPointerEnter={this.onPointerEnter}
                 onPointerLeave={this.onPointerLeave}
                 ref={(row: HTMLDivElement | null) => {
@@ -141,3 +137,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
         );
     }
 }
+function // e => this.schemaView?.startDrag(e, this.props.Document, this._ref!, this.props.rowIndex) ?? true,
+returnTrue(e: PointerEvent, down: number[], delta: number[]): boolean {
+    throw new Error('Function not implemented.');
+}
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index e2f6d99f1..4cfc5850c 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -21,8 +21,8 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
     render() {
         return (
             <div className="schema-table-cell" style={{ width: this.props.columnWidth }}>
-                {/* {Field.toString(this.props.Document[this.props.fieldKey] as Field)} */}
-                <EditableView contents={Field.toString(this.props.Document[this.props.fieldKey] as Field)} GetValue={() => Field.toKeyValueString(this.props.Document, this.props.fieldKey)} SetValue={(value: string) => true} />
+                {Field.toString(this.props.Document[this.props.fieldKey] as Field)}
+                {/* <EditableView contents={Field.toString(this.props.Document[this.props.fieldKey] as Field)} GetValue={() => Field.toKeyValueString(this.props.Document, this.props.fieldKey)} SetValue={(value: string) => true} /> */}
             </div>
         );
     }
-- 
cgit v1.2.3-70-g09d2


From d7cb4929e437f2a03336e21b16aa4fb0cebf5ebe Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Tue, 28 Feb 2023 17:20:17 -0500
Subject: added dragging code

---
 .../collectionSchema/CollectionSchemaView.tsx      |  2 +-
 .../collections/collectionSchema/SchemaRowBox.tsx  | 70 ++++++++++------------
 2 files changed, 34 insertions(+), 38 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaRowBox.tsx')

diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 22b8496aa..0cf5a1ed9 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -396,7 +396,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     };
 
     @action
-    startDrag = (e: React.PointerEvent, doc: Doc, ref: HTMLDivElement, index: number) => {
+    startDrag = (e: PointerEvent, doc: Doc, ref: HTMLDivElement, index: number) => {
         if (!this._selectedDocs.has(doc)) {
             this.clearSelection();
             this.addDocToSelection(doc, false, index);
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index d67e6f2d7..0e7b0fa16 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -13,6 +13,7 @@ import { SchemaTableCell } from './SchemaTableCell';
 import { Colors } from '../../global/globalEnums';
 import { DocCast, StrCast } from '../../../../fields/Types';
 import { setupMoveUpEvents, emptyFunction } from '../../../../Utils';
+import { DragManager } from '../../../util/DragManager';
 
 @observer
 export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
@@ -46,48 +47,47 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
         setupMoveUpEvents(
             this,
             e,
-            // e => this.schemaView?.startDrag(e, this.props.Document, this._ref!, this.props.rowIndex) ?? true,
-            returnTrue,
+            e => this.schemaView?.startDrag(e, this.rootDoc, this._ref!, this.rowIndex) ?? true,
             emptyFunction,
-            e => this.schemaView?.selectRow(e, this.props.Document, this._ref!, this.rowIndex)
+            e => this.schemaView?.selectRow(e, this.rootDoc, this._ref!, this.rowIndex)
         );
     };
 
-    // onPointerEnter = (e: any) => {
-    //     if (!this.props.dragging) return;
-    //     document.removeEventListener('pointermove', this.onPointerMove);
-    //     document.addEventListener('pointermove', this.onPointerMove);
-    // };
+    onPointerEnter = (e: any) => {
+        if (!this.schemaView?._isDragging) return;
+        document.removeEventListener('pointermove', this.onPointerMove);
+        document.addEventListener('pointermove', this.onPointerMove);
+    };
 
-    // onPointerMove = (e: any) => {
-    //     if (!this.props.dragging) return;
-    //     let dragIsRow: boolean = true;
-    //     DragManager.docsBeingDragged.forEach(doc => {
-    //         dragIsRow = this.props.selectedDocs.has(doc);
-    //     });
-    //     if (this._ref && dragIsRow) {
-    //         const rect = this._ref.getBoundingClientRect();
-    //         const y = e.clientY - rect.top; //y position within the element.
-    //         const height = this._ref.clientHeight;
-    //         const halfLine = height / 2;
-    //         if (y <= halfLine) {
-    //             this._ref.style.borderTop = `solid 2px ${Colors.MEDIUM_BLUE}`;
-    //             this._ref.style.borderBottom = '0px';
-    //             this.props.dropIndex(this.props.rowIndex);
-    //         } else if (y > halfLine) {
-    //             this._ref.style.borderTop = '0px';
-    //             this._ref.style.borderBottom = `solid 2px ${Colors.MEDIUM_BLUE}`;
-    //             this.props.dropIndex(this.props.rowIndex + 1);
-    //         }
-    //     }
-    // };
+    onPointerMove = (e: any) => {
+        if (!this.schemaView?._isDragging) return;
+        let dragIsRow: boolean = true;
+        DragManager.docsBeingDragged.forEach(doc => {
+            dragIsRow = this.schemaView?._selectedDocs.has(doc) ?? false;
+        });
+        if (this._ref && dragIsRow) {
+            const rect = this._ref.getBoundingClientRect();
+            const y = e.clientY - rect.top; //y position within the element.
+            const height = this._ref.clientHeight;
+            const halfLine = height / 2;
+            if (y <= halfLine) {
+                this._ref.style.borderTop = `solid 2px ${Colors.MEDIUM_BLUE}`;
+                this._ref.style.borderBottom = '0px';
+                this.schemaView?.setDropIndex(this.rowIndex);
+            } else if (y > halfLine) {
+                this._ref.style.borderTop = '0px';
+                this._ref.style.borderBottom = `solid 2px ${Colors.MEDIUM_BLUE}`;
+                this.schemaView?.setDropIndex(this.rowIndex + 1);
+            }
+        }
+    };
 
     onPointerLeave = (e: any) => {
         if (this._ref) {
             this._ref.style.borderTop = '0px';
             this._ref.style.borderBottom = '0px';
         }
-        // document.removeEventListener('pointermove', this.onPointerMove);
+        document.removeEventListener('pointermove', this.onPointerMove);
     };
 
     render() {
@@ -100,10 +100,10 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
                         : { height: CollectionSchemaView._rowHeight, pointerEvents: this.schemaView?.props.isContentActive() ? 'all' : undefined }
                 }
                 onPointerDown={this.onRowPointerDown}
-                // onPointerEnter={this.onPointerEnter}
+                onPointerEnter={this.onPointerEnter}
                 onPointerLeave={this.onPointerLeave}
                 ref={(row: HTMLDivElement | null) => {
-                    // row && this.props.addRowRef(this.props.Document, row);
+                    row && this.schemaView?.addRowRef(this.rootDoc, row);
                     this._ref = row;
                 }}>
                 <div
@@ -137,7 +137,3 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
         );
     }
 }
-function // e => this.schemaView?.startDrag(e, this.props.Document, this._ref!, this.props.rowIndex) ?? true,
-returnTrue(e: PointerEvent, down: number[], delta: number[]): boolean {
-    throw new Error('Function not implemented.');
-}
-- 
cgit v1.2.3-70-g09d2


From 027c89584d087ada9d45a46cb620b157ae29d0b9 Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Tue, 28 Feb 2023 17:44:16 -0500
Subject: arrow key movement

---
 .../collectionSchema/CollectionSchemaView.tsx      | 46 ++++++++++------------
 .../collections/collectionSchema/SchemaRowBox.tsx  |  2 -
 2 files changed, 20 insertions(+), 28 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaRowBox.tsx')

diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 0cf5a1ed9..a0e1ae8b2 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -125,32 +125,26 @@ export class CollectionSchemaView extends CollectionSubView() {
 
     @action
     onKeyDown = (e: KeyboardEvent) => {
-        // if (this._selectedDocs.size > 0) {
-        //     if (e.key == 'ArrowDown') {
-        //         const lastDoc = Array.from(this._selectedDocs.values()).lastElement();
-        //         const lastIndex = this.childDocs.indexOf(lastDoc);
-        //         if (lastIndex >= 0 && lastIndex < this.childDocs.length - 1) {
-        //             this._selectedDocs.clear();
-        //             const newDoc = this.childDocs[lastIndex + 1];
-        //             this._selectedDocs.add(newDoc);
-        //             const presDocView = DocumentManager.Instance.getDocumentView(this.rootDoc);
-        //         if (presDocView) SelectionManager.SelectView(presDocView, false);
-        //             SelectionManager.SelectSchemaViewDoc(newDoc);
-        //             this._previewDoc = newDoc;
-        //         }
-        //     }
-        //     if (e.key == 'ArrowUp') {
-        //         const firstDoc = Array.from(this._selectedDocs.values())[0];
-        //         const firstIndex = this.childDocs.indexOf(firstDoc);
-        //         if (firstIndex > 0) {
-        //             this._selectedDocs.clear();
-        //             const newDoc = this.childDocs[firstIndex - 1];
-        //             this._selectedDocs.add(newDoc);
-        //             SelectionManager.SelectSchemaViewDoc(newDoc);
-        //             this._previewDoc = newDoc;
-        //         }
-        //     }
-        // }
+        if (this._selectedDocs.size > 0) {
+            if (e.key == 'ArrowDown') {
+                const lastDoc = Array.from(this._selectedDocs.values()).lastElement();
+                const lastIndex = this.rowIndex(lastDoc);
+                if (lastIndex >= 0 && lastIndex < this.childDocs.length - 1) {
+                    !e.shiftKey && this.clearSelection();
+                    const newDoc = this.childDocs[lastIndex + 1];
+                    this.addDocToSelection(newDoc, e.shiftKey, lastIndex + 1);
+                }
+            }
+            if (e.key == 'ArrowUp') {
+                const firstDoc = Array.from(this._selectedDocs.values())[0];
+                const firstIndex = this.rowIndex(firstDoc);
+                if (firstIndex > 0 && firstIndex < this.childDocs.length) {
+                    !e.shiftKey && this.clearSelection();
+                    const newDoc = this.childDocs[firstIndex - 1];
+                    this.addDocToSelection(newDoc, e.shiftKey, firstIndex - 1);
+                }
+            }
+        }
     };
 
     @undoBatch
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 0e7b0fa16..0ed5f2df4 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -38,8 +38,6 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
         return this.schemaView?.rowIndex(this.rootDoc) ?? -1;
     }
 
-    // isSelected = () => this.props.selectedDocs.has(this.props.Document);
-
     @action
     onRowPointerDown = (e: React.PointerEvent) => {
         e.stopPropagation();
-- 
cgit v1.2.3-70-g09d2


From 4137fa5fedae84aa781f3ba22ddfb2410a0cad9a Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Tue, 28 Feb 2023 21:15:37 -0500
Subject: preserve sort when adding docs, break sort when rearranging

---
 .../collectionSchema/CollectionSchemaView.tsx      | 45 ++++++++++++++--------
 .../collections/collectionSchema/SchemaRowBox.tsx  |  6 +--
 2 files changed, 33 insertions(+), 18 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaRowBox.tsx')

diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index a0e1ae8b2..1a26f1178 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -8,7 +8,7 @@ import { RichTextField } from '../../../../fields/RichTextField';
 import { listSpec } from '../../../../fields/Schema';
 import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../../fields/Types';
 import { ImageField } from '../../../../fields/URLField';
-import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, setupMoveUpEvents, smoothScroll, Utils } from '../../../../Utils';
+import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTransparent, returnTrue, setupMoveUpEvents, smoothScroll, Utils } from '../../../../Utils';
 import { Docs, DocUtils } from '../../../documents/Documents';
 import { DragManager } from '../../../util/DragManager';
 import { SelectionManager } from '../../../util/SelectionManager';
@@ -69,7 +69,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     }
 
     @computed get previewWidth() {
-        return NumCast(this.props.Document.schemaPreviewWidth);
+        return NumCast(this.layoutDoc.schemaPreviewWidth);
     }
 
     @computed get tableWidth() {
@@ -103,7 +103,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     }
 
     @computed get sortField() {
-        return StrCast(this.layoutDoc.sortField, 'creationDate');
+        return StrCast(this.layoutDoc.sortField);
     }
 
     @computed get sortDesc() {
@@ -149,10 +149,14 @@ export class CollectionSchemaView extends CollectionSubView() {
 
     @undoBatch
     @action
-    setSort = (field: string, desc: boolean) => {
+    setSort = (field: string | undefined, desc: boolean = false) => {
         this.layoutDoc.sortField = field;
         this.layoutDoc.sortDesc = desc;
 
+        console.log(field, desc);
+
+        if (field === undefined) return;
+
         this.childDocs.sort((docA, docB) => {
             const aStr = Field.toString(docA[field] as Field);
             const bStr = Field.toString(docB[field] as Field);
@@ -164,6 +168,12 @@ export class CollectionSchemaView extends CollectionSubView() {
         });
     };
 
+    addRow = (doc: Doc | Doc[]) => {
+        const result: boolean = this.addDocument(doc);
+        this.setSort(this.sortField, this.sortDesc);
+        return result;
+    };
+
     @undoBatch
     @action
     changeColumnKey = (index: number, newKey: string, defaultVal?: any) => {
@@ -316,6 +326,9 @@ export class CollectionSchemaView extends CollectionSubView() {
         if (this._selectedDocs.has(doc)) this._selectedDocs.delete(doc);
         const rowDocView = DocumentManager.Instance.getDocumentView(doc);
         if (rowDocView) SelectionManager.DeselectView(rowDocView);
+        if (this._selectedDocs.size === 0) {
+            this._lastSelectedRow = undefined;
+        }
     };
 
     @action
@@ -340,10 +353,8 @@ export class CollectionSchemaView extends CollectionSubView() {
             this._lastSelectedRow = index;
         } else if (ctrl) {
             if (!this._selectedDocs.has(doc)) {
-                console.log('add');
                 this.addDocToSelection(doc, true, index);
             } else {
-                console.log('remove');
                 this.removeDocFromSelection(doc);
             }
         } else {
@@ -370,6 +381,7 @@ export class CollectionSchemaView extends CollectionSubView() {
             this.props.removeDocument?.(this._selectedDocSortedArray);
             this.addDocument(this._selectedDocSortedArray);
             this.addDocument(pushedDocs);
+            this.setSort(undefined);
             return true;
         }
         return false;
@@ -383,10 +395,13 @@ export class CollectionSchemaView extends CollectionSubView() {
             undoBatch(
                 action(docus => {
                     this._isDragging = false;
-                    docus.map((doc: Doc) => this.addDocument(doc));
+                    docus.map((doc: Doc) => {
+                        this.addDocument(doc);
+                    });
                 })
             )
         );
+        this.setSort(undefined);
     };
 
     @action
@@ -422,7 +437,7 @@ export class CollectionSchemaView extends CollectionSubView() {
         const maxWidth = 1000;
         const movedWidth = this.props.ScreenToLocalTransform().transformDirection(nativeWidth.right - e.clientX, 0)[0];
         const width = movedWidth < minWidth ? minWidth : movedWidth > maxWidth ? maxWidth : movedWidth;
-        this.props.Document.schemaPreviewWidth = width;
+        this.layoutDoc.schemaPreviewWidth = width;
         return false;
     };
 
@@ -432,7 +447,7 @@ export class CollectionSchemaView extends CollectionSubView() {
         const newDoc = Docs.Create.TextDocument(value, { title: value, _autoHeight: true });
         FormattedTextBox.SelectOnLoad = newDoc[Id];
         FormattedTextBox.SelectOnLoadChar = forceEmptyNote ? '' : ' ';
-        return this.props.addDocument?.(newDoc) || false;
+        return this.addRow(newDoc) || false;
     };
 
     menuCallback = (x: number, y: number) => {
@@ -444,9 +459,9 @@ export class CollectionSchemaView extends CollectionSubView() {
         DocUtils.addDocumentCreatorMenuItems(
             doc => {
                 FormattedTextBox.SelectOnLoad = StrCast(doc[Id]);
-                return this.addDocument(doc);
+                return this.addRow(doc);
             },
-            this.addDocument,
+            this.addRow,
             x,
             y,
             true
@@ -463,7 +478,7 @@ export class CollectionSchemaView extends CollectionSubView() {
                             if (this.props.Document.isTemplateDoc) {
                                 Doc.MakeMetadataFieldTemplate(created, this.props.Document);
                             }
-                            return this.props.addDocument?.(created);
+                            return this.addRow(created);
                         }
                     },
                     icon: 'compress-arrows-alt',
@@ -482,7 +497,7 @@ export class CollectionSchemaView extends CollectionSubView() {
                                 Doc.MakeMetadataFieldTemplate(created, container);
                                 return Doc.AddDocToList(container, Doc.LayoutFieldKey(container), created);
                             }
-                            return this.props.addDocument?.(created) || false;
+                            return this.addRow(created) || false;
                         }
                     },
                     icon: 'compress-arrows-alt',
@@ -497,7 +512,7 @@ export class CollectionSchemaView extends CollectionSubView() {
                 if (this.props.Document.isTemplateDoc) {
                     Doc.MakeMetadataFieldTemplate(created, this.props.Document);
                 }
-                this.props.addDocument?.(created);
+                this.addRow(created);
             }
         });
         ContextMenu.Instance.displayMenu(x, y, undefined, true);
@@ -621,7 +636,7 @@ export class CollectionSchemaView extends CollectionSubView() {
                                 ContainingCollectionDoc={this.props.CollectionView?.props.Document}
                                 ContainingCollectionView={this.props.CollectionView}
                                 moveDocument={this.props.moveDocument}
-                                addDocument={this.props.addDocument}
+                                addDocument={this.addRow}
                                 removeDocument={this.props.removeDocument}
                                 whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
                                 addDocTab={this.props.addDocTab}
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 0ed5f2df4..d6a00966d 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -113,7 +113,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
                         className="schema-row-button"
                         onPointerDown={undoBatch(e => {
                             e.stopPropagation();
-                            this.props.removeDocument?.(this.props.Document);
+                            this.props.removeDocument?.(this.rootDoc);
                         })}>
                         <FontAwesomeIcon icon="times" />
                     </div>
@@ -121,14 +121,14 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
                         className="schema-row-button"
                         onPointerDown={e => {
                             e.stopPropagation();
-                            this.props.addDocTab(this.props.Document, OpenWhere.addRight);
+                            this.props.addDocTab(this.rootDoc, OpenWhere.addRight);
                         }}>
                         <FontAwesomeIcon icon="external-link-alt" />
                     </div>
                 </div>
                 <div className="row-cells">
                     {this.schemaView?.columnKeys?.map((key, index) => (
-                        <SchemaTableCell key={key} Document={this.props.Document} fieldKey={key} columnWidth={this.schemaView?.displayColumnWidths[index] ?? CollectionSchemaView._minColWidth} />
+                        <SchemaTableCell key={key} Document={this.rootDoc} fieldKey={key} columnWidth={this.schemaView?.displayColumnWidths[index] ?? CollectionSchemaView._minColWidth} />
                     ))}
                 </div>
             </div>
-- 
cgit v1.2.3-70-g09d2


From 9853c1e3ca1c3a1d2da210118b927adc559e67fa Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Wed, 1 Mar 2023 17:53:56 -0500
Subject: override onclick script

---
 .../collectionSchema/CollectionSchemaView.tsx        | 20 +++++++++++++-------
 .../collections/collectionSchema/SchemaRowBox.tsx    | 20 ++++++++++----------
 src/client/views/nodes/DocumentView.tsx              |  3 ++-
 3 files changed, 25 insertions(+), 18 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaRowBox.tsx')

diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 1a26f1178..02591489b 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -25,6 +25,7 @@ import { SchemaColumnHeader } from './SchemaColumnHeader';
 import { SchemaRowBox } from './SchemaRowBox';
 import { DefaultStyleProvider } from '../../StyleProvider';
 import { DocumentManager } from '../../../util/DocumentManager';
+import { ScriptField } from '../../../../fields/ScriptField';
 
 export enum ColumnType {
     Number,
@@ -338,12 +339,13 @@ export class CollectionSchemaView extends CollectionSubView() {
         this._lastSelectedRow = undefined;
     };
 
+    rowOnClickScript = ScriptField.MakeFunction('scriptContext.selectRow(self, shiftKey, ctrlKey || metaKey)', { scriptContext: 'any', shiftKey: 'boolean', ctrlKey: 'boolean', metaKey: 'boolean' })!;
+
     @action
-    selectRow = (e: PointerEvent, doc: Doc, ref: HTMLDivElement, index: number) => {
-        e.stopPropagation();
+    selectRow = (doc: Doc, shift: boolean, ctrl: boolean) => {
+        console.log(ctrl);
+        const index = this.childDocs.indexOf(doc);
         if (index < 0) return;
-        const ctrl = e.ctrlKey || e.metaKey;
-        const shift = e.shiftKey;
         if (shift && this._lastSelectedRow !== undefined) {
             const startRow = Math.min(this._lastSelectedRow, index);
             const endRow = Math.max(this._lastSelectedRow, index);
@@ -358,8 +360,10 @@ export class CollectionSchemaView extends CollectionSubView() {
                 this.removeDocFromSelection(doc);
             }
         } else {
-            this.clearSelection();
-            this.addDocToSelection(doc, false, index);
+            if (!this._selectedDocs.has(doc)) {
+                this.clearSelection();
+                this.addDocToSelection(doc, false, index);
+            }
         }
     };
 
@@ -405,7 +409,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     };
 
     @action
-    startDrag = (e: PointerEvent, doc: Doc, ref: HTMLDivElement, index: number) => {
+    startDrag = (e: PointerEvent, doc: Doc, index: number) => {
         if (!this._selectedDocs.has(doc)) {
             this.clearSelection();
             this.addDocToSelection(doc, false, index);
@@ -604,6 +608,8 @@ export class CollectionSchemaView extends CollectionSubView() {
                                         hideTitle={true}
                                         hideDocumentButtonBar={true}
                                         fitWidth={returnTrue}
+                                        onClick={() => this.rowOnClickScript}
+                                        scriptContext={this}
                                     />
                                 </div>
                             );
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index d6a00966d..5de9fdf5c 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -42,13 +42,13 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
     onRowPointerDown = (e: React.PointerEvent) => {
         e.stopPropagation();
 
-        setupMoveUpEvents(
-            this,
-            e,
-            e => this.schemaView?.startDrag(e, this.rootDoc, this._ref!, this.rowIndex) ?? true,
-            emptyFunction,
-            e => this.schemaView?.selectRow(e, this.rootDoc, this._ref!, this.rowIndex)
-        );
+        // setupMoveUpEvents(
+        //     this,
+        //     e,
+        //     e => this.schemaView?.startDrag(e, this.rootDoc, this.rowIndex) ?? true,
+        //     emptyFunction,
+        //     e => this.schemaView?.selectRow(e, this.rootDoc, this.rowIndex)
+        // );
     };
 
     onPointerEnter = (e: any) => {
@@ -97,9 +97,9 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
                         ? { height: CollectionSchemaView._rowHeight, backgroundColor: Colors.LIGHT_BLUE, pointerEvents: this.schemaView?.props.isContentActive() ? 'all' : undefined /*, opacity: this.props.dragging ? 0.5 : 1 */ }
                         : { height: CollectionSchemaView._rowHeight, pointerEvents: this.schemaView?.props.isContentActive() ? 'all' : undefined }
                 }
-                onPointerDown={this.onRowPointerDown}
-                onPointerEnter={this.onPointerEnter}
-                onPointerLeave={this.onPointerLeave}
+                // onPointerDown={this.onRowPointerDown}
+                // onPointerEnter={this.onPointerEnter}
+                // onPointerLeave={this.onPointerLeave}
                 ref={(row: HTMLDivElement | null) => {
                     row && this.schemaView?.addRowRef(this.rootDoc, row);
                     this._ref = row;
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 36c0240f1..5e7037754 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -644,7 +644,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                 }
             } else if (!this._longPress && this.onClickHandler?.script && !isScriptBox()) {
                 // bcz: hack? don't execute script if you're clicking on a scripting box itself
-                const { clientX, clientY, shiftKey, altKey } = e;
+                const { clientX, clientY, shiftKey, altKey, metaKey } = e;
                 const func = () =>
                     this.onClickHandler.script.run(
                         {
@@ -658,6 +658,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                             clientY,
                             shiftKey,
                             altKey,
+                            metaKey,
                         },
                         console.log
                     ).result?.select === true
-- 
cgit v1.2.3-70-g09d2


From fdf2f866e948d030e7b29009ed5c06e384d74fe1 Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Wed, 1 Mar 2023 21:17:28 -0500
Subject: drag and drop working

---
 .../collectionSchema/CollectionSchemaView.tsx            |  4 ++--
 .../views/collections/collectionSchema/SchemaRowBox.tsx  | 16 ++++------------
 2 files changed, 6 insertions(+), 14 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaRowBox.tsx')

diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 02591489b..c52a7f3e4 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -343,14 +343,14 @@ export class CollectionSchemaView extends CollectionSubView() {
 
     @action
     selectRow = (doc: Doc, shift: boolean, ctrl: boolean) => {
-        console.log(ctrl);
         const index = this.childDocs.indexOf(doc);
         if (index < 0) return;
         if (shift && this._lastSelectedRow !== undefined) {
             const startRow = Math.min(this._lastSelectedRow, index);
             const endRow = Math.max(this._lastSelectedRow, index);
             for (let i = startRow; i <= endRow; i++) {
-                this.addDocToSelection(this.childDocs[i], true, i);
+                const currDoc = this.childDocs[i];
+                if (!this._selectedDocs.has(currDoc)) this.addDocToSelection(currDoc, true, i);
             }
             this._lastSelectedRow = index;
         } else if (ctrl) {
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 5de9fdf5c..4b709f670 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -40,15 +40,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
 
     @action
     onRowPointerDown = (e: React.PointerEvent) => {
-        e.stopPropagation();
-
-        // setupMoveUpEvents(
-        //     this,
-        //     e,
-        //     e => this.schemaView?.startDrag(e, this.rootDoc, this.rowIndex) ?? true,
-        //     emptyFunction,
-        //     e => this.schemaView?.selectRow(e, this.rootDoc, this.rowIndex)
-        // );
+        setupMoveUpEvents(this, e, e => this.schemaView?.startDrag(e, this.rootDoc, this.rowIndex) ?? true, emptyFunction, emptyFunction, false);
     };
 
     onPointerEnter = (e: any) => {
@@ -97,9 +89,9 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
                         ? { height: CollectionSchemaView._rowHeight, backgroundColor: Colors.LIGHT_BLUE, pointerEvents: this.schemaView?.props.isContentActive() ? 'all' : undefined /*, opacity: this.props.dragging ? 0.5 : 1 */ }
                         : { height: CollectionSchemaView._rowHeight, pointerEvents: this.schemaView?.props.isContentActive() ? 'all' : undefined }
                 }
-                // onPointerDown={this.onRowPointerDown}
-                // onPointerEnter={this.onPointerEnter}
-                // onPointerLeave={this.onPointerLeave}
+                onPointerDown={this.onRowPointerDown}
+                onPointerEnter={this.onPointerEnter}
+                onPointerLeave={this.onPointerLeave}
                 ref={(row: HTMLDivElement | null) => {
                     row && this.schemaView?.addRowRef(this.rootDoc, row);
                     this._ref = row;
-- 
cgit v1.2.3-70-g09d2


From 67a0081bb4fb713b730fa86a5b67d3c061426514 Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Wed, 1 Mar 2023 21:45:13 -0500
Subject: cells editable

---
 .../collections/collectionSchema/SchemaRowBox.tsx  |  4 +-
 .../collectionSchema/SchemaTableCell.tsx           | 45 +++++++++++++++++++++-
 2 files changed, 45 insertions(+), 4 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaRowBox.tsx')

diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 4b709f670..05197d05f 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -93,7 +93,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
                 onPointerEnter={this.onPointerEnter}
                 onPointerLeave={this.onPointerLeave}
                 ref={(row: HTMLDivElement | null) => {
-                    row && this.schemaView?.addRowRef(this.rootDoc, row);
+                    row && this.schemaView?.addRowRef?.(this.rootDoc, row);
                     this._ref = row;
                 }}>
                 <div
@@ -120,7 +120,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
                 </div>
                 <div className="row-cells">
                     {this.schemaView?.columnKeys?.map((key, index) => (
-                        <SchemaTableCell key={key} Document={this.rootDoc} fieldKey={key} columnWidth={this.schemaView?.displayColumnWidths[index] ?? CollectionSchemaView._minColWidth} />
+                        <SchemaTableCell key={key} Document={this.rootDoc} fieldKey={key} columnWidth={this.schemaView?.displayColumnWidths[index] ?? CollectionSchemaView._minColWidth} isRowActive={this.props.isContentActive} />
                     ))}
                 </div>
             </div>
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 4cfc5850c..0f832e7c4 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -9,20 +9,61 @@ import { FieldValue } from '../../../../fields/Types';
 import { CompileScript } from '../../../util/Scripting';
 import { EditableView } from '../../EditableView';
 import { MAX_ROW_HEIGHT } from '../../global/globalCssVariables.scss';
+import { FieldView, FieldViewProps } from '../../nodes/FieldView';
+import { KeyValueBox } from '../../nodes/KeyValueBox';
+import { returnEmptyFilter, returnEmptyDoclist, returnFalse, emptyFunction, returnZero } from '../../../../Utils';
+import { DefaultStyleProvider } from '../../StyleProvider';
+import { Transform } from '../../../util/Transform';
+import { CollectionSchemaView } from './CollectionSchemaView';
 
 export interface SchemaTableCellProps {
     Document: Doc;
     fieldKey: string;
     columnWidth: number;
+    isRowActive: () => boolean | undefined;
 }
 
 @observer
 export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
     render() {
+        const props: FieldViewProps = {
+            Document: this.props.Document,
+            // DataDoc: this.props.doc,
+            docFilters: returnEmptyFilter,
+            docRangeFilters: returnEmptyFilter,
+            searchFilterDocs: returnEmptyDoclist,
+            styleProvider: DefaultStyleProvider,
+            docViewPath: returnEmptyDoclist,
+            ContainingCollectionView: undefined,
+            ContainingCollectionDoc: undefined,
+            fieldKey: this.props.fieldKey,
+            rootSelected: returnFalse,
+            isSelected: returnFalse,
+            setHeight: returnFalse,
+            select: emptyFunction,
+            dropAction: 'alias',
+            bringToFront: emptyFunction,
+            renderDepth: 1,
+            isContentActive: returnFalse,
+            whenChildContentsActiveChanged: emptyFunction,
+            ScreenToLocalTransform: Transform.Identity,
+            focus: emptyFunction,
+            PanelWidth: () => this.props.columnWidth,
+            PanelHeight: () => CollectionSchemaView._rowHeight,
+            addDocTab: returnFalse,
+            pinToPres: returnZero,
+        };
+
         return (
-            <div className="schema-table-cell" style={{ width: this.props.columnWidth }}>
-                {Field.toString(this.props.Document[this.props.fieldKey] as Field)}
+            <div className="schema-table-cell" style={{ width: this.props.columnWidth, pointerEvents: this.props.isRowActive() ? 'all' : 'none' }}>
+                {/* {Field.toString(this.props.Document[this.props.fieldKey] as Field)} */}
                 {/* <EditableView contents={Field.toString(this.props.Document[this.props.fieldKey] as Field)} GetValue={() => Field.toKeyValueString(this.props.Document, this.props.fieldKey)} SetValue={(value: string) => true} /> */}
+                <EditableView
+                    contents={<FieldView {...props} />}
+                    height={'auto'}
+                    GetValue={() => Field.toKeyValueString(this.props.Document, this.props.fieldKey)}
+                    SetValue={(value: string) => KeyValueBox.SetField(this.props.Document, this.props.fieldKey, value)}
+                />
             </div>
         );
     }
-- 
cgit v1.2.3-70-g09d2


From 3fed87fe05a70a5ef63ed7989c7a28faee68bf4b Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Wed, 22 Mar 2023 17:42:28 -0400
Subject: shift enter shortcut to fill column

---
 .../views/collections/collectionSchema/CollectionSchemaView.scss | 7 +++----
 .../views/collections/collectionSchema/CollectionSchemaView.tsx  | 7 +++++++
 src/client/views/collections/collectionSchema/SchemaRowBox.tsx   | 9 ++++++++-
 .../views/collections/collectionSchema/SchemaTableCell.tsx       | 8 +++++++-
 4 files changed, 25 insertions(+), 6 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaRowBox.tsx')

diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
index 1853fb589..287e2b01b 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
@@ -109,6 +109,8 @@
     align-items: center;
     padding: 0;
     z-index: 1;
+    border: 1px solid $medium-gray;
+    overflow: hidden;
 
     .schema-column-title {
         flex-grow: 2;
@@ -146,7 +148,6 @@
 }
 
 .schema-row-wrapper {
-    // max-height: 70px;
     overflow: hidden;
 }
 
@@ -159,16 +160,14 @@
     display: flex;
     flex-direction: row;
     height: 100%;
-    // max-height: 70px;
     overflow: auto;
 }
 
-.schema-column-header,
 .schema-table-cell,
 .row-menu {
     border: 1px solid $medium-gray;
-    padding: 5px;
     overflow: hidden;
+    padding: 5px;
 }
 
 .schema-row {
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 4498a2258..48db1467c 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -28,6 +28,7 @@ import { DocumentManager } from '../../../util/DocumentManager';
 import { ScriptField } from '../../../../fields/ScriptField';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { IconButton } from 'browndash-components';
+import { KeyValueBox } from '../../nodes/KeyValueBox';
 
 export enum ColumnType {
     Number,
@@ -607,6 +608,12 @@ export class CollectionSchemaView extends CollectionSubView() {
         this.closeColumnMenu();
     };
 
+    setColumnValues = (key: string, value: string) => {
+        let success: boolean = true;
+        this.childDocs.forEach(doc => success && KeyValueBox.SetField(doc, key, value));
+        return success;
+    };
+
     @action
     openColumnMenu = (index: number, newCol: boolean) => {
         this._makeNewColumn = false;
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 05197d05f..37999484d 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -120,7 +120,14 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
                 </div>
                 <div className="row-cells">
                     {this.schemaView?.columnKeys?.map((key, index) => (
-                        <SchemaTableCell key={key} Document={this.rootDoc} fieldKey={key} columnWidth={this.schemaView?.displayColumnWidths[index] ?? CollectionSchemaView._minColWidth} isRowActive={this.props.isContentActive} />
+                        <SchemaTableCell
+                            key={key}
+                            Document={this.rootDoc}
+                            fieldKey={key}
+                            columnWidth={this.schemaView?.displayColumnWidths[index] ?? CollectionSchemaView._minColWidth}
+                            isRowActive={this.props.isContentActive}
+                            setColumnValues={(field, value) => this.schemaView?.setColumnValues(field, value) ?? false}
+                        />
                     ))}
                 </div>
             </div>
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index d475c3b6f..13e45963e 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -15,6 +15,7 @@ export interface SchemaTableCellProps {
     fieldKey: string;
     columnWidth: number;
     isRowActive: () => boolean | undefined;
+    setColumnValues: (field: string, value: string) => boolean;
 }
 
 @observer
@@ -53,7 +54,12 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
                     <EditableView
                         contents={<FieldView {...props} />}
                         GetValue={() => Field.toKeyValueString(this.props.Document, this.props.fieldKey)}
-                        SetValue={(value: string) => KeyValueBox.SetField(this.props.Document, this.props.fieldKey, value)}
+                        SetValue={(value: string, shiftDown?: boolean, enterKey?: boolean) => {
+                            if (shiftDown && enterKey) {
+                                this.props.setColumnValues(this.props.fieldKey, value);
+                            }
+                            return KeyValueBox.SetField(this.props.Document, this.props.fieldKey, value);
+                        }}
                         editing={this.props.isRowActive() ? undefined : false}
                     />
                 </div>
-- 
cgit v1.2.3-70-g09d2


From 00150352f45e474705f7c4ebe7ce375e59b1f45a Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 23 Mar 2023 21:04:33 -0400
Subject: fixed up pointer events so that schema and freeform items can be
 selected without selecting the collection.  however, dragging the item drags
 the collection unless the collection is selected.   cleaned up selected docs
 in schema to not keep a parallel observableSet to SelectionManager..

---
 .../collections/collectionSchema/CollectionSchemaView.tsx  | 14 +++++---------
 .../views/collections/collectionSchema/SchemaRowBox.tsx    | 11 +++++------
 src/client/views/nodes/DocumentView.tsx                    |  2 +-
 3 files changed, 11 insertions(+), 16 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaRowBox.tsx')

diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index a5f5ca2ae..5f795c5ac 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -54,7 +54,9 @@ export class CollectionSchemaView extends CollectionSubView() {
     public static _previewDividerWidth: number = 4;
 
     @observable _lastSelectedRow: number | undefined;
-    @observable _selectedDocs: ObservableSet = new ObservableSet<Doc>();
+    @computed get _selectedDocs() {
+        return new Set(SelectionManager.Docs().filter(doc => Doc.AreProtosEqual(DocCast(doc.context), this.props.Document)));
+    }
     @observable _rowEles: ObservableMap = new ObservableMap<Doc, HTMLDivElement>();
     @observable _colEles: HTMLDivElement[] = [];
     @observable _isDragging: boolean = false;
@@ -322,7 +324,6 @@ export class CollectionSchemaView extends CollectionSubView() {
 
     @action
     addDocToSelection = (doc: Doc, extendSelection: boolean, index: number) => {
-        this._selectedDocs.add(doc);
         const rowDocView = DocumentManager.Instance.getDocumentView(doc);
         if (rowDocView) SelectionManager.SelectView(rowDocView, extendSelection);
         this._lastSelectedRow = index;
@@ -330,7 +331,6 @@ export class CollectionSchemaView extends CollectionSubView() {
 
     @action
     removeDocFromSelection = (doc: Doc) => {
-        if (this._selectedDocs.has(doc)) this._selectedDocs.delete(doc);
         const rowDocView = DocumentManager.Instance.getDocumentView(doc);
         if (rowDocView) SelectionManager.DeselectView(rowDocView);
         if (this._selectedDocs.size === 0) {
@@ -340,7 +340,6 @@ export class CollectionSchemaView extends CollectionSubView() {
 
     @action
     clearSelection = () => {
-        this._selectedDocs.clear();
         SelectionManager.DeselectAll();
         this._lastSelectedRow = undefined;
     };
@@ -898,10 +897,7 @@ export class CollectionSchemaView extends CollectionSubView() {
                     className="schema-table"
                     style={{
                         pointerEvents: this.isContentActive() ? 'all' : 'none',
-                    }}
-                    onPointerDown={action(() => {
-                        this.clearSelection();
-                    })}>
+                    }}>
                     <div className="schema-header-row" style={{ height: CollectionSchemaView._rowHeight }}>
                         <div className="row-menu" style={{ width: CollectionSchemaView._rowMenuWidth }}>
                             <div
@@ -933,7 +929,7 @@ export class CollectionSchemaView extends CollectionSubView() {
                     </div>
                     {this._columnMenuIndex !== undefined && this.renderColumnMenu}
                     {this._filterColumnIndex !== undefined && this.renderFilterMenu}
-                    <div className="schema-table-content" onPointerDown={e => e.stopPropagation()}>
+                    <div className="schema-table-content">
                         {this.childDocs.map((doc: Doc, index: number) => {
                             const dataDoc = !doc.isTemplateDoc && !doc.isTemplateForField && !doc.PARAMS ? undefined : this.props.DataDoc;
                             let dref: Opt<DocumentView>;
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 37999484d..aa69e2b9c 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -1,19 +1,17 @@
 import React = require('react');
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, computed, ObservableSet } from 'mobx';
+import { action, computed } from 'mobx';
 import { observer } from 'mobx-react';
-import { Doc } from '../../../../fields/Doc';
+import { emptyFunction, setupMoveUpEvents } from '../../../../Utils';
+import { DragManager } from '../../../util/DragManager';
 import { undoBatch } from '../../../util/UndoManager';
 import { ViewBoxBaseComponent } from '../../DocComponent';
+import { Colors } from '../../global/globalEnums';
 import { OpenWhere } from '../../nodes/DocumentView';
 import { FieldView, FieldViewProps } from '../../nodes/FieldView';
 import { CollectionSchemaView } from './CollectionSchemaView';
 import './CollectionSchemaView.scss';
 import { SchemaTableCell } from './SchemaTableCell';
-import { Colors } from '../../global/globalEnums';
-import { DocCast, StrCast } from '../../../../fields/Types';
-import { setupMoveUpEvents, emptyFunction } from '../../../../Utils';
-import { DragManager } from '../../../util/DragManager';
 
 @observer
 export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
@@ -40,6 +38,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
 
     @action
     onRowPointerDown = (e: React.PointerEvent) => {
+        if (!this.isContentActive()) return;
         setupMoveUpEvents(this, e, e => this.schemaView?.startDrag(e, this.rootDoc, this.rowIndex) ?? true, emptyFunction, emptyFunction, false);
     };
 
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index d7a61a797..c13934945 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -1128,7 +1128,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
             <div
                 className="documentView-contentsView"
                 style={{
-                    pointerEvents: this.pointerEvents === 'visiblePainted' ? 'none' : this.pointerEvents,
+                    pointerEvents: (this.pointerEvents === 'visiblePainted' ? 'none' : this.pointerEvents) ?? 'all',
                     height: this.headerMargin ? `calc(100% - ${this.headerMargin}px)` : undefined,
                 }}>
                 {!this._retryThumb || !this.thumbShown() ? null : (
-- 
cgit v1.2.3-70-g09d2


From bdeeb202d264b2710f21b816f4e05a29793aa78e Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 23 Mar 2023 21:17:43 -0400
Subject: fixed dragging schema rows.  fixed not being able to click row
 buttons unless schema view is active.

---
 .../collections/collectionSchema/CollectionSchemaView.tsx    | 12 +++++-------
 .../views/collections/collectionSchema/SchemaRowBox.tsx      |  3 ++-
 2 files changed, 7 insertions(+), 8 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaRowBox.tsx')

diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 5f795c5ac..151e6cbef 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -884,6 +884,8 @@ export class CollectionSchemaView extends CollectionSubView() {
     rowHeightFunc = () => CollectionSchemaView._rowHeight;
     rowClickScriptFunc = () => this.rowOnClickScript;
     isContentActive = () => this.props.isSelected() || this.props.isContentActive();
+    screenToLocal = () => this.props.ScreenToLocalTransform().translate(-this.tableWidth, 0);
+    previewWidthFunc = () => this.previewWidth;
     render() {
         return (
             <div
@@ -893,11 +895,7 @@ export class CollectionSchemaView extends CollectionSubView() {
                     this.createDashEventsTarget(ele);
                 }}
                 onDrop={this.onExternalDrop.bind(this)}>
-                <div
-                    className="schema-table"
-                    style={{
-                        pointerEvents: this.isContentActive() ? 'all' : 'none',
-                    }}>
+                <div className="schema-table">
                     <div className="schema-header-row" style={{ height: CollectionSchemaView._rowHeight }}>
                         <div className="row-menu" style={{ width: CollectionSchemaView._rowMenuWidth }}>
                             <div
@@ -982,11 +980,11 @@ export class CollectionSchemaView extends CollectionSubView() {
                                 focus={DocUtils.DefaultFocus}
                                 renderDepth={this.props.renderDepth}
                                 rootSelected={this.rootSelected}
-                                PanelWidth={() => this.previewWidth}
+                                PanelWidth={this.previewWidthFunc}
                                 PanelHeight={this.props.PanelHeight}
                                 isContentActive={returnTrue}
                                 isDocumentActive={returnFalse}
-                                ScreenToLocalTransform={() => this.props.ScreenToLocalTransform().translate(-this.tableWidth, 0)}
+                                ScreenToLocalTransform={this.screenToLocal}
                                 docFilters={this.childDocFilters}
                                 docRangeFilters={this.childDocRangeFilters}
                                 searchFilterDocs={this.searchFilterDocs}
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index aa69e2b9c..87284be70 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -39,7 +39,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
     @action
     onRowPointerDown = (e: React.PointerEvent) => {
         if (!this.isContentActive()) return;
-        setupMoveUpEvents(this, e, e => this.schemaView?.startDrag(e, this.rootDoc, this.rowIndex) ?? true, emptyFunction, emptyFunction, false);
+        setupMoveUpEvents(this, e, e => this.schemaView?.startDrag(e, this.rootDoc, this.rowIndex) ?? true, emptyFunction, emptyFunction);
     };
 
     onPointerEnter = (e: any) => {
@@ -99,6 +99,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
                     className="row-menu"
                     style={{
                         width: CollectionSchemaView._rowMenuWidth,
+                        pointerEvents: !this.isContentActive() ? 'none' : undefined,
                     }}>
                     <div
                         className="schema-row-button"
-- 
cgit v1.2.3-70-g09d2


From 3a3e496dda5f9a1f5286a2c9f62524de59794ade Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 24 Mar 2023 03:37:41 -0400
Subject: overhaul of selection api so that schema and other views behave like
 freeform and use document views onClick for selection

---
 src/client/util/SelectionManager.ts                |  45 +--
 .../views/collections/CollectionCarousel3DView.tsx | 149 +++++-----
 src/client/views/collections/CollectionView.tsx    |   2 +-
 .../CollectionFreeFormLayoutEngines.tsx            |   7 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  |   9 +-
 .../collectionFreeForm/MarqueeOptionsMenu.tsx      |   2 -
 .../CollectionMulticolumnView.tsx                  |   3 +-
 .../CollectionMultirowView.tsx                     |   3 +-
 .../collectionSchema/CollectionSchemaView.tsx      | 318 +++++++++------------
 .../collections/collectionSchema/SchemaRowBox.tsx  |  31 +-
 .../nodes/CollectionFreeFormDocumentView.scss      |   4 +-
 src/client/views/nodes/DocumentView.tsx            |  18 +-
 12 files changed, 282 insertions(+), 309 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaRowBox.tsx')

diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts
index 0f4f77588..313c255a0 100644
--- a/src/client/util/SelectionManager.ts
+++ b/src/client/util/SelectionManager.ts
@@ -1,3 +1,4 @@
+import { ModalManager } from '@material-ui/core';
 import { action, observable, ObservableMap } from 'mobx';
 import { computedFn } from 'mobx-utils';
 import { Doc, Opt } from '../../fields/Doc';
@@ -10,7 +11,8 @@ import { ScriptingGlobals } from './ScriptingGlobals';
 export namespace SelectionManager {
     class Manager {
         @observable IsDragging: boolean = false;
-        SelectedViews: ObservableMap<DocumentView, Doc> = new ObservableMap();
+        SelectedViewsMap: ObservableMap<DocumentView, Doc> = new ObservableMap();
+        @observable SelectedViews: DocumentView[] = [];
         @observable SelectedSchemaDocument: Doc | undefined;
 
         @action
@@ -20,7 +22,7 @@ export namespace SelectionManager {
         @action
         SelectView(docView: DocumentView, ctrlPressed: boolean): void {
             // if doc is not in SelectedDocuments, add it
-            if (!manager.SelectedViews.get(docView) && docView.props.Document.type !== DocumentType.MARKER) {
+            if (!manager.SelectedViewsMap.get(docView) && docView.props.Document.type !== DocumentType.MARKER) {
                 if (!ctrlPressed) {
                     if (LinkManager.currentLink && !LinkManager.Links(docView.rootDoc).includes(LinkManager.currentLink) && docView.rootDoc !== LinkManager.currentLink) {
                         LinkManager.currentLink = undefined;
@@ -28,33 +30,38 @@ export namespace SelectionManager {
                     this.DeselectAll();
                 }
 
-                manager.SelectedViews.set(docView, docView.rootDoc);
+                manager.SelectedViews.push(docView);
+                manager.SelectedViewsMap.set(docView, docView.rootDoc);
                 docView.props.whenChildContentsActiveChanged(true);
-            } else if (!ctrlPressed && (Array.from(manager.SelectedViews.entries()).length > 1 || manager.SelectedSchemaDocument)) {
-                Array.from(manager.SelectedViews.keys()).map(dv => dv !== docView && dv.props.whenChildContentsActiveChanged(false));
+            } else if (!ctrlPressed && (Array.from(manager.SelectedViewsMap.entries()).length > 1 || manager.SelectedSchemaDocument)) {
+                Array.from(manager.SelectedViewsMap.keys()).map(dv => dv !== docView && dv.props.whenChildContentsActiveChanged(false));
                 manager.SelectedSchemaDocument = undefined;
-                manager.SelectedViews.clear();
-                manager.SelectedViews.set(docView, docView.rootDoc);
+                manager.SelectedViews.length = 0;
+                manager.SelectedViewsMap.clear();
+                manager.SelectedViews.push(docView);
+                manager.SelectedViewsMap.set(docView, docView.rootDoc);
             }
         }
         @action
-        DeselectView(docView: DocumentView): void {
-            if (manager.SelectedViews.get(docView)) {
-                manager.SelectedViews.delete(docView);
+        DeselectView(docView?: DocumentView): void {
+            if (docView && manager.SelectedViewsMap.get(docView)) {
+                manager.SelectedViewsMap.delete(docView);
+                manager.SelectedViews.splice(manager.SelectedViews.indexOf(docView), 1);
                 docView.props.whenChildContentsActiveChanged(false);
             }
         }
         @action
         DeselectAll(): void {
             manager.SelectedSchemaDocument = undefined;
-            Array.from(manager.SelectedViews.keys()).forEach(dv => dv.props.whenChildContentsActiveChanged(false));
-            manager.SelectedViews.clear();
+            Array.from(manager.SelectedViewsMap.keys()).forEach(dv => dv.props.whenChildContentsActiveChanged(false));
+            manager.SelectedViewsMap.clear();
+            manager.SelectedViews.length = 0;
         }
     }
 
     const manager = new Manager();
 
-    export function DeselectView(docView: DocumentView): void {
+    export function DeselectView(docView?: DocumentView): void {
         manager.DeselectView(docView);
     }
     export function SelectView(docView: DocumentView, ctrlPressed: boolean): void {
@@ -67,7 +74,7 @@ export namespace SelectionManager {
 
     const IsSelectedCache = computedFn(function isSelected(doc: DocumentView) {
         // wrapping get() in a computedFn only generates mobx() invalidations when the return value of the function for the specific get parameters has changed
-        return manager.SelectedViews.get(doc) ? true : false;
+        return manager.SelectedViewsMap.get(doc) ? true : false;
     });
     // computed functions, such as used in IsSelected generate errors if they're called outside of a
     // reaction context.  Specifying the context with 'outsideReaction' allows an efficiency feature
@@ -76,7 +83,7 @@ export namespace SelectionManager {
         return !doc
             ? false
             : outsideReaction
-            ? manager.SelectedViews.get(doc)
+            ? manager.SelectedViewsMap.get(doc)
                 ? true
                 : false // get() accesses a hashtable -- setting anything in the hashtable generates a mobx invalidation for every get()
             : IsSelectedCache(doc);
@@ -85,7 +92,7 @@ export namespace SelectionManager {
     export function DeselectAll(except?: Doc): void {
         let found: DocumentView | undefined = undefined;
         if (except) {
-            for (const view of Array.from(manager.SelectedViews.keys())) {
+            for (const view of Array.from(manager.SelectedViewsMap.keys())) {
                 if (view.props.Document === except) found = view;
             }
         }
@@ -95,13 +102,15 @@ export namespace SelectionManager {
     }
 
     export function Views(): Array<DocumentView> {
-        return Array.from(manager.SelectedViews.keys()); //.filter(dv => manager.SelectedViews.get(dv)?._viewType !== CollectionViewType.Docking);
+        return manager.SelectedViews;
+        // Array.from(manager.SelectedViewsMap.keys()); //.filter(dv => manager.SelectedViews.get(dv)?._viewType !== CollectionViewType.Docking);
     }
     export function SelectedSchemaDoc(): Doc | undefined {
         return manager.SelectedSchemaDocument;
     }
     export function Docs(): Doc[] {
-        return Array.from(manager.SelectedViews.values()).filter(doc => doc?._viewType !== CollectionViewType.Docking);
+        return manager.SelectedViews.map(dv => dv.rootDoc).filter(doc => doc?._viewType !== CollectionViewType.Docking);
+        // Array.from(manager.SelectedViewsMap.values()).filter(doc => doc?._viewType !== CollectionViewType.Docking);
     }
 }
 ScriptingGlobals.add(function SelectionManager_selectedDocType(type: string, expertMode: boolean, checkContext?: boolean) {
diff --git a/src/client/views/collections/CollectionCarousel3DView.tsx b/src/client/views/collections/CollectionCarousel3DView.tsx
index 01f41869e..57ff1b292 100644
--- a/src/client/views/collections/CollectionCarousel3DView.tsx
+++ b/src/client/views/collections/CollectionCarousel3DView.tsx
@@ -9,7 +9,7 @@ import { OmitKeys, returnFalse, Utils } from '../../../Utils';
 import { DragManager } from '../../util/DragManager';
 import { DocumentView } from '../nodes/DocumentView';
 import { StyleProp } from '../StyleProvider';
-import "./CollectionCarousel3DView.scss";
+import './CollectionCarousel3DView.scss';
 import { CollectionSubView } from './CollectionSubView';
 
 @observer
@@ -20,134 +20,143 @@ export class CollectionCarousel3DView extends CollectionSubView() {
 
     private _dropDisposer?: DragManager.DragDropDisposer;
 
-    componentWillUnmount() { this._dropDisposer?.(); }
+    componentWillUnmount() {
+        this._dropDisposer?.();
+    }
 
-    protected createDashEventsTarget = (ele: HTMLDivElement | null) => { //used for stacking and masonry view
+    protected createDashEventsTarget = (ele: HTMLDivElement | null) => {
+        //used for stacking and masonry view
         this._dropDisposer?.();
         if (ele) {
             this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc);
         }
-    }
+    };
 
     panelWidth = () => this.props.PanelWidth() / 3;
     panelHeight = () => this.props.PanelHeight() * 0.6;
     onChildDoubleClick = () => ScriptCast(this.layoutDoc.onChildDoubleClick);
+    isContentActive = () => this.props.isSelected() || this.props.isContentActive() || this.props.isAnyChildContentActive();
+    isChildContentActive = () => (this.isContentActive() ? true : false);
+
     @computed get content() {
         const currentIndex = NumCast(this.layoutDoc._itemIndex);
-        const displayDoc = (childPair: { layout: Doc, data: Doc }) => {
-            return <DocumentView  {...OmitKeys(this.props, ["NativeWidth", "NativeHeight", "childLayoutTemplate", "childLayoutString"]).omit}
-                onDoubleClick={this.onChildDoubleClick}
-                renderDepth={this.props.renderDepth + 1}
-                LayoutTemplate={this.props.childLayoutTemplate}
-                LayoutTemplateString={this.props.childLayoutString}
-                Document={childPair.layout}
-                DataDoc={childPair.data}
-                PanelWidth={this.panelWidth}
-                PanelHeight={this.panelHeight}
-                bringToFront={returnFalse}
-            />;
+        const displayDoc = (childPair: { layout: Doc; data: Doc }) => {
+            return (
+                <DocumentView
+                    {...OmitKeys(this.props, ['NativeWidth', 'NativeHeight', 'childLayoutTemplate', 'childLayoutString']).omit}
+                    onDoubleClick={this.onChildDoubleClick}
+                    renderDepth={this.props.renderDepth + 1}
+                    LayoutTemplate={this.props.childLayoutTemplate}
+                    LayoutTemplateString={this.props.childLayoutString}
+                    Document={childPair.layout}
+                    DataDoc={childPair.data}
+                    isContentActive={this.isChildContentActive}
+                    isDocumentActive={this.props.childDocumentsActive?.() || this.Document._childDocumentsActive ? this.props.isDocumentActive : this.isContentActive}
+                    PanelWidth={this.panelWidth}
+                    PanelHeight={this.panelHeight}
+                    bringToFront={returnFalse}
+                />
+            );
         };
 
-        return (this.childLayoutPairs.map((childPair, index) => {
+        return this.childLayoutPairs.map((childPair, index) => {
             return (
-                <div key={childPair.layout[Id]}
-                    className={`collectionCarousel3DView-item${index === currentIndex ? "-active" : ""} ${index}`}
-                    style={index === currentIndex ?
-                        { opacity: '1', transform: 'scale(1.3)', width: this.panelWidth() } :
-                        { opacity: '0.5', transform: 'scale(0.6)', userSelect: 'none', width: this.panelWidth() }}>
+                <div
+                    key={childPair.layout[Id]}
+                    className={`collectionCarousel3DView-item${index === currentIndex ? '-active' : ''} ${index}`}
+                    style={index === currentIndex ? { opacity: '1', transform: 'scale(1.3)', width: this.panelWidth() } : { opacity: '0.5', transform: 'scale(0.6)', userSelect: 'none', width: this.panelWidth() }}>
                     {displayDoc(childPair)}
-                </div>);
-        }));
+                </div>
+            );
+        });
     }
 
     changeSlide = (direction: number) => {
         this.layoutDoc._itemIndex = (NumCast(this.layoutDoc._itemIndex) + direction + this.childLayoutPairs.length) % this.childLayoutPairs.length;
-    }
+    };
 
     onArrowClick = (e: React.MouseEvent, direction: number) => {
         e.stopPropagation();
         this.changeSlide(direction);
-        !this.layoutDoc.autoScrollOn && (this.layoutDoc.showScrollButton = (direction === 1) ? "fwd" : "back"); // while autoscroll is on, keep the other autoscroll button hidden
+        !this.layoutDoc.autoScrollOn && (this.layoutDoc.showScrollButton = direction === 1 ? 'fwd' : 'back'); // while autoscroll is on, keep the other autoscroll button hidden
         !this.layoutDoc.autoScrollOn && this.fadeScrollButton(); // keep pause button visible while autoscroll is on
-    }
+    };
 
     interval?: number;
     startAutoScroll = (direction: number) => {
         this.interval = window.setInterval(() => {
             this.changeSlide(direction);
         }, this.scrollSpeed);
-    }
+    };
 
     stopAutoScroll = () => {
         window.clearInterval(this.interval);
         this.interval = undefined;
         this.fadeScrollButton();
-    }
+    };
 
     toggleAutoScroll = (direction: number) => {
         this.layoutDoc.autoScrollOn = this.layoutDoc.autoScrollOn ? false : true;
         this.layoutDoc.autoScrollOn ? this.startAutoScroll(direction) : this.stopAutoScroll();
-    }
+    };
 
     fadeScrollButton = () => {
         window.setTimeout(() => {
-            !this.layoutDoc.autoScrollOn && (this.layoutDoc.showScrollButton = "none"); //fade away after 1.5s if it's not clicked.
+            !this.layoutDoc.autoScrollOn && (this.layoutDoc.showScrollButton = 'none'); //fade away after 1.5s if it's not clicked.
         }, 1500);
-    }
+    };
 
     @computed get buttons() {
         if (!this.props.isContentActive()) return null;
-        return <div className="arrow-buttons" >
-            <div key="back" className="carousel3DView-back" style={{ background: `${StrCast(this.props.Document.backgroundColor)}` }}
-                onClick={(e) => this.onArrowClick(e, -1)}
-            >
-                <FontAwesomeIcon icon={"angle-left"} size={"2x"} />
-            </div>
-            <div key="fwd" className="carousel3DView-fwd" style={{ background: `${StrCast(this.props.Document.backgroundColor)}` }}
-                onClick={(e) => this.onArrowClick(e, 1)}
-            >
-                <FontAwesomeIcon icon={"angle-right"} size={"2x"} />
+        return (
+            <div className="arrow-buttons">
+                <div key="back" className="carousel3DView-back" style={{ background: `${StrCast(this.props.Document.backgroundColor)}` }} onClick={e => this.onArrowClick(e, -1)}>
+                    <FontAwesomeIcon icon={'angle-left'} size={'2x'} />
+                </div>
+                <div key="fwd" className="carousel3DView-fwd" style={{ background: `${StrCast(this.props.Document.backgroundColor)}` }} onClick={e => this.onArrowClick(e, 1)}>
+                    <FontAwesomeIcon icon={'angle-right'} size={'2x'} />
+                </div>
+                {this.autoScrollButton}
             </div>
-            {this.autoScrollButton}
-        </div>;
+        );
     }
 
     @computed get autoScrollButton() {
         const whichButton = this.layoutDoc.showScrollButton;
-        return <>
-            <div className={`carousel3DView-back-scroll${whichButton === "back" ? "" : "-hidden"}`} style={{ background: `${StrCast(this.props.Document.backgroundColor)}` }}
-                onClick={() => this.toggleAutoScroll(-1)}>
-                {this.layoutDoc.autoScrollOn ? <FontAwesomeIcon icon={"pause"} size={"1x"} /> : <FontAwesomeIcon icon={"angle-double-left"} size={"1x"} />}
-            </div>
-            <div className={`carousel3DView-fwd-scroll${whichButton === "fwd" ? "" : "-hidden"}`} style={{ background: `${StrCast(this.props.Document.backgroundColor)}` }}
-                onClick={() => this.toggleAutoScroll(1)}>
-                {this.layoutDoc.autoScrollOn ? <FontAwesomeIcon icon={"pause"} size={"1x"} /> : <FontAwesomeIcon icon={"angle-double-right"} size={"1x"} />}
-            </div>
-        </>;
+        return (
+            <>
+                <div className={`carousel3DView-back-scroll${whichButton === 'back' ? '' : '-hidden'}`} style={{ background: `${StrCast(this.props.Document.backgroundColor)}` }} onClick={() => this.toggleAutoScroll(-1)}>
+                    {this.layoutDoc.autoScrollOn ? <FontAwesomeIcon icon={'pause'} size={'1x'} /> : <FontAwesomeIcon icon={'angle-double-left'} size={'1x'} />}
+                </div>
+                <div className={`carousel3DView-fwd-scroll${whichButton === 'fwd' ? '' : '-hidden'}`} style={{ background: `${StrCast(this.props.Document.backgroundColor)}` }} onClick={() => this.toggleAutoScroll(1)}>
+                    {this.layoutDoc.autoScrollOn ? <FontAwesomeIcon icon={'pause'} size={'1x'} /> : <FontAwesomeIcon icon={'angle-double-right'} size={'1x'} />}
+                </div>
+            </>
+        );
     }
 
     @computed get dots() {
-        return (this.childLayoutPairs.map((_child, index) =>
-            <div key={Utils.GenerateGuid()} className={`dot${index === NumCast(this.layoutDoc._itemIndex) ? "-active" : ""}`}
-                onClick={() => this.layoutDoc._itemIndex = index} />));
+        return this.childLayoutPairs.map((_child, index) => <div key={Utils.GenerateGuid()} className={`dot${index === NumCast(this.layoutDoc._itemIndex) ? '-active' : ''}`} onClick={() => (this.layoutDoc._itemIndex = index)} />);
     }
 
     render() {
         const index = NumCast(this.layoutDoc._itemIndex);
         const translateX = this.panelWidth() * (1 - index);
 
-        return <div className="collectionCarousel3DView-outer" ref={this.createDashEventsTarget}
-            style={{
-                background: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BackgroundColor),
-                color: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.Color),
-            }}  >
-            <div className="carousel-wrapper" style={{ transform: `translateX(${translateX}px)` }}>
-                {this.content}
-            </div>
-            {this.props.Document._chromeHidden ? (null) : this.buttons}
-            <div className="dot-bar">
-                {this.dots}
+        return (
+            <div
+                className="collectionCarousel3DView-outer"
+                ref={this.createDashEventsTarget}
+                style={{
+                    background: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BackgroundColor),
+                    color: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.Color),
+                }}>
+                <div className="carousel-wrapper" style={{ transform: `translateX(${translateX}px)` }}>
+                    {this.content}
+                </div>
+                {this.props.Document._chromeHidden ? null : this.buttons}
+                <div className="dot-bar">{this.dots}</div>
             </div>
-        </div>;
+        );
     }
-}
\ No newline at end of file
+}
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index eafa50d27..51624689e 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -257,7 +257,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
         return StrCast(this.rootDoc.childLayoutString, this.props.childLayoutString);
     }
 
-    isContentActive = (outsideReaction?: boolean) => this.props.isContentActive();
+    isContentActive = (outsideReaction?: boolean) => this.props.isContentActive() || this.isAnyChildContentActive();
 
     render() {
         TraceMobx();
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
index fa0695fb2..81b0c4d8a 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
@@ -116,6 +116,8 @@ export function computeStarburstLayout(poolData: Map<string, PoolData>, pivotDoc
             zIndex: NumCast(layout.zIndex),
             pair: { layout, data },
             replica: '',
+            color: 'white',
+            backgroundColor: 'white',
         });
     });
     const divider = { type: 'div', color: 'transparent', x: -burstRadius[0], y: 0, width: 15, height: 15, payload: undefined };
@@ -408,7 +410,7 @@ function normalizeResults(
         .map(ele => {
             const newPosRaw = ele[1];
             if (newPosRaw) {
-                const newPos = {
+                const newPos: PoolData = {
                     x: newPosRaw.x * scale,
                     y: newPosRaw.y * scale,
                     z: newPosRaw.z,
@@ -417,6 +419,9 @@ function normalizeResults(
                     zIndex: newPosRaw.zIndex,
                     width: (newPosRaw.width || 0) * scale,
                     height: newPosRaw.height! * scale,
+                    backgroundColor: newPosRaw.backgroundColor,
+                    opacity: newPosRaw.opacity,
+                    color: newPosRaw.color,
                     pair: ele[1].pair,
                 };
                 poolData.set(newPos.pair.layout[Id] + (newPos.replica || ''), { transition: 'all 1s', ...newPos });
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 3a8edb1a5..4f81af95d 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1291,10 +1291,9 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     };
     pointerEvents = () => {
         const engine = this.props.layoutEngine?.() || StrCast(this.props.Document._layoutEngine);
-        const pointerEvents =
-            this.props.isContentActive() === false || DocumentDecorations.Instance.Interacting
-                ? 'none'
-                : this.props.childPointerEvents ?? (this.props.viewDefDivClick || (engine === computePassLayout.name && !this.props.isSelected(true)) ? 'none' : this.props.pointerEvents?.());
+        const pointerEvents = DocumentDecorations.Instance.Interacting
+            ? 'none'
+            : this.props.childPointerEvents ?? (this.props.viewDefDivClick || (engine === computePassLayout.name && !this.props.isSelected(true)) ? 'none' : this.props.pointerEvents?.());
         return pointerEvents;
     };
     getChildDocView(entry: PoolData) {
@@ -1995,7 +1994,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         TraceMobx();
         return (
             <div
-                className={'collectionfreeformview-container'}
+                className="collectionfreeformview-container"
                 ref={this.createDashEventsTarget}
                 onWheel={this.onPointerWheel}
                 onClick={this.onClick}
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx b/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx
index 9581563ce..c9168d40a 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx
@@ -3,8 +3,6 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { Tooltip } from '@material-ui/core';
 import { observer } from 'mobx-react';
 import { unimplementedFunction } from '../../../../Utils';
-import { DocumentType } from '../../../documents/DocumentTypes';
-import { SelectionManager } from '../../../util/SelectionManager';
 import { AntimodeMenu, AntimodeMenuProps } from '../../AntimodeMenu';
 
 @observer
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index 88d045fa7..b73b1d779 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -2,14 +2,13 @@ import { action, computed } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
 import { Doc, DocListCast } from '../../../../fields/Doc';
-import { List } from '../../../../fields/List';
 import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types';
 import { returnFalse } from '../../../../Utils';
 import { DragManager, dropActionType } from '../../../util/DragManager';
 import { SnappingManager } from '../../../util/SnappingManager';
 import { Transform } from '../../../util/Transform';
 import { undoBatch } from '../../../util/UndoManager';
-import { DocFocusOptions, DocumentView } from '../../nodes/DocumentView';
+import { DocumentView } from '../../nodes/DocumentView';
 import { CollectionSubView } from '../CollectionSubView';
 import './CollectionMulticolumnView.scss';
 import ResizeBar from './MulticolumnResizer';
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
index f18917bef..0cca83803 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
@@ -2,14 +2,13 @@ import { action, computed } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
 import { Doc, DocListCast } from '../../../../fields/Doc';
-import { List } from '../../../../fields/List';
 import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types';
 import { returnFalse } from '../../../../Utils';
 import { DragManager, dropActionType } from '../../../util/DragManager';
 import { SnappingManager } from '../../../util/SnappingManager';
 import { Transform } from '../../../util/Transform';
 import { undoBatch } from '../../../util/UndoManager';
-import { DocFocusOptions, DocumentView } from '../../nodes/DocumentView';
+import { DocumentView } from '../../nodes/DocumentView';
 import { CollectionSubView } from '../CollectionSubView';
 import './CollectionMultirowView.scss';
 import HeightLabel from './MultirowHeightLabel';
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 151e6cbef..ad31113a2 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -1,15 +1,17 @@
 import React = require('react');
-import { action, computed, observable, ObservableMap, ObservableSet, untracked } from 'mobx';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { action, computed, observable, ObservableMap, trace, untracked } from 'mobx';
 import { observer } from 'mobx-react';
-import { Doc, DocListCast, Field, Opt, StrListCast } from '../../../../fields/Doc';
+import { Doc, DocListCast, Field, StrListCast } from '../../../../fields/Doc';
 import { Id } from '../../../../fields/FieldSymbols';
 import { List } from '../../../../fields/List';
 import { RichTextField } from '../../../../fields/RichTextField';
 import { listSpec } from '../../../../fields/Schema';
 import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../../fields/Types';
 import { ImageField } from '../../../../fields/URLField';
-import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTransparent, returnTrue, setupMoveUpEvents, smoothScroll, Utils } from '../../../../Utils';
+import { emptyFunction, returnEmptyDoclist, returnEmptyString, returnFalse, returnTrue, setupMoveUpEvents, smoothScroll } from '../../../../Utils';
 import { Docs, DocUtils } from '../../../documents/Documents';
+import { DocumentManager } from '../../../util/DocumentManager';
 import { DragManager } from '../../../util/DragManager';
 import { SelectionManager } from '../../../util/SelectionManager';
 import { Transform } from '../../../util/Transform';
@@ -17,18 +19,14 @@ import { undoBatch } from '../../../util/UndoManager';
 import { ContextMenu } from '../../ContextMenu';
 import { ContextMenuProps } from '../../ContextMenuItem';
 import { EditableView } from '../../EditableView';
-import { DocComponentView, DocFocusOptions, DocumentView } from '../../nodes/DocumentView';
+import { DocFocusOptions, DocumentView } from '../../nodes/DocumentView';
 import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox';
+import { KeyValueBox } from '../../nodes/KeyValueBox';
+import { DefaultStyleProvider } from '../../StyleProvider';
 import { CollectionSubView } from '../CollectionSubView';
 import './CollectionSchemaView.scss';
 import { SchemaColumnHeader } from './SchemaColumnHeader';
 import { SchemaRowBox } from './SchemaRowBox';
-import { DefaultStyleProvider } from '../../StyleProvider';
-import { DocumentManager } from '../../../util/DocumentManager';
-import { ScriptField } from '../../../../fields/ScriptField';
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { IconButton } from 'browndash-components';
-import { KeyValueBox } from '../../nodes/KeyValueBox';
 
 export enum ColumnType {
     Number,
@@ -43,7 +41,6 @@ const defaultColumnKeys: string[] = ['title', 'type', 'author', 'creationDate',
 @observer
 export class CollectionSchemaView extends CollectionSubView() {
     private _ref: HTMLDivElement | null = null;
-    private _selectedDocSortedArray: Doc[] = [];
     private _closestDropIndex: number = 0;
     private _previewRef: HTMLDivElement | null = null;
     private _makeNewColumn: boolean = false;
@@ -53,13 +50,11 @@ export class CollectionSchemaView extends CollectionSubView() {
     public static _rowMenuWidth: number = 100;
     public static _previewDividerWidth: number = 4;
 
-    @observable _lastSelectedRow: number | undefined;
     @computed get _selectedDocs() {
-        return new Set(SelectionManager.Docs().filter(doc => Doc.AreProtosEqual(DocCast(doc.context), this.props.Document)));
+        return SelectionManager.Docs().filter(doc => Doc.AreProtosEqual(DocCast(doc.context), this.props.Document));
     }
     @observable _rowEles: ObservableMap = new ObservableMap<Doc, HTMLDivElement>();
     @observable _colEles: HTMLDivElement[] = [];
-    @observable _isDragging: boolean = false;
     @observable _displayColumnWidths: number[] | undefined;
     @observable _columnMenuIndex: number | undefined;
     @observable _menuOptions: string[] = [];
@@ -133,7 +128,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     }
 
     componentDidMount() {
-        this.props.setContentView?.(this as DocComponentView);
+        this.props.setContentView?.(this);
         document.addEventListener('keydown', this.onKeyDown);
     }
 
@@ -143,24 +138,36 @@ export class CollectionSchemaView extends CollectionSubView() {
 
     @action
     onKeyDown = (e: KeyboardEvent) => {
-        if (this._selectedDocs.size > 0) {
-            if (e.key == 'ArrowDown') {
-                const lastDoc = Array.from(this._selectedDocs.values()).lastElement();
-                const lastIndex = this.rowIndex(lastDoc);
-                if (lastIndex >= 0 && lastIndex < this.childDocs.length - 1) {
-                    !e.shiftKey && this.clearSelection();
-                    const newDoc = this.childDocs[lastIndex + 1];
-                    this.addDocToSelection(newDoc, e.shiftKey, lastIndex + 1);
-                }
-            }
-            if (e.key == 'ArrowUp') {
-                const firstDoc = Array.from(this._selectedDocs.values())[0];
-                const firstIndex = this.rowIndex(firstDoc);
-                if (firstIndex > 0 && firstIndex < this.childDocs.length) {
-                    !e.shiftKey && this.clearSelection();
-                    const newDoc = this.childDocs[firstIndex - 1];
-                    this.addDocToSelection(newDoc, e.shiftKey, firstIndex - 1);
-                }
+        if (this._selectedDocs.length > 0) {
+            switch (e.key) {
+                case 'ArrowDown':
+                    {
+                        const lastDoc = this._selectedDocs.lastElement();
+                        const lastIndex = this.rowIndex(lastDoc);
+                        const curDoc = this.childDocs[lastIndex];
+                        if (lastIndex >= 0 && lastIndex < this.childDocs.length - 1) {
+                            !e.shiftKey && this.clearSelection();
+                            const newDoc = this.childDocs[lastIndex + 1];
+                            if (this._selectedDocs.includes(newDoc)) SelectionManager.DeselectView(DocumentManager.Instance.getFirstDocumentView(curDoc));
+                            else this.addDocToSelection(newDoc, e.shiftKey, lastIndex + 1);
+                        }
+                        e.stopPropagation();
+                    }
+                    break;
+                case 'ArrowUp':
+                    {
+                        const firstDoc = this._selectedDocs.lastElement();
+                        const firstIndex = this.rowIndex(firstDoc);
+                        const curDoc = this.childDocs[firstIndex];
+                        if (firstIndex > 0 && firstIndex < this.childDocs.length) {
+                            !e.shiftKey && this.clearSelection();
+                            const newDoc = this.childDocs[firstIndex - 1];
+                            if (this._selectedDocs.includes(newDoc)) SelectionManager.DeselectView(DocumentManager.Instance.getFirstDocumentView(curDoc));
+                            else this.addDocToSelection(newDoc, e.shiftKey, firstIndex - 1);
+                        }
+                        e.stopPropagation();
+                    }
+                    break;
             }
         }
     };
@@ -326,60 +333,25 @@ export class CollectionSchemaView extends CollectionSubView() {
     addDocToSelection = (doc: Doc, extendSelection: boolean, index: number) => {
         const rowDocView = DocumentManager.Instance.getDocumentView(doc);
         if (rowDocView) SelectionManager.SelectView(rowDocView, extendSelection);
-        this._lastSelectedRow = index;
-    };
-
-    @action
-    removeDocFromSelection = (doc: Doc) => {
-        const rowDocView = DocumentManager.Instance.getDocumentView(doc);
-        if (rowDocView) SelectionManager.DeselectView(rowDocView);
-        if (this._selectedDocs.size === 0) {
-            this._lastSelectedRow = undefined;
-        }
     };
 
     @action
-    clearSelection = () => {
-        SelectionManager.DeselectAll();
-        this._lastSelectedRow = undefined;
-    };
-
-    rowOnClickScript = ScriptField.MakeFunction('scriptContext.selectRow(self, shiftKey, ctrlKey || metaKey)', { scriptContext: 'any', shiftKey: 'boolean', ctrlKey: 'boolean', metaKey: 'boolean' })!;
-
-    @action
-    selectRow = (doc: Doc, shift: boolean, ctrl: boolean) => {
-        const index = this.childDocs.indexOf(doc);
-        if (index < 0) return;
-        if (shift && this._lastSelectedRow !== undefined) {
-            const startRow = Math.min(this._lastSelectedRow, index);
-            const endRow = Math.max(this._lastSelectedRow, index);
-            for (let i = startRow; i <= endRow; i++) {
-                const currDoc = this.childDocs[i];
-                if (!this._selectedDocs.has(currDoc)) this.addDocToSelection(currDoc, true, i);
-            }
-            this._lastSelectedRow = index;
-        } else if (ctrl) {
-            if (!this._selectedDocs.has(doc)) {
-                this.addDocToSelection(doc, true, index);
-            } else {
-                this.removeDocFromSelection(doc);
-            }
-        } else {
-            if (!this._selectedDocs.has(doc)) {
-                this.clearSelection();
-                this.addDocToSelection(doc, false, index);
-            }
+    clearSelection = () => SelectionManager.DeselectAll();
+
+    selectRows = (rootDoc: Doc, lastSelected: Doc) => {
+        const index = this.childDocs.indexOf(rootDoc);
+        const lastSelectedRow = this.childDocs.indexOf(lastSelected);
+        const startRow = Math.min(lastSelectedRow, index);
+        const endRow = Math.max(lastSelectedRow, index);
+        for (let i = startRow; i <= endRow; i++) {
+            const currDoc = this.childDocs[i];
+            if (!this._selectedDocs.includes(currDoc)) this.addDocToSelection(currDoc, true, i);
         }
     };
 
-    @action
-    sortedSelectedDocs = (): Doc[] => {
-        return this.childDocs.filter(doc => this._selectedDocs.has(doc));
-    };
+    sortedSelectedDocs = () => this.childDocs.filter(doc => this._selectedDocs.includes(doc));
 
-    setDropIndex = (index: number) => {
-        this._closestDropIndex = index;
-    };
+    setDropIndex = (index: number) => (this._closestDropIndex = index);
 
     @action
     onInternalDrop = (e: Event, de: DragManager.DropEvent) => {
@@ -394,17 +366,20 @@ export class CollectionSchemaView extends CollectionSubView() {
                 return total + curr;
             }, CollectionSchemaView._rowMenuWidth);
             this.swapColumns(de.complete.columnDragData.colIndex, i);
+            e.stopPropagation();
             return true;
         }
-        if (super.onInternalDrop(e, de)) {
-            this._isDragging = false;
-            const pushedDocs: Doc[] = this.childDocs.filter((doc: Doc, index: number) => index >= this._closestDropIndex && !this._selectedDocs.has(doc));
+        const draggedDocs = de.complete.docDragData?.draggedDocuments;
+        if (draggedDocs && super.onInternalDrop(e, de)) {
+            const pushedDocs = this.childDocs.filter((doc, index) => index >= this._closestDropIndex && !draggedDocs.includes(doc));
             this.props.removeDocument?.(pushedDocs);
-            this.props.removeDocument?.(this._selectedDocSortedArray);
-            this.addDocument(this._selectedDocSortedArray);
+            this.props.removeDocument?.(draggedDocs);
+            this.addDocument(draggedDocs);
             this.addDocument(pushedDocs);
             this.setSort(undefined);
-            this.clearSelection();
+            SelectionManager.DeselectAll();
+            setTimeout(() => draggedDocs.forEach(doc => DocumentManager.Instance.AddViewRenderedCb(doc, dv => dv.select(true))), 100);
+            e.stopPropagation();
             return true;
         }
         return false;
@@ -412,46 +387,11 @@ export class CollectionSchemaView extends CollectionSubView() {
 
     @action
     onExternalDrop = async (e: React.DragEvent): Promise<void> => {
-        super.onExternalDrop(
-            e,
-            {},
-            undoBatch(
-                action(docus => {
-                    this._isDragging = false;
-                    docus.map((doc: Doc) => {
-                        this.addDocument(doc);
-                    });
-                })
-            )
-        );
+        super.onExternalDrop(e, {}, undoBatch(action(docus => docus.map((doc: Doc) => this.addDocument(doc)))));
         this.setSort(undefined);
     };
 
-    @action
-    startDrag = (e: PointerEvent, doc: Doc, index: number) => {
-        if (!this._selectedDocs.has(doc)) {
-            this.clearSelection();
-            this.addDocToSelection(doc, false, index);
-        }
-        this._isDragging = true;
-        this._selectedDocSortedArray = this.sortedSelectedDocs();
-        const dragData = new DragManager.DocumentDragData(this._selectedDocSortedArray, 'move');
-        dragData.moveDocument = this.props.moveDocument;
-        const dragItem: HTMLElement[] = Array.from(this._selectedDocs.values()).map((doc: Doc) => this._rowEles.get(doc));
-
-        DragManager.StartDocumentDrag(
-            dragItem.map(ele => ele),
-            dragData,
-            e.clientX,
-            e.clientY,
-            undefined
-        );
-        return true;
-    };
-
-    onDividerDown = (e: React.PointerEvent) => {
-        setupMoveUpEvents(this, e, this.onDividerMove, emptyFunction, emptyFunction);
-    };
+    onDividerDown = (e: React.PointerEvent) => setupMoveUpEvents(this, e, this.onDividerMove, emptyFunction, emptyFunction);
 
     @action
     onDividerMove = (e: PointerEvent, down: number[], delta: number[]) => {
@@ -557,9 +497,6 @@ export class CollectionSchemaView extends CollectionSubView() {
         return undefined;
     };
 
-    isChildContentActive = () =>
-        this.props.isDocumentActive?.() && (this.props.childDocumentsActive?.() || BoolCast(this.rootDoc.childDocumentsActive)) ? true : this.props.childDocumentsActive?.() === false || this.rootDoc.childDocumentsActive === false ? false : undefined;
-
     @computed get fieldDefaultInput() {
         switch (this._newFieldType) {
             case ColumnType.Number:
@@ -644,23 +581,17 @@ export class CollectionSchemaView extends CollectionSubView() {
         ContextMenu.Instance.clearItems();
         ContextMenu.Instance.addItem({
             description: 'Change field',
-            event: () => {
-                this.openColumnMenu(index, false);
-            },
+            event: () => this.openColumnMenu(index, false),
             icon: 'pencil-alt',
         });
         ContextMenu.Instance.addItem({
             description: 'Filter field',
-            event: () => {
-                this.openFilterMenu(index);
-            },
+            event: () => this.openFilterMenu(index),
             icon: 'filter',
         });
         ContextMenu.Instance.addItem({
             description: 'Delete column',
-            event: () => {
-                this.removeColumn(index);
-            },
+            event: () => this.removeColumn(index),
             icon: 'trash',
         });
         ContextMenu.Instance.displayMenu(x, y, undefined, false);
@@ -672,9 +603,7 @@ export class CollectionSchemaView extends CollectionSubView() {
         this._menuOptions = this.documentKeys.filter(value => value.toLowerCase().includes(this._menuValue.toLowerCase()));
     };
 
-    getFieldFilters = (field: string) => {
-        return StrListCast(this.Document._docFilters).filter(filter => filter.split(':')[0] == field);
-    };
+    getFieldFilters = (field: string) => StrListCast(this.Document._docFilters).filter(filter => filter.split(':')[0] == field);
 
     removeFieldFilters = (field: string) => {
         this.getFieldFilters(field).forEach(filter => {
@@ -694,9 +623,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     };
 
     @action
-    updateFilterSearch = (e: React.ChangeEvent<HTMLInputElement>) => {
-        this._filterValue = e.target.value;
-    };
+    updateFilterSearch = (e: React.ChangeEvent<HTMLInputElement>) => (this._filterValue = e.target.value);
 
     @computed get newFieldMenu() {
         return (
@@ -705,7 +632,6 @@ export class CollectionSchemaView extends CollectionSubView() {
                     <input
                         type="radio"
                         name="newFieldType"
-                        id=""
                         checked={this._newFieldType == ColumnType.Number}
                         onChange={action(() => {
                             this._newFieldType = ColumnType.Number;
@@ -718,7 +644,6 @@ export class CollectionSchemaView extends CollectionSubView() {
                     <input
                         type="radio"
                         name="newFieldType"
-                        id=""
                         checked={this._newFieldType == ColumnType.Boolean}
                         onChange={action(() => {
                             this._newFieldType = ColumnType.Boolean;
@@ -731,7 +656,6 @@ export class CollectionSchemaView extends CollectionSubView() {
                     <input
                         type="radio"
                         name="newFieldType"
-                        id=""
                         checked={this._newFieldType == ColumnType.String}
                         onChange={action(() => {
                             this._newFieldType = ColumnType.String;
@@ -880,13 +804,11 @@ export class CollectionSchemaView extends CollectionSubView() {
         );
     }
 
-    tableWidthFunc = () => this.tableWidth;
-    rowHeightFunc = () => CollectionSchemaView._rowHeight;
-    rowClickScriptFunc = () => this.rowOnClickScript;
     isContentActive = () => this.props.isSelected() || this.props.isContentActive();
     screenToLocal = () => this.props.ScreenToLocalTransform().translate(-this.tableWidth, 0);
     previewWidthFunc = () => this.previewWidth;
     render() {
+        trace();
         return (
             <div
                 className="collectionSchemaView"
@@ -894,6 +816,12 @@ export class CollectionSchemaView extends CollectionSubView() {
                     this._ref = ele;
                     this.createDashEventsTarget(ele);
                 }}
+                onPointerDown={e => {
+                    // this is analogous to the panning code for a freeform view.
+                    // however, schema views don't pan so it does nothing.  but it does eat the pointerDown event
+                    // if the content is active to prevent the schema from being dragged
+                    this.isContentActive() && setupMoveUpEvents(this, e, returnFalse, emptyFunction, emptyFunction, false);
+                }}
                 onDrop={this.onExternalDrop.bind(this)}>
                 <div className="schema-table">
                     <div className="schema-header-row" style={{ height: CollectionSchemaView._rowHeight }}>
@@ -927,53 +855,16 @@ export class CollectionSchemaView extends CollectionSubView() {
                     </div>
                     {this._columnMenuIndex !== undefined && this.renderColumnMenu}
                     {this._filterColumnIndex !== undefined && this.renderFilterMenu}
-                    <div className="schema-table-content">
-                        {this.childDocs.map((doc: Doc, index: number) => {
-                            const dataDoc = !doc.isTemplateDoc && !doc.isTemplateForField && !doc.PARAMS ? undefined : this.props.DataDoc;
-                            let dref: Opt<DocumentView>;
-                            return (
-                                <div className="schema-row-wrapper" style={{ maxHeight: CollectionSchemaView._rowHeight }}>
-                                    <DocumentView
-                                        {...this.props}
-                                        ref={r => (dref = r || undefined)}
-                                        LayoutTemplate={this.props.childLayoutTemplate}
-                                        LayoutTemplateString={SchemaRowBox.LayoutString(this.props.fieldKey)}
-                                        Document={doc}
-                                        DataDoc={dataDoc}
-                                        ContainingCollectionView={this.props.CollectionView}
-                                        ContainingCollectionDoc={this.Document}
-                                        PanelWidth={this.tableWidthFunc}
-                                        PanelHeight={this.rowHeightFunc}
-                                        styleProvider={DefaultStyleProvider}
-                                        focus={this.focusDocument}
-                                        docFilters={this.childDocFilters}
-                                        docRangeFilters={this.childDocRangeFilters}
-                                        searchFilterDocs={this.searchFilterDocs}
-                                        rootSelected={this.rootSelected}
-                                        ScreenToLocalTransform={Transform.Identity}
-                                        bringToFront={emptyFunction}
-                                        isDocumentActive={this.isContentActive}
-                                        isContentActive={emptyFunction}
-                                        hideDecorations={true}
-                                        hideTitle={true}
-                                        hideDocumentButtonBar={true}
-                                        hideLinkAnchors={true}
-                                        fitWidth={returnTrue}
-                                        onClick={this.rowClickScriptFunc}
-                                        scriptContext={this}
-                                    />
-                                </div>
-                            );
-                        })}
-                    </div>
+                    <CollectionSchemaViewDocs schema={this} />
+
                     <EditableView GetValue={returnEmptyString} SetValue={this.addNewTextDoc} placeholder={"Type ':' for commands"} contents={'+ New Node'} menuCallback={this.menuCallback} />
                 </div>
                 {this.previewWidth > 0 && <div className="schema-preview-divider" style={{ width: CollectionSchemaView._previewDividerWidth }} onPointerDown={this.onDividerDown}></div>}
                 {this.previewWidth > 0 && (
                     <div style={{ width: `${this.previewWidth}px` }} ref={ref => (this._previewRef = ref)}>
-                        {this._lastSelectedRow !== undefined && (
+                        {Array.from(this._selectedDocs).lastElement() && (
                             <DocumentView
-                                Document={this.childDocs[this._lastSelectedRow]}
+                                Document={Array.from(this._selectedDocs).lastElement()}
                                 DataDoc={undefined}
                                 fitContentsToBox={returnTrue}
                                 dontCenter={'y'}
@@ -1007,3 +898,54 @@ export class CollectionSchemaView extends CollectionSubView() {
         );
     }
 }
+
+interface CollectionSchemaViewDocsProps {
+    schema: CollectionSchemaView;
+}
+
+@observer
+class CollectionSchemaViewDocs extends React.Component<CollectionSchemaViewDocsProps> {
+    tableWidthFunc = () => this.props.schema.tableWidth;
+    rowHeightFunc = () => CollectionSchemaView._rowHeight;
+    render() {
+        return (
+            <div className="schema-table-content">
+                {this.props.schema.childDocs.map((doc: Doc, index: number) => {
+                    const dataDoc = !doc.isTemplateDoc && !doc.isTemplateForField && !doc.PARAMS ? undefined : this.props.schema.props.DataDoc;
+                    return (
+                        <div className="schema-row-wrapper" style={{ maxHeight: CollectionSchemaView._rowHeight }}>
+                            <DocumentView
+                                {...this.props.schema.props}
+                                LayoutTemplate={this.props.schema.props.childLayoutTemplate}
+                                LayoutTemplateString={SchemaRowBox.LayoutString(this.props.schema.props.fieldKey)}
+                                Document={doc}
+                                DataDoc={dataDoc}
+                                ContainingCollectionView={this.props.schema.props.CollectionView}
+                                ContainingCollectionDoc={this.props.schema.Document}
+                                PanelWidth={this.tableWidthFunc}
+                                PanelHeight={this.rowHeightFunc}
+                                styleProvider={DefaultStyleProvider}
+                                focus={this.props.schema.focusDocument}
+                                docFilters={this.props.schema.childDocFilters}
+                                docRangeFilters={this.props.schema.childDocRangeFilters}
+                                searchFilterDocs={this.props.schema.searchFilterDocs}
+                                rootSelected={this.props.schema.rootSelected}
+                                ScreenToLocalTransform={Transform.Identity}
+                                bringToFront={emptyFunction}
+                                isDocumentActive={this.props.schema.props.childDocumentsActive?.() ? this.props.schema.props.isDocumentActive : this.props.schema.isContentActive}
+                                isContentActive={emptyFunction}
+                                whenChildContentsActiveChanged={active => this.props.schema.props.whenChildContentsActiveChanged(active)}
+                                hideDecorations={true}
+                                hideTitle={true}
+                                hideDocumentButtonBar={true}
+                                hideLinkAnchors={true}
+                                fitWidth={returnTrue}
+                                scriptContext={this}
+                            />
+                        </div>
+                    );
+                })}
+            </div>
+        );
+    }
+}
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 87284be70..0c8c0ee59 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -1,9 +1,9 @@
 import React = require('react');
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, computed } from 'mobx';
+import { computed } from 'mobx';
 import { observer } from 'mobx-react';
-import { emptyFunction, setupMoveUpEvents } from '../../../../Utils';
 import { DragManager } from '../../../util/DragManager';
+import { SnappingManager } from '../../../util/SnappingManager';
 import { undoBatch } from '../../../util/UndoManager';
 import { ViewBoxBaseComponent } from '../../DocComponent';
 import { Colors } from '../../global/globalEnums';
@@ -36,24 +36,30 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
         return this.schemaView?.rowIndex(this.rootDoc) ?? -1;
     }
 
-    @action
-    onRowPointerDown = (e: React.PointerEvent) => {
-        if (!this.isContentActive()) return;
-        setupMoveUpEvents(this, e, e => this.schemaView?.startDrag(e, this.rootDoc, this.rowIndex) ?? true, emptyFunction, emptyFunction);
+    componentDidMount(): void {
+        this.props.setContentView?.(this);
+    }
+
+    select = (ctrlKey: boolean, shiftKey: boolean) => {
+        if (!this.schemaView) return;
+        const lastSelected = Array.from(this.schemaView._selectedDocs).lastElement();
+        if (shiftKey && lastSelected) this.schemaView.selectRows(this.rootDoc, lastSelected);
+        else {
+            this.props.select?.(ctrlKey);
+        }
     };
 
     onPointerEnter = (e: any) => {
-        if (!this.schemaView?._isDragging) return;
+        //if (!this.schemaView?._isDragging) return;
+        if (!SnappingManager.GetIsDragging()) return;
         document.removeEventListener('pointermove', this.onPointerMove);
         document.addEventListener('pointermove', this.onPointerMove);
     };
 
     onPointerMove = (e: any) => {
-        if (!this.schemaView?._isDragging) return;
-        let dragIsRow: boolean = true;
-        DragManager.docsBeingDragged.forEach(doc => {
-            dragIsRow = this.schemaView?._selectedDocs.has(doc) ?? false;
-        });
+        if (!SnappingManager.GetIsDragging()) return;
+        const dragIsRow = DragManager.docsBeingDragged.some(doc => doc.context === this.schemaDoc); //  this.schemaView?._selectedDocs.has(doc) ?? false;
+
         if (this._ref && dragIsRow) {
             const rect = this._ref.getBoundingClientRect();
             const y = e.clientY - rect.top; //y position within the element.
@@ -88,7 +94,6 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
                         ? { height: CollectionSchemaView._rowHeight, backgroundColor: Colors.LIGHT_BLUE, pointerEvents: this.schemaView?.props.isContentActive() ? 'all' : undefined /*, opacity: this.props.dragging ? 0.5 : 1 */ }
                         : { height: CollectionSchemaView._rowHeight, pointerEvents: this.schemaView?.props.isContentActive() ? 'all' : undefined }
                 }
-                onPointerDown={this.onRowPointerDown}
                 onPointerEnter={this.onPointerEnter}
                 onPointerLeave={this.onPointerLeave}
                 ref={(row: HTMLDivElement | null) => {
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.scss b/src/client/views/nodes/CollectionFreeFormDocumentView.scss
index 724394025..f99011b8f 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.scss
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.scss
@@ -5,5 +5,5 @@
     touch-action: manipulation;
     top: 0;
     left: 0;
-    pointer-events: none;
-}
\ No newline at end of file
+    //pointer-events: none;
+}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index c13934945..1f717932e 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -121,6 +121,7 @@ export interface DocComponentView {
     addDocTab?: (doc: Doc, where: OpenWhere) => boolean; // determines how to add a document - used in following links to open the target ina local lightbox
     reverseNativeScaling?: () => boolean; // DocumentView's setup screenToLocal based on the doc having a nativeWidth/Height.  However, some content views (e.g., FreeFormView w/ fitContentsToBox set) may ignore the native dimensions so this flags the DocumentView to not do Nativre scaling.
     shrinkWrap?: () => void; // requests a document to display all of its contents with no white space.  currently only implemented (needed?) for freeform views
+    select?: (ctrlKey: boolean, shiftKey: boolean) => void;
     menuControls?: () => JSX.Element; // controls to display in the top menu bar when the document is selected.
     isAnyChildContentActive?: () => boolean; // is any child content of the document active
     getKeyFrameEditing?: () => boolean; // whether the document is in keyframe editing mode (if it is, then all hidden documents that are not active at the keyframe time will still be shown)
@@ -236,7 +237,7 @@ export interface DocumentViewInternalProps extends DocumentViewProps {
     NativeHeight: () => number;
     isSelected: (outsideReaction?: boolean) => boolean;
     isHovering: () => boolean;
-    select: (ctrlPressed: boolean) => void;
+    select: (ctrlPressed: boolean, shiftPress?: boolean) => void;
     DocumentView: () => DocumentView;
     viewPath: () => DocumentView[];
 }
@@ -538,7 +539,9 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
 
     startDragging(x: number, y: number, dropAction: dropActionType, hideSource = false) {
         if (this._mainCont.current) {
-            const dragData = new DragManager.DocumentDragData([this.props.Document]);
+            const views = SelectionManager.Views().filter(dv => dv.docView?._mainCont.current);
+            const selected = views.some(dv => dv.rootDoc === this.Document) ? views : [this.props.DocumentView()];
+            const dragData = new DragManager.DocumentDragData(selected.map(dv => dv.rootDoc));
             const [left, top] = this.props.ScreenToLocalTransform().scale(this.NativeDimScaling).inverse().transformPoint(0, 0);
             dragData.offset = this.props
                 .ScreenToLocalTransform()
@@ -551,8 +554,13 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
             dragData.canEmbed = this.props.canEmbedOnDrag;
             const ffview = this.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView;
             ffview && runInAction(() => (ffview.ChildDrag = this.props.DocumentView()));
-            DragManager.StartDocumentDrag([this._mainCont.current], dragData, x, y, { hideSource: hideSource || (!dropAction && !this.layoutDoc.onDragStart && !this.props.dontHideOnDrag) }, () =>
-                setTimeout(action(() => ffview && (ffview.ChildDrag = undefined)))
+            DragManager.StartDocumentDrag(
+                selected.map(dv => dv.docView!._mainCont.current!),
+                dragData,
+                x,
+                y,
+                { hideSource: hideSource || (!dropAction && !this.layoutDoc.onDragStart && !this.props.dontHideOnDrag) },
+                () => setTimeout(action(() => ffview && (ffview.ChildDrag = undefined)))
             ); // this needs to happen after the drop event is processed.
             ffview?.setupDragLines(false);
         }
@@ -659,7 +667,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                         }),
                         350
                     );
-                    this.props.select(e.ctrlKey || e.shiftKey);
+                    (this._componentView?.select ?? this.props.select)(e.ctrlKey || e.metaKey, e.shiftKey);
                 }
                 preventDefault = false;
             }
-- 
cgit v1.2.3-70-g09d2


From fd71eb1a130058207b45cc6a1da0dbd97f6dd4f1 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 24 Mar 2023 23:18:44 -0400
Subject: fixed showing keyValueBox when document opacity is 0 or it is hidden.
  fixed toggling link targets.  fixed sorting and undoing schema view changes.

---
 src/client/util/DocumentManager.ts                 |  1 +
 src/client/views/StyleProvider.tsx                 |  5 +-
 src/client/views/collections/CollectionSubView.tsx |  2 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  1 +
 .../collectionSchema/CollectionSchemaView.tsx      | 81 +++++++++++-----------
 .../collections/collectionSchema/SchemaRowBox.tsx  |  1 -
 src/client/views/nodes/DocumentView.tsx            |  9 ++-
 src/client/views/nodes/LabelBox.tsx                |  1 +
 8 files changed, 54 insertions(+), 47 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaRowBox.tsx')

diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 947613801..ccf370662 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -262,6 +262,7 @@ export class DocumentManager {
         finished?: () => void
     ) => {
         const docContextPath = DocumentManager.GetContextPath(targetDoc, true);
+        if (docContextPath.some(doc => doc.hidden)) options.toggleTarget = false;
         let rootContextView = await new Promise<DocumentView>(res => {
             const viewIndex = docContextPath.findIndex(doc => this.getDocumentView(doc));
             if (viewIndex !== -1) return res(this.getDocumentView(docContextPath[viewIndex])!);
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index d1e85a65b..1b5eb3342 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -146,6 +146,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
             return (
                 (doc &&
                     !doc.presentationTargetDoc &&
+                    !props?.LayoutTemplateString?.includes(KeyValueBox.name) &&
                     props?.showTitle?.() !== '' &&
                     StrCast(
                         doc._showTitle,
@@ -169,7 +170,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
             if (!backColor) return undefined;
             return lightOrDark(backColor);
         case StyleProp.Hidden:
-            return BoolCast(doc?.hidden);
+            return props?.LayoutTemplateString?.includes(KeyValueBox.name) ? false : BoolCast(doc?.hidden);
         case StyleProp.BorderRounding:
             return StrCast(doc?.[fieldKey + 'borderRounding'], StrCast(doc?.borderRounding, doc?._viewType === CollectionViewType.Pile ? '50%' : ''));
         case StyleProp.TitleHeight:
@@ -288,7 +289,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
         }
         case StyleProp.PointerEvents:
             const isInk = doc && StrCast(Doc.Layout(doc).layout).includes(InkingStroke.name);
-            if (MainView.Instance._exploreMode) return isInk ? 'visiblePainted' : 'all';
+            if (MainView.Instance._exploreMode || doc?.unrendered) return isInk ? 'visiblePainted' : 'all';
             if (doc?.pointerEvents) return StrCast(doc.pointerEvents);
             if (props?.contentPointerEvents) return StrCast(props.contentPointerEvents);
             if (props?.pointerEvents?.() === 'none') return 'none';
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index bd74c9399..5100d8d67 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -79,7 +79,7 @@ export function CollectionSubView<X>(moreProps?: X) {
                 .map(doc => Doc.GetLayoutDataDocPair(Document, !this.props.isAnnotationOverlay ? DataDoc : undefined, doc))
                 .filter(pair => {
                     // filter out any documents that have a proto that we don't have permissions to
-                    return pair.layout && (!pair.layout.proto || (pair.layout.proto instanceof Doc && GetEffectiveAcl(pair.layout.proto) !== AclPrivate));
+                    return !pair.layout?.hidden && pair.layout && (!pair.layout.proto || (pair.layout.proto instanceof Doc && GetEffectiveAcl(pair.layout.proto) !== AclPrivate));
                 });
             return validPairs.map(({ data, layout }) => ({ data: data as Doc, layout: layout! })); // this mapping is a bit of a hack to coerce types
         }
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 4f81af95d..e7d1eeb90 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -319,6 +319,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
 
     getView = async (doc: Doc): Promise<Opt<DocumentView>> => {
         return new Promise<Opt<DocumentView>>(res => {
+            doc.hidden && (doc.hidden = false);
             const findDoc = (finish: (dv: DocumentView) => void) => DocumentManager.Instance.AddViewRenderedCb(doc, dv => finish(dv));
             findDoc(dv => res(dv));
         });
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index ad31113a2..f5d3243f4 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -40,7 +40,6 @@ const defaultColumnKeys: string[] = ['title', 'type', 'author', 'creationDate',
 
 @observer
 export class CollectionSchemaView extends CollectionSubView() {
-    private _ref: HTMLDivElement | null = null;
     private _closestDropIndex: number = 0;
     private _previewRef: HTMLDivElement | null = null;
     private _makeNewColumn: boolean = false;
@@ -177,18 +176,6 @@ export class CollectionSchemaView extends CollectionSubView() {
     setSort = (field: string | undefined, desc: boolean = false) => {
         this.layoutDoc.sortField = field;
         this.layoutDoc.sortDesc = desc;
-
-        if (field === undefined) return;
-
-        this.childDocs.sort((docA, docB) => {
-            const aStr = Field.toString(docA[field] as Field);
-            const bStr = Field.toString(docB[field] as Field);
-            var out = 0;
-            if (aStr < bStr) out = -1;
-            if (aStr > bStr) out = 1;
-            if (desc) out *= -1;
-            return out;
-        });
     };
 
     addRow = (doc: Doc | Doc[]) => {
@@ -372,10 +359,9 @@ export class CollectionSchemaView extends CollectionSubView() {
         const draggedDocs = de.complete.docDragData?.draggedDocuments;
         if (draggedDocs && super.onInternalDrop(e, de)) {
             const pushedDocs = this.childDocs.filter((doc, index) => index >= this._closestDropIndex && !draggedDocs.includes(doc));
-            this.props.removeDocument?.(pushedDocs);
-            this.props.removeDocument?.(draggedDocs);
-            this.addDocument(draggedDocs);
-            this.addDocument(pushedDocs);
+            const pushedAndDraggedDocs = [...pushedDocs, ...draggedDocs];
+            const removed = this.childDocs.slice().filter(doc => !pushedAndDraggedDocs.includes(doc));
+            this.dataDoc[this.fieldKey ?? 'data'] = new List<Doc>([...removed, ...draggedDocs, ...pushedDocs]);
             this.setSort(undefined);
             SelectionManager.DeselectAll();
             setTimeout(() => draggedDocs.forEach(doc => DocumentManager.Instance.AddViewRenderedCb(doc, dv => dv.select(true))), 100);
@@ -804,16 +790,30 @@ export class CollectionSchemaView extends CollectionSubView() {
         );
     }
 
+    @computed get sortedDocs() {
+        const field = StrCast(this.layoutDoc.sortField);
+        const desc = BoolCast(this.layoutDoc.sortDesc);
+        return !field
+            ? this.childDocs
+            : this.childDocs.sort((docA, docB) => {
+                  const aStr = Field.toString(docA[field] as Field);
+                  const bStr = Field.toString(docB[field] as Field);
+                  var out = 0;
+                  if (aStr < bStr) out = -1;
+                  if (aStr > bStr) out = 1;
+                  if (desc) out *= -1;
+                  return out;
+              });
+    }
+    sortedDocsFunc = () => this.sortedDocs;
     isContentActive = () => this.props.isSelected() || this.props.isContentActive();
     screenToLocal = () => this.props.ScreenToLocalTransform().translate(-this.tableWidth, 0);
     previewWidthFunc = () => this.previewWidth;
     render() {
-        trace();
         return (
             <div
                 className="collectionSchemaView"
                 ref={(ele: HTMLDivElement | null) => {
-                    this._ref = ele;
                     this.createDashEventsTarget(ele);
                 }}
                 onPointerDown={e => {
@@ -834,28 +834,26 @@ export class CollectionSchemaView extends CollectionSubView() {
                                 <FontAwesomeIcon icon="plus" />
                             </div>
                         </div>
-                        {this.columnKeys.map((key, index) => {
-                            return (
-                                <SchemaColumnHeader
-                                    key={index}
-                                    columnIndex={index}
-                                    columnKeys={this.columnKeys}
-                                    columnWidths={this.displayColumnWidths}
-                                    sortField={this.sortField}
-                                    sortDesc={this.sortDesc}
-                                    setSort={this.setSort}
-                                    removeColumn={this.removeColumn}
-                                    resizeColumn={this.startResize}
-                                    openContextMenu={this.openContextMenu}
-                                    dragColumn={this.dragColumn}
-                                    setColRef={this.setColRef}
-                                />
-                            );
-                        })}
+                        {this.columnKeys.map((key, index) => (
+                            <SchemaColumnHeader
+                                key={index}
+                                columnIndex={index}
+                                columnKeys={this.columnKeys}
+                                columnWidths={this.displayColumnWidths}
+                                sortField={this.sortField}
+                                sortDesc={this.sortDesc}
+                                setSort={this.setSort}
+                                removeColumn={this.removeColumn}
+                                resizeColumn={this.startResize}
+                                openContextMenu={this.openContextMenu}
+                                dragColumn={this.dragColumn}
+                                setColRef={this.setColRef}
+                            />
+                        ))}
                     </div>
                     {this._columnMenuIndex !== undefined && this.renderColumnMenu}
                     {this._filterColumnIndex !== undefined && this.renderFilterMenu}
-                    <CollectionSchemaViewDocs schema={this} />
+                    <CollectionSchemaViewDocs schema={this} childDocs={this.sortedDocsFunc} sortField={StrCast(this.layoutDoc.sortField)} sortDesc={BoolCast(this.layoutDoc.sortDesc)} />
 
                     <EditableView GetValue={returnEmptyString} SetValue={this.addNewTextDoc} placeholder={"Type ':' for commands"} contents={'+ New Node'} menuCallback={this.menuCallback} />
                 </div>
@@ -901,6 +899,9 @@ export class CollectionSchemaView extends CollectionSubView() {
 
 interface CollectionSchemaViewDocsProps {
     schema: CollectionSchemaView;
+    childDocs: () => Doc[];
+    sortField: string; // I don't know why these are needed since the childDocs function changes when the sort changes.  However, for some reason that doesn't cause a re-render...
+    sortDesc: boolean;
 }
 
 @observer
@@ -910,8 +911,8 @@ class CollectionSchemaViewDocs extends React.Component<CollectionSchemaViewDocsP
     render() {
         return (
             <div className="schema-table-content">
-                {this.props.schema.childDocs.map((doc: Doc, index: number) => {
-                    const dataDoc = !doc.isTemplateDoc && !doc.isTemplateForField && !doc.PARAMS ? undefined : this.props.schema.props.DataDoc;
+                {this.props.childDocs().map((doc: Doc, index: number) => {
+                    const dataDoc = !doc.isTemplateDoc && !doc.isTemplateForField ? undefined : this.props.schema.props.DataDoc;
                     return (
                         <div className="schema-row-wrapper" style={{ maxHeight: CollectionSchemaView._rowHeight }}>
                             <DocumentView
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 0c8c0ee59..10f307068 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -50,7 +50,6 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
     };
 
     onPointerEnter = (e: any) => {
-        //if (!this.schemaView?._isDragging) return;
         if (!SnappingManager.GetIsDragging()) return;
         document.removeEventListener('pointermove', this.onPointerMove);
         document.addEventListener('pointermove', this.onPointerMove);
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 1f717932e..42c2b28ba 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -332,7 +332,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
         return this.props.NativeHeight();
     }
     @computed get onClickHandler() {
-        const noClick = this.rootSelected() || this.props.isSelected() || this._componentView?.isAnyChildContentActive?.();
+        const noClick = this.props.LayoutTemplateString?.includes(KeyValueBox.name) || this.rootSelected() || this.props.isSelected() || this._componentView?.isAnyChildContentActive?.();
         return noClick ? undefined : this.props.onClick?.() ?? this.props.onBrowseClick?.() ?? Cast(this.Document.onClick, ScriptField, Cast(this.layoutDoc.onClick, ScriptField, null));
     }
     @computed get onDoubleClickHandler() {
@@ -1483,7 +1483,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
         });
 
         const animRenderDoc = DocumentViewInternal.AnimationEffect(renderDoc, this.rootDoc[AnimationSym], this.rootDoc);
-        return (
+        return this.hidden ? null : (
             <div
                 className={`${DocumentView.ROOT_DIV} docView-hack`}
                 ref={this._mainCont}
@@ -1640,6 +1640,9 @@ export class DocumentView extends React.Component<DocumentViewProps> {
         const hideCount = this.props.renderDepth === -1 || SnappingManager.GetIsDragging() || (this.isSelected() && this.props.renderDepth) || !this._isHovering || this.hideLinkButton;
         return hideCount ? null : <DocumentLinksButton View={this} scaling={this.linkButtonInverseScaling} OnHover={true} Bottom={this.topMost} ShowCount={true} />;
     }
+    @computed get hidden() {
+        return this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Hidden);
+    }
 
     @computed get docViewPath(): DocumentView[] {
         return this.props.docViewPath ? [...this.props.docViewPath(), this] : [this];
@@ -1826,7 +1829,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
         const yshift = Math.abs(this.Yshift) <= 0.001 ? this.props.PanelHeight() : undefined;
         const isButton = this.props.Document.type === DocumentType.FONTICON || this.props.Document._viewType === CollectionViewType.Linear;
 
-        return (
+        return this.hidden ? null : (
             <div
                 className="contentFittingDocumentView"
                 onPointerEnter={action(() => {
diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx
index 6e0b4be37..916458dfd 100644
--- a/src/client/views/nodes/LabelBox.tsx
+++ b/src/client/views/nodes/LabelBox.tsx
@@ -131,6 +131,7 @@ export class LabelBox extends ViewBoxBaseComponent<FieldViewProps & LabelBoxProp
                     style={{
                         backgroundColor: this.hoverColor,
                         fontSize: StrCast(this.layoutDoc._fontSize),
+                        color: StrCast(this.layoutDoc._color),
                         fontFamily: StrCast(this.layoutDoc._fontFamily) || 'inherit',
                         letterSpacing: StrCast(this.layoutDoc.letterSpacing),
                         textTransform: StrCast(this.layoutDoc.textTransform) as any,
-- 
cgit v1.2.3-70-g09d2


From dabac69d26c8e8e69bd55466ce221d9e33e36638 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 28 Mar 2023 14:23:17 -0400
Subject: numerous changes to try to simplify event handling in DocumentView -
 got rid of isContentActive in DocComponent since it's in DocumentView.  
 Including adding 'enableDragWhenActive' , 'onClickScriptDisable',

---
 src/Utils.ts                                       |  17 +-
 src/client/documents/Documents.ts                  |   3 +-
 src/client/util/CurrentUserUtils.ts                |  12 +-
 src/client/views/DocComponent.tsx                  |  13 --
 src/client/views/DocumentDecorations.tsx           |   8 +-
 src/client/views/InkingStroke.tsx                  |   2 +-
 src/client/views/MainView.tsx                      |   8 +-
 src/client/views/StyleProvider.tsx                 |   4 +-
 .../views/collections/CollectionStackingView.tsx   |   2 +
 src/client/views/collections/TabDocView.tsx        |   4 +-
 src/client/views/collections/TreeView.tsx          |   6 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 100 +--------
 .../collectionLinear/CollectionLinearView.scss     |  10 +-
 .../collectionLinear/CollectionLinearView.tsx      |  18 +-
 .../collectionSchema/CollectionSchemaView.scss     |   3 +-
 .../collectionSchema/CollectionSchemaView.tsx      |  46 ++--
 .../collections/collectionSchema/SchemaRowBox.tsx  |   8 +-
 src/client/views/global/globalCssVariables.scss    |   3 +-
 .../views/global/globalCssVariables.scss.d.ts      |   2 +-
 src/client/views/nodes/ColorBox.tsx                |   2 +-
 src/client/views/nodes/DocumentView.tsx            | 238 ++++-----------------
 src/client/views/nodes/FunctionPlotBox.tsx         |   2 +-
 src/client/views/nodes/KeyValueBox.tsx             |  15 +-
 src/client/views/nodes/KeyValuePair.tsx            |   9 +-
 src/client/views/nodes/LinkBox.tsx                 |   9 +-
 src/client/views/nodes/ScriptingBox.tsx            |   4 +-
 src/client/views/nodes/WebBox.tsx                  |   2 +-
 src/client/views/nodes/button/FontIconBox.scss     |  10 +-
 src/client/views/nodes/button/FontIconBox.tsx      |   6 +-
 .../views/nodes/formattedText/FormattedTextBox.tsx |   9 +-
 src/client/views/nodes/trails/PresBox.tsx          |   4 +-
 src/client/views/pdf/PDFViewer.tsx                 |   9 -
 src/fields/Doc.ts                                  |   2 +-
 src/fields/ScriptField.ts                          |   2 +-
 34 files changed, 171 insertions(+), 421 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaRowBox.tsx')

diff --git a/src/Utils.ts b/src/Utils.ts
index ae1478943..0c7deaf5d 100644
--- a/src/Utils.ts
+++ b/src/Utils.ts
@@ -8,8 +8,12 @@ import { Message } from './server/Message';
 import Color = require('color');
 
 export namespace Utils {
+    export let CLICK_TIME = 300;
     export let DRAG_THRESHOLD = 4;
     export let SNAP_THRESHOLD = 10;
+    export function isClick(x: number, y: number, downX: number, downY: number, downTime: number) {
+        return Date.now() - downTime < Utils.CLICK_TIME && Math.abs(x - downX) < Utils.DRAG_THRESHOLD && Math.abs(y - downY) < Utils.DRAG_THRESHOLD;
+    }
 
     export function readUploadedFileAsText(inputFile: File) {
         const temporaryFileReader = new FileReader();
@@ -509,11 +513,22 @@ export function returnTrue() {
     return true;
 }
 
+export function returnAlways(): 'always' {
+    return 'always';
+}
+export function returnNever(): 'never' {
+    return 'never';
+}
+
+export function returnDefault(): 'default' {
+    return 'default';
+}
+
 export function returnFalse() {
     return false;
 }
 
-export function returnAll() {
+export function returnAll(): 'all' {
     return 'all';
 }
 
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 2bc1b5b1d..c484db0db 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -230,6 +230,7 @@ export class DocumentOptions {
     contextMenuIcons?: List<string>;
     defaultDoubleClick?: 'ignore' | 'default'; // ignore double clicks, or deafult (undefined) means open document full screen
     waitForDoubleClickToClick?: 'always' | 'never' | 'default'; // whether a click function wait for double click to expire.  'default' undefined = wait only if there's a click handler, "never" = never wait, "always" = alway wait
+    enableDragWhenActive?: boolean;
     dontUndo?: boolean; // whether button clicks should be undoable (this is set to true for Undo/Redo/and sidebar buttons that open the siebar panel)
     description?: string; // added for links
     layout?: string | Doc; // default layout string for a document
@@ -587,7 +588,7 @@ export namespace Docs {
                 DocumentType.FONTICON,
                 {
                     layout: { view: FontIconBox, dataField: 'icon' },
-                    options: { defaultDoubleClick: 'ignore', waitForDoubleClickToClick: 'never', hideLinkButton: true, _width: 40, _height: 40 },
+                    options: { defaultDoubleClick: 'ignore', waitForDoubleClickToClick: 'never', enableDragWhenActive: true, hideLinkButton: true, _width: 40, _height: 40 },
                 },
             ],
             [
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 814b7b072..b21f53221 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -62,7 +62,7 @@ export class CurrentUserUtils {
         const requiredTypeNameFields:{btnOpts:DocumentOptions, templateOpts:DocumentOptions, template:(opts:DocumentOptions) => Doc}[] = [
             {
                 btnOpts: { title: "slide", icon: "address-card" }, 
-                templateOpts: { _width: 400, _height: 300, title: "slideView", childDocumentsActive: true, _xMargin: 3, _yMargin: 3, system: true }, 
+                templateOpts: { _width: 400, _height: 300, title: "slideView",  _xMargin: 3, _yMargin: 3, system: true }, 
                 template: (opts:DocumentOptions) => Docs.Create.MultirowDocument(
                     [
                         Docs.Create.MulticolumnDocument([], { title: "data", _height: 200,  system: true }),
@@ -95,7 +95,7 @@ export class CurrentUserUtils {
 
         const reqdOpts:DocumentOptions = {
             title: "Experimental Tools", _xMargin: 0, _showTitle: "title", _chromeHidden: true,
-            _stayInCollection: true, _hideContextMenu: true, _forceActive: true, system: true, childDocumentsActive: true,
+            _stayInCollection: true, _hideContextMenu: true, _forceActive: true, system: true,
             _autoHeight: true, _width: 500, _height: 300, _fitWidth: true, _columnWidth: 35, ignoreClick: true, _lockedPosition: true,
         };
         const reqdScripts = { dropConverter : "convertToButtons(dragData)" };
@@ -184,10 +184,10 @@ export class CurrentUserUtils {
                 case DocumentType.IMG : creator = imageBox; break;
                 case DocumentType.FONTICON: creator = fontBox; break;
             }
-            const allopts = {system: true, ...opts};
+            const allopts = {system: true, onClickScriptDisable: "never",  ...opts};
             return DocUtils.AssignScripts(  (curIcon?.iconTemplate === opts.iconTemplate ? 
                       DocUtils.AssignOpts(curIcon, allopts):undefined) ?? ((templateIconsDoc[iconFieldName] = MakeTemplate(creator(allopts), true, iconFieldName, templateField))),
-                {onClick:"deiconifyView(documentView)", onDoubleClick: "deiconifyViewToLightbox(documentView)"});
+                {onClick:"deiconifyView(documentView)", onDoubleClick: "deiconifyViewToLightbox(documentView)", });
         };
         const labelBox = (opts: DocumentOptions, data?:string) => Docs.Create.LabelDocument({
             textTransform: "unset", letterSpacing: "unset", _singleLine: false, _minFontSize: 14, _maxFontSize: 24, borderRounding: "5px",  _width: 150, _height: 70, _xPadding: 10, _yPadding: 10, ...opts
@@ -314,7 +314,7 @@ export class CurrentUserUtils {
         const creatorBtns = CurrentUserUtils.creatorBtnDescriptors(doc).map((reqdOpts) => {
             const btn = dragCreatorDoc ? DocListCast(dragCreatorDoc.data).find(doc => doc.title === reqdOpts.title): undefined;
             const opts:DocumentOptions = {...OmitKeys(reqdOpts, ["funcs", "scripts", "backgroundColor"]).omit, 
-                _nativeWidth: 50, _nativeHeight: 50, _width: 35, _height: 35, _hideContextMenu: true, _stayInCollection: true, 
+                _width: 35, _height: 35, _hideContextMenu: true, _stayInCollection: true, 
                 btnType: ButtonType.ToolButton, backgroundColor: reqdOpts.backgroundColor ?? Colors.DARK_GRAY, color: Colors.WHITE, system: true,
                 _removeDropProperties: new List<string>(["_stayInCollection"]),
                 };
@@ -324,7 +324,7 @@ export class CurrentUserUtils {
         const reqdOpts:DocumentOptions = {
             title: "Basic Item Creators", _showTitle: "title", _xMargin: 0, _stayInCollection: true, _hideContextMenu: true, _chromeHidden: true, system: true,
             _autoHeight: true, _width: 500, _height: 300, _fitWidth: true, _columnWidth: 40, ignoreClick: true, _lockedPosition: true, _forceActive: true,
-            childDocumentsActive: true, childDropAction: 'alias' 
+             childDropAction: 'alias' 
         };
         const reqdScripts = { dropConverter: "convertToButtons(dragData)" };
         return DocUtils.AssignScripts(DocUtils.AssignOpts(dragCreatorDoc, reqdOpts, creatorBtns) ?? Docs.Create.MasonryDocument(creatorBtns, reqdOpts), reqdScripts);
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index 0b92fd864..9fc1487a0 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -82,12 +82,6 @@ export function ViewBoxBaseComponent<P extends ViewBoxBaseProps>() {
             return this.props.fieldKey;
         }
 
-        isContentActive = (outsideReaction?: boolean) =>
-            this.props.isContentActive?.() === false
-                ? false
-                : Doc.ActiveTool !== InkTool.None || this.props.isContentActive?.() || this.props.Document.forceActive || this.props.isSelected(outsideReaction) || this.props.rootSelected(outsideReaction)
-                ? true
-                : undefined;
         protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
     }
     return Component;
@@ -135,13 +129,6 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps>()
 
         isAnyChildContentActive = () => this._isAnyChildContentActive;
 
-        isContentActive = (outsideReaction?: boolean) =>
-            this.props.isContentActive?.() === false
-                ? false
-                : Doc.ActiveTool !== InkTool.None || this.props.isContentActive?.() || this.props.Document.forceActive || this.props.isSelected(outsideReaction) || this.props.rootSelected(outsideReaction) || this.isAnyChildContentActive()
-                ? true
-                : undefined;
-
         lookupField = (field: string) => ScriptCast((this.layoutDoc as any).lookupField)?.script.run({ self: this.layoutDoc, data: this.rootDoc, field: field }).result;
 
         protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 2d2d3c2f6..985e6f88f 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -916,9 +916,11 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
                                         pointerEvents: 'none',
                                     }}>
                                     {this._isRotating ? null : (
-                                        <div className="documentDecorations-rotation" style={{ pointerEvents: 'all' }} onPointerDown={this.onRotateDown} onContextMenu={e => e.preventDefault()}>
-                                            <IconButton icon={<FaUndo />} isCircle={true} hoverStyle={'lighten'} backgroundColor={Colors.DARK_GRAY} color={Colors.LIGHT_GRAY} />
-                                        </div>
+                                        <Tooltip enterDelay={750} title={<div className="dash-tooltip">tap to set rotate center, drag to rotate</div>}>
+                                            <div className="documentDecorations-rotation" style={{ pointerEvents: 'all' }} onPointerDown={this.onRotateDown} onContextMenu={e => e.preventDefault()}>
+                                                <IconButton icon={<FaUndo />} isCircle={true} hoverStyle={'lighten'} backgroundColor={Colors.DARK_GRAY} color={Colors.LIGHT_GRAY} />
+                                            </div>
+                                        </Tooltip>
                                     )}
                                 </div>
                                 {!this._showRotCenter ? null : (
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index a085b69a5..e3642fdaf 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -473,7 +473,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
                             dontRegisterView={true}
                             noSidebar={true}
                             dontScale={true}
-                            isContentActive={this.isContentActive}
+                            isContentActive={this.props.isContentActive}
                         />
                     </div>
                 )}
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index c84d204d5..f5adc17d0 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -40,7 +40,7 @@ import { DashboardView } from './DashboardView';
 import { DictationOverlay } from './DictationOverlay';
 import { DocumentDecorations } from './DocumentDecorations';
 import { GestureOverlay } from './GestureOverlay';
-import { DASHBOARD_SELECTOR_HEIGHT, LEFT_MENU_WIDTH } from './global/globalCssVariables.scss';
+import { TOPBAR_HEIGHT, LEFT_MENU_WIDTH } from './global/globalCssVariables.scss';
 import { Colors } from './global/globalEnums';
 import { KeyManager } from './GlobalKeyHandler';
 import { InkTranscription } from './InkTranscription';
@@ -86,7 +86,7 @@ export class MainView extends React.Component {
         return this._hideUI ? 0 : 27;
     } //  27 comes form lm.config.defaultConfig.dimensions.headerHeight in goldenlayout.js
     @computed private get topOfDashUI() {
-        return this._hideUI || LightboxView.LightboxDoc ? 0 : Number(DASHBOARD_SELECTOR_HEIGHT.replace('px', ''));
+        return this._hideUI || LightboxView.LightboxDoc ? 0 : Number(TOPBAR_HEIGHT.replace('px', ''));
     }
     @computed private get topOfHeaderBarDoc() {
         return this.topOfDashUI;
@@ -872,7 +872,7 @@ export class MainView extends React.Component {
 
     @computed get docButtons() {
         return !Doc.MyDockedBtns ? null : (
-            <div className="mainView-docButtons" ref={this._docBtnRef} style={{ height: !Doc.MyDockedBtns.linearViewIsExpanded ? '42px' : undefined }}>
+            <div className="mainView-docButtons" ref={this._docBtnRef}>
                 <CollectionLinearView
                     Document={Doc.MyDockedBtns}
                     DataDoc={undefined}
@@ -910,7 +910,7 @@ export class MainView extends React.Component {
         );
     }
     @computed get snapLines() {
-        return !SnappingManager.GetShowSnapLines() ? null : (
+        return !SelectionManager.Views().some(dv => dv.rootDoc.showSnapLines) ? null : (
             <div className="mainView-snapLines">
                 <svg style={{ width: '100%', height: '100%' }}>
                     {SnappingManager.horizSnapLines().map(l => (
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index 1b5eb3342..faaa4e1f9 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -89,6 +89,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
     const isAnchor = property.includes(':anchor');
     const isAnnotated = property.includes(':annotated');
     const isOpen = property.includes(':open');
+    const boxBackground = property.includes(':box');
     const fieldKey = props?.fieldKey ? props.fieldKey + '-' : isCaption ? 'caption-' : '';
     const lockedPosition = () => doc && BoolCast(doc._lockedPosition);
     const backgroundCol = () => props?.styleProvider?.(doc, props, StyleProp.BackgroundColor);
@@ -200,7 +201,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
                     docColor = docColor || (darkScheme() ? 'transparent' : 'transparent');
                     break;
                 case DocumentType.FONTICON:
-                    docColor = docColor || Colors.DARK_GRAY;
+                    docColor = boxBackground ? undefined : docColor || Colors.DARK_GRAY;
                     break;
                 case DocumentType.RTF:
                     docColor = docColor || (darkScheme() ? Colors.DARK_GRAY : Colors.LIGHT_GRAY);
@@ -289,6 +290,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
         }
         case StyleProp.PointerEvents:
             const isInk = doc && StrCast(Doc.Layout(doc).layout).includes(InkingStroke.name);
+            if (docProps?.DocumentView?.().ComponentView?.overridePointerEvents?.() !== undefined) return docProps?.DocumentView?.().ComponentView?.overridePointerEvents?.();
             if (MainView.Instance._exploreMode || doc?.unrendered) return isInk ? 'visiblePainted' : 'all';
             if (doc?.pointerEvents) return StrCast(doc.pointerEvents);
             if (props?.contentPointerEvents) return StrCast(props.contentPointerEvents);
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 33d468950..64ec419ec 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -325,6 +325,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
                 fitWidth={this.props.childFitWidth}
                 isContentActive={doc.isLinkButton ? this.isChildButtonContentActive : this.isChildContentActive}
                 onKey={this.onKeyDown}
+                onBrowseClick={this.props.onBrowseClick}
                 isDocumentActive={this.isContentActive}
                 LayoutTemplate={this.props.childLayoutTemplate}
                 LayoutTemplateString={this.props.childLayoutString}
@@ -659,6 +660,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
                         addDocument={this.props.addDocument}
                         moveDocument={this.props.moveDocument}
                         addDocTab={this.props.addDocTab}
+                        onBrowseClick={this.props.onBrowseClick}
                         pinToPres={emptyFunction}
                         rootSelected={this.props.isSelected}
                         removeDocument={this.props.removeDocument}
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 5e6849e7c..93b816581 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -10,7 +10,6 @@ import { Id } from '../../../fields/FieldSymbols';
 import { List } from '../../../fields/List';
 import { FieldId } from '../../../fields/RefField';
 import { listSpec } from '../../../fields/Schema';
-import { ScriptField } from '../../../fields/ScriptField';
 import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../fields/Types';
 import { emptyFunction, lightOrDark, returnEmptyDoclist, returnFalse, returnTrue, setupMoveUpEvents, simulateMouseClick, Utils } from '../../../Utils';
 import { DocServer } from '../../DocServer';
@@ -28,6 +27,7 @@ import { LightboxView } from '../LightboxView';
 import { MainView } from '../MainView';
 import { DocFocusOptions, DocumentView, DocumentViewProps, OpenWhere, OpenWhereMod } from '../nodes/DocumentView';
 import { DashFieldView } from '../nodes/formattedText/DashFieldView';
+import { KeyValueBox } from '../nodes/KeyValueBox';
 import { PinProps, PresBox, PresMovement } from '../nodes/trails';
 import { DefaultStyleProvider, StyleProp } from '../StyleProvider';
 import { CollectionDockingView } from './CollectionDockingView';
@@ -35,7 +35,6 @@ import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormV
 import { CollectionView } from './CollectionView';
 import './TabDocView.scss';
 import React = require('react');
-import { KeyValueBox } from '../nodes/KeyValueBox';
 const _global = (window /* browser */ || global) /* node */ as any;
 
 interface TabDocViewProps {
@@ -429,6 +428,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                     ContainingCollectionDoc={undefined}
                     onBrowseClick={MainView.Instance.exploreMode}
                     isContentActive={returnTrue}
+                    isDocumentActive={returnFalse}
                     PanelWidth={this.PanelWidth}
                     PanelHeight={this.PanelHeight}
                     styleProvider={DefaultStyleProvider}
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 257428d56..99b7549c0 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -573,6 +573,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                         </div>
                     )}
                     <ul
+                        style={{ cursor: 'inherit' }}
                         key={expandKey + 'more'}
                         title="click to change sort order"
                         className={''} //this.doc.treeViewHideTitle ? 'no-indent' : ''}
@@ -629,7 +630,7 @@ export class TreeView extends React.Component<TreeViewProps> {
             );
         } else if (this.treeViewExpandedView === 'fields') {
             return (
-                <ul key={this.doc[Id] + this.doc.title}>
+                <ul key={this.doc[Id] + this.doc.title} style={{ cursor: 'inherit' }}>
                     <div>{this.expandedField}</div>
                 </ul>
             );
@@ -903,7 +904,8 @@ export class TreeView extends React.Component<TreeViewProps> {
                 hideDecorationTitle={this.props.treeView.outlineMode}
                 hideResizeHandles={this.props.treeView.outlineMode}
                 styleProvider={this.titleStyleProvider}
-                onClickScriptDisable="never"
+                enableDragWhenActive={true}
+                onClickScriptDisable="never" // tree docViews have a script to show fields, etc.
                 docViewPath={returnEmptyDoclist}
                 treeViewDoc={this.props.treeView.props.Document}
                 addDocument={undefined}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 8104ab1a7..aed3683d4 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -821,9 +821,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         if (InteractionUtils.IsType(e, InteractionUtils.PENTYPE)) return false;
         if (InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE)) {
             Doc.ActiveTool = InkTool.None;
-            if (this.props.isContentActive(true)) e.stopPropagation();
         } else {
-            this.props.DocumentView?.().docView?.cancelMoveEvents();
             if (this.tryDragCluster(e, this._hitCluster)) {
                 return true;
             }
@@ -955,96 +953,6 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         return tVals;
     };
 
-    handle1PointerMove = (e: TouchEvent, me: InteractionUtils.MultiTouchEvent<TouchEvent>) => {
-        if (!e.cancelBubble) {
-            const myTouches = InteractionUtils.GetMyTargetTouches(me, this.prevPoints, true);
-            if (myTouches[0]) {
-                if (Doc.ActiveTool === InkTool.None) {
-                    if (this.tryDragCluster(e, this._hitCluster)) {
-                        e.stopPropagation(); // doesn't actually stop propagation since all our listeners are listening to events on 'document'  however it does mark the event as cancelBubble=true which we test for in the move event handlers
-                        e.preventDefault();
-                        document.removeEventListener('pointermove', this.onPointerMove);
-                        return;
-                    }
-                    // TODO: nda - this allows us to pan collections with finger -> only want to do this when collection is selected'
-                    this.pan(myTouches[0]);
-                }
-            }
-            // e.stopPropagation();
-            e.preventDefault();
-        }
-    };
-
-    handle2PointersMove = (e: TouchEvent, me: InteractionUtils.MultiTouchEvent<TouchEvent>) => {
-        // pinch zooming
-        if (!e.cancelBubble) {
-            const myTouches = InteractionUtils.GetMyTargetTouches(me, this.prevPoints, true);
-            const pt1 = myTouches[0];
-            const pt2 = myTouches[1];
-
-            if (this.prevPoints.size === 2) {
-                const oldPoint1 = this.prevPoints.get(pt1.identifier);
-                const oldPoint2 = this.prevPoints.get(pt2.identifier);
-                if (oldPoint1 && oldPoint2) {
-                    const dir = InteractionUtils.Pinching(pt1, pt2, oldPoint1, oldPoint2);
-
-                    // if zooming, zoom
-                    if (dir !== 0) {
-                        const d1 = Math.sqrt(Math.pow(pt1.clientX - oldPoint1.clientX, 2) + Math.pow(pt1.clientY - oldPoint1.clientY, 2));
-                        const d2 = Math.sqrt(Math.pow(pt2.clientX - oldPoint2.clientX, 2) + Math.pow(pt2.clientY - oldPoint2.clientY, 2));
-                        const centerX = Math.min(pt1.clientX, pt2.clientX) + Math.abs(pt2.clientX - pt1.clientX) / 2;
-                        const centerY = Math.min(pt1.clientY, pt2.clientY) + Math.abs(pt2.clientY - pt1.clientY) / 2;
-
-                        // calculate the raw delta value
-                        const rawDelta = dir * (d1 + d2);
-
-                        // this floors and ceils the delta value to prevent jitteriness
-                        const delta = Math.sign(rawDelta) * Math.min(Math.abs(rawDelta), 8);
-                        this.zoom(centerX, centerY, delta * window.devicePixelRatio);
-                        this.prevPoints.set(pt1.identifier, pt1);
-                        this.prevPoints.set(pt2.identifier, pt2);
-                    }
-                    // this is not zooming. derive some form of panning from it.
-                    else {
-                        // use the centerx and centery as the "new mouse position"
-                        const centerX = Math.min(pt1.clientX, pt2.clientX) + Math.abs(pt2.clientX - pt1.clientX) / 2;
-                        const centerY = Math.min(pt1.clientY, pt2.clientY) + Math.abs(pt2.clientY - pt1.clientY) / 2;
-                        // const transformed = this.getTransform().inverse().transformPoint(centerX, centerY);
-
-                        this._lastX = centerX;
-                        this._lastY = centerY;
-                    }
-                }
-            }
-            // e.stopPropagation();
-            e.preventDefault();
-        }
-    };
-
-    @action
-    handle2PointersDown = (e: React.TouchEvent, me: InteractionUtils.MultiTouchEvent<React.TouchEvent>) => {
-        if (this.props.isContentActive(true)) {
-            // const pt1: React.Touch | null = e.targetTouches.item(0);
-            // const pt2: React.Touch | null = e.targetTouches.item(1);
-            // // if (!pt1 || !pt2) return;
-            const myTouches = InteractionUtils.GetMyTargetTouches(me, this.prevPoints, true);
-            const pt1 = myTouches[0];
-            const pt2 = myTouches[1];
-            if (pt1 && pt2) {
-                const centerX = Math.min(pt1.clientX, pt2.clientX) + Math.abs(pt2.clientX - pt1.clientX) / 2;
-                const centerY = Math.min(pt1.clientY, pt2.clientY) + Math.abs(pt2.clientY - pt1.clientY) / 2;
-                this._lastX = centerX;
-                this._lastY = centerY;
-
-                this.removeMoveListeners();
-                this.addMoveListeners();
-                this.removeEndListeners();
-                this.addEndListeners();
-                e.stopPropagation();
-            }
-        }
-    };
-
     cleanUpInteractions = () => {
         this.removeMoveListeners();
         this.removeEndListeners();
@@ -1637,7 +1545,11 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
             } else {
                 const canvas = oldDiv;
                 const img = document.createElement('img'); // create a Image Element
-                img.src = canvas.toDataURL(); //image source
+                try {
+                    img.src = canvas.toDataURL(); //image source
+                } catch (e) {
+                    console.log(e);
+                }
                 img.style.width = canvas.style.width;
                 img.style.height = canvas.style.height;
                 const newCan = newDiv as HTMLCanvasElement;
@@ -2265,6 +2177,8 @@ export function CollectionBrowseClick(dv: DocumentView, clientX: number, clientY
         const ffview = selfFfview && selfFfview.rootDoc[selfFfview.props.scaleField || '_viewScale'] !== 0.5 ? selfFfview : parFfview; // if focus doc is a freeform that is not at it's default 0.5 scale, then zoom out on it.  Otherwise, zoom out on the parent ffview
         ffview?.zoomSmoothlyAboutPt(ffview.getTransform().transformPoint(clientX, clientY), 0.5, browseTransitionTime);
         Doc.linkFollowHighlight(dv?.props.Document, false);
+    } else {
+        DocumentManager.Instance.showDocument(dv.rootDoc, { zoomScale: 0.8, willZoomCentered: true });
     }
 }
 ScriptingGlobals.add(CollectionBrowseClick);
diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.scss b/src/client/views/collections/collectionLinear/CollectionLinearView.scss
index 521bcda1e..3e3709827 100644
--- a/src/client/views/collections/collectionLinear/CollectionLinearView.scss
+++ b/src/client/views/collections/collectionLinear/CollectionLinearView.scss
@@ -1,9 +1,13 @@
 @import '../../global/globalCssVariables';
 @import '../../_nodeModuleOverrides';
 
+.collectionLinearView {
+    width: 100%;
+}
 .collectionLinearView-label {
     color: black;
     background-color: $light-gray;
+    width: 100%;
 }
 .collectionLinearView-outer {
     overflow: visible;
@@ -15,8 +19,6 @@
     }
 
     &.true {
-        padding-left: 5px;
-        padding-right: 5px;
         border-left: $standard-border;
         background-color: $medium-blue-alt;
     }
@@ -29,7 +31,6 @@
         display: flex;
         height: 100%;
         align-items: center;
-        gap: 5px;
 
         .collectionView {
             overflow: visible !important;
@@ -101,13 +102,12 @@
             background-color: $medium-blue;
             padding: 5;
             border-radius: 2px;
-            height: 25;
+            height: 100%;
             min-width: 25;
             margin: 0;
             color: $white;
             display: flex;
             font-weight: 100;
-            width: fit-content;
             transition: transform 0.2s;
             align-items: center;
             justify-content: center;
diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
index d54e8ce98..a062c65fc 100644
--- a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
+++ b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
@@ -1,5 +1,5 @@
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { StylesProvider, Tooltip } from '@material-ui/core';
+import { Tooltip } from '@material-ui/core';
 import { action, IReactionDisposer, observable, reaction, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
@@ -11,8 +11,6 @@ import { CollectionViewType } from '../../../documents/DocumentTypes';
 import { DocumentManager } from '../../../util/DocumentManager';
 import { DragManager, dropActionType } from '../../../util/DragManager';
 import { Transform } from '../../../util/Transform';
-import { Colors, Shadows } from '../../global/globalEnums';
-import { media_state } from '../../nodes/AudioBox';
 import { DocumentLinksButton } from '../../nodes/DocumentLinksButton';
 import { DocumentView } from '../../nodes/DocumentView';
 import { LinkDescriptionPopup } from '../../nodes/LinkDescriptionPopup';
@@ -46,7 +44,7 @@ export class CollectionLinearView extends CollectionSubView() {
 
     componentDidMount() {
         this._widthDisposer = reaction(
-            () => 5 + (this.layoutDoc.linearViewIsExpanded ? this.childDocs.length * this.rootDoc[HeightSym]() : 10),
+            () => 5 + this.dimension() + (this.layoutDoc.linearViewIsExpanded ? this.childDocs.filter(doc => !doc.hidden).reduce((tot, doc) => (doc[WidthSym]() || this.dimension()) + tot + 4, 0) : 0),
             width => this.childDocs.length && (this.layoutDoc._width = width),
             { fireImmediately: true }
         );
@@ -180,10 +178,10 @@ export class CollectionLinearView extends CollectionSubView() {
                 ref={r => (dref = r || undefined)}
                 style={{
                     pointerEvents: 'all',
-                    width: nested ? undefined : NumCast(doc._width),
-                    height: nested ? undefined : NumCast(doc._height),
-                    marginLeft: !nested ? 2.5 : 0,
-                    marginRight: !nested ? 2.5 : 0,
+                    width: NumCast(doc._width),
+                    height: NumCast(doc._height),
+                    marginLeft: 2,
+                    marginRight: 2,
                     // width: NumCast(pair.layout._width),
                     // height: NumCast(pair.layout._height),
                 }}>
@@ -199,7 +197,7 @@ export class CollectionLinearView extends CollectionSubView() {
                     rootSelected={this.props.isSelected}
                     removeDocument={this.props.removeDocument}
                     ScreenToLocalTransform={docXf}
-                    PanelWidth={nested ? doc[WidthSym] : this.dimension}
+                    PanelWidth={doc[WidthSym]}
                     PanelHeight={nested || doc._height ? doc[HeightSym] : this.dimension}
                     renderDepth={this.props.renderDepth + 1}
                     dontRegisterView={BoolCast(this.rootDoc.childDontRegisterViews)}
@@ -236,7 +234,7 @@ export class CollectionLinearView extends CollectionSubView() {
 
         return (
             <div className={`collectionLinearView-outer ${this.layoutDoc.linearViewSubMenu}`} style={{ backgroundColor: this.layoutDoc.linearViewIsExpanded ? undefined : 'transparent' }}>
-                <div className="collectionLinearView" ref={this.createDashEventsTarget} onContextMenu={this.myContextMenu}>
+                <div className="collectionLinearView" ref={this.createDashEventsTarget} onContextMenu={this.myContextMenu} style={{ minHeight: this.dimension() }}>
                     {!this.props.Document.linearViewExpandable ? null : (
                         <Tooltip title={<div className="dash-tooltip">{isExpanded ? 'Close' : 'Open'}</div>} placement="top">
                             {menuOpener}
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
index 34e591195..1ef2fb4ef 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
@@ -8,7 +8,8 @@
 
     .schema-table {
         background-color: $white;
-        cursor: default;
+        cursor: grab;
+        overflow: scroll;
 
         .schema-column-menu,
         .schema-filter-menu {
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 60202a19e..d47c9762c 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -9,7 +9,7 @@ import { RichTextField } from '../../../../fields/RichTextField';
 import { listSpec } from '../../../../fields/Schema';
 import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../../fields/Types';
 import { ImageField } from '../../../../fields/URLField';
-import { emptyFunction, returnEmptyDoclist, returnEmptyString, returnFalse, returnTrue, setupMoveUpEvents, smoothScroll } from '../../../../Utils';
+import { emptyFunction, returnDefault, returnEmptyDoclist, returnEmptyString, returnFalse, returnNever, returnTrue, setupMoveUpEvents, smoothScroll } from '../../../../Utils';
 import { Docs, DocUtils } from '../../../documents/Documents';
 import { DocumentManager } from '../../../util/DocumentManager';
 import { DragManager } from '../../../util/DragManager';
@@ -46,7 +46,7 @@ export class CollectionSchemaView extends CollectionSubView() {
 
     public static _rowHeight: number = 40;
     public static _minColWidth: number = 25;
-    public static _rowMenuWidth: number = 100;
+    public static _rowMenuWidth: number = 60;
     public static _previewDividerWidth: number = 4;
 
     @computed get _selectedDocs() {
@@ -364,7 +364,11 @@ export class CollectionSchemaView extends CollectionSubView() {
             this.dataDoc[this.fieldKey ?? 'data'] = new List<Doc>([...removed, ...draggedDocs, ...pushedDocs]);
             this.setSort(undefined);
             SelectionManager.DeselectAll();
-            setTimeout(() => draggedDocs.forEach(doc => DocumentManager.Instance.AddViewRenderedCb(doc, dv => dv.select(true))), 100);
+            draggedDocs.forEach(doc => {
+                const draggedView = DocumentManager.Instance.getFirstDocumentView(doc);
+                if (draggedView) DocumentManager.Instance.RemoveView(draggedView);
+                DocumentManager.Instance.AddViewRenderedCb(doc, dv => dv.select(true));
+            });
             e.stopPropagation();
             return true;
         }
@@ -812,26 +816,17 @@ export class CollectionSchemaView extends CollectionSubView() {
     previewWidthFunc = () => this.previewWidth;
     render() {
         return (
-            <div
-                className="collectionSchemaView"
-                ref={(ele: HTMLDivElement | null) => {
-                    this.createDashEventsTarget(ele);
-                }}
-                onPointerDown={e => {
-                    // this is analogous to the panning code for a freeform view.
-                    // however, schema views don't pan so it does nothing.  but it does eat the pointerDown event
-                    // if the content is active to prevent the schema from being dragged
-                    this.isContentActive() && setupMoveUpEvents(this, e, returnFalse, emptyFunction, emptyFunction, false);
-                }}
-                onDrop={this.onExternalDrop.bind(this)}>
-                <div className="schema-table">
+            <div className="collectionSchemaView" ref={(ele: HTMLDivElement | null) => this.createDashEventsTarget(ele)} onDrop={this.onExternalDrop.bind(this)}>
+                <div
+                    className="schema-table"
+                    onWheel={e => this.props.isContentActive() && e.stopPropagation()}
+                    ref={r => {
+                        // prevent wheel events from passively propagating up through containers
+                        r?.addEventListener('wheel', (e: WheelEvent) => {}, { passive: false });
+                    }}>
                     <div className="schema-header-row" style={{ height: CollectionSchemaView._rowHeight }}>
                         <div className="row-menu" style={{ width: CollectionSchemaView._rowMenuWidth }}>
-                            <div
-                                className="schema-header-button"
-                                onPointerDown={e => {
-                                    this._columnMenuIndex && this._columnMenuIndex === -1 ? this.closeColumnMenu() : this.openColumnMenu(-1, true);
-                                }}>
+                            <div className="schema-header-button" onPointerDown={e => (this._columnMenuIndex === -1 ? this.closeColumnMenu() : this.openColumnMenu(-1, true))}>
                                 <FontAwesomeIcon icon="plus" />
                             </div>
                         </div>
@@ -867,8 +862,9 @@ export class CollectionSchemaView extends CollectionSubView() {
                                 DataDoc={undefined}
                                 fitContentsToBox={returnTrue}
                                 dontCenter={'y'}
+                                onClickScriptDisable="always"
                                 focus={DocUtils.DefaultFocus}
-                                renderDepth={this.props.renderDepth}
+                                renderDepth={this.props.renderDepth + 1}
                                 rootSelected={this.rootSelected}
                                 PanelWidth={this.previewWidthFunc}
                                 PanelHeight={this.props.PanelHeight}
@@ -915,16 +911,22 @@ class CollectionSchemaViewDocs extends React.Component<CollectionSchemaViewDocsP
                     return (
                         <div className="schema-row-wrapper" style={{ maxHeight: CollectionSchemaView._rowHeight }}>
                             <DocumentView
+                                key={doc[Id]}
                                 {...this.props.schema.props}
                                 LayoutTemplate={this.props.schema.props.childLayoutTemplate}
                                 LayoutTemplateString={SchemaRowBox.LayoutString(this.props.schema.props.fieldKey)}
                                 Document={doc}
                                 DataDoc={dataDoc}
+                                renderDepth={this.props.schema.props.renderDepth + 1}
                                 ContainingCollectionView={this.props.schema.props.CollectionView}
                                 ContainingCollectionDoc={this.props.schema.Document}
                                 PanelWidth={this.tableWidthFunc}
                                 PanelHeight={this.rowHeightFunc}
                                 styleProvider={DefaultStyleProvider}
+                                waitForDoubleClickToClick={returnNever}
+                                defaultDoubleClick={returnDefault}
+                                enableDragWhenActive={true}
+                                onClickScriptDisable="always"
                                 focus={this.props.schema.focusDocument}
                                 docFilters={this.props.schema.childDocFilters}
                                 docRangeFilters={this.props.schema.childDocRangeFilters}
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 10f307068..2defaae00 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -88,11 +88,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
         return (
             <div
                 className="schema-row"
-                style={
-                    this.props.isSelected()
-                        ? { height: CollectionSchemaView._rowHeight, backgroundColor: Colors.LIGHT_BLUE, pointerEvents: this.schemaView?.props.isContentActive() ? 'all' : undefined /*, opacity: this.props.dragging ? 0.5 : 1 */ }
-                        : { height: CollectionSchemaView._rowHeight, pointerEvents: this.schemaView?.props.isContentActive() ? 'all' : undefined }
-                }
+                style={{ height: CollectionSchemaView._rowHeight, backgroundColor: this.props.isSelected() ? Colors.LIGHT_BLUE : undefined, pointerEvents: this.schemaView?.props.isContentActive() ? 'all' : undefined }}
                 onPointerEnter={this.onPointerEnter}
                 onPointerLeave={this.onPointerLeave}
                 ref={(row: HTMLDivElement | null) => {
@@ -103,7 +99,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
                     className="row-menu"
                     style={{
                         width: CollectionSchemaView._rowMenuWidth,
-                        pointerEvents: !this.isContentActive() ? 'none' : undefined,
+                        pointerEvents: !this.props.isContentActive() ? 'none' : undefined,
                     }}>
                     <div
                         className="schema-row-button"
diff --git a/src/client/views/global/globalCssVariables.scss b/src/client/views/global/globalCssVariables.scss
index 430a36dce..3496bb835 100644
--- a/src/client/views/global/globalCssVariables.scss
+++ b/src/client/views/global/globalCssVariables.scss
@@ -59,7 +59,6 @@ $standard-border-radius: 3px;
 // shadow
 $standard-box-shadow: 0px 3px 4px rgba(0, 0, 0, 0.3);
 
-$dashboardselector-height: 32px;
 $mainTextInput-zindex: 999; // then text input overlay so that it's context menu will appear over decorations, etc
 $docDecorations-zindex: 998; // then doc decorations appear over everything else
 $remoteCursors-zindex: 997; // ... not sure what level the remote cursors should go -- is this right?
@@ -79,7 +78,7 @@ $TREE_BULLET_WIDTH: 20px;
     MAX_ROW_HEIGHT: $MAX_ROW_HEIGHT;
     SEARCH_THUMBNAIL_SIZE: $search-thumnail-size;
     ANTIMODEMENU_HEIGHT: $antimodemenu-height;
-    DASHBOARD_SELECTOR_HEIGHT: $dashboardselector-height;
+    TOPBAR_HEIGHT: $topbar-height;
     DFLT_IMAGE_NATIVE_DIM: $DFLT_IMAGE_NATIVE_DIM;
     LEFT_MENU_WIDTH: $LEFT_MENU_WIDTH;
     TREE_BULLET_WIDTH: $TREE_BULLET_WIDTH;
diff --git a/src/client/views/global/globalCssVariables.scss.d.ts b/src/client/views/global/globalCssVariables.scss.d.ts
index 3375579d6..537ea1e5d 100644
--- a/src/client/views/global/globalCssVariables.scss.d.ts
+++ b/src/client/views/global/globalCssVariables.scss.d.ts
@@ -6,7 +6,7 @@ interface IGlobalScss {
     MAX_ROW_HEIGHT: string;
     SEARCH_THUMBNAIL_SIZE: string;
     ANTIMODEMENU_HEIGHT: string;
-    DASHBOARD_SELECTOR_HEIGHT: string;
+    TOPBAR_HEIGHT: string;
     DFLT_IMAGE_NATIVE_DIM: string;
     LEFT_MENU_WIDTH: string;
     TREE_BULLET_WIDTH: string;
diff --git a/src/client/views/nodes/ColorBox.tsx b/src/client/views/nodes/ColorBox.tsx
index c229a966a..70ba7e182 100644
--- a/src/client/views/nodes/ColorBox.tsx
+++ b/src/client/views/nodes/ColorBox.tsx
@@ -51,7 +51,7 @@ export class ColorBox extends ViewBoxBaseComponent<FieldViewProps>() {
         const scaling = Math.min(this.layoutDoc.fitWidth ? 10000 : this.props.PanelHeight() / this.rootDoc[HeightSym](), this.props.PanelWidth() / this.rootDoc[WidthSym]());
         return (
             <div
-                className={`colorBox-container${this.isContentActive() ? '-interactive' : ''}`}
+                className={`colorBox-container${this.props.isContentActive() ? '-interactive' : ''}`}
                 onPointerDown={e => e.button === 0 && !e.ctrlKey && e.stopPropagation()}
                 onClick={e => e.stopPropagation()}
                 style={{ transform: `scale(${scaling})`, width: `${100 * scaling}%`, height: `${100 * scaling}%` }}>
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 541dddd83..9a3e77e6e 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -5,7 +5,6 @@ import { action, computed, IReactionDisposer, observable, reaction, runInAction
 import { observer } from 'mobx-react';
 import { Bounce, Fade, Flip, LightSpeed, Roll, Rotate, Zoom } from 'react-reveal';
 import { AclAdmin, AclEdit, AclPrivate, AnimationSym, DataSym, Doc, DocListCast, Field, Opt, StrListCast, WidthSym } from '../../../fields/Doc';
-import { Document } from '../../../fields/documentSchemas';
 import { Id } from '../../../fields/FieldSymbols';
 import { InkTool } from '../../../fields/InkField';
 import { List } from '../../../fields/List';
@@ -15,7 +14,7 @@ import { BoolCast, Cast, DocCast, ImageCast, NumCast, ScriptCast, StrCast } from
 import { AudioField } from '../../../fields/URLField';
 import { GetEffectiveAcl, SharingPermissions, TraceMobx } from '../../../fields/util';
 import { MobileInterface } from '../../../mobile/MobileInterface';
-import { emptyFunction, isTargetChildOf as isParentOf, lightOrDark, OmitKeys, returnEmptyString, returnFalse, returnNone, returnTrue, returnVal, simulateMouseClick, Utils } from '../../../Utils';
+import { emptyFunction, isTargetChildOf as isParentOf, lightOrDark, OmitKeys, returnEmptyString, returnFalse, returnTrue, returnVal, simulateMouseClick, Utils } from '../../../Utils';
 import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils';
 import { DocServer } from '../../DocServer';
 import { Docs, DocUtils } from '../../documents/Documents';
@@ -50,11 +49,9 @@ import { FieldViewProps } from './FieldView';
 import { FormattedTextBox } from './formattedText/FormattedTextBox';
 import { LinkAnchorBox } from './LinkAnchorBox';
 import { RadialMenu } from './RadialMenu';
-import { ScriptingBox } from './ScriptingBox';
 import { PresEffect, PresEffectDirection } from './trails';
 import { PinProps, PresBox } from './trails/PresBox';
 import React = require('react');
-import { KeyValueBox } from './KeyValueBox';
 const { Howl } = require('howler');
 
 interface Window {
@@ -135,6 +132,7 @@ export interface DocComponentView {
     componentUI?: (boundsLeft: number, boundsTop: number) => JSX.Element | null;
     incrementalRendering?: () => void;
     fitWidth?: () => boolean; // whether the component always fits width (eg, KeyValueBox)
+    overridePointerEvents?: () => 'all' | 'none' | undefined; // if the conmponent overrides the pointer events for the document
     fieldKey?: string;
     annotationKey?: string;
     getTitle?: () => string;
@@ -195,6 +193,9 @@ export interface DocumentViewSharedProps {
     forceAutoHeight?: boolean;
     disableDocBrushing?: boolean; // should highlighting for this view be disabled when same document in another view is hovered over.
     onClickScriptDisable?: 'never' | 'always'; // undefined = only when selected
+    enableDragWhenActive?: boolean;
+    waitForDoubleClickToClick?: () => 'never' | 'always' | undefined;
+    defaultDoubleClick?: () => 'default' | 'ignore' | undefined;
     pointerEvents?: () => Opt<string>;
     scriptContext?: any; // can be assigned anything and will be passed as 'scriptContext' to any OnClick script that executes on this document
     createNewFilterDoc?: () => void;
@@ -255,8 +256,6 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
     private _downX: number = 0;
     private _downY: number = 0;
     private _downTime: number = 0;
-    private _firstX: number = -1;
-    private _firstY: number = -1;
     private _lastTap: number = 0;
     private _doubleTap = false;
     private _mainCont = React.createRef<HTMLDivElement>();
@@ -333,11 +332,12 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
         return this.props.NativeHeight();
     }
     @computed get disableClickScriptFunc() {
+        const onScriptDisable = this.props.onClickScriptDisable ?? this._componentView?.onClickScriptDisable?.() ?? this.layoutDoc.onClickScriptDisable;
+        // prettier-ignore
         return (
             DocumentView.LongPress ||
-            this.props.onClickScriptDisable === 'always' ||
-            this._componentView?.onClickScriptDisable?.() ||
-            (this.props.onClickScriptDisable !== 'never' && (this.rootSelected() || this.props.isSelected())) ||
+            onScriptDisable === 'always' ||
+            (onScriptDisable !== 'never' && (this.rootSelected() || this.props.isSelected())) ||
             this._componentView?.isAnyChildContentActive?.()
         );
     }
@@ -360,7 +360,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
     componentDidMount() {
         this.setupHandlers();
     }
-    //componentDidUpdate() { this.setupHandlers(); }
+
     setupHandlers() {
         this.cleanupHandlers(false);
         if (this._mainCont.current) {
@@ -378,151 +378,6 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
         Object.values(this._disposers).forEach(disposer => disposer?.());
     }
 
-    handle1PointerHoldStart = (e: Event, me: InteractionUtils.MultiTouchEvent<React.TouchEvent>): any => {
-        this.removeMoveListeners();
-        this.removeEndListeners();
-        document.removeEventListener('pointermove', this.onPointerMove);
-        document.removeEventListener('pointerup', this.onPointerUp);
-        if (RadialMenu.Instance._display === false) {
-            this.addHoldMoveListeners();
-            this.addHoldEndListeners();
-            this.onRadialMenu(e, me);
-            const pt = me.touchEvent.touches[me.touchEvent.touches.length - 1];
-            this._firstX = pt.pageX;
-            this._firstY = pt.pageY;
-        }
-    };
-
-    handle1PointerHoldMove = (e: Event, me: InteractionUtils.MultiTouchEvent<TouchEvent>): void => {
-        const pt = me.touchEvent.touches[me.touchEvent.touches.length - 1];
-
-        if (this._firstX === -1 || this._firstY === -1) {
-            return;
-        }
-        if (Math.abs(pt.pageX - this._firstX) > 150 || Math.abs(pt.pageY - this._firstY) > 150) {
-            this.handle1PointerHoldEnd(e, me);
-        }
-    };
-
-    handle1PointerHoldEnd = (e: Event, me: InteractionUtils.MultiTouchEvent<TouchEvent>): void => {
-        this.removeHoldMoveListeners();
-        this.removeHoldEndListeners();
-        RadialMenu.Instance.closeMenu();
-        this._firstX = -1;
-        this._firstY = -1;
-        SelectionManager.DeselectAll();
-        me.touchEvent.stopPropagation();
-        me.touchEvent.preventDefault();
-        e.stopPropagation();
-        if (RadialMenu.Instance.used) {
-            this.onContextMenu(undefined, me.touches[0].pageX, me.touches[0].pageY);
-        }
-    };
-
-    handle2PointersDown = (e: React.TouchEvent, me: InteractionUtils.MultiTouchEvent<React.TouchEvent>) => {
-        if (!this.props.isSelected()) {
-            e.stopPropagation();
-            e.preventDefault();
-
-            this.removeMoveListeners();
-            this.addMoveListeners();
-            this.removeEndListeners();
-            this.addEndListeners();
-        }
-    };
-
-    handle1PointerDown = (e: React.TouchEvent, me: InteractionUtils.MultiTouchEvent<React.TouchEvent>) => {
-        SelectionManager.DeselectAll();
-        if (this.Document.onPointerDown) return;
-        const touch = me.touchEvent.changedTouches.item(0);
-        if (touch) {
-            this._downX = touch.clientX;
-            this._downY = touch.clientY;
-            if ((this.props.isDocumentActive?.() || this.layoutDoc.onDragStart || this.onClickHandler) && !e.ctrlKey && !this.layoutDoc._lockedPosition && !DocListCast(Doc.MyOverlayDocs?.data).includes(this.layoutDoc)) {
-                e.stopPropagation();
-            }
-            this.removeMoveListeners();
-            this.addMoveListeners();
-            this.removeEndListeners();
-            this.addEndListeners();
-            e.stopPropagation();
-        }
-    };
-
-    handle1PointerMove = (e: TouchEvent, me: InteractionUtils.MultiTouchEvent<TouchEvent>) => {
-        if (e.cancelBubble && this.props.isDocumentActive?.()) {
-            this.removeMoveListeners();
-        } else if (!e.cancelBubble && (this.props.isDocumentActive?.() || this.layoutDoc.onDragStart || this.onClickHandler) && !this.layoutDoc._lockedPosition && !DocListCast(Doc.MyOverlayDocs?.data).includes(this.layoutDoc)) {
-            const touch = me.touchEvent.changedTouches.item(0);
-            if (touch && (Math.abs(this._downX - touch.clientX) > 3 || Math.abs(this._downY - touch.clientY) > 3)) {
-                if (!this.topMost || this.layoutDoc.onDragStart || this.onClickHandler) {
-                    this.cleanUpInteractions();
-                    this.startDragging(this._downX, this._downY, this.Document.dropAction ? (this.Document.dropAction as any) : e.ctrlKey || e.altKey ? 'alias' : undefined);
-                }
-            }
-            e.stopPropagation(); // doesn't actually stop propagation since all our listeners are listening to events on 'document'  however it does mark the event as cancelBubble=true which we test for in the move event handlers
-            e.preventDefault();
-        }
-    };
-
-    @action
-    handle2PointersMove = (e: TouchEvent, me: InteractionUtils.MultiTouchEvent<TouchEvent>) => {
-        const myTouches = InteractionUtils.GetMyTargetTouches(me, this.prevPoints, true);
-        const pt1 = myTouches[0];
-        const pt2 = myTouches[1];
-        const oldPoint1 = this.prevPoints.get(pt1.identifier);
-        const oldPoint2 = this.prevPoints.get(pt2.identifier);
-        const pinching = InteractionUtils.Pinning(pt1, pt2, oldPoint1!, oldPoint2!);
-        if (pinching !== 0 && oldPoint1 && oldPoint2) {
-            const dW = Math.abs(pt1.clientX - pt2.clientX) - Math.abs(oldPoint1.clientX - oldPoint2.clientX);
-            const dH = Math.abs(pt1.clientY - pt2.clientY) - Math.abs(oldPoint1.clientY - oldPoint2.clientY);
-            const dX = -1 * Math.sign(dW);
-            const dY = -1 * Math.sign(dH);
-
-            if (dX !== 0 || dY !== 0 || dW !== 0 || dH !== 0) {
-                const doc = Document(this.props.Document);
-                const layoutDoc = Document(Doc.Layout(this.props.Document));
-                let nwidth = Doc.NativeWidth(layoutDoc);
-                let nheight = Doc.NativeHeight(layoutDoc);
-                const width = layoutDoc._width || 0;
-                const height = layoutDoc._height || (nheight / nwidth) * width;
-                const scale = this.props.ScreenToLocalTransform().Scale * this.NativeDimScaling;
-                const actualdW = Math.max(width + dW * scale, 20);
-                const actualdH = Math.max(height + dH * scale, 20);
-                doc.x = (doc.x || 0) + dX * (actualdW - width);
-                doc.y = (doc.y || 0) + dY * (actualdH - height);
-                const fixedAspect = e.ctrlKey || (nwidth && nheight);
-                if (fixedAspect && (!nwidth || !nheight)) {
-                    Doc.SetNativeWidth(layoutDoc, (nwidth = layoutDoc._width || 0));
-                    Doc.SetNativeHeight(layoutDoc, (nheight = layoutDoc._height || 0));
-                }
-                if (nwidth > 0 && nheight > 0) {
-                    if (Math.abs(dW) > Math.abs(dH)) {
-                        if (!fixedAspect) {
-                            Doc.SetNativeWidth(layoutDoc, (actualdW / (layoutDoc._width || 1)) * Doc.NativeWidth(layoutDoc));
-                        }
-                        layoutDoc._width = actualdW;
-                        if (fixedAspect && !this.props.DocumentView().fitWidth) layoutDoc._height = (nheight / nwidth) * layoutDoc._width;
-                        else layoutDoc._height = actualdH;
-                    } else {
-                        if (!fixedAspect) {
-                            Doc.SetNativeHeight(layoutDoc, (actualdH / (layoutDoc._height || 1)) * Doc.NativeHeight(doc));
-                        }
-                        layoutDoc._height = actualdH;
-                        if (fixedAspect && !this.props.DocumentView().fitWidth) layoutDoc._width = (nwidth / nheight) * layoutDoc._height;
-                        else layoutDoc._width = actualdW;
-                    }
-                } else {
-                    dW && (layoutDoc._width = actualdW);
-                    dH && (layoutDoc._height = actualdH);
-                    dH && layoutDoc._autoHeight && (layoutDoc._autoHeight = false);
-                }
-            }
-            e.stopPropagation();
-            e.preventDefault();
-        }
-    };
-
     @action
     onRadialMenu = (e: Event, me: InteractionUtils.MultiTouchEvent<React.TouchEvent>): void => {
         const pt = me.touchEvent.touches[me.touchEvent.touches.length - 1];
@@ -591,11 +446,12 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
     };
 
     onClick = action((e: React.MouseEvent | React.PointerEvent) => {
-        if (!this.Document.ignoreClick && this.props.renderDepth >= 0 && Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD && Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD) {
+        if (!this.Document.ignoreClick && this.pointerEvents !== 'none' && this.props.renderDepth >= 0 && Utils.isClick(e.clientX, e.clientY, this._downX, this._downY, this._downTime)) {
             let stopPropagate = true;
             let preventDefault = true;
             (this.rootDoc._raiseWhenDragged === undefined ? DragManager.GetRaiseWhenDragged() : this.rootDoc._raiseWhenDragged) && this.props.bringToFront(this.rootDoc);
             if (this._doubleTap) {
+                const defaultDblclick = this.props.defaultDoubleClick?.() || this.Document.defaultDoubleClick;
                 if (this.onDoubleClickHandler?.script) {
                     const { clientX, clientY, shiftKey, altKey, ctrlKey } = e; // or we could call e.persist() to capture variables
                     // prettier-ignore
@@ -609,7 +465,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                             value: undefined,
                         }, console.log  );
                     UndoManager.RunInBatch(() => (func().result?.select === true ? this.props.select(false) : ''), 'on double click');
-                } else if (!Doc.IsSystem(this.rootDoc) && (this.Document.defaultDoubleClick === undefined || this.Document.defaultDoubleClick === 'default')) {
+                } else if (!Doc.IsSystem(this.rootDoc) && (defaultDblclick === undefined || defaultDblclick === 'default')) {
                     UndoManager.RunInBatch(() => this.props.addDocTab(this.rootDoc, OpenWhere.lightbox), 'double tap');
                     SelectionManager.DeselectAll();
                     Doc.UnBrushDoc(this.props.Document);
@@ -649,15 +505,16 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                         LinkFollower.FollowLink(undefined, this.Document, e.altKey);
                     };
                 } else {
+                    // onDragStart implies a button doc that we don't want to select when clicking. RootDocument & isTemplateForField implies we're clicking on part of a template instance and we want to select the whole template, not the part
                     if ((this.layoutDoc.onDragStart || this.props.Document.rootDocument) && !(e.ctrlKey || e.button > 0)) {
-                        // onDragStart implies a button doc that we don't want to select when clicking. RootDocument & isTemplateForField implies we're clicking on part of a template instance and we want to select the whole template, not the part
                         stopPropagate = false; // don't stop propagation for field templates -- want the selection to propagate up to the root document of the template
                     }
                     preventDefault = false;
                 }
 
                 this._singleClickFunc = clickFunc ?? (() => (this._componentView?.select ?? this.props.select)(e.ctrlKey || e.metaKey, e.shiftKey));
-                if ((clickFunc && this.Document.waitForDoubleClickToClick !== 'never') || this.Document.waitForDoubleClickToClick === 'always') {
+                const waitFordblclick = this.props.waitForDoubleClickToClick?.() ?? this.Document.waitForDoubleClickToClick;
+                if ((clickFunc && waitFordblclick !== 'never') || waitFordblclick === 'always') {
                     this._doubleClickTimeout && clearTimeout(this._doubleClickTimeout);
                     this._doubleClickTimeout = setTimeout(this._singleClickFunc, 300);
                 } else {
@@ -673,55 +530,46 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
     @action
     onPointerDown = (e: React.PointerEvent): void => {
         this._longPressSelector = setTimeout(() => DocumentView.LongPress && this.props.select(false), 1000);
-        if (!(e.nativeEvent as any).DownDocView) (e.nativeEvent as any).DownDocView = GestureOverlay.DownDocView = this.props.DocumentView();
-        if (this.rootDoc.type === DocumentType.INK && Doc.ActiveTool === InkTool.Eraser) return;
-        // continue if the event hasn't been canceled AND we are using a mouse or this has an onClick or onDragStart function (meaning it is a button document)
-        if (!(InteractionUtils.IsType(e, InteractionUtils.MOUSETYPE) || [InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool))) {
-            if (!InteractionUtils.IsType(e, InteractionUtils.PENTYPE)) {
-                e.stopPropagation();
-                if (SelectionManager.IsSelected(this.props.DocumentView(), true) && this.props.Document._viewType !== CollectionViewType.Docking) e.preventDefault(); // goldenlayout needs to be able to move its tabs, so can't preventDefault for it
-                // TODO: check here for panning/inking
-            }
-            return;
-        }
+        if (!GestureOverlay.DownDocView) GestureOverlay.DownDocView = this.props.DocumentView();
+
         this._downX = e.clientX;
         this._downY = e.clientY;
         this._downTime = Date.now();
         if ((Doc.ActiveTool === InkTool.None || this.props.addDocTab === returnFalse) && !(this.props.Document.rootDocument && !(e.ctrlKey || e.button > 0))) {
-            // if this is part of a template, let the event go up to the tempalte root unless right/ctrl clicking
+            // click events stop here if the document is active and no modes are overriding it
+            // if this is part of a template, let the event go up to the template root unless right/ctrl clicking
             if (
-                (this.props.isDocumentActive?.() || this.layoutDoc.onDragStart) &&
+                // prettier-ignore
+                this.props.isDocumentActive?.() &&
                 !this.props.onBrowseClick?.() &&
                 !this.Document.ignoreClick &&
                 !e.ctrlKey &&
-                (e.button === 0 || InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE)) &&
+                e.button === 0 &&
+                this.pointerEvents !== 'none' &&
                 !DocListCast(Doc.MyOverlayDocs?.data).includes(this.layoutDoc)
             ) {
                 e.stopPropagation();
                 // don't preventDefault anymore.  Goldenlayout, PDF text selection and RTF text selection all need it to go though
                 //if (this.props.isSelected(true) && this.rootDoc.type !== DocumentType.PDF && this.layoutDoc._viewType !== CollectionViewType.Docking) e.preventDefault();
+
+                // listen to move events if document content isn't active or document is draggable
+                if (!this.layoutDoc._lockedPosition && (!this.isContentActive() || this.props.enableDragWhenActive || this.rootDoc.enableDragWhenActive)) {
+                    document.addEventListener('pointermove', this.onPointerMove);
+                }
             }
-            if (this.props.isDocumentActive?.()) {
-                document.removeEventListener('pointermove', this.onPointerMove);
-                document.addEventListener('pointermove', this.onPointerMove);
-            }
-            document.removeEventListener('pointerup', this.onPointerUp);
             document.addEventListener('pointerup', this.onPointerUp);
         }
     };
 
     @action
     onPointerMove = (e: PointerEvent): void => {
-        if (this.layoutDoc._lockedPosition || DocListCast(Doc.MyOverlayDocs?.data).includes(this.layoutDoc)) return;
         if (InteractionUtils.IsType(e, InteractionUtils.PENTYPE) || [InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) return;
 
-        if (((!this.topMost && this.props.isDocumentActive?.()) || this.layoutDoc.onDragStart) && (e.buttons === 1 || InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE))) {
+        if (e.buttons === 1 || InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE)) {
             if (Math.abs(this._downX - e.clientX) > 3 || Math.abs(this._downY - e.clientY) > 3) {
                 this.cleanupPointerEvents();
                 this.startDragging(this._downX, this._downY, ((e.ctrlKey || e.altKey) && 'alias') || ((this.Document.dropAction || this.props.dropAction || undefined) as dropActionType));
             }
-            e.stopPropagation(); // doesn't actually stop propagation since all our listeners are listening to events on 'document'  however it does mark the event as cancelBubble=true which we test for in the move event handlers
-            e.preventDefault();
         }
     };
 
@@ -738,13 +586,11 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
         this.cleanupPointerEvents();
         this._longPressSelector && clearTimeout(this._longPressSelector);
 
-        const now = Date.now();
         if (this.onPointerUpHandler?.script && !InteractionUtils.IsType(e, InteractionUtils.PENTYPE)) {
             this.onPointerUpHandler.script.run({ self: this.rootDoc, this: this.layoutDoc }, console.log);
-        } else if (now - this._downTime < 300) {
-            this._doubleTap = now - this._lastTap < 300 && e.button === 0 && Math.abs(e.clientX - this._downX) < 2 && Math.abs(e.clientY - this._downY) < 2;
-            // bcz: this is a placeholder.  documents, when selected, should stopPropagation on doubleClicks if they want to keep the DocumentView from getting them
-            if (!this.props.isSelected(true) || ![DocumentType.PDF, DocumentType.RTF].includes(StrCast(this.rootDoc.type) as any)) this._lastTap = Date.now(); // don't want to process the start of a double tap if the doucment is selected
+        } else if (e.button === 0 && Utils.isClick(e.clientX, e.clientY, this._downX, this._downY, this._downTime)) {
+            this._doubleTap = Date.now() - this._lastTap < Utils.CLICK_TIME;
+            if (!this.props.isSelected(true)) this._lastTap = Date.now(); // don't want to process the start of a double tap if the doucment is selected
         }
         if (DocumentView.LongPress) e.preventDefault();
     };
@@ -1386,11 +1232,11 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
             </div>
         );
     }
-    @observable _: string = '';
+
     renderDoc = (style: object) => {
         TraceMobx();
         const thumb = ImageCast(this.layoutDoc['thumb-frozen'], ImageCast(this.layoutDoc.thumb))?.url?.href.replace('.png', '_m.png');
-        const isButton = this.props.Document.type === DocumentType.FONTICON;
+        const background = this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BackgroundColor + ':box');
         if (!(this.props.Document instanceof Doc) || GetEffectiveAcl(this.props.Document[DataSym]) === AclPrivate || this.hidden) return null;
         return (
             this.docContents ?? (
@@ -1399,7 +1245,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                     id={this.props.Document[Id]}
                     style={{
                         ...style,
-                        background: isButton || thumb ? undefined : this.backgroundColor,
+                        background: thumb ? undefined : background,
                         opacity: this.opacity,
                         cursor: Doc.ActiveTool === InkTool.None ? 'grab' : 'crosshair',
                         color: StrCast(this.layoutDoc.color, 'inherit'),
@@ -1809,7 +1655,6 @@ export class DocumentView extends React.Component<DocumentViewProps> {
         TraceMobx();
         const xshift = Math.abs(this.Xshift) <= 0.001 ? this.props.PanelWidth() : undefined;
         const yshift = Math.abs(this.Yshift) <= 0.001 ? this.props.PanelHeight() : undefined;
-        const isButton = this.props.Document.type === DocumentType.FONTICON || this.props.Document._viewType === CollectionViewType.Linear;
 
         return this.hidden ? null : (
             <div
@@ -1831,12 +1676,11 @@ export class DocumentView extends React.Component<DocumentViewProps> {
                         ref={this.ContentRef}
                         style={{
                             transition: this.props.dataTransition,
-                            transform: isButton ? undefined : `translate(${this.centeringX}px, ${this.centeringY}px)`,
-                            width: isButton ? '100%' : xshift ?? `${(100 * (this.props.PanelWidth() - this.Xshift * 2)) / this.props.PanelWidth()}%`,
-                            height:
-                                isButton || this.props.LayoutTemplateString?.includes(KeyValueBox.name) || this.props.forceAutoHeight
-                                    ? undefined
-                                    : yshift ?? (this.fitWidth ? `${this.panelHeight}px` : `${(((100 * this.effectiveNativeHeight) / this.effectiveNativeWidth) * this.props.PanelWidth()) / this.props.PanelHeight()}%`),
+                            transform: `translate(${this.centeringX}px, ${this.centeringY}px)`,
+                            width: xshift ?? `${(100 * (this.props.PanelWidth() - this.Xshift * 2)) / this.props.PanelWidth()}%`,
+                            height: this.props.forceAutoHeight
+                                ? undefined
+                                : yshift ?? (this.fitWidth ? `${this.panelHeight}px` : `${(((100 * this.effectiveNativeHeight) / this.effectiveNativeWidth) * this.props.PanelWidth()) / this.props.PanelHeight()}%`),
                         }}>
                         <DocumentViewInternal
                             {...this.props}
diff --git a/src/client/views/nodes/FunctionPlotBox.tsx b/src/client/views/nodes/FunctionPlotBox.tsx
index 75b4907cd..b43e359ff 100644
--- a/src/client/views/nodes/FunctionPlotBox.tsx
+++ b/src/client/views/nodes/FunctionPlotBox.tsx
@@ -101,7 +101,7 @@ export class FunctionPlotBox extends ViewBoxAnnotatableComponent<FieldViewProps>
             <div
                 ref={this.createDropTarget}
                 style={{
-                    pointerEvents: !this.isContentActive() ? 'all' : undefined,
+                    pointerEvents: !this.props.isContentActive() ? 'all' : undefined,
                     width: this.props.PanelWidth(),
                     height: this.props.PanelHeight(),
                 }}>
diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx
index 9c31ed3e4..57018fb93 100644
--- a/src/client/views/nodes/KeyValueBox.tsx
+++ b/src/client/views/nodes/KeyValueBox.tsx
@@ -4,8 +4,9 @@ import { Doc, Field, FieldResult } from '../../../fields/Doc';
 import { List } from '../../../fields/List';
 import { RichTextField } from '../../../fields/RichTextField';
 import { ComputedField, ScriptField } from '../../../fields/ScriptField';
-import { BoolCast, DocCast, NumCast } from '../../../fields/Types';
+import { DocCast, NumCast } from '../../../fields/Types';
 import { ImageField } from '../../../fields/URLField';
+import { returnAll, returnAlways, returnTrue } from '../../../Utils';
 import { Docs } from '../../documents/Documents';
 import { SetupDrag } from '../../util/DragManager';
 import { CompiledScript, CompileScript, ScriptOptions } from '../../util/Scripting';
@@ -20,7 +21,6 @@ import './KeyValueBox.scss';
 import { KeyValuePair } from './KeyValuePair';
 import React = require('react');
 import e = require('express');
-import { returnTrue } from '../../../Utils';
 
 export type KVPScript = {
     script: CompiledScript;
@@ -42,8 +42,11 @@ export class KeyValueBox extends React.Component<FieldViewProps> {
     componentDidMount() {
         this.props.setContentView?.(this);
     }
-    onClickScriptDisable: () => 'always' = () => 'always';
+    reverseNativeScaling = returnTrue;
+    able = returnAlways;
     fitWidth = returnTrue;
+    overridePointerEvents = returnAll;
+    onClickScriptDisable = returnAlways;
 
     @observable private rows: KeyValuePair[] = [];
 
@@ -69,9 +72,9 @@ export class KeyValueBox extends React.Component<FieldViewProps> {
     };
     public static CompileKVPScript(value: string): KVPScript | undefined {
         const eq = value.startsWith('=');
-        value = eq ? value.substr(1) : value;
-        const dubEq = value.startsWith(':=') ? 'computed' : value.startsWith(';=') ? 'script' : false;
-        value = dubEq ? value.substr(2) : value;
+        value = eq ? value.substring(1) : value;
+        const dubEq = value.startsWith(':=') ? 'computed' : value.startsWith('$=') ? 'script' : false;
+        value = dubEq ? value.substring(2) : value;
         const options: ScriptOptions = { addReturn: true, typecheck: false, params: { this: Doc.name, self: Doc.name, _last_: 'any', _readOnly_: 'boolean' }, editable: false };
         if (dubEq) options.typecheck = false;
         const script = CompileScript(value, options);
diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx
index c4adc7f1a..94434dce7 100644
--- a/src/client/views/nodes/KeyValuePair.tsx
+++ b/src/client/views/nodes/KeyValuePair.tsx
@@ -1,19 +1,18 @@
 import { action, observable } from 'mobx';
 import { observer } from 'mobx-react';
-import { Doc, Field, Opt } from '../../../fields/Doc';
-import { emptyFunction, returnFalse, returnOne, returnZero, returnEmptyFilter, returnEmptyDoclist, emptyPath } from '../../../Utils';
-import { Docs } from '../../documents/Documents';
+import { Doc, Field } from '../../../fields/Doc';
+import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnZero } from '../../../Utils';
 import { Transform } from '../../util/Transform';
 import { undoBatch } from '../../util/UndoManager';
 import { ContextMenu } from '../ContextMenu';
 import { EditableView } from '../EditableView';
+import { DefaultStyleProvider } from '../StyleProvider';
+import { OpenWhere } from './DocumentView';
 import { FieldView, FieldViewProps } from './FieldView';
 import { KeyValueBox } from './KeyValueBox';
 import './KeyValueBox.scss';
 import './KeyValuePair.scss';
 import React = require('react');
-import { DefaultStyleProvider } from '../StyleProvider';
-import { OpenWhere } from './DocumentView';
 
 // Represents one row in a key value plane
 
diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx
index 470f7e803..46ccdecae 100644
--- a/src/client/views/nodes/LinkBox.tsx
+++ b/src/client/views/nodes/LinkBox.tsx
@@ -1,6 +1,6 @@
 import React = require('react');
 import { observer } from 'mobx-react';
-import { emptyFunction, returnFalse, returnTrue } from '../../../Utils';
+import { emptyFunction, returnAlways, returnFalse, returnTrue } from '../../../Utils';
 import { ViewBoxBaseComponent } from '../DocComponent';
 import { StyleProp } from '../StyleProvider';
 import { ComparisonBox } from './ComparisonBox';
@@ -12,23 +12,22 @@ export class LinkBox extends ViewBoxBaseComponent<FieldViewProps>() {
     public static LayoutString(fieldKey: string) {
         return FieldView.LayoutString(LinkBox, fieldKey);
     }
-    isContentActiveFunc = () => this.isContentActive();
 
-    onClickScriptDisable: () => 'always' = () => 'always';
+    onClickScriptDisable = returnAlways;
     componentDidMount() {
         this.props.setContentView?.(this);
     }
     render() {
         if (this.dataDoc.treeViewOpen === undefined) setTimeout(() => (this.dataDoc.treeViewOpen = true));
         return (
-            <div className={`linkBox-container${this.isContentActive() ? '-interactive' : ''}`} style={{ background: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BackgroundColor) }}>
+            <div className={`linkBox-container${this.props.isContentActive() ? '-interactive' : ''}`} style={{ background: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BackgroundColor) }}>
                 <ComparisonBox
                     {...this.props}
                     fieldKey="anchor"
                     setHeight={emptyFunction}
                     dontRegisterView={true}
                     renderDepth={this.props.renderDepth + 1}
-                    isContentActive={this.isContentActiveFunc}
+                    isContentActive={this.props.isContentActive}
                     addDocument={returnFalse}
                     removeDocument={returnFalse}
                     moveDocument={returnFalse}
diff --git a/src/client/views/nodes/ScriptingBox.tsx b/src/client/views/nodes/ScriptingBox.tsx
index 5683b0fe7..f09962b22 100644
--- a/src/client/views/nodes/ScriptingBox.tsx
+++ b/src/client/views/nodes/ScriptingBox.tsx
@@ -8,7 +8,7 @@ import { listSpec } from '../../../fields/Schema';
 import { ScriptField } from '../../../fields/ScriptField';
 import { BoolCast, Cast, DocCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
 import { TraceMobx } from '../../../fields/util';
-import { returnEmptyString, returnTrue } from '../../../Utils';
+import { returnAlways, returnEmptyString, returnTrue } from '../../../Utils';
 import { DragManager } from '../../util/DragManager';
 import { InteractionUtils } from '../../util/InteractionUtils';
 import { CompileScript, ScriptParam } from '../../util/Scripting';
@@ -114,7 +114,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
         }
     }
 
-    onClickScriptDisable: () => 'always' = () => 'always';
+    onClickScriptDisable = returnAlways;
 
     @action
     componentDidMount() {
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 73283263f..d57518a8d 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -876,7 +876,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         return WebBox.sidebarResizerWidth + nativeDiff * (this.props.NativeDimScaling?.() || 1);
     };
     @computed get content() {
-        const interactive = this.isContentActive() && this.props.pointerEvents?.() !== 'none' && Doc.ActiveTool === InkTool.None;
+        const interactive = this.props.isContentActive() && this.props.pointerEvents?.() !== 'none' && Doc.ActiveTool === InkTool.None;
         return (
             <div className={'webBox-cont' + (interactive ? '-interactive' : '')} onKeyDown={e => e.stopPropagation()} style={{ width: !this.layoutDoc.forceReflow ? NumCast(this.layoutDoc[this.fieldKey + '-nativeWidth']) || `100%` : '100%' }}>
                 {this.urlContent}
diff --git a/src/client/views/nodes/button/FontIconBox.scss b/src/client/views/nodes/button/FontIconBox.scss
index 7fe1436c7..f3b43501b 100644
--- a/src/client/views/nodes/button/FontIconBox.scss
+++ b/src/client/views/nodes/button/FontIconBox.scss
@@ -158,7 +158,7 @@
         width: 100%;
         border-radius: 100%;
         flex-direction: column;
-        margin-top: -4px;
+        // margin-top: -4px;
 
         svg {
             width: 60% !important;
@@ -427,11 +427,11 @@
     }
 
     .dropbox-background {
-        width: 100vw;
-        height: 100vh;
-        top: 0;
+        width: 200vw;
+        height: 200vh;
+        top: -100vh;
         z-index: 20;
-        left: 0;
+        left: -100vw;
         background: transparent;
         position: fixed;
     }
diff --git a/src/client/views/nodes/button/FontIconBox.tsx b/src/client/views/nodes/button/FontIconBox.tsx
index 468bcc4d8..28e6eaf1c 100644
--- a/src/client/views/nodes/button/FontIconBox.tsx
+++ b/src/client/views/nodes/button/FontIconBox.tsx
@@ -618,11 +618,10 @@ ScriptingGlobals.add(function setFontAttr(attr: 'font' | 'fontColor' | 'highligh
     const editorView = RichTextMenu.Instance?.TextView?.EditorView;
     const selected = SelectionManager.Docs().lastElement();
     // prettier-ignore
-    const map: Map<'font'|'fontColor'|'highlight'|'fontSize', { checkResult: () => any; setDoc: () => void; setMode?: () => void }> = new Map([
+    const map: Map<'font'|'fontColor'|'highlight'|'fontSize', { checkResult: () => any; setDoc: () => void;}> = new Map([
         ['font', {
             checkResult: () => RichTextMenu.Instance?.fontFamily,
             setDoc: () => value && RichTextMenu.Instance.setFontFamily(value),
-            setMode: () => Doc.UserDoc().textAlign = value,
         }],
         ['highlight', {
             checkResult: () =>(selected ?? Doc.UserDoc())._fontHighlight,
@@ -645,8 +644,7 @@ ScriptingGlobals.add(function setFontAttr(attr: 'font' | 'fontColor' | 'highligh
     if (checkResult) {
         return map.get(attr)?.checkResult();
     }
-    if (editorView?.state) map.get(attr)?.setDoc();
-    else map.get(attr)?.setMode?.();
+    map.get(attr)?.setDoc?.();
 });
 
 type attrname = 'noAutoLink' | 'dictation' | 'bold' | 'italics' | 'underline' | 'left' | 'center' | 'right' | 'bullet' | 'decimal';
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 3ce2366f8..ee4249b02 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -1470,20 +1470,14 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                 //      but that's changed, so this shouldn't be needed.
                 //e.stopPropagation();  // if the text box is selected, then it consumes all down events
                 document.addEventListener('pointerup', this.onSelectEnd);
-                document.addEventListener('pointermove', this.onSelectMove);
             }
         }
         if (e.button === 2 || (e.button === 0 && e.ctrlKey)) {
             e.preventDefault();
         }
     };
-    onSelectMove = (e: PointerEvent) => {
-        this.props.DocumentView?.().docView?.cancelMoveEvents();
-        e.stopPropagation();
-    };
     onSelectEnd = (e: PointerEvent) => {
         document.removeEventListener('pointerup', this.onSelectEnd);
-        document.removeEventListener('pointermove', this.onSelectMove);
     };
     onPointerUp = (e: React.PointerEvent): void => {
         const editor = this._editorView!;
@@ -1534,6 +1528,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
     @observable public static Focused: FormattedTextBox | undefined;
 
     onClick = (e: React.MouseEvent): void => {
+        if (!this.props.isContentActive()) return;
         if ((e.nativeEvent as any).handledByInnerReactInstance) {
             e.stopPropagation();
             return;
@@ -1876,7 +1871,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                     r?.addEventListener(
                         'wheel', // if scrollTop is 0, then don't let wheel trigger scroll on any container (which it would since onScroll won't be triggered on this)
                         (e: WheelEvent) => {
-                            if (this.isContentActive()) {
+                            if (this.props.isContentActive()) {
                                 if (!NumCast(this.layoutDoc._scrollTop) && e.deltaY <= 0) e.preventDefault();
                                 e.stopPropagation();
                             }
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index e79e7472a..3376c29a9 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -1027,8 +1027,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
     removeDocument = (doc: Doc) => Doc.RemoveDocFromList(this.rootDoc, this.fieldKey, doc);
     getTransform = () => this.props.ScreenToLocalTransform().translate(-5, -65); // listBox padding-left and pres-box-cont minHeight
     panelHeight = () => this.props.PanelHeight() - 40;
-    isContentActive = (outsideReaction?: boolean) =>
-        Doc.ActiveTool === InkTool.None && !this.layoutDoc._lockedPosition && (this.layoutDoc.forceActive || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false;
+    isContentActive = (outsideReaction?: boolean) => this.props.isContentActive(outsideReaction);
+    //.ActiveTool === InkTool.None && !this.layoutDoc._lockedPosition && (this.layoutDoc.forceActive || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false;
 
     /**
      * For sorting the array so that the order is maintained when it is dropped.
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index eb3087399..c5060a2c2 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -381,7 +381,6 @@ export class PDFViewer extends React.Component<IViewerProps> {
             const target = e.target as any;
             if (e.target && (target.className.includes('endOfContent') || (target.parentElement.className !== 'textLayer' && target.parentElement.parentElement?.className !== 'textLayer'))) {
                 this._textSelecting = false;
-                document.addEventListener('pointermove', this.onSelectMove); // need this to prevent document from being dragged if stopPropagation doesn't get called
             } else {
                 // if textLayer is hit, then we select text instead of using a marquee so clear out the marquee.
                 setTimeout(
@@ -391,7 +390,6 @@ export class PDFViewer extends React.Component<IViewerProps> {
 
                 this._styleRule = addStyleSheetRule(PDFViewer._annotationStyle, 'htmlAnnotation', { 'pointer-events': 'none' });
                 document.addEventListener('pointerup', this.onSelectEnd);
-                document.addEventListener('pointermove', this.onSelectMove);
             }
         }
     };
@@ -401,12 +399,6 @@ export class PDFViewer extends React.Component<IViewerProps> {
         this.isAnnotating = false;
         this._marqueeing = undefined;
         this._textSelecting = true;
-        document.removeEventListener('pointermove', this.onSelectMove);
-    };
-
-    onSelectMove = (e: PointerEvent) => {
-        this.props.DocumentView?.().docView?.cancelMoveEvents();
-        e.stopPropagation();
     };
 
     @action
@@ -414,7 +406,6 @@ export class PDFViewer extends React.Component<IViewerProps> {
         this.isAnnotating = false;
         clearStyleSheetRules(PDFViewer._annotationStyle);
         this.props.select(false);
-        document.removeEventListener('pointermove', this.onSelectMove);
         document.removeEventListener('pointerup', this.onSelectEnd);
 
         const sel = window.getSelection();
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 4d82551db..553c4525c 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -31,7 +31,7 @@ export namespace Field {
     export function toKeyValueString(doc: Doc, key: string): string {
         const onDelegate = Object.keys(doc).includes(key);
         const field = ComputedField.WithoutComputed(() => FieldValue(doc[key]));
-        return !Field.IsField(field) ? '' : (onDelegate ? '=' : '') + (field instanceof ComputedField ? `:=${field.script.originalScript}` : Field.toScriptString(field));
+        return !Field.IsField(field) ? '' : (onDelegate ? '=' : '') + (field instanceof ComputedField ? `:=${field.script.originalScript}` : field instanceof ScriptField ? `$=${field.script.originalScript}` : Field.toScriptString(field));
     }
     export function toScriptString(field: Field): string {
         switch (typeof field) {
diff --git a/src/fields/ScriptField.ts b/src/fields/ScriptField.ts
index feb419597..2b8750714 100644
--- a/src/fields/ScriptField.ts
+++ b/src/fields/ScriptField.ts
@@ -114,7 +114,7 @@ export class ScriptField extends ObjectField {
     }
 
     [ToScriptString]() {
-        return 'script field';
+        return this.script.originalScript;
     }
     [ToString]() {
         return this.script.originalScript;
-- 
cgit v1.2.3-70-g09d2


From fb9ec75c46bc237bc6c8df24ee998e6de90168a1 Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Wed, 12 Apr 2023 20:55:14 -0400
Subject: readonly fields and schema key info display

---
 src/client/documents/Documents.ts                  | 51 ++++++++++++----------
 .../collectionSchema/CollectionSchemaView.scss     | 11 ++++-
 .../collectionSchema/CollectionSchemaView.tsx      | 48 +++++++++++++++-----
 .../collections/collectionSchema/SchemaRowBox.tsx  |  1 +
 .../collectionSchema/SchemaTableCell.tsx           |  8 +++-
 5 files changed, 82 insertions(+), 37 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaRowBox.tsx')

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 979b294e0..6b60c1801 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -69,12 +69,14 @@ class EmptyBox {
 }
 export abstract class FInfo {
     description: string = '';
+    readOnly: boolean = false;
     fieldType?: string;
     values?: Field[];
     // format?: string; // format to display values (e.g, decimal places, $, etc)
     // parse?: ScriptField; // parse a value from a string
-    constructor(d: string) {
+    constructor(d: string, readOnly?: boolean) {
         this.description = d;
+        this.readOnly = readOnly ?? false;
     }
 }
 class BoolInfo extends FInfo {
@@ -84,16 +86,16 @@ class BoolInfo extends FInfo {
 class NumInfo extends FInfo {
     fieldType? = 'number';
     values?: number[] = [];
-    constructor(d: string, values?: number[]) {
-        super(d);
+    constructor(d: string, readOnly?: boolean, values?: number[]) {
+        super(d, readOnly);
         this.values = values;
     }
 }
 class StrInfo extends FInfo {
     fieldType? = 'string';
     values?: string[] = [];
-    constructor(d: string, values?: string[]) {
-        super(d);
+    constructor(d: string, readOnly?: boolean, values?: string[]) {
+        super(d, readOnly);
         this.values = values;
     }
 }
@@ -101,21 +103,24 @@ class DocInfo extends FInfo {
     fieldType? = 'Doc';
     values?: Doc[] = [];
     constructor(d: string, values?: Doc[]) {
-        super(d);
+        super(d, true);
         this.values = values;
     }
 }
 class DimInfo extends FInfo {
     fieldType? = 'DimUnit';
     values? = [DimUnit.Pixel, DimUnit.Ratio];
+    readOnly = true;
 }
 class PEInfo extends FInfo {
     fieldType? = 'pointerEvents';
     values? = ['all', 'none'];
+    readOnly = true;
 }
 class DAInfo extends FInfo {
     fieldType? = 'dropActionType';
     values? = ['alias', 'copy', 'move', 'same', 'proto', 'none'];
+    readOnly = true;
 }
 type BOOLt = BoolInfo | boolean;
 type NUMt = NumInfo | number;
@@ -127,12 +132,12 @@ type DROPt = DAInfo | dropActionType;
 export class DocumentOptions {
     x?: NUMt = new NumInfo('x coordinate of document in a freeform view');
     y?: NUMt = new NumInfo('y coordinage of document in a freeform view');
-    z?: NUMt = new NumInfo('whether document is in overlay (1) or not (0)', [1, 0]);
-    system?: BOOLt = new BoolInfo('is this a system created/owned doc');
-    type?: STRt = new StrInfo('type of document', Array.from(Object.keys(DocumentType)));
+    z?: NUMt = new NumInfo('whether document is in overlay (1) or not (0)', false, [1, 0]);
+    system?: BOOLt = new BoolInfo('is this a system created/owned doc', true);
+    type?: STRt = new StrInfo('type of document', true, Array.from(Object.keys(DocumentType)));
     title?: string;
     _dropAction?: DROPt = new DAInfo("what should happen to this document when it's dropped somewhere else");
-    allowOverlayDrop?: BOOLt = new BoolInfo('can documents be dropped onto this document without using dragging title bar or holding down embed key (ctrl)?');
+    allowOverlayDrop?: BOOLt = new BoolInfo('can documents be dropped onto this document without using dragging title bar or holding down embed key (ctrl)?', true);
     childDropAction?: DROPt = new DAInfo("what should happen to the source document when it's dropped onto a child of a collection ");
     targetDropAction?: DROPt = new DAInfo('what should happen to the source document when ??? ');
     userColor?: STRt = new StrInfo('color associated with a Dash user (seen in header fields of shared documents)');
@@ -146,14 +151,14 @@ export class DocumentOptions {
     _panY?: NUMt = new NumInfo('vertical pan location of a freeform view');
     _width?: NUMt = new NumInfo('displayed width of a document');
     _height?: NUMt = new NumInfo('displayed height of document');
-    _nativeWidth?: NUMt = new NumInfo('native width of document contents (e.g., the pixel width of an image)');
-    _nativeHeight?: NUMt = new NumInfo('native height of document contents (e.g., the pixel height of an image)');
-    _nativeDimModifiable?: BOOLt = new BoolInfo('native dimensions can be modified using document decoration reizers');
-    _nativeHeightUnfrozen?: BOOLt = new BoolInfo('native height can be changed independent of width by dragging decoration resizers');
-    _dimMagnitude?: NUMt = new NumInfo("magnitude of collectionMulti{row,col} element's width or height");
-    _dimUnit?: DIMt = new DimInfo("units of collectionMulti{row,col} element's width or height - 'px' or '*' for pixels or relative units");
-    _fitWidth?: BOOLt = new BoolInfo('whether document should scale its contents to fit its rendered width or not (e.g., for PDFviews)');
-    _fitContentsToBox?: BOOLt = new BoolInfo('whether a freeformview should zoom/scale to create a shrinkwrapped view of its content');
+    _nativeWidth?: NUMt = new NumInfo('native width of document contents (e.g., the pixel width of an image)', true);
+    _nativeHeight?: NUMt = new NumInfo('native height of document contents (e.g., the pixel height of an image)', true);
+    _nativeDimModifiable?: BOOLt = new BoolInfo('native dimensions can be modified using document decoration reizers', true);
+    _nativeHeightUnfrozen?: BOOLt = new BoolInfo('native height can be changed independent of width by dragging decoration resizers', true);
+    _dimMagnitude?: NUMt = new NumInfo("magnitude of collectionMulti{row,col} element's width or height", true);
+    _dimUnit?: DIMt = new DimInfo("units of collectionMulti{row,col} element's width or height - 'px' or '*' for pixels or relative units", true);
+    _fitWidth?: BOOLt = new BoolInfo('whether document should scale its contents to fit its rendered width or not (e.g., for PDFviews)', true);
+    _fitContentsToBox?: BOOLt = new BoolInfo('whether a freeformview should zoom/scale to create a shrinkwrapped view of its content', true);
     _contentBounds?: List<number>; // the (forced) bounds of the document to display. format is: [left, top, right, bottom]
     _lockedPosition?: boolean; // lock the x,y coordinates of the document so that it can't be dragged
     _lockedTransform?: boolean; // lock the panx,pany and scale parameters of the document so that it be panned/zoomed
@@ -196,11 +201,11 @@ export class DocumentOptions {
     _timecodeToShow?: number; // the time that a document should be displayed (e.g., when an annotation shows up as a video plays)
     _timecodeToHide?: number; // the time that a document should be hidden
     _timelineLabel?: boolean; // whether the document exists on a timeline
-    '_carousel-caption-xMargin'?: NUMt = new NumInfo('x margin of caption inside of a carouself collection');
-    '_carousel-caption-yMargin'?: NUMt = new NumInfo('y margin of caption inside of a carouself collection');
-    'icon-nativeWidth'?: NUMt = new NumInfo('native width of icon view');
-    'icon-nativeHeight'?: NUMt = new NumInfo('native height of icon view');
-    'dragFactory-count'?: NUMt = new NumInfo('number of items created from a drag button (used for setting title with incrementing index)');
+    '_carousel-caption-xMargin'?: NUMt = new NumInfo('x margin of caption inside of a carouself collection', true);
+    '_carousel-caption-yMargin'?: NUMt = new NumInfo('y margin of caption inside of a carouself collection', true);
+    'icon-nativeWidth'?: NUMt = new NumInfo('native width of icon view', true);
+    'icon-nativeHeight'?: NUMt = new NumInfo('native height of icon view', true);
+    'dragFactory-count'?: NUMt = new NumInfo('number of items created from a drag button (used for setting title with incrementing index)', true);
     openFactoryLocation?: string; // an OpenWhere value to place the factory created document
     openFactoryAsDelegate?: boolean; //
     lat?: number;
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
index 6118aef3f..a9434fde3 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
@@ -20,6 +20,7 @@
             background: $light-gray;
             position: absolute;
             min-width: 200px;
+            max-width: 400px;
             display: flex;
             flex-direction: column;
             align-items: flex-start;
@@ -30,14 +31,20 @@
                 margin: 10px;
             }
 
-            .schema-key-search-result {
+            .schema-search-result {
                 cursor: pointer;
-                padding: 2px 10px;
+                padding: 5px 10px;
                 width: 100%;
 
                 &:hover {
                     background-color: $medium-gray;
                 }
+
+                .schema-search-result-type,
+                .schema-search-result-desc {
+                    color: $dark-gray;
+                    font-size: $body-text;
+                }
             }
 
             .schema-key-search,
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 245e1abc0..d3992d12c 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -9,7 +9,7 @@ import { List } from '../../../../fields/List';
 import { listSpec } from '../../../../fields/Schema';
 import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../../fields/Types';
 import { emptyFunction, returnDefault, returnEmptyDoclist, returnEmptyString, returnFalse, returnNever, returnTrue, setupMoveUpEvents, smoothScroll } from '../../../../Utils';
-import { Docs, DocUtils } from '../../../documents/Documents';
+import { Docs, DocumentOptions, DocUtils, FInfo } from '../../../documents/Documents';
 import { DocumentManager } from '../../../util/DocumentManager';
 import { DragManager } from '../../../util/DragManager';
 import { SelectionManager } from '../../../util/SelectionManager';
@@ -40,6 +40,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     private _closestDropIndex: number = 0;
     private _previewRef: HTMLDivElement | null = null;
     private _makeNewColumn: boolean = false;
+    private _documentOptions: DocumentOptions = new DocumentOptions();
 
     public static _rowHeight: number = 40;
     public static _minColWidth: number = 25;
@@ -54,7 +55,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     @observable _colEles: HTMLDivElement[] = [];
     @observable _displayColumnWidths: number[] | undefined;
     @observable _columnMenuIndex: number | undefined;
-    @observable _menuOptions: string[] = [];
+    @observable _menuOptions: [string, { description: string; type: string; readOnly: boolean }][] = [];
     @observable _newFieldWarning: string = '';
     @observable _makeNewField: boolean = false;
     @observable _newFieldDefault: any = 0;
@@ -63,7 +64,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     @observable _filterColumnIndex: number | undefined;
     @observable _filterSearchValue: string = '';
 
-    get documentKeys() {
+    get keyInfos() {
         const docs = this.childDocs;
         const keys: { [key: string]: boolean } = {};
         // bcz: ugh.  this is untracked since otherwise a large collection of documents will blast the server for all their fields.
@@ -75,7 +76,22 @@ export class CollectionSchemaView extends CollectionSubView() {
         untracked(() => docs.map(doc => Doc.GetAllPrototypes(doc).map(proto => Object.keys(proto).forEach(key => (keys[key] = false)))));
 
         // this.columns.forEach(key => (keys[key.heading] = true));
-        return Array.from(Object.keys(keys));
+
+        let computedKeys: { [key: string]: { description: string; type: string; readOnly: boolean } } = {};
+        Object.keys(keys).forEach((key: string) => {
+            computedKeys[key] = { description: '', type: '', readOnly: false };
+        });
+
+        Object.entries(this._documentOptions).forEach((pair: [string, any]) => {
+            const info: FInfo = pair[1];
+            computedKeys[pair[0]] = { description: info.description, type: info.fieldType ?? '', readOnly: info.readOnly };
+        });
+
+        return computedKeys;
+    }
+
+    get documentKeys() {
+        return Object.keys(this.keyInfos);
     }
 
     @computed get previewWidth() {
@@ -441,7 +457,8 @@ export class CollectionSchemaView extends CollectionSubView() {
     onSearchKeyDown = (e: React.KeyboardEvent) => {
         switch (e.key) {
             case 'Enter':
-                this._menuOptions.length > 0 && this._menuValue.length > 0 ? this.setKey(this._menuOptions[0]) : action(() => (this._makeNewField = true))();
+                const menuKeys = Object.keys(this._menuOptions);
+                menuKeys.length > 0 && this._menuValue.length > 0 ? this.setKey(menuKeys[0]) : action(() => (this._makeNewField = true))();
                 break;
             case 'Escape':
                 this.closeColumnMenu();
@@ -470,7 +487,7 @@ export class CollectionSchemaView extends CollectionSubView() {
         this._makeNewColumn = false;
         this._columnMenuIndex = index;
         this._menuValue = '';
-        this._menuOptions = this.documentKeys;
+        this._menuOptions = Object.entries(this.keyInfos);
         this._makeNewField = false;
         this._newFieldWarning = '';
         this._makeNewField = false;
@@ -516,7 +533,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     @action
     updateKeySearch = (e: React.ChangeEvent<HTMLInputElement>) => {
         this._menuValue = e.target.value;
-        this._menuOptions = this.documentKeys.filter(value => value.toLowerCase().includes(this._menuValue.toLowerCase()));
+        this._menuOptions = Object.entries(this.keyInfos).filter(value => value[0].toLowerCase().includes(this._menuValue.toLowerCase()));
     };
 
     getFieldFilters = (field: string) => StrListCast(this.Document._docFilters).filter(filter => filter.split(':')[0] == field);
@@ -618,14 +635,23 @@ export class CollectionSchemaView extends CollectionSubView() {
                             { passive: false }
                         )
                     }>
-                    {this._menuOptions.map(key => (
+                    {this._menuOptions.map(([key, info]) => (
                         <div
-                            className="schema-key-search-result"
+                            className="schema-search-result"
                             onPointerDown={e => {
                                 e.stopPropagation();
                                 this.setKey(key);
                             }}>
-                            {key}
+                            <p>
+                                <span className="schema-search-result-key">
+                                    {key}
+                                    {info.type ? ', ' : ''}
+                                </span>
+                                <span className="schema-search-result-type" style={{ color: info.readOnly ? 'red' : 'inherit' }}>
+                                    {info.type}
+                                </span>
+                            </p>
+                            <p className="schema-search-result-desc">{info.description}</p>
                         </div>
                     ))}
                 </div>
@@ -825,7 +851,7 @@ class CollectionSchemaViewDocs extends React.Component<CollectionSchemaViewDocsP
                 {this.props.childDocs().docs.map((doc: Doc, index: number) => {
                     const dataDoc = !doc.isTemplateDoc && !doc.isTemplateForField ? undefined : this.props.schema.props.DataDoc;
                     return (
-                        <div className="schema-row-wrapper" style={{ maxHeight: CollectionSchemaView._rowHeight }}>
+                        <div className="schema-row-wrapper" style={{ height: CollectionSchemaView._rowHeight }}>
                             <DocumentView
                                 key={doc[Id]}
                                 {...this.props.schema.props}
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 2defaae00..aa8a61205 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -123,6 +123,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
                         <SchemaTableCell
                             key={key}
                             Document={this.rootDoc}
+                            schemaView={this.schemaView}
                             fieldKey={key}
                             columnWidth={this.schemaView?.displayColumnWidths[index] ?? CollectionSchemaView._minColWidth}
                             isRowActive={this.props.isContentActive}
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 13e45963e..42c9f9d48 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -9,9 +9,11 @@ import { KeyValueBox } from '../../nodes/KeyValueBox';
 import { DefaultStyleProvider } from '../../StyleProvider';
 import { CollectionSchemaView } from './CollectionSchemaView';
 import './CollectionSchemaView.scss';
+import { computed } from 'mobx';
 
 export interface SchemaTableCellProps {
     Document: Doc;
+    schemaView: CollectionSchemaView | undefined;
     fieldKey: string;
     columnWidth: number;
     isRowActive: () => boolean | undefined;
@@ -20,6 +22,10 @@ export interface SchemaTableCellProps {
 
 @observer
 export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
+    get readOnly() {
+        return this.props.schemaView?.keyInfos[this.props.fieldKey].readOnly;
+    }
+
     render() {
         const props: FieldViewProps = {
             Document: this.props.Document,
@@ -50,7 +56,7 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
 
         return (
             <div className="schema-table-cell" style={{ width: this.props.columnWidth }}>
-                <div className="schemacell-edit-wrapper" style={this.props.isRowActive() ? { cursor: 'text', pointerEvents: 'auto' } : { cursor: 'default', pointerEvents: 'none' }}>
+                <div className="schemacell-edit-wrapper" style={this.props.isRowActive() && !this.readOnly ? { cursor: 'text', pointerEvents: 'auto' } : { cursor: 'default', pointerEvents: 'none' }}>
                     <EditableView
                         contents={<FieldView {...props} />}
                         GetValue={() => Field.toKeyValueString(this.props.Document, this.props.fieldKey)}
-- 
cgit v1.2.3-70-g09d2


From 5cd64622f14ede408d3baca4a10d155b60392e46 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 13 Apr 2023 22:22:07 -0400
Subject: lots of changes to get rid of ContainingCollectionDoc and
 ContainingCollectionView props.

---
 src/client/documents/Documents.ts                  |  8 +--
 src/client/util/CurrentUserUtils.ts                |  2 +-
 src/client/util/DocumentManager.ts                 | 83 ++++++++++------------
 src/client/util/DragManager.ts                     |  4 +-
 .../util/Import & Export/DirectoryImportBox.tsx    |  6 +-
 src/client/util/ReplayMovements.ts                 | 64 ++++++-----------
 src/client/util/SelectionManager.ts                |  6 +-
 src/client/util/SharingManager.tsx                 |  5 +-
 src/client/util/TrackMovements.ts                  | 36 +++++-----
 src/client/views/DashboardView.tsx                 | 17 ++---
 src/client/views/DocComponent.tsx                  |  1 -
 src/client/views/DocumentDecorations.tsx           |  8 +--
 src/client/views/GestureOverlay.tsx                |  4 +-
 src/client/views/InkStrokeProperties.ts            |  3 +-
 src/client/views/LightboxView.tsx                  |  4 +-
 src/client/views/MainView.tsx                      | 20 ++----
 src/client/views/OverlayView.tsx                   | 10 +--
 src/client/views/Palette.tsx                       | 31 ++++----
 src/client/views/PropertiesDocContextSelector.tsx  | 22 ++++--
 src/client/views/PropertiesView.tsx                |  2 -
 src/client/views/StyleProvider.tsx                 | 11 ++-
 src/client/views/TemplateMenu.tsx                  |  2 -
 .../views/collections/CollectionCarouselView.tsx   |  1 -
 src/client/views/collections/CollectionMenu.tsx    |  6 +-
 .../views/collections/CollectionNoteTakingView.tsx |  4 --
 .../views/collections/CollectionPileView.tsx       |  2 +-
 .../collections/CollectionStackedTimeline.tsx      |  2 -
 .../views/collections/CollectionStackingView.tsx   |  4 --
 .../views/collections/CollectionTreeView.tsx       | 10 +--
 src/client/views/collections/CollectionView.tsx    |  5 +-
 src/client/views/collections/TabDocView.tsx        |  6 +-
 src/client/views/collections/TreeView.tsx          | 54 ++++++--------
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 31 ++++----
 .../collectionLinear/CollectionLinearView.tsx      |  5 +-
 .../CollectionMulticolumnView.tsx                  |  2 -
 .../CollectionMultirowView.tsx                     |  2 -
 .../collectionSchema/CollectionSchemaView.tsx      |  6 +-
 .../collections/collectionSchema/SchemaRowBox.tsx  |  2 +-
 .../collectionSchema/SchemaTableCell.tsx           |  2 -
 src/client/views/linking/LinkMenuItem.tsx          | 21 +-----
 src/client/views/linking/LinkPopup.tsx             |  4 +-
 .../views/nodes/CollectionFreeFormDocumentView.tsx |  7 +-
 src/client/views/nodes/DocumentContentsView.tsx    |  1 -
 src/client/views/nodes/DocumentLinksButton.tsx     |  2 +-
 src/client/views/nodes/DocumentView.tsx            | 12 ++--
 src/client/views/nodes/FieldView.tsx               |  1 +
 src/client/views/nodes/KeyValuePair.tsx            |  2 -
 src/client/views/nodes/LinkDocPreview.tsx          |  4 +-
 src/client/views/nodes/ScreenshotBox.tsx           |  5 +-
 src/client/views/nodes/button/FontIconBox.tsx      |  4 +-
 .../views/nodes/formattedText/DashDocView.tsx      |  7 +-
 .../views/nodes/formattedText/DashFieldView.tsx    |  5 +-
 .../views/nodes/formattedText/FormattedTextBox.tsx | 20 ++++--
 src/client/views/nodes/trails/PresBox.tsx          |  1 -
 src/client/views/nodes/trails/PresElementBox.tsx   | 27 ++++---
 src/client/views/topbar/TopBar.tsx                 | 51 ++-----------
 src/mobile/AudioUpload.tsx                         | 76 ++++++++++----------
 src/mobile/MobileInterface.tsx                     |  4 +-
 58 files changed, 291 insertions(+), 456 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaRowBox.tsx')

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 8d97ce5af..09b45a481 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -1285,10 +1285,6 @@ export namespace DocUtils {
         return rangeFilteredDocs;
     }
 
-    export function DefaultFocus(doc: Doc, options: DocFocusOptions) {
-        return undefined;
-    }
-
     export let ActiveRecordings: { props: FieldViewProps; getAnchor: (addAsAnnotation: boolean) => Doc }[] = [];
 
     export function MakeLinkToActiveAudio(getSourceDoc: () => Doc | undefined, broadcastEvent = true) {
@@ -1299,10 +1295,9 @@ export namespace DocUtils {
         });
     }
 
-    export function MakeLink(source: Doc, target: Doc, linkSettings: { linkRelationship?: string; description?: string; linkDisplay?: boolean }, id?: string, allowParCollectionLink?: boolean, showPopup?: number[]) {
+    export function MakeLink(source: Doc, target: Doc, linkSettings: { linkRelationship?: string; description?: string; linkDisplay?: boolean }, id?: string, showPopup?: number[]) {
         if (!linkSettings.linkRelationship) linkSettings.linkRelationship = target.type === DocumentType.RTF ? 'Commentary:Comments On' : 'link';
         const sv = DocumentManager.Instance.getDocumentView(source);
-        if (!allowParCollectionLink && sv?.props.ContainingCollectionDoc === target) return;
         if (target.doc === Doc.UserDoc()) return undefined;
 
         const makeLink = action((linkDoc: Doc, showPopup?: number[]) => {
@@ -1371,7 +1366,6 @@ export namespace DocUtils {
                         value: 'any',
                         _readOnly_: 'boolean',
                         scriptContext: 'any',
-                        thisContainer: Doc.name,
                         documentView: Doc.name,
                         heading: Doc.name,
                         checked: 'boolean',
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 76ea3e3ea..abf7313a4 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -110,7 +110,7 @@ export class CurrentUserUtils {
         const tempClicks = DocCast(doc[field]);
         const reqdClickOpts:DocumentOptions = {_width: 300, _height:200, system: true};
         const reqdTempOpts:{opts:DocumentOptions, script: string}[] = [
-            { opts: { title: "Open In Target",        targetScriptKey: "onChildClick"},       script: "docCast(thisContainer.target).then((target) => target && (target.proto.data = new List([self])))"},
+            { opts: { title: "Open In Target",        targetScriptKey: "onChildClick"},       script: "docCast(documentView?.props.docViewPath().lastElement()?.rootDoc.target).then((target) => target && (target.proto.data = new List([self])))"},
             { opts: { title: "Open Detail On Right",  targetScriptKey: "onChildDoubleClick"}, script: `openDoc(self.doubleClickView.${OpenWhere.addRight})`}];
         const reqdClickList = reqdTempOpts.map(opts => {
             const allOpts = {...reqdClickOpts, ...opts.opts};
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index ccf370662..ad89e8653 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -1,15 +1,11 @@
-import { loadAsync } from 'jszip';
-import { action, observable, ObservableSet, runInAction } from 'mobx';
+import { action, observable, ObservableSet } from 'mobx';
 import { AnimationSym, Doc, Opt } from '../../fields/Doc';
 import { Id } from '../../fields/FieldSymbols';
 import { listSpec } from '../../fields/Schema';
 import { Cast, DocCast, StrCast } from '../../fields/Types';
 import { AudioField } from '../../fields/URLField';
-import { emptyFunction } from '../../Utils';
 import { CollectionViewType } from '../documents/DocumentTypes';
 import { CollectionDockingView } from '../views/collections/CollectionDockingView';
-import { CollectionFreeFormView } from '../views/collections/collectionFreeForm';
-import { CollectionView } from '../views/collections/CollectionView';
 import { TabDocView } from '../views/collections/TabDocView';
 import { LightboxView } from '../views/LightboxView';
 import { MainView } from '../views/MainView';
@@ -39,7 +35,7 @@ export class DocumentManager {
     private _viewRenderedCbs: { doc: Doc; func: (dv: DocumentView) => any }[] = [];
     public AddViewRenderedCb = (doc: Opt<Doc>, func: (dv: DocumentView) => any) => {
         if (doc) {
-            const dv = this.getDocumentViewById(doc[Id]);
+            const dv = this.getDocumentView(doc);
             this._viewRenderedCbs.push({ doc, func });
             if (dv) {
                 this.callAddViewFuncs(dv);
@@ -129,42 +125,24 @@ export class DocumentManager {
         return this.getDocumentViewsById(doc[Id]);
     }
 
-    public getDocumentViewById(id: string, preferredCollection?: CollectionView): DocumentView | undefined {
-        if (!id) return undefined;
-        let toReturn: DocumentView | undefined;
-        const passes = preferredCollection ? [preferredCollection, undefined] : [undefined];
-
-        for (const pass of passes) {
-            Array.from(DocumentManager.Instance.DocumentViews).map(view => {
-                if (view.rootDoc[Id] === id && (!pass || view.props.ContainingCollectionView === preferredCollection)) {
-                    toReturn = view;
-                    return;
-                }
-            });
-            if (!toReturn) {
-                Array.from(DocumentManager.Instance.DocumentViews).map(view => {
-                    const doc = view.rootDoc.proto;
-                    if (doc && doc[Id] === id && (!pass || view.props.ContainingCollectionView === preferredCollection)) {
-                        toReturn = view;
-                    }
-                });
-            } else {
-                break;
-            }
-        }
-
-        return toReturn;
-    }
-
-    public getDocumentView(toFind: Doc, preferredCollection?: CollectionView): DocumentView | undefined {
-        const found =
+    public getDocumentView(toFind: Doc | undefined, preferredCollection?: DocumentView): DocumentView | undefined {
+        const doc =
+            // bcz: this was temporary code used to match documents by data url instead of by id. intended only for repairing the DB
             // Array.from(DocumentManager.Instance.DocumentViews).find(
             //     dv =>
             //         ((dv.rootDoc.data as any)?.url?.href && (dv.rootDoc.data as any)?.url?.href === (toFind.data as any)?.url?.href) ||
             //         ((DocCast(dv.rootDoc.annotationOn)?.data as any)?.url?.href && (DocCast(dv.rootDoc.annotationOn)?.data as any)?.url?.href === (DocCast(toFind.annotationOn)?.data as any)?.url?.href)
             // )?.rootDoc ??
             toFind;
-        return this.getDocumentViewById(found[Id], preferredCollection);
+        const docViewArray = Array.from(DocumentManager.Instance.DocumentViews);
+        const passes = !doc ? [] : preferredCollection ? [preferredCollection, undefined] : [undefined];
+        return passes.reduce(
+            (pass, toReturn) =>
+                toReturn ??
+                docViewArray.filter(view => view.rootDoc === doc).find(view => !pass || view.props.docViewPath().lastElement() === preferredCollection) ??
+                docViewArray.filter(view => Doc.GetProto(view.rootDoc) === doc).find(view => !pass || view.props.docViewPath().lastElement() === preferredCollection),
+            undefined as Opt<DocumentView>
+        );
     }
 
     public getLightboxDocumentView = (toFind: Doc, originatingDoc: Opt<Doc> = undefined): DocumentView | undefined => {
@@ -247,7 +225,8 @@ export class DocumentManager {
     public showDocumentView = async (targetDocView: DocumentView, options: DocFocusOptions) => {
         const docViewPath = targetDocView.docViewPath.slice();
         let rootContextView = docViewPath.shift();
-        return rootContextView && this.focusViewsInPath(rootContextView, options, async () => ({ childDocView: docViewPath.shift(), viewSpec: undefined }));
+        await (rootContextView && this.focusViewsInPath(rootContextView, options, async () => ({ childDocView: docViewPath.shift(), viewSpec: undefined })));
+        if (options.toggleTarget && (!options.didMove || targetDocView.rootDoc.hidden)) targetDocView.rootDoc.hidden = !targetDocView.rootDoc.hidden;
     };
 
     // shows a document by first:
@@ -318,15 +297,25 @@ export class DocumentManager {
         }
     }
 }
-export function DocFocusOrOpen(doc: Doc, collectionDoc?: Doc) {
-    const cv = collectionDoc && DocumentManager.Instance.getDocumentView(collectionDoc);
-    const dv = DocumentManager.Instance.getDocumentView(doc, (cv?.ComponentView as CollectionFreeFormView)?.props.CollectionView);
-    if (dv) {
-        DocumentManager.Instance.showDocumentView(dv, { willZoomCentered: true });
-    } else {
-        const context = doc.context !== Doc.MyFilesystem && Cast(doc.context, Doc, null);
-        const showDoc = context || doc;
-        DocumentManager.Instance.showDocument(Doc.BestAlias(showDoc), { openLocation: OpenWhere.addRight }, () => DocumentManager.Instance.showDocument(doc, { willZoomCentered: true }));
-    }
+export function DocFocusOrOpen(doc: Doc, options: DocFocusOptions = { willZoomCentered: true, openLocation: OpenWhere.addRight }, containingDoc?: Doc) {
+    const func = () => {
+        const cv = DocumentManager.Instance.getDocumentView(containingDoc);
+        const dv = DocumentManager.Instance.getDocumentView(doc, cv);
+        if (dv && (!containingDoc || dv.props.docViewPath().lastElement()?.Document === containingDoc)) {
+            DocumentManager.Instance.showDocumentView(dv, options).then(() => dv && Doc.linkFollowHighlight(dv.rootDoc));
+        } else {
+            const showDoc = Doc.BestAlias(DocCast((containingDoc ?? doc.context) !== Doc.MyFilesystem ? containingDoc ?? doc.context : undefined, doc));
+            DocumentManager.Instance.showDocument(showDoc, { ...options, toggleTarget: undefined }, () => DocumentManager.Instance.showDocument(doc, options)).then(() => {
+                const cv = DocumentManager.Instance.getDocumentView(containingDoc);
+                const dv = DocumentManager.Instance.getDocumentView(doc, cv);
+                dv && Doc.linkFollowHighlight(dv.rootDoc);
+            });
+        }
+    };
+    if (doc.hidden) {
+        doc.hidden = false;
+        options.toggleTarget = false;
+        setTimeout(func);
+    } else func();
 }
 ScriptingGlobals.add(DocFocusOrOpen);
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index 7d2aa813f..7e6de5e67 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -3,10 +3,8 @@ import { DateField } from '../../fields/DateField';
 import { Doc, Field, Opt, StrListCast } from '../../fields/Doc';
 import { List } from '../../fields/List';
 import { PrefetchProxy } from '../../fields/Proxy';
-import { listSpec } from '../../fields/Schema';
-import { SchemaHeaderField } from '../../fields/SchemaHeaderField';
 import { ScriptField } from '../../fields/ScriptField';
-import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../fields/Types';
+import { BoolCast, ScriptCast, StrCast } from '../../fields/Types';
 import { emptyFunction, Utils } from '../../Utils';
 import { Docs, DocUtils } from '../documents/Documents';
 import * as globalCssVariables from '../views/global/globalCssVariables.scss';
diff --git a/src/client/util/Import & Export/DirectoryImportBox.tsx b/src/client/util/Import & Export/DirectoryImportBox.tsx
index 559958c2b..76b1323c4 100644
--- a/src/client/util/Import & Export/DirectoryImportBox.tsx	
+++ b/src/client/util/Import & Export/DirectoryImportBox.tsx	
@@ -14,12 +14,14 @@ import { AcceptableMedia, Upload } from '../../../server/SharedMediaTypes';
 import { Utils } from '../../../Utils';
 import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils';
 import { Docs, DocumentOptions, DocUtils } from '../../documents/Documents';
+import { DocumentType } from '../../documents/DocumentTypes';
 import { Networking } from '../../Network';
 import { FieldView, FieldViewProps } from '../../views/nodes/FieldView';
 import { DocumentManager } from '../DocumentManager';
 import './DirectoryImportBox.scss';
 import ImportMetadataEntry, { keyPlaceholder, valuePlaceholder } from './ImportMetadataEntry';
 import React = require('react');
+import _ = require('lodash');
 
 const unsupported = ['text/html', 'text/plain'];
 
@@ -155,8 +157,8 @@ export class DirectoryImportBox extends React.Component<FieldViewProps> {
             x: NumCast(doc.x),
             y: NumCast(doc.y) + offset,
         };
-        const parent = this.props.ContainingCollectionView;
-        if (parent) {
+        const parent = _.nth(this.props.docViewPath(), -2); // last element of path is this box's document view, 2nd to last is any collection or other document that may contain it.
+        if (parent?.rootDoc.type === DocumentType.COL) {
             let importContainer: Doc;
             if (docs.length < 50) {
                 importContainer = Docs.Create.MasonryDocument(docs, options);
diff --git a/src/client/util/ReplayMovements.ts b/src/client/util/ReplayMovements.ts
index d5bffc5e2..40261985a 100644
--- a/src/client/util/ReplayMovements.ts
+++ b/src/client/util/ReplayMovements.ts
@@ -7,6 +7,7 @@ import { CollectionDockingView } from '../views/collections/CollectionDockingVie
 import { DocServer } from '../DocServer';
 import { Movement, Presentation } from './TrackMovements';
 import { OpenWhereMod } from '../views/nodes/DocumentView';
+import { returnTransparent } from '../../Utils';
 
 export class ReplayMovements {
     private timers: NodeJS.Timeout[] | null;
@@ -60,17 +61,11 @@ export class ReplayMovements {
             return;
         }
 
-        let docIdtoDoc: Map<string, Doc> = new Map();
-        try {
-            docIdtoDoc = await this.loadPresentation(presentation);
-        } catch {
-            console.error('[recordingApi.ts] setVideoBox(): error loading presentation - no replay movements');
-            throw 'error loading docs from server';
-        }
+        const docIdtoDoc = this.loadPresentation(presentation);
 
         this.videoBoxDisposeFunc = reaction(
             () => ({ playing: videoBox._playing, timeViewed: videoBox.player?.currentTime || 0 }),
-            ({ playing, timeViewed }) => (playing ? this.playMovements(presentation, docIdtoDoc, timeViewed) : this.pauseMovements())
+            ({ playing, timeViewed }) => (playing ? this.playMovements(presentation, timeViewed) : this.pauseMovements())
         );
         this.videoBox = videoBox;
     };
@@ -93,45 +88,33 @@ export class ReplayMovements {
         this.pauseMovements();
     };
 
-    loadPresentation = async (presentation: Presentation) => {
+    loadPresentation = (presentation: Presentation) => {
         const { movements } = presentation;
         if (movements === null) {
             throw '[recordingApi.ts] followMovements() failed: no presentation data';
         }
 
         // generate a set of all unique docIds
-        const docIds = new Set<string>();
-        for (const { docId } of movements) {
-            if (!docIds.has(docId)) docIds.add(docId);
-        }
-
-        const docIdtoDoc = new Map<string, Doc>();
-
-        let refFields = await DocServer.GetRefFields([...docIds.keys()]);
-        for (const docId in refFields) {
-            if (!refFields[docId]) {
-                throw `one field was undefined`;
-            }
-            docIdtoDoc.set(docId, refFields[docId] as Doc);
+        const docs = new Set<Doc>();
+        for (const { doc } of movements) {
+            if (!docs.has(doc)) docs.add(doc);
         }
-        // console.info('loadPresentation refFields', refFields, docIdtoDoc);
 
-        return docIdtoDoc;
+        return docs;
     };
 
     // returns undefined if the docView isn't open on the screen
-    getCollectionFFView = (docId: string) => {
-        const isInView = DocumentManager.Instance.getDocumentViewById(docId);
+    getCollectionFFView = (doc: Doc) => {
+        const isInView = DocumentManager.Instance.getDocumentView(doc);
         if (isInView) {
             return isInView.ComponentView as CollectionFreeFormView;
         }
     };
 
     // will open the doc in a tab then return the CollectionFFView that holds it
-    openTab = (docId: string, docIdtoDoc: Map<string, Doc>) => {
-        const doc = docIdtoDoc.get(docId);
-        if (doc == undefined) {
-            console.error(`docIdtoDoc did not contain docId ${docId}`);
+    openTab = (doc: Doc) => {
+        if (doc === undefined) {
+            console.error(`doc undefined`);
             return undefined;
         }
         // console.log('openTab', docId, doc);
@@ -149,13 +132,12 @@ export class ReplayMovements {
         document.Document._panY = panY;
     };
 
-    getFirstMovements = (movements: Movement[]): Map<string, Movement> => {
+    getFirstMovements = (movements: Movement[]): Map<Doc, Movement> => {
         if (movements === null) return new Map();
         // generate a set of all unique docIds
-        const docIdtoFirstMove = new Map();
+        const docIdtoFirstMove = new Map<Doc, Movement>();
         for (const move of movements) {
-            const { docId } = move;
-            if (!docIdtoFirstMove.has(docId)) docIdtoFirstMove.set(docId, move);
+            if (!docIdtoFirstMove.has(move.doc)) docIdtoFirstMove.set(move.doc, move);
         }
         return docIdtoFirstMove;
     };
@@ -165,7 +147,7 @@ export class ReplayMovements {
         Doc.UserDoc().presentationMode = 'none';
     };
 
-    public playMovements = (presentation: Presentation, docIdtoDoc: Map<string, Doc>, timeViewed: number = 0) => {
+    public playMovements = (presentation: Presentation, timeViewed: number = 0) => {
         // console.info('playMovements', presentation, timeViewed, docIdtoDoc);
 
         if (presentation.movements === null || presentation.movements.length === 0) {
@@ -183,13 +165,13 @@ export class ReplayMovements {
         const handleFirstMovements = () => {
             // if the first movement is a closed tab, open it
             const firstMovement = filteredMovements[0];
-            const isClosed = this.getCollectionFFView(firstMovement.docId) === undefined;
-            if (isClosed) this.openTab(firstMovement.docId, docIdtoDoc);
+            const isClosed = this.getCollectionFFView(firstMovement.doc) === undefined;
+            if (isClosed) this.openTab(firstMovement.doc);
 
             // for the open tabs, set it to the first move
             const docIdtoFirstMove = this.getFirstMovements(filteredMovements);
-            for (const [docId, firstMove] of docIdtoFirstMove) {
-                const colFFView = this.getCollectionFFView(docId);
+            for (const [doc, firstMove] of docIdtoFirstMove) {
+                const colFFView = this.getCollectionFFView(doc);
                 if (colFFView) this.zoomAndPan(firstMove, colFFView);
             }
         };
@@ -200,12 +182,12 @@ export class ReplayMovements {
             const timeDiff = movement.time - timeViewed * 1000;
 
             return setTimeout(() => {
-                const collectionFFView = this.getCollectionFFView(movement.docId);
+                const collectionFFView = this.getCollectionFFView(movement.doc);
                 if (collectionFFView) {
                     this.zoomAndPan(movement, collectionFFView);
                 } else {
                     // tab wasn't open - open it and play the movement
-                    const openedColFFView = this.openTab(movement.docId, docIdtoDoc);
+                    const openedColFFView = this.openTab(movement.doc);
                     console.log('openedColFFView', openedColFFView);
                     openedColFFView && this.zoomAndPan(movement, openedColFFView);
                 }
diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts
index 313c255a0..bfad93334 100644
--- a/src/client/util/SelectionManager.ts
+++ b/src/client/util/SelectionManager.ts
@@ -1,4 +1,3 @@
-import { ModalManager } from '@material-ui/core';
 import { action, observable, ObservableMap } from 'mobx';
 import { computedFn } from 'mobx-utils';
 import { Doc, Opt } from '../../fields/Doc';
@@ -64,8 +63,9 @@ export namespace SelectionManager {
     export function DeselectView(docView?: DocumentView): void {
         manager.DeselectView(docView);
     }
-    export function SelectView(docView: DocumentView, ctrlPressed: boolean): void {
-        manager.SelectView(docView, ctrlPressed);
+    export function SelectView(docView: DocumentView | undefined, ctrlPressed: boolean): void {
+        if (!docView) DeselectAll();
+        else manager.SelectView(docView, ctrlPressed);
     }
     export function SelectSchemaViewDoc(document: Opt<Doc>, deselectAllFirst?: boolean): void {
         if (deselectAllFirst) manager.DeselectAll();
diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx
index 3c05af4bb..a73eda04c 100644
--- a/src/client/util/SharingManager.tsx
+++ b/src/client/util/SharingManager.tsx
@@ -370,11 +370,10 @@ export class SharingManager extends React.Component<{}> {
         const docs = SelectionManager.Views().length > 1 ? SelectionManager.Views().map(docView => docView.props.Document) : [this.targetDoc];
         return (
             <span
-                className={'focus-span'}
+                className="focus-span"
                 title={title}
                 onClick={() => {
-                    let context: Opt<CollectionView>;
-                    if (this.targetDoc && this.targetDocView && docs.length === 1 && (context = this.targetDocView.props.ContainingCollectionView)) {
+                    if (this.targetDoc && this.targetDocView && docs.length === 1) {
                         DocumentManager.Instance.showDocument(this.targetDoc, { willZoomCentered: true });
                     }
                 }}
diff --git a/src/client/util/TrackMovements.ts b/src/client/util/TrackMovements.ts
index 4a2ccd706..2f16307b3 100644
--- a/src/client/util/TrackMovements.ts
+++ b/src/client/util/TrackMovements.ts
@@ -9,7 +9,7 @@ export type Movement = {
     panX: number;
     panY: number;
     scale: number;
-    docId: string;
+    doc: Doc;
 };
 
 export type Presentation = {
@@ -28,7 +28,7 @@ export class TrackMovements {
     private tracking: boolean;
     private absoluteStart: number;
     // instance variable for holding the FFViews and their disposers
-    private recordingFFViews: Map<string, IReactionDisposer> | null;
+    private recordingFFViews: Map<Doc, IReactionDisposer> | null;
     private tabChangeDisposeFunc: IReactionDisposer | null;
 
     // create static instance and getter for global use
@@ -55,33 +55,33 @@ export class TrackMovements {
         return this.currentPresentation.movements === null;
     }
 
-    private addRecordingFFView(doc: Doc, key: string = doc[Id]): void {
+    private addRecordingFFView(doc: Doc): void {
         // console.info('adding dispose func : docId', key, 'doc', doc);
 
         if (this.recordingFFViews === null) {
             console.warn('addFFView on null RecordingApi');
             return;
         }
-        if (this.recordingFFViews.has(key)) {
-            console.warn('addFFView : key already in map');
+        if (this.recordingFFViews.has(doc)) {
+            console.warn('addFFView : doc already in map');
             return;
         }
 
         const disposeFunc = reaction(
             () => ({ x: NumCast(doc.panX, -1), y: NumCast(doc.panY, -1), scale: NumCast(doc.viewScale, 0) }),
-            res => res.x !== -1 && res.y !== -1 && this.tracking && this.trackMovement(res.x, res.y, key, res.scale)
+            res => res.x !== -1 && res.y !== -1 && this.tracking && this.trackMovement(res.x, res.y, doc, res.scale)
         );
-        this.recordingFFViews?.set(key, disposeFunc);
+        this.recordingFFViews?.set(doc, disposeFunc);
     }
 
-    private removeRecordingFFView = (key: string) => {
+    private removeRecordingFFView = (doc: Doc) => {
         // console.info('removing dispose func : docId', key);
         if (this.recordingFFViews === null) {
             console.warn('removeFFView on null RecordingApi');
             return;
         }
-        this.recordingFFViews.get(key)?.();
-        this.recordingFFViews.delete(key);
+        this.recordingFFViews.get(doc)?.();
+        this.recordingFFViews.delete(doc);
     };
 
     // in the case where only one tab was changed (updates not across dashboards), set only one to true
@@ -90,15 +90,15 @@ export class TrackMovements {
 
         // so that the size comparisons are correct, we must filter to only the FFViews
         const isFFView = (doc: Doc) => doc && 'viewType' in doc && doc.viewType === 'freeform';
-        const tabbedFFViews = new Set<string>();
+        const tabbedFFViews = new Set<Doc>();
         for (const DashDoc of tabbedDocs) {
-            if (isFFView(DashDoc)) tabbedFFViews.add(DashDoc[Id]);
+            if (isFFView(DashDoc)) tabbedFFViews.add(DashDoc);
         }
 
         // new tab was added - need to add it
         if (tabbedFFViews.size > this.recordingFFViews.size) {
             for (const DashDoc of tabbedDocs) {
-                if (!this.recordingFFViews.has(DashDoc[Id])) {
+                if (!this.recordingFFViews.has(DashDoc)) {
                     if (isFFView(DashDoc)) {
                         this.addRecordingFFView(DashDoc);
 
@@ -110,9 +110,9 @@ export class TrackMovements {
         }
         // tab was removed - need to remove it from recordingFFViews
         else if (tabbedFFViews.size < this.recordingFFViews.size) {
-            for (const [key] of this.recordingFFViews) {
-                if (!tabbedFFViews.has(key)) {
-                    this.removeRecordingFFView(key);
+            for (const [doc] of this.recordingFFViews) {
+                if (!tabbedFFViews.has(doc)) {
+                    this.removeRecordingFFView(doc);
                     if (onlyOne) return;
                 }
             }
@@ -214,7 +214,7 @@ export class TrackMovements {
         }
     };
 
-    private trackMovement = (panX: number, panY: number, docId: string, scale: number = 0) => {
+    private trackMovement = (panX: number, panY: number, doc: Doc, scale: number = 0) => {
         // ensure we are recording to track
         if (!this.tracking) {
             console.error('[recordingApi.ts] trackMovements(): tracking is false');
@@ -231,7 +231,7 @@ export class TrackMovements {
         // get the time
         const time = new Date().getTime() - this.absoluteStart;
         // make new movement object
-        const movement: Movement = { time, panX, panY, scale, docId };
+        const movement: Movement = { time, panX, panY, scale, doc };
 
         // add that movement to the current presentation data's movement array
         this.currentPresentation.movements && this.currentPresentation.movements.push(movement);
diff --git a/src/client/views/DashboardView.tsx b/src/client/views/DashboardView.tsx
index 2b586b0e2..dee161931 100644
--- a/src/client/views/DashboardView.tsx
+++ b/src/client/views/DashboardView.tsx
@@ -109,17 +109,8 @@ export class DashboardView extends React.Component {
                     />
                 </div>
                 <div className="button-bar">
-                    <Button text="Cancel" borderRadius={10} hoverStyle={'gray'} fontSize={FontSize.SECONDARY} onClick={this.abortCreateNewDashboard} />
-                    <Button
-                        text="Create"
-                        borderRadius={10}
-                        backgroundColor={Colors.LIGHT_BLUE}
-                        hoverStyle={'darken'}
-                        fontSize={FontSize.SECONDARY}
-                        onClick={() => {
-                            this.createNewDashboard(this.newDashboardName!, this.newDashboardColor);
-                        }}
-                    />
+                    <Button text="Cancel" onClick={this.abortCreateNewDashboard} />
+                    <Button text="Create" onClick={() => this.createNewDashboard(this.newDashboardName!, this.newDashboardColor)} />
                 </div>
             </div>
         );
@@ -163,7 +154,7 @@ export class DashboardView extends React.Component {
                 <div className="dashboard-view">
                     <div className="left-menu">
                         <div className="new-dashboard-button">
-                            <Button icon={<FaPlus />} hoverStyle="darken" backgroundColor={Colors.LIGHT_BLUE} size={Size.MEDIUM} fontSize={FontSize.HEADER} text="New" onClick={() => this.setNewDashboardName('')} borderRadius={50} />
+                            <Button icon={<FaPlus />} size={Size.MEDIUM} text="New" onClick={() => this.setNewDashboardName('')} />
                         </div>
                         <div className={`text-button ${this.selectedDashboardGroup === DashboardGroup.MyDashboards && 'selected'}`} onClick={() => this.selectDashboardGroup(DashboardGroup.MyDashboards)}>
                             My Dashboards
@@ -196,7 +187,7 @@ export class DashboardView extends React.Component {
                                                 e.stopPropagation();
                                                 this.onContextMenu(dashboard, e);
                                             }}>
-                                            <IconButton isCircle={true} size={Size.SMALL} hoverStyle="gray" icon={<FontAwesomeIcon color="black" size="lg" icon="bars" />} />
+                                            <Button size={Size.SMALL} icon={<FontAwesomeIcon color="black" size="lg" icon="bars" />} />
                                         </div>
                                     </div>
                                 </div>
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index 9fc1487a0..a59189fd2 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -52,7 +52,6 @@ export function DocComponent<P extends DocComponentProps>() {
 interface ViewBoxBaseProps {
     Document: Doc;
     DataDoc?: Doc;
-    ContainingCollectionDoc: Opt<Doc>;
     DocumentView?: () => DocumentView;
     fieldKey: string;
     isSelected: (outsideReaction?: boolean) => boolean;
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 9ffbe083f..9a4aaf00e 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -33,6 +33,7 @@ import { ImageBox } from './nodes/ImageBox';
 import React = require('react');
 import { RichTextField } from '../../fields/RichTextField';
 import { LinkFollower } from '../util/LinkFollower';
+import _ = require('lodash');
 
 @observer
 export class DocumentDecorations extends React.Component<{ PanelWidth: number; PanelHeight: number; boundsLeft: number; boundsTop: number }, { value: string }> {
@@ -303,8 +304,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
         SelectionManager.DeselectAll();
     };
 
-    onSelectorClick = () => SelectionManager.Views()?.[0]?.props.ContainingCollectionView?.props.select(false);
-
+    onSelectorClick = () => SelectionManager.Views()?.[0]?.props.docViewPath?.().lastElement()?.select(false);
     /**
      * Handles setting up events when user clicks on the border radius editor
      * @param e PointerEvent
@@ -744,7 +744,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
             seldocview.props.hideDeleteButton ||
             seldocview.rootDoc.hideDeleteButton ||
             SelectionManager.Views().some(docView => {
-                const collectionAcl = docView.props.ContainingCollectionView ? GetEffectiveAcl(docView.props.ContainingCollectionDoc?.[DataSym]) : AclEdit;
+                const collectionAcl = docView.props.docViewPath()?.lastElement() ? GetEffectiveAcl(docView.props.docViewPath().lastElement().rootDoc[DataSym]) : AclEdit;
                 return docView.rootDoc.stayInCollection || (collectionAcl !== AclAdmin && collectionAcl !== AclEdit && GetEffectiveAcl(docView.rootDoc) !== AclAdmin);
             });
 
@@ -865,7 +865,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
                                     <div key="b" className={`documentDecorations-bottomResizer ${resizerScheme}`} onPointerDown={this.onPointerDown} onContextMenu={e => e.preventDefault()} />
                                     <div key="br" className={`documentDecorations-bottomRightResizer ${resizerScheme}`} onPointerDown={this.onPointerDown} onContextMenu={e => e.preventDefault()} />
 
-                                    {seldocview.props.renderDepth <= 1 || !seldocview.props.ContainingCollectionView ? null : topBtn('selector', 'arrow-alt-circle-up', undefined, this.onSelectorClick, 'tap to select containing document')}
+                                    {seldocview.props.renderDepth <= 1 || !seldocview.props.docViewPath().lastElement() ? null : topBtn('selector', 'arrow-alt-circle-up', undefined, this.onSelectorClick, 'tap to select containing document')}
                                 </>
                             )}
                             {useRounding && (
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index 0feccb742..13faae783 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -1010,14 +1010,12 @@ export class GestureOverlay extends Touchable<GestureOverlayProps> {
                 renderDepth={0}
                 styleProvider={returnEmptyString}
                 docViewPath={returnEmptyDoclist}
-                focus={DocUtils.DefaultFocus}
+                focus={emptyFunction}
                 whenChildContentsActiveChanged={emptyFunction}
                 bringToFront={emptyFunction}
                 docRangeFilters={returnEmptyFilter}
                 docFilters={returnEmptyFilter}
                 searchFilterDocs={returnEmptyDoclist}
-                ContainingCollectionView={undefined}
-                ContainingCollectionDoc={undefined}
             />
         );
     };
diff --git a/src/client/views/InkStrokeProperties.ts b/src/client/views/InkStrokeProperties.ts
index e6df0801c..156825f41 100644
--- a/src/client/views/InkStrokeProperties.ts
+++ b/src/client/views/InkStrokeProperties.ts
@@ -373,10 +373,11 @@ export class InkStrokeProperties {
 
     snapToAllCurves = (screenDragPt: { X: number; Y: number }, inkView: DocumentView, snapData: { nearestPt: { X: number; Y: number }; distance: number }, ink: InkData, controlIndex: number) => {
         const containingCollection = inkView.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView;
+        const containingDocView = inkView.props.CollectionFreeFormDocumentView?.().props.DocumentView?.();
         containingCollection?.childDocs
             .filter(doc => doc.type === DocumentType.INK)
             .forEach(doc => {
-                const testInkView = DocumentManager.Instance.getDocumentView(doc, containingCollection?.props.CollectionView);
+                const testInkView = DocumentManager.Instance.getDocumentView(doc, containingDocView);
                 const snapped = testInkView?.ComponentView?.snapPt?.(screenDragPt, doc === inkView.rootDoc ? this.excludeSelfSnapSegs(ink, controlIndex) : []);
                 if (snapped && snapped.distance < snapData.distance) {
                     const snappedInkPt = doc === inkView.rootDoc ? snapped.nearestPt : inkView.ComponentView?.ptFromScreen?.(testInkView?.ComponentView?.ptToScreen?.(snapped.nearestPt) ?? { X: 0, Y: 0 }); // convert from snapped ink coordinate system to dragged ink coordinate system by converting to/from screen space
diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx
index 976c8763e..69eec8456 100644
--- a/src/client/views/LightboxView.tsx
+++ b/src/client/views/LightboxView.tsx
@@ -266,8 +266,6 @@ export class LightboxView extends React.Component<LightboxViewProps> {
                             docFilters={this.docFilters}
                             docRangeFilters={returnEmptyFilter}
                             searchFilterDocs={returnEmptyDoclist}
-                            ContainingCollectionView={undefined}
-                            ContainingCollectionDoc={undefined}
                             addDocument={undefined}
                             removeDocument={undefined}
                             whenChildContentsActiveChanged={emptyFunction}
@@ -275,7 +273,7 @@ export class LightboxView extends React.Component<LightboxViewProps> {
                             pinToPres={TabDocView.PinDoc}
                             bringToFront={emptyFunction}
                             onBrowseClick={MainView.Instance.exploreMode}
-                            focus={DocUtils.DefaultFocus}
+                            focus={emptyFunction}
                         />
                     </GestureOverlay>
                 </div>
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 60459cf30..0384d925e 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -595,14 +595,12 @@ export class MainView extends React.Component {
                     PanelWidth={this.headerBarDocWidth}
                     PanelHeight={this.headerBarDocHeight}
                     renderDepth={0}
-                    focus={DocUtils.DefaultFocus}
+                    focus={emptyFunction}
                     whenChildContentsActiveChanged={emptyFunction}
                     bringToFront={emptyFunction}
                     docFilters={returnEmptyFilter}
                     docRangeFilters={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
-                    ContainingCollectionView={undefined}
-                    ContainingCollectionDoc={undefined}
                 />
             </div>
         );
@@ -626,14 +624,12 @@ export class MainView extends React.Component {
                     ScreenToLocalTransform={this._hideUI ? this.mainScreenToLocalXf : Transform.Identity}
                     PanelWidth={this.mainDocViewWidth}
                     PanelHeight={this.mainDocViewHeight}
-                    focus={DocUtils.DefaultFocus}
+                    focus={emptyFunction}
                     whenChildContentsActiveChanged={emptyFunction}
                     bringToFront={emptyFunction}
                     docFilters={returnEmptyFilter}
                     docRangeFilters={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
-                    ContainingCollectionView={undefined}
-                    ContainingCollectionDoc={undefined}
                     suppressSetHeight={true}
                     renderDepth={this._hideUI ? 0 : -1}
                 />
@@ -727,14 +723,12 @@ export class MainView extends React.Component {
                         renderDepth={0}
                         isContentActive={returnTrue}
                         scriptContext={CollectionDockingView.Instance?.props.Document}
-                        focus={DocUtils.DefaultFocus}
+                        focus={emptyFunction}
                         whenChildContentsActiveChanged={emptyFunction}
                         bringToFront={emptyFunction}
                         docFilters={returnEmptyFilter}
                         docRangeFilters={returnEmptyFilter}
                         searchFilterDocs={returnEmptyDoclist}
-                        ContainingCollectionView={undefined}
-                        ContainingCollectionDoc={undefined}
                     />
                 </div>
                 {this.docButtons}
@@ -758,7 +752,7 @@ export class MainView extends React.Component {
                     PanelHeight={this.leftMenuHeight}
                     renderDepth={0}
                     docViewPath={returnEmptyDoclist}
-                    focus={DocUtils.DefaultFocus}
+                    focus={emptyFunction}
                     styleProvider={DefaultStyleProvider}
                     isContentActive={returnTrue}
                     whenChildContentsActiveChanged={emptyFunction}
@@ -766,8 +760,6 @@ export class MainView extends React.Component {
                     docFilters={returnEmptyFilter}
                     docRangeFilters={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
-                    ContainingCollectionView={undefined}
-                    ContainingCollectionDoc={undefined}
                     scriptContext={this}
                 />
             </div>
@@ -900,13 +892,11 @@ export class MainView extends React.Component {
                     PanelWidth={this.leftMenuFlyoutWidth}
                     PanelHeight={this.leftMenuFlyoutHeight}
                     renderDepth={0}
-                    focus={DocUtils.DefaultFocus}
+                    focus={emptyFunction}
                     whenChildContentsActiveChanged={emptyFunction}
                     docFilters={returnEmptyFilter}
                     docRangeFilters={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
-                    ContainingCollectionView={undefined}
-                    ContainingCollectionDoc={undefined}
                 />
                 {['watching', 'recording'].includes(String(this.userDoc?.presentationMode) ?? '') ? <div style={{ border: '.5rem solid green', padding: '5px' }}>{StrCast(this.userDoc?.presentationMode)}</div> : <></>}
             </div>
diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx
index ec22128d4..bdc48d03a 100644
--- a/src/client/views/OverlayView.tsx
+++ b/src/client/views/OverlayView.tsx
@@ -1,4 +1,4 @@
-import { action, computed, observable, trace } from 'mobx';
+import { action, computed, observable } from 'mobx';
 import { observer } from 'mobx-react';
 import { computedFn } from 'mobx-utils';
 import * as React from 'react';
@@ -10,15 +10,13 @@ import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, retu
 import { DocUtils } from '../documents/Documents';
 import { DocumentType } from '../documents/DocumentTypes';
 import { DragManager } from '../util/DragManager';
-import { ScriptingGlobals } from '../util/ScriptingGlobals';
 import { Transform } from '../util/Transform';
 import { CollectionFreeFormLinksView } from './collections/collectionFreeForm/CollectionFreeFormLinksView';
 import { LightboxView } from './LightboxView';
 import { MainView } from './MainView';
 import { DocumentView } from './nodes/DocumentView';
 import './OverlayView.scss';
-import { ScriptingRepl } from './ScriptingRepl';
-import { DefaultStyleProvider, testDocProps } from './StyleProvider';
+import { DefaultStyleProvider } from './StyleProvider';
 
 export type OverlayDisposer = () => void;
 
@@ -223,7 +221,7 @@ export class OverlayView extends React.Component {
                             isDocumentActive={returnTrue}
                             isContentActive={returnTrue}
                             whenChildContentsActiveChanged={emptyFunction}
-                            focus={DocUtils.DefaultFocus}
+                            focus={emptyFunction}
                             styleProvider={DefaultStyleProvider}
                             docViewPath={returnEmptyDoclist}
                             addDocTab={d.type === DocumentType.PRES ? MainView.addDocTabFunc : returnFalse}
@@ -231,8 +229,6 @@ export class OverlayView extends React.Component {
                             docFilters={returnEmptyFilter}
                             docRangeFilters={returnEmptyFilter}
                             searchFilterDocs={returnEmptyDoclist}
-                            ContainingCollectionView={undefined}
-                            ContainingCollectionDoc={undefined}
                         />
                     </div>
                 );
diff --git a/src/client/views/Palette.tsx b/src/client/views/Palette.tsx
index 954529bc9..3ad28c418 100644
--- a/src/client/views/Palette.tsx
+++ b/src/client/views/Palette.tsx
@@ -1,12 +1,12 @@
-import { IReactionDisposer, observable, reaction } from "mobx";
-import { observer } from "mobx-react";
-import * as React from "react";
-import { Doc } from "../../fields/Doc";
-import { NumCast } from "../../fields/Types";
-import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, emptyPath } from "../../Utils";
-import { Transform } from "../util/Transform";
-import { DocumentView } from "./nodes/DocumentView";
-import "./Palette.scss";
+import { IReactionDisposer, observable, reaction } from 'mobx';
+import { observer } from 'mobx-react';
+import * as React from 'react';
+import { Doc } from '../../fields/Doc';
+import { NumCast } from '../../fields/Types';
+import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, emptyPath } from '../../Utils';
+import { Transform } from '../util/Transform';
+import { DocumentView } from './nodes/DocumentView';
+import './Palette.scss';
 
 export interface PaletteProps {
     x: number;
@@ -23,20 +23,20 @@ export default class Palette extends React.Component<PaletteProps> {
     componentDidMount = () => {
         this._selectedDisposer = reaction(
             () => NumCast(this.props.thumbDoc.selectedIndex),
-            (i) => this._selectedIndex = i,
+            i => (this._selectedIndex = i),
             { fireImmediately: true }
         );
-    }
+    };
 
     componentWillUnmount = () => {
         this._selectedDisposer?.();
-    }
+    };
 
     render() {
         return (
             <div className="palette-container" style={{ transform: `translate(${this.props.x}px, ${this.props.y}px)` }}>
                 <div className="palette-thumb" style={{ transform: `translate(${this.props.thumb[0] - this.props.x}px, ${this.props.thumb[1] - this.props.y}px)` }}>
-                    <div className="palette-thumbContent" style={{ transform: `translate(-${(this._selectedIndex * 50) + 10}px, 0px)` }}>
+                    <div className="palette-thumbContent" style={{ transform: `translate(-${this._selectedIndex * 50 + 10}px, 0px)` }}>
                         <DocumentView
                             Document={this.props.thumbDoc}
                             DataDoc={undefined}
@@ -59,12 +59,11 @@ export default class Palette extends React.Component<PaletteProps> {
                             docFilters={returnEmptyFilter}
                             docRangeFilters={returnEmptyFilter}
                             searchFilterDocs={returnEmptyDoclist}
-                            ContainingCollectionView={undefined}
-                            ContainingCollectionDoc={undefined} />
+                        />
                         <div className="palette-cover" style={{ transform: `translate(${Math.max(0, this._selectedIndex) * 50.75 + 23}px, 0px)` }}></div>
                     </div>
                 </div>
             </div>
         );
     }
-}
\ No newline at end of file
+}
diff --git a/src/client/views/PropertiesDocContextSelector.tsx b/src/client/views/PropertiesDocContextSelector.tsx
index 2c7da5931..93eec61f3 100644
--- a/src/client/views/PropertiesDocContextSelector.tsx
+++ b/src/client/views/PropertiesDocContextSelector.tsx
@@ -22,9 +22,9 @@ export class PropertiesDocContextSelector extends React.Component<PropertiesDocC
     @computed get _docs() {
         if (!this.props.DocView) return [];
         const target = this.props.DocView.props.Document;
-        const targetContext = this.props.DocView.props.ContainingCollectionDoc;
+        const targetContext = this.props.DocView.props.docViewPath().lastElement()?.rootDoc;
         const aliases = DocListCast(target.aliases);
-        const containerProtos = aliases.filter(alias => alias.context && alias.context instanceof Doc && Cast(alias.context, Doc, null) !== targetContext).reduce((set, alias) => set.add(Cast(alias.context, Doc, null)), new Set<Doc>());
+        const containerProtos = aliases.filter(alias => alias.context && alias.context instanceof Doc).reduce((set, alias) => set.add(Cast(alias.context, Doc, null)), new Set<Doc>());
         const containerSets = Array.from(containerProtos.keys()).map(container => DocListCast(container.aliases));
         const containers = containerSets.reduce((p, set) => {
             set.map(s => p.add(s));
@@ -42,6 +42,7 @@ export class PropertiesDocContextSelector extends React.Component<PropertiesDocC
         return doclayouts
             .filter(doc => !Doc.AreProtosEqual(doc, CollectionDockingView.Instance?.props.Document))
             .filter(doc => !Doc.IsSystem(doc))
+            .filter(doc => doc !== targetContext)
             .map(doc => ({ col: doc, target }));
     }
 
@@ -53,8 +54,21 @@ export class PropertiesDocContextSelector extends React.Component<PropertiesDocC
             col._panY = NumCast(target.y) + NumCast(target._height) / 2;
         }
         col.hidden = false;
-        this.props.addDocTab(col, (OpenWhere.toggle + ':' + OpenWhereMod.right) as OpenWhere);
-        setTimeout(() => DocFocusOrOpen(Doc.GetProto(this.props.DocView!.props.Document), col), 100);
+        //this.props.addDocTab(col, (OpenWhere.toggle + ':' + OpenWhereMod.right) as OpenWhere);
+        setTimeout(
+            () =>
+                this.props.DocView &&
+                DocFocusOrOpen(
+                    Doc.GetProto(this.props.DocView.props.Document),
+                    {
+                        //
+                        willZoomCentered: true,
+                        openLocation: (OpenWhere.toggle + ':' + OpenWhereMod.right) as OpenWhere,
+                    },
+                    col
+                ),
+            100
+        );
     };
 
     render() {
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index fbc7d7696..6582c3f2a 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -341,8 +341,6 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                         docFilters={returnEmptyFilter}
                         docRangeFilters={returnEmptyFilter}
                         searchFilterDocs={returnEmptyDoclist}
-                        ContainingCollectionDoc={undefined}
-                        ContainingCollectionView={undefined}
                         addDocument={returnFalse}
                         moveDocument={undefined}
                         removeDocument={returnFalse}
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index b950b4860..739d6d819 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -18,7 +18,7 @@ import { TreeSort } from './collections/TreeView';
 import { Colors } from './global/globalEnums';
 import { InkingStroke } from './InkingStroke';
 import { MainView } from './MainView';
-import { DocumentViewProps } from './nodes/DocumentView';
+import { DocumentViewProps, OpenWhere } from './nodes/DocumentView';
 import { FieldViewProps } from './nodes/FieldView';
 import { KeyValueBox } from './nodes/KeyValueBox';
 import { SliderBox } from './nodes/SliderBox';
@@ -295,7 +295,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
                 default:
                     return doc.z
                         ? `#9c9396  ${StrCast(doc?.boxShadow, '10px 10px 0.9vw')}` // if it's a floating doc, give it a big shadow
-                        : props?.ContainingCollectionDoc?._useClusters
+                        : props?.docViewPath().lastElement()?.rootDoc._useClusters
                         ? `${backgroundCol()} ${StrCast(doc.boxShadow, `0vw 0vw ${(lockedPosition() ? 100 : 50) / (docProps?.NativeDimScaling?.() || 1)}px`)}` // if it's just in a cluster, make the shadown roughly match the cluster border extent
                         : NumCast(doc.group, -1) !== -1
                         ? `gray ${StrCast(doc.boxShadow, `0vw 0vw ${(lockedPosition() ? 100 : 50) / (docProps?.NativeDimScaling?.() || 1)}px`)}` // if it's just in a cluster, make the shadown roughly match the cluster border extent
@@ -316,7 +316,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
             return undefined; // fixes problem with tree view elements getting pointer events when the tree view is not active
         case StyleProp.Decorations:
             const lock = () => {
-                if (props?.ContainingCollectionDoc?._viewType === CollectionViewType.Freeform) {
+                if (props?.docViewPath().lastElement()?.rootDoc?._viewType === CollectionViewType.Freeform) {
                     return doc?.pointerEvents !== 'none' ? null : (
                         <div className="styleProvider-lock" onClick={() => toggleLockedPosition(doc)}>
                             <FontAwesomeIcon icon={'lock'} style={{ color: 'red' }} size="lg" />
@@ -383,10 +383,7 @@ export function DashboardStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps
         return doc._viewType === CollectionViewType.Docking ? null : (
             <>
                 {DashboardToggleButton(doc, 'hidden', 'eye-slash', 'eye', () => {
-                    doc.hidden = doc.hidden ? undefined : true;
-                    if (!doc.hidden) {
-                        DocFocusOrOpen(doc, props?.ContainingCollectionDoc);
-                    }
+                    DocFocusOrOpen(doc, { toggleTarget: true, willPan: true, openLocation: OpenWhere.addRight }, props?.docViewPath().lastElement()?.rootDoc);
                 })}
             </>
         );
diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx
index 45db240a9..c5a501aa6 100644
--- a/src/client/views/TemplateMenu.tsx
+++ b/src/client/views/TemplateMenu.tsx
@@ -114,8 +114,6 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
                 <CollectionTreeView
                     Document={Doc.MyTemplates}
                     CollectionView={undefined}
-                    ContainingCollectionDoc={undefined}
-                    ContainingCollectionView={undefined}
                     styleProvider={DefaultStyleProvider}
                     setHeight={returnFalse}
                     docViewPath={returnEmptyDoclist}
diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx
index c0220f804..0e4556eb4 100644
--- a/src/client/views/collections/CollectionCarouselView.tsx
+++ b/src/client/views/collections/CollectionCarouselView.tsx
@@ -62,7 +62,6 @@ export class CollectionCarouselView extends CollectionSubView() {
                         onClick={this.onContentClick}
                         hideCaptions={showCaptions ? true : false}
                         renderDepth={this.props.renderDepth + 1}
-                        ContainingCollectionView={this.props.CollectionView}
                         LayoutTemplate={this.props.childLayoutTemplate}
                         LayoutTemplateString={this.props.childLayoutString}
                         Document={curDoc.layout}
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 225743748..2007f73aa 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -134,8 +134,6 @@ export class CollectionMenu extends AntimodeMenu<CollectionMenuProps> {
                     docFilters={returnEmptyFilter}
                     docRangeFilters={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
-                    ContainingCollectionView={undefined}
-                    ContainingCollectionDoc={undefined}
                 />
             </div>
         );
@@ -642,8 +640,8 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewMenu
                         key="float"
                         style={{
                             backgroundColor: this.props.docView.layoutDoc.z ? '121212' : undefined,
-                            pointerEvents: this.props.docView.props.ContainingCollectionDoc?._viewType !== CollectionViewType.Freeform ? 'none' : undefined,
-                            color: this.props.docView.props.ContainingCollectionDoc?._viewType !== CollectionViewType.Freeform ? 'dimgrey' : undefined,
+                            pointerEvents: this.props.docView.props.docViewPath().lastElement()?.rootDoc?._viewType !== CollectionViewType.Freeform ? 'none' : undefined,
+                            color: this.props.docView.props.docViewPath().lastElement()?.rootDoc?._viewType !== CollectionViewType.Freeform ? 'dimgrey' : undefined,
                         }}
                         onClick={undoBatch(() => this.props.docView.props.CollectionFreeFormDocumentView?.().float())}>
                         <FontAwesomeIcon icon={['fab', 'buffer']} size={'lg'} />
diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx
index aec0734b4..80e81bc1c 100644
--- a/src/client/views/collections/CollectionNoteTakingView.tsx
+++ b/src/client/views/collections/CollectionNoteTakingView.tsx
@@ -255,8 +255,6 @@ export class CollectionNoteTakingView extends CollectionSubView() {
                 hideTitle={this.props.childHideTitle?.()}
                 docRangeFilters={this.childDocRangeFilters}
                 searchFilterDocs={this.searchFilterDocs}
-                ContainingCollectionDoc={this.props.CollectionView?.props.Document}
-                ContainingCollectionView={this.props.CollectionView}
                 addDocument={this.props.addDocument}
                 moveDocument={this.props.moveDocument}
                 removeDocument={this.props.removeDocument}
@@ -632,8 +630,6 @@ export class CollectionNoteTakingView extends CollectionSubView() {
                         docFilters={this.props.docFilters}
                         docRangeFilters={this.props.docRangeFilters}
                         searchFilterDocs={this.props.searchFilterDocs}
-                        ContainingCollectionView={undefined}
-                        ContainingCollectionDoc={undefined}
                     />
                 </div>
             );
diff --git a/src/client/views/collections/CollectionPileView.tsx b/src/client/views/collections/CollectionPileView.tsx
index ba90ed8cd..fd9b0c0ce 100644
--- a/src/client/views/collections/CollectionPileView.tsx
+++ b/src/client/views/collections/CollectionPileView.tsx
@@ -30,7 +30,7 @@ export class CollectionPileView extends CollectionSubView() {
         // pileups are designed to go away when they are empty.
         this._disposers.selected = reaction(
             () => this.childDocs.length,
-            num => !num && this.props.ContainingCollectionView?.removeDocument(this.props.Document)
+            num => !num && this.props.CollectionFreeFormDocumentView?.().props.removeDocument?.(this.props.Document)
         );
     }
     componentWillUnmount() {
diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx
index bbd81d06d..22a575989 100644
--- a/src/client/views/collections/CollectionStackedTimeline.tsx
+++ b/src/client/views/collections/CollectionStackedTimeline.tsx
@@ -815,8 +815,6 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps>
                     whenChildContentsActiveChanged={emptyFunction}
                     focus={focusFunc}
                     isContentActive={returnFalse}
-                    ContainingCollectionView={undefined}
-                    ContainingCollectionDoc={undefined}
                     searchFilterDocs={returnEmptyDoclist}
                     docFilters={returnEmptyFilter}
                     docRangeFilters={returnEmptyFilter}
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index a85ee0e02..67f5dc9f4 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -346,8 +346,6 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
                 hideTitle={this.props.childHideTitle?.()}
                 docRangeFilters={this.childDocRangeFilters}
                 searchFilterDocs={this.searchFilterDocs}
-                ContainingCollectionDoc={this.props.CollectionView?.props.Document}
-                ContainingCollectionView={this.props.CollectionView}
                 xPadding={NumCast(this.layoutDoc._childXPadding, this.props.childXPadding)}
                 yPadding={NumCast(this.layoutDoc._childYPadding, this.props.childYPadding)}
                 addDocument={this.props.addDocument}
@@ -678,8 +676,6 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
                         docFilters={this.props.docFilters}
                         docRangeFilters={this.props.docRangeFilters}
                         searchFilterDocs={this.props.searchFilterDocs}
-                        ContainingCollectionView={undefined}
-                        ContainingCollectionDoc={undefined}
                     />
                 </div>
             );
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 4a11e8f0b..92932fb61 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -164,7 +164,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
             this.props.removeDocument?.(doc);
             if (ind > 0) {
                 FormattedTextBox.SelectOnLoad = prev[Id];
-                DocumentManager.Instance.getDocumentView(prev, this.props.CollectionView)?.select(false);
+                DocumentManager.Instance.getDocumentView(prev, this.props.DocumentView?.())?.select(false);
             }
             return true;
         }
@@ -242,8 +242,6 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
                 docFilters={returnEmptyFilter}
                 docRangeFilters={returnEmptyFilter}
                 searchFilterDocs={returnEmptyDoclist}
-                ContainingCollectionDoc={this.doc}
-                ContainingCollectionView={this.props.CollectionView}
                 addDocument={returnFalse}
                 moveDocument={returnFalse}
                 removeDocument={returnFalse}
@@ -272,7 +270,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
             this,
             this.doc,
             this.props.DataDoc,
-            this.props.ContainingCollectionDoc,
+            undefined,
             undefined,
             addDoc,
             this.remove,
@@ -331,10 +329,10 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
                     isDocumentActive={returnTrue}
                     addDocument={this.props.addDocument}
                     moveDocument={this.props.moveDocument}
+                    removeDocument={this.props.removeDocument}
                     addDocTab={this.props.addDocTab}
                     pinToPres={emptyFunction}
                     rootSelected={this.props.isSelected}
-                    removeDocument={this.props.removeDocument}
                     ScreenToLocalTransform={Transform.Identity}
                     PanelWidth={this.return35}
                     PanelHeight={this.return35}
@@ -347,8 +345,6 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
                     docFilters={this.props.docFilters}
                     docRangeFilters={this.props.docRangeFilters}
                     searchFilterDocs={this.props.searchFilterDocs}
-                    ContainingCollectionView={undefined}
-                    ContainingCollectionDoc={undefined}
                 />
             </div>
         );
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index bc25ad43a..53fbcc3cc 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -279,7 +279,10 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
             CollectionView: this,
         };
         return (
-            <div className={'collectionView'} onContextMenu={this.onContextMenu} style={{ pointerEvents: this.props.ContainingCollectionDoc?._viewType === CollectionViewType.Freeform && this.rootDoc._lockedPosition ? 'none' : undefined }}>
+            <div
+                className="collectionView"
+                onContextMenu={this.onContextMenu}
+                style={{ pointerEvents: this.props.DocumentView?.()?.props.docViewPath().lastElement()?.rootDoc?._viewType === CollectionViewType.Freeform && this.rootDoc._lockedPosition ? 'none' : undefined }}>
                 {this.showIsTagged()}
                 {this.renderSubView(this.collectionViewType, props)}
             </div>
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 458712999..ef8f395c5 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -425,8 +425,6 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                     hideTitle={this.props.keyValue}
                     Document={this._document}
                     DataDoc={!Doc.AreProtosEqual(this._document[DataSym], this._document) ? this._document[DataSym] : undefined}
-                    ContainingCollectionView={undefined}
-                    ContainingCollectionDoc={undefined}
                     onBrowseClick={MainView.Instance.exploreMode}
                     waitForDoubleClickToClick={MainView.Instance.waitForDoubleClick}
                     isContentActive={returnTrue}
@@ -580,8 +578,6 @@ export class TabMinimapView extends React.Component<TabMinimapViewProps> {
                 <CollectionFreeFormView
                     Document={this.props.document}
                     CollectionView={undefined}
-                    ContainingCollectionView={undefined}
-                    ContainingCollectionDoc={undefined}
                     docViewPath={returnEmptyDoclist}
                     childLayoutTemplate={this.childLayoutTemplate} // bcz: Ugh .. should probably be rendering a CollectionView or the minimap should be part of the collectionFreeFormView to avoid having to set stuff like this.
                     noOverlay={true} // don't render overlay Docs since they won't scale
@@ -603,7 +599,7 @@ export class TabMinimapView extends React.Component<TabMinimapViewProps> {
                     ScreenToLocalTransform={Transform.Identity}
                     renderDepth={0}
                     whenChildContentsActiveChanged={emptyFunction}
-                    focus={DocUtils.DefaultFocus}
+                    focus={emptyFunction}
                     styleProvider={TabMinimapView.miniStyleProvider}
                     addDocTab={this.props.addDocTab}
                     pinToPres={TabDocView.PinDoc}
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 75e76019e..8b1dfc767 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -42,7 +42,7 @@ export interface TreeViewProps {
     prevSibling?: Doc;
     document: Doc;
     dataDoc?: Doc;
-    containerCollection: Doc;
+    treeViewParent: Doc;
     renderDepth: number;
     dropAction: dropActionType;
     addDocTab: (doc: Doc, where: OpenWhere) => boolean;
@@ -143,7 +143,7 @@ export class TreeView extends React.Component<TreeViewProps> {
         return this.validExpandViewTypes.includes(StrCast(this.doc.treeViewExpandedView)) ? StrCast(this.doc.treeViewExpandedView) : this.defaultExpandedView;
     }
     @computed get MAX_EMBED_HEIGHT() {
-        return NumCast(this.props.containerCollection.maxEmbedHeight, 200);
+        return NumCast(this.props.treeViewParent.maxEmbedHeight, 200);
     }
     @computed get dataDoc() {
         return this.props.document.treeViewChildrenOnRoot ? this.doc : this.doc[DataSym];
@@ -194,7 +194,7 @@ export class TreeView extends React.Component<TreeViewProps> {
         const ind = this.dataDoc[key].indexOf(doc);
 
         const res = (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && Doc.RemoveDocFromList(this.dataDoc, key, doc), true);
-        res && ind > 0 && DocumentManager.Instance.getDocumentView(this.dataDoc[key][ind - 1], this.props.treeView.props.CollectionView)?.select(false);
+        res && ind > 0 && DocumentManager.Instance.getDocumentView(this.dataDoc[key][ind - 1], this.props.treeView.props.DocumentView?.())?.select(false);
         return res;
     };
 
@@ -385,7 +385,7 @@ export class TreeView extends React.Component<TreeViewProps> {
         };
         const addDoc = inside ? localAdd : parentAddDoc;
         const move = (!dropAction || dropAction === 'proto' || dropAction === 'move' || dropAction === 'same') && moveDocument;
-        const canAdd = (!this.props.treeView.outlineMode && !StrCast((inside ? this.props.document : this.props.containerCollection)?.freezeChildren).includes('add')) || forceAdd;
+        const canAdd = (!this.props.treeView.outlineMode && !StrCast((inside ? this.props.document : this.props.treeViewParent)?.freezeChildren).includes('add')) || forceAdd;
         if (canAdd) {
             this.props.parentTreeView instanceof TreeView && (this.props.parentTreeView.dropping = true);
             const res = UndoManager.RunInTempBatch(() => droppedDocuments.reduce((added, d) => (move ? move(d, undefined, addDoc) || (dropAction === 'proto' ? addDoc(d) : false) : addDoc(d)) || added, false));
@@ -406,7 +406,7 @@ export class TreeView extends React.Component<TreeViewProps> {
     getTransform = () => this.refTransform(this._tref.current);
     embeddedPanelWidth = () => this.props.panelWidth() / (this.props.treeView.props.NativeDimScaling?.() || 1);
     embeddedPanelHeight = () => {
-        const layoutDoc = (temp => temp && Doc.expandTemplateLayout(temp, this.props.document, ''))(this.props.treeView.props.childLayoutTemplate?.()) || this.layoutDoc;
+        const layoutDoc = (temp => temp && Doc.expandTemplateLayout(temp, this.props.document))(this.props.treeView.props.childLayoutTemplate?.()) || this.layoutDoc;
         return Math.min(
             layoutDoc[HeightSym](),
             this.MAX_EMBED_HEIGHT,
@@ -416,7 +416,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                 return layoutDoc._fitWidth
                     ? !Doc.NativeHeight(layoutDoc)
                         ? NumCast(layoutDoc._height)
-                        : Math.min((this.embeddedPanelWidth() * NumCast(layoutDoc.scrollHeight, Doc.NativeHeight(layoutDoc))) / (Doc.NativeWidth(layoutDoc) || NumCast(this.props.containerCollection._height)))
+                        : Math.min((this.embeddedPanelWidth() * NumCast(layoutDoc.scrollHeight, Doc.NativeHeight(layoutDoc))) / (Doc.NativeWidth(layoutDoc) || NumCast(this.props.treeViewParent._height)))
                     : (this.embeddedPanelWidth() * layoutDoc[HeightSym]()) / layoutDoc[WidthSym]();
             })()
         );
@@ -452,7 +452,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                     this,
                     doc,
                     undefined,
-                    this.props.containerCollection,
+                    this.props.treeViewParent,
                     this.props.prevSibling,
                     addDoc,
                     remDoc,
@@ -596,7 +596,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                                   this,
                                   this.layoutDoc,
                                   this.dataDoc,
-                                  this.props.containerCollection,
+                                  this.props.treeViewParent,
                                   this.props.prevSibling,
                                   addDoc,
                                   remDoc,
@@ -656,7 +656,7 @@ export class TreeView extends React.Component<TreeViewProps> {
             this.onCheckedClick?.script.run(
                 {
                     this: this.doc.isTemplateForField && this.props.dataDoc ? this.props.dataDoc : this.doc,
-                    heading: this.props.containerCollection.title,
+                    heading: this.props.treeViewParent.title,
                     checked: this.doc.treeViewChecked === 'check' ? 'x' : this.doc.treeViewChecked === 'x' ? 'remove' : 'check',
                     containingTreeView: this.props.treeView.props.Document,
                 },
@@ -724,9 +724,11 @@ export class TreeView extends React.Component<TreeViewProps> {
     };
 
     @observable headerEleWidth = 0;
-    @computed get headerElements() {
+    @computed get titleButtons() {
+        const customHeaderButtons = this.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.Decorations);
         return this.props.treeViewHideHeaderFields() || this.doc.treeViewHideHeaderFields ? null : (
             <>
+                {customHeaderButtons} {/* e.g.,. hide button is set by dashboardStyleProvider */}
                 {this.doc.hideContextMenu ? null : (
                     <FontAwesomeIcon
                         title="context menu"
@@ -779,9 +781,7 @@ export class TreeView extends React.Component<TreeViewProps> {
         return StrListCast(this.doc.childContextMenuLabels).map((label, i) => ({ script: customScripts[i], filter: customFilters[i], icon: icons[i], label }));
     };
 
-    onChildClick = () => {
-        return this.props.onChildClick?.() ?? (this._editTitleScript?.() || ScriptField.MakeFunction(`DocFocusOrOpen(self)`)!);
-    };
+    onChildClick = () => this.props.onChildClick?.() ?? (this._editTitleScript?.() || ScriptField.MakeFunction(`DocFocusOrOpen(self)`)!);
 
     onChildDoubleClick = () => ScriptCast(this.props.treeView.Document.treeViewChildDoubleClick, !this.props.treeView.outlineMode ? this._openScript?.() : null);
 
@@ -906,7 +906,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                 styleProvider={this.titleStyleProvider}
                 enableDragWhenActive={true}
                 onClickScriptDisable="never" // tree docViews have a script to show fields, etc.
-                docViewPath={returnEmptyDoclist}
+                docViewPath={this.props.treeView.props.docViewPath}
                 treeViewDoc={this.props.treeView.props.Document}
                 addDocument={undefined}
                 addDocTab={this.props.addDocTab}
@@ -937,12 +937,8 @@ export class TreeView extends React.Component<TreeViewProps> {
                 docFilters={returnEmptyFilter}
                 docRangeFilters={returnEmptyFilter}
                 searchFilterDocs={returnEmptyDoclist}
-                ContainingCollectionView={this.props.treeView.props.CollectionView}
-                ContainingCollectionDoc={this.props.treeView.props.Document}
             />
         );
-
-        const buttons = this.props.styleProvider?.(this.doc, { ...this.props.treeView.props, ContainingCollectionDoc: this.props.parentTreeView?.doc }, StyleProp.Decorations + (Doc.IsSystem(this.props.containerCollection) ? ':afterHeader' : ''));
         return (
             <>
                 <div
@@ -958,8 +954,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                     {view}
                 </div>
                 <div className="treeView-rightButtons" ref={action((r: any) => r && (this.headerEleWidth = r.getBoundingClientRect().width))}>
-                    {buttons} {/* hide and lock buttons */}
-                    {this.headerElements}
+                    {this.titleButtons}
                 </div>
             </>
         );
@@ -1017,8 +1012,6 @@ export class TreeView extends React.Component<TreeViewProps> {
                     docFilters={returnEmptyFilter}
                     docRangeFilters={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
-                    ContainingCollectionDoc={this.props.containerCollection}
-                    ContainingCollectionView={undefined}
                     addDocument={this.props.addDocument}
                     moveDocument={this.move}
                     removeDocument={this.props.removeDoc}
@@ -1131,7 +1124,7 @@ export class TreeView extends React.Component<TreeViewProps> {
         childDocs: Doc[],
         treeView: CollectionTreeView,
         parentTreeView: CollectionTreeView | TreeView | undefined,
-        containerCollection: Doc,
+        treeViewParent: Doc,
         dataDoc: Doc | undefined,
         parentCollectionDoc: Doc | undefined,
         containerPrevSibling: Doc | undefined,
@@ -1162,19 +1155,19 @@ export class TreeView extends React.Component<TreeViewProps> {
         hierarchyIndex?: number[],
         renderCount?: number
     ) {
-        const viewSpecScript = Cast(containerCollection.viewSpecScript, ScriptField);
+        const viewSpecScript = Cast(treeViewParent.viewSpecScript, ScriptField);
         if (viewSpecScript) {
             childDocs = childDocs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result);
         }
 
-        const docs = TreeView.sortDocs(childDocs, StrCast(containerCollection.treeViewSortCriterion, TreeSort.None));
+        const docs = TreeView.sortDocs(childDocs, StrCast(treeViewParent.treeViewSortCriterion, TreeSort.None));
         const rowWidth = () => panelWidth() - treeBulletWidth() * (treeView.props.NativeDimScaling?.() || 1);
         const treeViewRefs = new Map<Doc, TreeView | undefined>();
         return docs
             .filter(child => child instanceof Doc)
             .map((child, i) => {
                 if (renderCount && i > renderCount) return null;
-                const pair = Doc.GetLayoutDataDocPair(containerCollection, dataDoc, child);
+                const pair = Doc.GetLayoutDataDocPair(treeViewParent, dataDoc, child);
                 if (!pair.layout || pair.data instanceof Promise) {
                     return null;
                 }
@@ -1192,10 +1185,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                     }
                 };
                 const indent = i === 0 ? undefined : (editTitle: boolean) => dentDoc(editTitle, docs[i - 1], undefined, treeViewRefs.get(docs[i - 1]));
-                const outdent =
-                    parentCollectionDoc?._viewType !== CollectionViewType.Tree
-                        ? undefined
-                        : (editTitle: boolean) => dentDoc(editTitle, parentCollectionDoc, containerPrevSibling, parentTreeView instanceof TreeView ? parentTreeView.props.parentTreeView : undefined);
+                const outdent = !parentCollectionDoc ? undefined : (editTitle: boolean) => dentDoc(editTitle, parentCollectionDoc, containerPrevSibling, parentTreeView instanceof TreeView ? parentTreeView.props.parentTreeView : undefined);
                 const addDocument = (doc: Doc | Doc[], relativeTo?: Doc, before?: boolean) => add(doc, relativeTo ?? docs[i], before !== undefined ? before : false);
                 const childLayout = Doc.Layout(pair.layout);
                 const rowHeight = () => {
@@ -1208,7 +1198,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                         ref={r => treeViewRefs.set(child, r ? r : undefined)}
                         document={pair.layout}
                         dataDoc={pair.data}
-                        containerCollection={containerCollection}
+                        treeViewParent={treeViewParent}
                         prevSibling={docs[i]}
                         // TODO: [AL] add these
                         hierarchyIndex={hierarchyIndex ? [...hierarchyIndex, i + 1] : undefined}
@@ -1220,7 +1210,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                         onCheckedClick={onCheckedClick}
                         onChildClick={onChildClick}
                         renderDepth={renderDepth}
-                        removeDoc={StrCast(containerCollection.freezeChildren).includes('remove') ? undefined : remove}
+                        removeDoc={StrCast(treeViewParent.freezeChildren).includes('remove') ? undefined : remove}
                         addDocument={addDocument}
                         styleProvider={styleProvider}
                         panelWidth={rowWidth}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 7ae7be3c8..a3f5e73fb 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -262,7 +262,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     };
     selectDocuments = (docs: Doc[]) => {
         SelectionManager.DeselectAll();
-        docs.map(doc => DocumentManager.Instance.getDocumentView(doc, this.props.CollectionView)).map(dv => dv && SelectionManager.SelectView(dv, true));
+        docs.map(doc => DocumentManager.Instance.getDocumentView(doc, this.props.DocumentView?.())).map(dv => dv && SelectionManager.SelectView(dv, true));
     };
     addDocument = (newBox: Doc | Doc[]) => {
         let retVal = false;
@@ -319,7 +319,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         // glr: freeform transform speed can be set by adjusting presTransition field - needs a way of knowing when presentation is not active...
         if (didMove) {
             const focusTime = options?.instant ? 0 : options.zoomTime ?? 500;
-            options.zoomScale && scale && (this.Document[this.scaleFieldKey] = scale);
+            (options.zoomScale || options.willZoomCentered) && scale && (this.Document[this.scaleFieldKey] = scale);
             this.setPan(panX, panY, focusTime, true); // docs that are floating in their collection can't be panned to from their collection -- need to propagate the pan to a parent freeform somehow
             return focusTime;
         }
@@ -378,19 +378,17 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                 1
             );
             if (sorted.length && refDoc && NumCast(sorted[0].layout.y) < NumCast(refDoc.y)) {
-                const topIndexed = NumCast(refDoc.y) < NumCast(sorted[0].layout.y) + NumCast(sorted[0].layout._height);
+                const topIndexed = NumCast(refDoc.y) < NumCast(sorted[0].layout.y) + NumCast(sorted[0].layout._height) / 2;
                 const deltay = sorted.length > 1 ? NumCast(refDoc.y) - (NumCast(sorted[0].layout.y) + (topIndexed ? 0 : NumCast(sorted[0].layout._height))) : 0;
                 const deltax = sorted.length > 1 ? NumCast(refDoc.x) - NumCast(sorted[0].layout.x) : 0;
 
                 let lastx = NumCast(refDoc.x);
                 let lasty = NumCast(refDoc.y) + (topIndexed ? 0 : NumCast(refDoc._height));
-                setTimeout(
-                    action(() =>
-                        sorted.slice(1).forEach((pair, i) => {
-                            lastx = pair.layout.x = lastx + deltax;
-                            lasty = (pair.layout.y = lasty + deltay) + (topIndexed ? 0 : NumCast(pair.layout._height));
-                        })
-                    )
+                runInAction(() =>
+                    sorted.slice(1).forEach((pair, i) => {
+                        lastx = pair.layout.x = lastx + deltax;
+                        lasty = (pair.layout.y = lasty + deltay) + (topIndexed ? 0 : NumCast(pair.layout._height));
+                    })
                 );
             }
         }
@@ -464,7 +462,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
             const ptsParent = e instanceof PointerEvent ? e : e.targetTouches.item(0);
             if (ptsParent) {
                 const eles = this.childLayoutPairs.map(pair => pair.layout).filter(cd => (this.props.Document._useClusters ? NumCast(cd.cluster) : NumCast(cd.group, -1)) === cluster);
-                const clusterDocs = eles.map(ele => DocumentManager.Instance.getDocumentView(ele, this.props.CollectionView)!);
+                const clusterDocs = eles.map(ele => DocumentManager.Instance.getDocumentView(ele, this.props.DocumentView?.())!);
                 const { left, top } = clusterDocs[0].getBounds() || { left: 0, top: 0 };
                 const de = new DragManager.DocumentDragData(eles, e.ctrlKey || e.altKey ? 'alias' : undefined);
                 de.moveDocument = this.props.moveDocument;
@@ -872,7 +870,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         const eraserMax = { X: Math.max(lastPoint.X, currPoint.X), Y: Math.max(lastPoint.Y, currPoint.Y) };
 
         return this.childDocs
-            .map(doc => DocumentManager.Instance.getDocumentView(doc, this.props.CollectionView))
+            .map(doc => DocumentManager.Instance.getDocumentView(doc, this.props.DocumentView?.()))
             .filter(inkView => inkView?.ComponentView instanceof InkingStroke)
             .map(inkView => ({ inkViewBounds: inkView!.getBounds(), inkStroke: inkView!.ComponentView as InkingStroke, inkView: inkView! }))
             .filter(
@@ -966,7 +964,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         this.childDocs
             .filter(doc => doc.type === DocumentType.INK && !doc.dontIntersect)
             .forEach(doc => {
-                const otherInk = DocumentManager.Instance.getDocumentView(doc, this.props.CollectionView)?.ComponentView as InkingStroke;
+                const otherInk = DocumentManager.Instance.getDocumentView(doc, this.props.DocumentView?.())?.ComponentView as InkingStroke;
                 const { inkData: otherInkData } = otherInk?.inkScaledData() ?? { inkData: [] };
                 const otherScreenPts = otherInkData.map(point => otherInk.ptToScreen(point));
                 const otherCtrlPts = otherScreenPts.map(spt => (ink.ComponentView as InkingStroke).ptFromScreen(spt));
@@ -1121,7 +1119,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
 
     @action
     nudge = (x: number, y: number, nudgeTime: number = 500) => {
-        if (this.props.ContainingCollectionDoc?._viewType !== CollectionViewType.Freeform || this.props.ContainingCollectionDoc._panX !== undefined) {
+        const collectionDoc = this.props.docViewPath().lastElement().rootDoc;
+        if (collectionDoc?._viewType !== CollectionViewType.Freeform || collectionDoc._panX !== undefined) {
             this.setPan(
                 NumCast(this.layoutDoc[this.panXFieldKey]) + ((this.props.PanelWidth() / 2) * x) / this.zoomScaling(), // nudge x,y as a function of panel dimension and scale
                 NumCast(this.layoutDoc[this.panYFieldKey]) + ((this.props.PanelHeight() / 2) * -y) / this.zoomScaling(),
@@ -1256,8 +1255,6 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                 replica={entry.replica}
                 suppressSetHeight={this.layoutEngine ? true : false}
                 renderCutoffProvider={this.renderCutoffProvider}
-                ContainingCollectionView={this.props.CollectionView}
-                ContainingCollectionDoc={this.props.Document}
                 CollectionFreeFormView={this}
                 LayoutTemplate={childLayout.z ? undefined : this.props.childLayoutTemplate}
                 LayoutTemplateString={childLayout.z ? undefined : this.props.childLayoutString}
@@ -1779,7 +1776,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                 const lines = text.split('\n');
                 const height = 30 + 15 * lines.length;
 
-                this.props.ContainingCollectionView?.addDocument(Docs.Create.TextDocument(text, { title: lines[0], x: NumCast(this.layoutDoc.x) + NumCast(this.layoutDoc._width) + 20, y: NumCast(this.layoutDoc.y), _width: 200, _height: height }));
+                this.addDocument(Docs.Create.TextDocument(text, { title: lines[0], x: NumCast(this.layoutDoc.x) + NumCast(this.layoutDoc._width) + 20, y: NumCast(this.layoutDoc.y), _width: 200, _height: height }));
             }
         }
     };
diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
index c7d9b6619..97eed7752 100644
--- a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
+++ b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
@@ -209,8 +209,6 @@ export class CollectionLinearView extends CollectionSubView() {
                     docFilters={this.props.docFilters}
                     docRangeFilters={this.props.docRangeFilters}
                     searchFilterDocs={this.props.searchFilterDocs}
-                    ContainingCollectionView={undefined}
-                    ContainingCollectionDoc={undefined}
                     hideResizeHandles={true}
                 />
             </div>
@@ -251,8 +249,7 @@ export class CollectionLinearView extends CollectionSubView() {
                                 self: this.rootDoc,
                                 _readOnly_: false,
                                 scriptContext: this.props.scriptContext,
-                                thisContainer: this.props.ContainingCollectionDoc,
-                                documentView: this.props.docViewPath().lastElement(),
+                                documentView: this.props.DocumentView?.(),
                             });
                             this.layoutDoc.linearViewIsExpanded = this.addMenuToggle.current!.checked;
                         })}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index b73b1d779..78d3d1b6e 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -262,8 +262,6 @@ export class CollectionMulticolumnView extends CollectionSubView() {
                 docFilters={this.childDocFilters}
                 docRangeFilters={this.childDocRangeFilters}
                 searchFilterDocs={this.searchFilterDocs}
-                ContainingCollectionDoc={this.props.CollectionView?.props.Document}
-                ContainingCollectionView={this.props.CollectionView}
                 dontRegisterView={this.props.dontRegisterView}
                 addDocument={this.props.addDocument}
                 moveDocument={this.props.moveDocument}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
index 0cca83803..4d61dc272 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
@@ -261,8 +261,6 @@ export class CollectionMultirowView extends CollectionSubView() {
                 docFilters={this.childDocFilters}
                 docRangeFilters={this.childDocRangeFilters}
                 searchFilterDocs={this.searchFilterDocs}
-                ContainingCollectionDoc={this.props.CollectionView?.props.Document}
-                ContainingCollectionView={this.props.CollectionView}
                 dontRegisterView={this.props.dontRegisterView}
                 addDocument={this.props.addDocument}
                 moveDocument={this.props.moveDocument}
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index fd9bcf681..6d5a73e55 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -793,7 +793,7 @@ export class CollectionSchemaView extends CollectionSubView() {
                                 fitContentsToBox={returnTrue}
                                 dontCenter={'y'}
                                 onClickScriptDisable="always"
-                                focus={DocUtils.DefaultFocus}
+                                focus={emptyFunction}
                                 renderDepth={this.props.renderDepth + 1}
                                 rootSelected={this.rootSelected}
                                 PanelWidth={this.previewWidthFunc}
@@ -806,8 +806,6 @@ export class CollectionSchemaView extends CollectionSubView() {
                                 searchFilterDocs={this.searchFilterDocs}
                                 styleProvider={DefaultStyleProvider}
                                 docViewPath={returnEmptyDoclist}
-                                ContainingCollectionDoc={this.props.CollectionView?.props.Document}
-                                ContainingCollectionView={this.props.CollectionView}
                                 moveDocument={this.props.moveDocument}
                                 addDocument={this.addRow}
                                 removeDocument={this.props.removeDocument}
@@ -849,8 +847,6 @@ class CollectionSchemaViewDocs extends React.Component<CollectionSchemaViewDocsP
                                 Document={doc}
                                 DataDoc={dataDoc}
                                 renderDepth={this.props.schema.props.renderDepth + 1}
-                                ContainingCollectionView={this.props.schema.props.CollectionView}
-                                ContainingCollectionDoc={this.props.schema.Document}
                                 PanelWidth={this.tableWidthFunc}
                                 PanelHeight={this.rowHeightFunc}
                                 styleProvider={DefaultStyleProvider}
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 2defaae00..856537927 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -29,7 +29,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
     }
 
     @computed get schemaDoc() {
-        return this.props.ContainingCollectionDoc!;
+        return this.props.DocumentView?.().props.docViewPath().lastElement()?.rootDoc;
     }
 
     @computed get rowIndex() {
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 13e45963e..5f8ffe8b0 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -28,8 +28,6 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
             searchFilterDocs: returnEmptyDoclist,
             styleProvider: DefaultStyleProvider,
             docViewPath: returnEmptyDoclist,
-            ContainingCollectionView: undefined,
-            ContainingCollectionDoc: undefined,
             fieldKey: this.props.fieldKey,
             rootSelected: returnFalse,
             isSelected: returnFalse,
diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx
index 29e7cd3ad..d703c9595 100644
--- a/src/client/views/linking/LinkMenuItem.tsx
+++ b/src/client/views/linking/LinkMenuItem.tsx
@@ -44,25 +44,10 @@ export async function StartLinkTargetsDrag(dragEle: HTMLElement, docView: Docume
         }
 
         const dragData = new DragManager.DocumentDragData(moddrag.length ? moddrag : draggedDocs);
-        dragData.moveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean): boolean => {
-            docView.props.removeDocument?.(doc);
-            addDocument(doc);
-            return true;
-        };
-        const containingView = docView.props.ContainingCollectionView;
-        const finishDrag = (e: DragManager.DragCompleteEvent) =>
-            e.docDragData &&
-            (e.docDragData.droppedDocuments = dragData.draggedDocuments.reduce((droppedDocs, d) => {
-                const dvs = DocumentManager.Instance.getDocumentViews(d).filter(dv => dv.props.ContainingCollectionView === containingView);
-                if (dvs.length) {
-                    dvs.forEach(dv => droppedDocs.push(dv.props.Document));
-                } else {
-                    droppedDocs.push(Doc.MakeAlias(d));
-                }
-                return droppedDocs;
-            }, [] as Doc[]));
+        dragData.canEmbed = true;
+        dragData.moveDocument = (docView.props.docViewPath().lastElement()?.ComponentView as any)?.props.CollectionView?.moveDocument; // this is equal to docView.props.moveDocument, but moveDocument is not a defined prop of a DocumentView .. but maybe it should be?
 
-        DragManager.StartDrag([dragEle], dragData, downX, downY, undefined, finishDrag);
+        DragManager.StartDocumentDrag([dragEle], dragData, downX, downY, undefined);
     }
 }
 
diff --git a/src/client/views/linking/LinkPopup.tsx b/src/client/views/linking/LinkPopup.tsx
index 7bdace2b6..5f2d4a7b6 100644
--- a/src/client/views/linking/LinkPopup.tsx
+++ b/src/client/views/linking/LinkPopup.tsx
@@ -85,15 +85,13 @@ export class LinkPopup extends React.Component<LinkPopupProps> {
                         PanelWidth={this.getPWidth}
                         PanelHeight={this.getPHeight}
                         renderDepth={0}
-                        focus={DocUtils.DefaultFocus}
+                        focus={emptyFunction}
                         docViewPath={returnEmptyDoclist}
                         whenChildContentsActiveChanged={emptyFunction}
                         bringToFront={emptyFunction}
                         docFilters={returnEmptyFilter}
                         docRangeFilters={returnEmptyFilter}
                         searchFilterDocs={returnEmptyDoclist}
-                        ContainingCollectionView={undefined}
-                        ContainingCollectionDoc={undefined}
                     />
                 </div>
             </div>
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 9bdb2cee7..24b9f3b25 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -160,8 +160,9 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
     }
 
     @action public float = () => {
-        const { Document: topDoc, ContainingCollectionView: container } = this.props;
-        const screenXf = container?.screenToLocalTransform();
+        const topDoc = this.rootDoc;
+        const containerDocView = this.props.docViewPath().lastElement();
+        const screenXf = containerDocView?.screenToLocalTransform();
         if (screenXf) {
             SelectionManager.DeselectAll();
             if (topDoc.z) {
@@ -178,7 +179,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
                 topDoc.x = fpt[0];
                 topDoc.y = fpt[1];
             }
-            setTimeout(() => SelectionManager.SelectView(DocumentManager.Instance.getDocumentView(topDoc, container)!, false), 0);
+            setTimeout(() => SelectionManager.SelectView(DocumentManager.Instance.getDocumentView(topDoc, containerDocView), false), 0);
         }
     };
 
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index dbcfe43cf..76a5ce7b3 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -154,7 +154,6 @@ export class DocumentContentsView extends React.Component<
             // these are the properties in  DocumentViewProps that need to be removed to pass on only DocumentSharedViewProps to the FieldViews
             'hideResizeHandles',
             'hideTitle',
-            'treeViewDoc',
             'contentPointerEvents',
             'radialMenu',
             'LayoutTemplateString',
diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx
index df3299eef..47705d53d 100644
--- a/src/client/views/nodes/DocumentLinksButton.tsx
+++ b/src/client/views/nodes/DocumentLinksButton.tsx
@@ -142,7 +142,7 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
             } else if (startLink !== endLink) {
                 endLink = endLinkView?.docView?._componentView?.getAnchor?.(true, pinProps) || endLink;
                 startLink = DocumentLinksButton.StartLinkView?.docView?._componentView?.getAnchor?.(true) || startLink;
-                const linkDoc = DocUtils.MakeLink(startLink, endLink, { linkRelationship: DocumentLinksButton.AnnotationId ? 'hypothes.is annotation' : undefined }, undefined, true);
+                const linkDoc = DocUtils.MakeLink(startLink, endLink, { linkRelationship: DocumentLinksButton.AnnotationId ? 'hypothes.is annotation' : undefined });
 
                 LinkManager.currentLink = linkDoc;
 
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index f161a7b9b..be07f1fe5 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -148,8 +148,6 @@ export interface DocumentViewSharedProps {
     DataDoc?: Doc;
     contentBounds?: () => undefined | { x: number; y: number; r: number; b: number };
     fitContentsToBox?: () => boolean; // used by freeformview to fit its contents to its panel. corresponds to _fitContentsToBox property on a Document
-    ContainingCollectionView: Opt<CollectionView>;
-    ContainingCollectionDoc: Opt<Doc>;
     suppressSetHeight?: boolean;
     thumbShown?: () => boolean;
     setContentView?: (view: DocComponentView) => any;
@@ -179,6 +177,7 @@ export interface DocumentViewSharedProps {
     ScreenToLocalTransform: () => Transform;
     bringToFront: (doc: Doc, sendToBack?: boolean) => void;
     canEmbedOnDrag?: boolean;
+    treeViewDoc?: Doc;
     xPadding?: number;
     yPadding?: number;
     dropAction?: dropActionType;
@@ -210,7 +209,6 @@ export interface DocumentViewProps extends DocumentViewSharedProps {
     hideOpenButton?: boolean;
     hideDeleteButton?: boolean;
     hideLinkAnchors?: boolean;
-    treeViewDoc?: Doc;
     isDocumentActive?: () => boolean | undefined; // whether a document should handle pointer events
     isContentActive: () => boolean | undefined; // whether document contents should handle pointer events
     contentPointerEvents?: string; // pointer events allowed for content of a document view.  eg. set to "none" in menuSidebar for sharedDocs so that you can select a document, but not interact with its contents
@@ -429,7 +427,6 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                             this: this.layoutDoc,
                             self: this.rootDoc,
                             scriptContext: this.props.scriptContext,
-                            thisContainer: this.props.ContainingCollectionDoc,
                             documentView: this.props.DocumentView(),
                             clientX, clientY,  altKey,  shiftKey,  ctrlKey,
                             value: undefined,
@@ -456,7 +453,6 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                                 self: this.rootDoc,
                                 _readOnly_: false,
                                 scriptContext: this.props.scriptContext,
-                                thisContainer: this.props.ContainingCollectionDoc,
                                 documentView: this.props.DocumentView(),
                                 clientX,
                                 clientY,
@@ -605,7 +601,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                 }
                 if (de.complete.annoDragData || this.rootDoc !== linkdrag.linkSourceDoc.context) {
                     const dropDoc = de.complete.annoDragData?.dropDocument ?? this._componentView?.getAnchor?.(true) ?? this.rootDoc;
-                    de.complete.linkDocument = DocUtils.MakeLink(linkdrag.linkSourceDoc, dropDoc, {}, undefined, undefined, [de.x, de.y - 50]);
+                    de.complete.linkDocument = DocUtils.MakeLink(linkdrag.linkSourceDoc, dropDoc, {}, undefined, [de.x, de.y - 50]);
                 }
             }
         }
@@ -697,7 +693,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
             !Doc.noviceMode && templateDoc && appearanceItems.push({ description: 'Open Template   ', event: () => this.props.addDocTab(templateDoc, OpenWhere.addRight), icon: 'eye' });
             !appearance && appearanceItems.length && cm.addItem({ description: 'UI Controls...', subitems: appearanceItems, icon: 'compass' });
 
-            if (!Doc.IsSystem(this.rootDoc) && this.rootDoc._viewType !== CollectionViewType.Docking && this.props.ContainingCollectionDoc?._viewType !== CollectionViewType.Tree) {
+            if (!Doc.IsSystem(this.rootDoc) && this.rootDoc._viewType !== CollectionViewType.Docking && this.props.docViewPath().lastElement()?.rootDoc?._viewType !== CollectionViewType.Tree) {
                 const existingOnClick = cm.findByDescription('OnClick...');
                 const onClicks: ContextMenuProps[] = existingOnClick && 'subitems' in existingOnClick ? existingOnClick.subitems : [];
 
@@ -1446,7 +1442,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
     scaleToScreenSpace = () => (1 / (this.props.NativeDimScaling?.() || 1)) * this.screenToLocalTransform().Scale;
     docViewPathFunc = () => this.docViewPath;
     isSelected = (outsideReaction?: boolean) => SelectionManager.IsSelected(this, outsideReaction);
-    select = (extendSelection: boolean) => SelectionManager.SelectView(this, !SelectionManager.Views().some(v => v.props.Document === this.props.ContainingCollectionDoc) && extendSelection);
+    select = (extendSelection: boolean) => SelectionManager.SelectView(this, extendSelection);
     NativeWidth = () => this.effectiveNativeWidth;
     NativeHeight = () => this.effectiveNativeHeight;
     PanelWidth = () => this.panelWidth;
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 8d3534a5c..86779e0dd 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -32,6 +32,7 @@ export interface FieldViewProps extends DocumentViewSharedProps {
     // See currentUserUtils headerTemplate for examples of creating text boxes from html which set some of these fields
     // Also, see InkingStroke for examples of creating text boxes from render() methods which set some of these fields
     backgroundColor?: string;
+    treeViewDoc?: Doc;
     color?: string;
     fontSize?: number;
     height?: number;
diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx
index 94434dce7..7ea6d42ff 100644
--- a/src/client/views/nodes/KeyValuePair.tsx
+++ b/src/client/views/nodes/KeyValuePair.tsx
@@ -61,8 +61,6 @@ export class KeyValuePair extends React.Component<KeyValuePairProps> {
             searchFilterDocs: returnEmptyDoclist,
             styleProvider: DefaultStyleProvider,
             docViewPath: returnEmptyDoclist,
-            ContainingCollectionView: undefined,
-            ContainingCollectionDoc: undefined,
             fieldKey: this.props.keyName,
             rootSelected: returnFalse,
             isSelected: returnFalse,
diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx
index fcc5b6975..c58b5dd8c 100644
--- a/src/client/views/nodes/LinkDocPreview.tsx
+++ b/src/client/views/nodes/LinkDocPreview.tsx
@@ -271,14 +271,12 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> {
                             docFilters={returnEmptyFilter}
                             docRangeFilters={returnEmptyFilter}
                             searchFilterDocs={returnEmptyDoclist}
-                            ContainingCollectionDoc={undefined}
-                            ContainingCollectionView={undefined}
                             renderDepth={0}
                             suppressSetHeight={true}
                             PanelWidth={this.width}
                             PanelHeight={this.height}
                             pointerEvents={returnNone}
-                            focus={DocUtils.DefaultFocus}
+                            focus={emptyFunction}
                             whenChildContentsActiveChanged={returnFalse}
                             ignoreAutoHeight={true} // need to ignore autoHeight otherwise autoHeight text boxes will expand beyond the preview panel size.
                             bringToFront={returnFalse}
diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx
index db11a7776..e015024fd 100644
--- a/src/client/views/nodes/ScreenshotBox.tsx
+++ b/src/client/views/nodes/ScreenshotBox.tsx
@@ -305,8 +305,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
                             addDocument={returnFalse}
                             CollectionView={undefined}
                             ScreenToLocalTransform={this.props.ScreenToLocalTransform}
-                            renderDepth={this.props.renderDepth + 1}
-                            ContainingCollectionDoc={this.props.ContainingCollectionDoc}>
+                            renderDepth={this.props.renderDepth + 1}>
                             <>
                                 {this.threed}
                                 {this.content}
@@ -330,7 +329,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
                                 moveDocument={returnFalse}
                                 addDocument={returnFalse}
                                 renderDepth={this.props.renderDepth + 1}
-                                ContainingCollectionDoc={this.props.ContainingCollectionDoc}></FormattedTextBox>
+                            />
                         )}
                     </div>
                 </div>
diff --git a/src/client/views/nodes/button/FontIconBox.tsx b/src/client/views/nodes/button/FontIconBox.tsx
index 8eacfbc51..1a75a7e76 100644
--- a/src/client/views/nodes/button/FontIconBox.tsx
+++ b/src/client/views/nodes/button/FontIconBox.tsx
@@ -568,12 +568,12 @@ ScriptingGlobals.add(function setBackgroundColor(color?: string, checkResult?: b
     if (selectedViews.length) {
         if (checkResult) {
             const selView = selectedViews.lastElement();
-            const layoutFrameNumber = Cast(selView.props.ContainingCollectionDoc?._currentFrame, 'number'); // frame number that container is at which determines layout frame values
+            const layoutFrameNumber = Cast(selView.props.docViewPath().lastElement()?.rootDoc?._currentFrame, 'number'); // frame number that container is at which determines layout frame values
             const contentFrameNumber = Cast(selView.rootDoc?._currentFrame, 'number', layoutFrameNumber ?? null); // frame number that content is at which determines what content is displayed
             return CollectionFreeFormDocumentView.getStringValues(selView?.rootDoc, contentFrameNumber).backgroundColor ?? 'transparent';
         }
         selectedViews.forEach(dv => {
-            const layoutFrameNumber = Cast(dv.props.ContainingCollectionDoc?._currentFrame, 'number'); // frame number that container is at which determines layout frame values
+            const layoutFrameNumber = Cast(dv.props.docViewPath().lastElement()?.rootDoc?._currentFrame, 'number'); // frame number that container is at which determines layout frame values
             const contentFrameNumber = Cast(dv.rootDoc?._currentFrame, 'number', layoutFrameNumber ?? null); // frame number that content is at which determines what content is displayed
             if (contentFrameNumber !== undefined) {
                 CollectionFreeFormDocumentView.setStringValues(contentFrameNumber, dv.rootDoc, { backgroundColor: color });
diff --git a/src/client/views/nodes/formattedText/DashDocView.tsx b/src/client/views/nodes/formattedText/DashDocView.tsx
index c00ab6a7e..b31fc01ff 100644
--- a/src/client/views/nodes/formattedText/DashDocView.tsx
+++ b/src/client/views/nodes/formattedText/DashDocView.tsx
@@ -9,10 +9,9 @@ import { DocServer } from '../../../DocServer';
 import { Docs, DocUtils } from '../../../documents/Documents';
 import { ColorScheme } from '../../../util/SettingsManager';
 import { Transform } from '../../../util/Transform';
-import { DocumentView } from '../DocumentView';
+import { DocFocusOptions, DocumentView } from '../DocumentView';
 import { FormattedTextBox } from './FormattedTextBox';
 import React = require('react');
-import { SelectionManager } from '../../../util/SelectionManager';
 
 export class DashDocView {
     dom: HTMLSpanElement; // container for label and value
@@ -151,7 +150,7 @@ export class DashDocViewInternal extends React.Component<IDashDocViewInternal> {
         const { scale, translateX, translateY } = Utils.GetScreenTransform(this._spanRef.current);
         return new Transform(-translateX, -translateY, 1).scale(1 / scale);
     };
-    outerFocus = (target: Doc) => this._textBox.props.focus(this._textBox.props.Document, {}); // ideally, this would scroll to show the focus target
+    outerFocus = (target: Doc, options: DocFocusOptions) => this._textBox.focus(target, options); // ideally, this would scroll to show the focus target
 
     onKeyDown = (e: any) => {
         e.stopPropagation();
@@ -212,8 +211,6 @@ export class DashDocViewInternal extends React.Component<IDashDocViewInternal> {
                     docFilters={this.props.tbox?.props.docFilters}
                     docRangeFilters={this.props.tbox?.props.docRangeFilters}
                     searchFilterDocs={this.props.tbox?.props.searchFilterDocs}
-                    ContainingCollectionView={this._textBox.props.ContainingCollectionView}
-                    ContainingCollectionDoc={this._textBox.props.ContainingCollectionDoc}
                 />
             </div>
         );
diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx
index f23426bb3..c43206629 100644
--- a/src/client/views/nodes/formattedText/DashFieldView.tsx
+++ b/src/client/views/nodes/formattedText/DashFieldView.tsx
@@ -235,10 +235,7 @@ export class DashFieldViewInternal extends React.Component<IDashFieldViewInterna
     };
 
     createPivotForField = (e: React.MouseEvent) => {
-        let container = this.props.tbox.props.ContainingCollectionView;
-        while (container?.props.Document.isTemplateForField || container?.props.Document.isTemplateDoc) {
-            container = container.props.ContainingCollectionView;
-        }
+        let container = this.props.tbox.props.DocumentView?.().props.docViewPath().lastElement();
         if (container) {
             const alias = Doc.MakeAlias(container.props.Document);
             alias._viewType = CollectionViewType.Time;
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 677c4662b..bc2a5d797 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -541,7 +541,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                 // embed document when dragg marked as embed
             } else if (de.embedKey) {
                 const target = dragData.droppedDocuments[0];
-                target._fitContentsToBox = true;
                 const node = schema.nodes.dashDoc.create({
                     width: target[WidthSym](),
                     height: target[HeightSym](),
@@ -552,6 +551,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                 if (!['alias', 'copy'].includes((dragData.dropAction ?? '') as any)) {
                     dragData.removeDocument?.(dragData.draggedDocuments[0]);
                 }
+                target._fitContentsToBox = true;
+                target.context = this.rootDoc;
                 const view = this._editorView!;
                 view.dispatch(view.state.tr.insert(view.posAtCoords({ left: de.x, top: de.y })!.pos, node));
                 e.stopPropagation();
@@ -880,7 +881,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
         if (this._editorView && this._recordingStart) {
             if (this._break) {
                 const textanchorFunc = () => {
-                    const tanch = Docs.Create.TextanchorDocument({ title: 'dictation anchor' });
+                    const tanch = Docs.Create.TextanchorDocument({ title: 'dictation anchor', unrendered: true });
                     return this.addDocument(tanch) ? tanch : undefined;
                 };
                 const link = DocUtils.MakeLinkToActiveAudio(textanchorFunc, false).lastElement();
@@ -956,7 +957,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
             let hadStart = start !== 0;
             frag.forEach((node, index) => {
                 const examinedNode = findAnchorNode(node, editor);
-                if (examinedNode?.node && (examinedNode.node.textContent || examinedNode.node.type === this._editorView?.state.schema.nodes.audiotag)) {
+                if (examinedNode?.node && (examinedNode.node.textContent || examinedNode.node.type === this._editorView?.state.schema.nodes.dashDoc || examinedNode.node.type === this._editorView?.state.schema.nodes.audiotag)) {
                     nodes.push(examinedNode.node);
                     !hadStart && (start = index + examinedNode.start);
                     hadStart = true;
@@ -971,9 +972,15 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                 }
                 return undefined;
             }
+            if (node.type === this._editorView?.state.schema.nodes.dashDoc) {
+                if (node.attrs.docId === textAnchorId) {
+                    return { node, start: 0 };
+                }
+                return undefined;
+            }
             if (!node.isText) {
                 const content = findAnchorFrag(node.content, editor);
-                return { node: node.copy(content.frag), start: content.start };
+                if (content.frag.childCount) return { node: content.frag.childCount ? content.frag.child(0) : node, start: content.start };
             }
             const marks = [...node.marks];
             const linkIndex = marks.findIndex(mark => mark.type === editor.state.schema.marks.linkAnchor);
@@ -987,7 +994,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
             const ret = findAnchorFrag(editor.state.doc.content, editor);
 
             const content = (ret.frag as any)?.content;
-            if ((ret.frag.size > 2 || (content?.length && content[0].type === this._editorView.state.schema.nodes.audiotag)) && ret.start >= 0) {
+            if ((ret.frag.size || (content?.length && content[0].type === this._editorView.state.schema.nodes.dashDoc) || (content?.length && content[0].type === this._editorView.state.schema.nodes.audiotag)) && ret.start >= 0) {
                 !options.instant && (this._focusSpeed = focusSpeed);
                 let selection = TextSelection.near(editor.state.doc.resolve(ret.start)); // default to near the start
                 if (ret.frag.firstChild) {
@@ -998,6 +1005,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                 addStyleSheetRule(FormattedTextBox._highlightStyleSheet, `${escAnchorId}`, { background: 'yellow', transform: 'scale(3)', 'transform-origin': 'left bottom' });
                 setTimeout(() => (this._focusSpeed = undefined), this._focusSpeed);
                 setTimeout(() => clearStyleSheetRules(FormattedTextBox._highlightStyleSheet), Math.max(this._focusSpeed || 0, 3000));
+                return focusSpeed;
+            } else {
+                return this.props.focus(this.rootDoc, options);
             }
         }
     };
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index 3589a9065..807a19771 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -2457,7 +2457,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
                         {mode !== CollectionViewType.Invalid ? (
                             <CollectionView
                                 {...this.props}
-                                ContainingCollectionDoc={this.props.Document}
                                 PanelWidth={this.props.PanelWidth}
                                 PanelHeight={this.panelHeight}
                                 childIgnoreNativeSize={true}
diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx
index 92696240b..502eef373 100644
--- a/src/client/views/nodes/trails/PresElementBox.tsx
+++ b/src/client/views/nodes/trails/PresElementBox.tsx
@@ -39,7 +39,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
     // Idea: this boolean will determine whether to automatically show the video when this preselement is selected.
     // @observable static showVideo: boolean = false;
     @computed get indexInPres() {
-        return DocListCast(this.presBox[StrCast(this.presBox.presFieldKey, 'data')]).indexOf(this.rootDoc);
+        return DocListCast(this.presBox?.[StrCast(this.presBox.presFieldKey, 'data')]).indexOf(this.rootDoc);
     } // the index field is where this document is in the presBox display list (since this value is different for each presentation element, the value can't be stored on the layout template which is used by all display elements)
     @computed get expandViewHeight() {
         return 100;
@@ -51,11 +51,10 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
         return this.presBoxView?.selectedArray;
     }
     @computed get presBoxView() {
-        const vpath = this.props.docViewPath();
-        return vpath.length > 1 ? (vpath[vpath.length - 2].ComponentView as PresBox) : undefined;
+        return this.props.DocumentView?.()?.props.docViewPath().lastElement()?.ComponentView as PresBox;
     }
     @computed get presBox() {
-        return this.props.ContainingCollectionDoc!;
+        return this.props.DocumentView?.().props.docViewPath().lastElement()?.rootDoc;
     }
     @computed get targetDoc() {
         return Cast(this.rootDoc.presentationTargetDoc, Doc, null) || this.rootDoc;
@@ -110,14 +109,12 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
                     docFilters={this.props.docFilters}
                     docRangeFilters={this.props.docRangeFilters}
                     searchFilterDocs={this.props.searchFilterDocs}
-                    ContainingCollectionView={undefined}
-                    ContainingCollectionDoc={undefined}
                     rootSelected={returnTrue}
                     addDocument={returnFalse}
                     removeDocument={returnFalse}
                     fitContentsToBox={returnTrue}
                     moveDocument={this.props.moveDocument!}
-                    focus={DocUtils.DefaultFocus}
+                    focus={emptyFunction}
                     whenChildContentsActiveChanged={returnFalse}
                     addDocTab={returnFalse}
                     pinToPres={returnFalse}
@@ -195,7 +192,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
         const dragData = new DragManager.DocumentDragData(this.presBoxView?.sortArray() ?? []);
         if (!dragData.draggedDocuments.length) dragData.draggedDocuments.push(this.rootDoc);
         dragData.dropAction = 'move';
-        dragData.treeViewDoc = this.presBox._viewType === CollectionViewType.Tree ? this.props.ContainingCollectionDoc : undefined; // this.props.DocumentView?.()?.props.treeViewDoc;
+        dragData.treeViewDoc = this.presBox?._viewType === CollectionViewType.Tree ? this.presBox : undefined; // this.props.DocumentView?.()?.props.treeViewDoc;
         dragData.moveDocument = this.props.moveDocument;
         const dragItem: HTMLElement[] = [];
         if (dragArray.length === 1) {
@@ -269,7 +266,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
     @undoBatch
     removeItem = action((e: React.MouseEvent) => {
         e.stopPropagation();
-        if (this.indexInPres < (this.presBoxView?.itemIndex || 0)) {
+        if (this.presBox && this.indexInPres < (this.presBoxView?.itemIndex || 0)) {
             this.presBox.itemIndex = (this.presBoxView?.itemIndex || 0) - 1;
         }
         this.props.removeDocument?.(this.rootDoc);
@@ -406,15 +403,15 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
     @computed
     get toolbarWidth(): number {
         const presBoxDocView = DocumentManager.Instance.getDocumentView(this.presBox);
-        let width: number = NumCast(this.presBox._width);
+        let width: number = NumCast(this.presBox?._width);
         if (presBoxDocView) width = presBoxDocView.props.PanelWidth();
         if (width === 0) width = 300;
         return width;
     }
 
     @computed get presButtons() {
-        const presBox: Doc = this.presBox; //presBox
-        const presBoxColor: string = StrCast(presBox._backgroundColor);
+        const presBox = this.presBox; //presBox
+        const presBoxColor: string = StrCast(presBox?._backgroundColor);
         const presColorBool: boolean = presBoxColor ? presBoxColor !== Colors.WHITE && presBoxColor !== 'transparent' : false;
         const targetDoc: Doc = this.targetDoc;
         const activeItem: Doc = this.rootDoc;
@@ -494,10 +491,10 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
 
     @computed get mainItem() {
         const isSelected: boolean = this.selectedArray?.has(this.rootDoc) ? true : false;
-        const isCurrent: boolean = this.presBox._itemIndex === this.indexInPres;
+        const isCurrent: boolean = this.presBox?._itemIndex === this.indexInPres;
         const miniView: boolean = this.toolbarWidth <= 110;
-        const presBox: Doc = this.presBox; //presBox
-        const presBoxColor: string = StrCast(presBox._backgroundColor);
+        const presBox = this.presBox; //presBox
+        const presBoxColor: string = StrCast(presBox?._backgroundColor);
         const presColorBool: boolean = presBoxColor ? presBoxColor !== Colors.WHITE && presBoxColor !== 'transparent' : false;
         const activeItem: Doc = this.rootDoc;
 
diff --git a/src/client/views/topbar/TopBar.tsx b/src/client/views/topbar/TopBar.tsx
index f2e9be61d..d63c25dbe 100644
--- a/src/client/views/topbar/TopBar.tsx
+++ b/src/client/views/topbar/TopBar.tsx
@@ -46,7 +46,7 @@ export class TopBar extends React.Component {
         return (
             <div className="topbar-left">
                 {Doc.ActiveDashboard ? (
-                    <IconButton onClick={this.navigateToHome} icon={<FontAwesomeIcon icon="home" />} isCircle={true} hoverStyle="gray" color={this.textColor} />
+                    <IconButton onClick={this.navigateToHome} icon={<FontAwesomeIcon icon="home" />} color={this.textColor} />
                 ) : (
                     <div className="logo-container">
                         <img className="logo" src="/assets/medium-blue-light-blue-circle.png" alt="dash logo"></img>
@@ -55,18 +55,7 @@ export class TopBar extends React.Component {
                     </div>
                 )}
                 {Doc.ActiveDashboard && (
-                    <Button
-                        text="Explore"
-                        tooltip="Browsing mode for directly navigating to documents"
-                        fontSize={FontSize.SECONDARY}
-                        isActive={MainView.Instance._exploreMode}
-                        size={Size.SMALL}
-                        color={this.textColor}
-                        borderRadius={5}
-                        hoverStyle="gray"
-                        iconPosition="right"
-                        onClick={action(() => (MainView.Instance._exploreMode = !MainView.Instance._exploreMode))}
-                    />
+                    <Button text="Explore" tooltip="Browsing mode for directly navigating to documents" size={Size.SMALL} color={this.textColor} onClick={action(() => (MainView.Instance._exploreMode = !MainView.Instance._exploreMode))} />
                 )}
             </div>
         );
@@ -94,13 +83,8 @@ export class TopBar extends React.Component {
                 <Button
                     text={StrCast(Doc.ActiveDashboard.title)}
                     tooltip="Browsing mode for directly navigating to documents"
-                    fontSize={FontSize.SECONDARY}
                     size={Size.SMALL}
                     color={'white'}
-                    type="outline"
-                    backgroundColor={Colors.MEDIUM_BLUE}
-                    borderRadius={5}
-                    hoverStyle="none"
                     onClick={(e: React.MouseEvent) => {
                         const dashView = Doc.ActiveDashboard && DocumentManager.Instance.getDocumentView(Doc.ActiveDashboard);
                         ContextMenu.Instance.addItem({ description: 'Open Dashboard View', event: this.navigateToHome, icon: 'edit' });
@@ -121,21 +105,13 @@ export class TopBar extends React.Component {
                     onClick={() => {
                         SharingManager.Instance.open(undefined, Doc.ActiveDashboard);
                     }}
-                    type="outline"
-                    fontSize={FontSize.SECONDARY}
                     size={Size.SMALL}
-                    borderRadius={5}
-                    hoverStyle="gray"
                 />
                 {!Doc.noviceMode && (
                     <IconButton
-                        fontSize={FontSize.SECONDARY}
-                        isCircle={true}
                         tooltip="Work on a copy of the dashboard layout"
                         size={Size.SMALL}
                         color={this.textColor}
-                        borderRadius={Borders.STANDARD}
-                        hoverStyle="gray"
                         onClick={async () => {
                             const batch = UndoManager.StartBatch('snapshot');
                             await DashboardView.snapshotDashboard();
@@ -156,26 +132,9 @@ export class TopBar extends React.Component {
     @computed get topbarRight() {
         return (
             <div className="topbar-right">
-                <IconButton size={Size.SMALL} isCircle={true} color={Colors.LIGHT_GRAY} backgroundColor={Colors.DARK_GRAY} hoverStyle="gray" onClick={() => ReportManager.Instance.open()} icon={<FaBug />} />
-                <IconButton
-                    size={Size.SMALL}
-                    isCircle={true}
-                    color={Colors.LIGHT_GRAY}
-                    backgroundColor={Colors.DARK_GRAY}
-                    hoverStyle="gray"
-                    onClick={() => window.open('https://brown-dash.github.io/Dash-Documentation/', '_blank')}
-                    icon={<FontAwesomeIcon icon="question-circle" />}
-                />
-                <IconButton
-                    size={Size.SMALL}
-                    isCircle={true}
-                    color={Colors.LIGHT_GRAY}
-                    backgroundColor={Colors.DARK_GRAY}
-                    hoverStyle="gray"
-                    isActive={SettingsManager.Instance.isOpen}
-                    onClick={() => SettingsManager.Instance.open()}
-                    icon={<FontAwesomeIcon icon="cog" />}
-                />
+                <IconButton size={Size.SMALL} color={Colors.LIGHT_GRAY} onClick={() => ReportManager.Instance.open()} icon={<FaBug />} />
+                <IconButton size={Size.SMALL} color={Colors.LIGHT_GRAY} onClick={() => window.open('https://brown-dash.github.io/Dash-Documentation/', '_blank')} icon={<FontAwesomeIcon icon="question-circle" />} />
+                <IconButton size={Size.SMALL} color={Colors.LIGHT_GRAY} onClick={() => SettingsManager.Instance.open()} icon={<FontAwesomeIcon icon="cog" />} />
                 {/* <Button text={'Logout'} borderRadius={5} hoverStyle={'gray'} backgroundColor={Colors.DARK_GRAY} color={this.textColor} fontSize={FontSize.SECONDARY} onClick={() => window.location.assign(Utils.prepend('/logout'))} /> */}
             </div>
         );
diff --git a/src/mobile/AudioUpload.tsx b/src/mobile/AudioUpload.tsx
index 64baa351c..a0b437354 100644
--- a/src/mobile/AudioUpload.tsx
+++ b/src/mobile/AudioUpload.tsx
@@ -13,13 +13,18 @@ import { listSpec } from '../fields/Schema';
 import { Cast, FieldValue } from '../fields/Types';
 import { nullAudio } from '../fields/URLField';
 import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, emptyPath } from '../Utils';
-import "./ImageUpload.scss";
+import './ImageUpload.scss';
 import { MobileInterface } from './MobileInterface';
 import React = require('react');
 
 @observer
 export class AudioUpload extends React.Component {
-    @observable public _audioCol: Doc = FieldValue(Cast(Docs.Create.FreeformDocument([Cast(Docs.Create.AudioDocument(nullAudio, { title: "mobile audio", _width: 500, _height: 100 }), Doc) as Doc], { title: "mobile audio", _width: 300, _height: 300, _fitContentsToBox: true, boxShadow: "0 0" }), Doc)) as Doc;
+    @observable public _audioCol: Doc = FieldValue(
+        Cast(
+            Docs.Create.FreeformDocument([Cast(Docs.Create.AudioDocument(nullAudio, { title: 'mobile audio', _width: 500, _height: 100 }), Doc) as Doc], { title: 'mobile audio', _width: 300, _height: 300, _fitContentsToBox: true, boxShadow: '0 0' }),
+            Doc
+        )
+    ) as Doc;
 
     /**
      * Handles the onclick functionality for the 'Restart' button
@@ -28,25 +33,36 @@ export class AudioUpload extends React.Component {
     @action
     clearUpload = () => {
         for (let i = 1; i < 8; i++) {
-            this.setOpacity(i, "0.2");
+            this.setOpacity(i, '0.2');
         }
-        this._audioCol = FieldValue(Cast(
-            Docs.Create.FreeformDocument(
-                [Cast(Docs.Create.AudioDocument(nullAudio, {
-                    title: "mobile audio",
-                    _width: 500,
-                    _height: 100
-                }), Doc) as Doc], { title: "mobile audio", _width: 300, _height: 300, _fitContentsToBox: true, boxShadow: "0 0" }), Doc)) as Doc;
-    }
+        this._audioCol = FieldValue(
+            Cast(
+                Docs.Create.FreeformDocument(
+                    [
+                        Cast(
+                            Docs.Create.AudioDocument(nullAudio, {
+                                title: 'mobile audio',
+                                _width: 500,
+                                _height: 100,
+                            }),
+                            Doc
+                        ) as Doc,
+                    ],
+                    { title: 'mobile audio', _width: 300, _height: 300, _fitContentsToBox: true, boxShadow: '0 0' }
+                ),
+                Doc
+            )
+        ) as Doc;
+    };
 
-    /** 
+    /**
      * Handles the onClick of the 'Close' button
      * Reset upload interface and toggle audio
      */
     closeUpload = () => {
         this.clearUpload();
         MobileInterface.Instance.toggleAudio();
-    }
+    };
 
     /**
      * Handles the on click of the 'Upload' button.
@@ -57,14 +73,14 @@ export class AudioUpload extends React.Component {
         const audioDoc = this._audioCol;
         const data = Cast(audioRightSidebar.data, listSpec(Doc));
         for (let i = 1; i < 8; i++) {
-            setTimeout(() => this.setOpacity(i, "1"), i * 200);
+            setTimeout(() => this.setOpacity(i, '1'), i * 200);
         }
         if (data) {
             data.push(audioDoc);
         }
         // Resets uploader after 3 seconds
         setTimeout(this.clearUpload, 3000);
-    }
+    };
 
     // Returns the upload audio menu
     private get uploadInterface() {
@@ -72,11 +88,13 @@ export class AudioUpload extends React.Component {
             <>
                 <ContextMenu />
                 <DictationOverlay />
-                <div style={{ display: "none" }}><RichTextMenu key="rich" /></div>
+                <div style={{ display: 'none' }}>
+                    <RichTextMenu key="rich" />
+                </div>
                 <div className="closeUpload" onClick={() => this.closeUpload()}>
-                    <FontAwesomeIcon icon="window-close" size={"lg"} />
+                    <FontAwesomeIcon icon="window-close" size={'lg'} />
                 </div>
-                <FontAwesomeIcon icon="microphone" size="lg" style={{ fontSize: "130" }} />
+                <FontAwesomeIcon icon="microphone" size="lg" style={{ fontSize: '130' }} />
                 <div className="audioUpload_cont">
                     <DocumentView
                         Document={this._audioCol}
@@ -96,12 +114,10 @@ export class AudioUpload extends React.Component {
                         isDocumentActive={returnTrue}
                         isContentActive={emptyFunction}
                         focus={emptyFunction}
-                        styleProvider={() => "rgba(0,0,0,0)"}
+                        styleProvider={() => 'rgba(0,0,0,0)'}
                         docViewPath={returnEmptyDoclist}
                         whenChildContentsActiveChanged={emptyFunction}
                         bringToFront={emptyFunction}
-                        ContainingCollectionView={undefined}
-                        ContainingCollectionDoc={undefined}
                     />
                 </div>
                 <div className="restart_label" onClick={this.clearUpload}>
@@ -125,28 +141,16 @@ export class AudioUpload extends React.Component {
 
     // Handles the setting of the loading bar
     setOpacity = (index: number, opacity: string) => {
-        const slab = document.getElementById("slab0" + index);
+        const slab = document.getElementById('slab0' + index);
         if (slab) {
             slab.style.opacity = opacity;
         }
-    }
+    };
 
     @observable private dialogueBoxOpacity = 1;
     @observable private overlayOpacity = 0.4;
 
     render() {
-        return (
-            <MainViewModal
-                contents={this.uploadInterface}
-                isDisplayed={true}
-                interactive={true}
-                dialogueBoxDisplayedOpacity={this.dialogueBoxOpacity}
-                overlayDisplayedOpacity={this.overlayOpacity}
-                closeOnExternalClick={this.closeUpload}
-            />
-        );
+        return <MainViewModal contents={this.uploadInterface} isDisplayed={true} interactive={true} dialogueBoxDisplayedOpacity={this.dialogueBoxOpacity} overlayDisplayedOpacity={this.overlayOpacity} closeOnExternalClick={this.closeUpload} />;
     }
-
 }
-
-
diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx
index 2ae597b0b..a543c2f70 100644
--- a/src/mobile/MobileInterface.tsx
+++ b/src/mobile/MobileInterface.tsx
@@ -397,7 +397,7 @@ export class MobileInterface extends React.Component {
                     renderDepth={0}
                     isDocumentActive={returnTrue}
                     isContentActive={emptyFunction}
-                    focus={DocUtils.DefaultFocus}
+                    focus={emptyFunction}
                     styleProvider={this.whitebackground}
                     docViewPath={returnEmptyDoclist}
                     whenChildContentsActiveChanged={emptyFunction}
@@ -405,8 +405,6 @@ export class MobileInterface extends React.Component {
                     docFilters={returnEmptyFilter}
                     docRangeFilters={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
-                    ContainingCollectionView={undefined}
-                    ContainingCollectionDoc={undefined}
                 />
             </div>
         );
-- 
cgit v1.2.3-70-g09d2


From 99326044a2d81a9f0d0312b4d209946e0f119b78 Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Mon, 24 Apr 2023 17:47:54 -0400
Subject: crappy version of schema image cell preview on hover

---
 .../collections/collectionSchema/SchemaRowBox.tsx  |  2 +-
 .../collectionSchema/SchemaTableCell.tsx           | 65 ++++++++++++++--------
 2 files changed, 43 insertions(+), 24 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaRowBox.tsx')

diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 59b571b58..79808d8f8 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -88,7 +88,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
         return (
             <div
                 className="schema-row"
-                style={{ height: CollectionSchemaView._rowHeight, backgroundColor: this.props.isSelected() ? Colors.LIGHT_BLUE : undefined, pointerEvents: this.schemaView?.props.isContentActive() ? 'all' : undefined }}
+                style={{ height: CollectionSchemaView._rowHeight, backgroundColor: this.props.isSelected() ? Colors.LIGHT_BLUE : undefined }}
                 onPointerEnter={this.onPointerEnter}
                 onPointerLeave={this.onPointerLeave}
                 ref={(row: HTMLDivElement | null) => {
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 4e31b1e1e..2325339fc 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -58,7 +58,7 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
         };
 
         return (
-            <div className="schemacell-edit-wrapper">
+            <div className="schemacell-edit-wrapper" style={{ cursor: !this.readOnly ? 'text' : 'default', pointerEvents: !this.readOnly && this.props.isRowActive() ? 'all' : 'none' }}>
                 <EditableView
                     contents={<FieldView {...props} />}
                     GetValue={() => Field.toKeyValueString(this.props.Document, this.props.fieldKey)}
@@ -76,9 +76,7 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
 
     getCellWithContent(content: any) {
         return (
-            <div
-                className="schema-table-cell"
-                style={this.props.isRowActive() && !this.readOnly ? { width: this.props.columnWidth, cursor: 'text', pointerEvents: 'auto' } : { width: this.props.columnWidth, cursor: 'default', pointerEvents: 'none' }}>
+            <div className="schema-table-cell" style={this.props.isRowActive() && !this.readOnly ? { width: this.props.columnWidth } : { width: this.props.columnWidth }}>
                 {content}
             </div>
         );
@@ -107,7 +105,7 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
             case ColumnType.Image:
                 return <SchemaImageCell {...this.props} />;
             case ColumnType.Date:
-                return <SchemaDateCell {...this.props} />;
+            // return <SchemaDateCell {...this.props} />;
             default:
                 return this.getCellWithContent(this.defaultCellContent);
         }
@@ -117,16 +115,18 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
 // mj: most of this is adapted from old schema code so I'm not sure what it does tbh
 @observer
 export class SchemaImageCell extends SchemaTableCell {
+    @observable _previewRef: HTMLImageElement | undefined;
+
     choosePath(url: URL) {
         if (url.protocol === 'data') return url.href; // if the url ises the data protocol, just return the href
         if (url.href.indexOf(window.location.origin) === -1) return Utils.CorsProxy(url.href); // otherwise, put it through the cors proxy erver
         if (!/\.(png|jpg|jpeg|gif|webp)$/.test(url.href.toLowerCase())) return url.href; //Why is this here — good question
 
         const ext = extname(url.href);
-        return url.href.replace(ext, '_o' + ext);
+        return url.href.replace(ext, '_s' + ext);
     }
 
-    get content() {
+    get url() {
         const field = Cast(this.props.Document[this.props.fieldKey], ImageField, null); // retrieve the primary image URL that is being rendered from the data doc
         const alts = DocListCast(this.props.Document[this.props.fieldKey + '-alternates']); // retrieve alternate documents that may be rendered as alternate images
         const altpaths = alts
@@ -136,13 +136,42 @@ export class SchemaImageCell extends SchemaTableCell {
         const paths = field ? [this.choosePath(field.url), ...altpaths] : altpaths;
         // If there is a path, follow it; otherwise, follow a link to a default image icon
         const url = paths.length ? paths : [Utils.CorsProxy('http://www.cs.brown.edu/~bcz/noImage.png')];
+        return url[0];
+    }
+
+    @action
+    showHoverPreview = (e: React.PointerEvent) => {
+        this._previewRef = document.createElement('img');
+        document.body.appendChild(this._previewRef);
+        const ext = extname(this.url);
+        this._previewRef.src = this.url.replace('_s' + ext, '_m' + ext);
+        this._previewRef.style.position = 'absolute';
+        this._previewRef.style.left = e.clientX + 10 + 'px';
+        this._previewRef.style.top = e.clientY + 10 + 'px';
+        this._previewRef.style.zIndex = '1000';
+    };
+
+    @action
+    moveHoverPreview = (e: React.PointerEvent) => {
+        if (!this._previewRef) return;
+        this._previewRef.style.left = e.clientX + 10 + 'px';
+        this._previewRef.style.top = e.clientY + 10 + 'px';
+    };
 
+    @action
+    removeHoverPreview = (e: React.PointerEvent) => {
+        if (!this._previewRef) return;
+        document.body.removeChild(this._previewRef);
+    };
+
+    get content() {
         const aspect = Doc.NativeAspect(this.props.Document); // aspect ratio
-        let width = Math.max(75, this.props.columnWidth); // get a with that is no smaller than 75px
-        const height = Math.max(75, width / aspect); // get a height either proportional to that or 75 px
-        width = height * aspect; // increase the width of the image if necessary to maintain proportionality
+        // let width = Math.max(75, this.props.columnWidth); // get a with that is no smaller than 75px
+        // const height = Math.max(75, width / aspect); // get a height either proportional to that or 75 px
+        const height = CollectionSchemaView._rowHeight - 10;
+        const width = height * aspect; // increase the width of the image if necessary to maintain proportionality
 
-        return <img src={url[0]} width={paths.length ? width : '20px'} height={paths.length ? height : '20px'} />;
+        return <img src={this.url} width={width} height={height} style={{}} draggable="false" onPointerEnter={this.showHoverPreview} onPointerMove={this.moveHoverPreview} onPointerLeave={this.removeHoverPreview} />;
     }
 
     render() {
@@ -171,18 +200,8 @@ export class SchemaDateCell extends SchemaTableCell {
     };
 
     get content() {
-        return !this._pickingDate ? (
-            <div onPointerDown={action(() => (this._pickingDate = true))}>{this.defaultCellContent}</div>
-        ) : (
-            <DatePicker
-                selected={this.date.date}
-                onSelect={(date: any) => {
-                    this.handleChange(date);
-                    this._pickingDate = false;
-                }}
-                onChange={(date: any) => this.handleChange(date)}
-            />
-        );
+        return <DatePicker dateFormat={'Pp'} selected={this.date.date} onChange={(date: any) => this.handleChange(date)} />;
+        // return !this._pickingDate ? <div onPointerDown={action(() => (this._pickingDate = true))}>{this.defaultCellContent}</div> : <DatePicker dateFormat={'Pp'} selected={this.date.date} onChange={(date: any) => this.handleChange(date)} />;
     }
 
     render() {
-- 
cgit v1.2.3-70-g09d2


From bc550e43b6042176cf59f04cbff51e1b21adaa8a Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Thu, 27 Apr 2023 00:41:43 -0400
Subject: trying to get schema keyboard controls working

---
 .../collectionSchema/CollectionSchemaView.tsx      | 43 ++++++++++++--
 .../collections/collectionSchema/SchemaRowBox.tsx  |  1 +
 .../collectionSchema/SchemaTableCell.tsx           | 65 +++++++++++++---------
 3 files changed, 78 insertions(+), 31 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaRowBox.tsx')

diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index f6dc2a3d7..92a04f5ec 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -74,6 +74,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     @observable _menuValue: string = '';
     @observable _filterColumnIndex: number | undefined;
     @observable _filterSearchValue: string = '';
+    @observable _selectedCell: [Doc, number] | undefined;
 
     get fieldInfos() {
         const docs = this.childDocs;
@@ -174,8 +175,11 @@ export class CollectionSchemaView extends CollectionSubView() {
                             !e.shiftKey && this.clearSelection();
                             const newDoc = this.sortedDocs.docs[lastIndex + 1];
                             if (this._selectedDocs.includes(newDoc)) SelectionManager.DeselectView(DocumentManager.Instance.getFirstDocumentView(curDoc));
-                            else this.addDocToSelection(newDoc, e.shiftKey, lastIndex + 1);
-                            this.scrollToDoc(newDoc, {});
+                            else {
+                                this.addDocToSelection(newDoc, e.shiftKey, lastIndex + 1);
+                                this._selectedCell && (this._selectedCell[0] = newDoc);
+                                this.scrollToDoc(newDoc, {});
+                            }
                         }
                         e.stopPropagation();
                         e.preventDefault();
@@ -191,13 +195,37 @@ export class CollectionSchemaView extends CollectionSubView() {
                             !e.shiftKey && this.clearSelection();
                             const newDoc = this.sortedDocs.docs[firstIndex - 1];
                             if (this._selectedDocs.includes(newDoc)) SelectionManager.DeselectView(DocumentManager.Instance.getFirstDocumentView(curDoc));
-                            else this.addDocToSelection(newDoc, e.shiftKey, firstIndex - 1);
-                            this.scrollToDoc(newDoc, {});
+                            else {
+                                this.addDocToSelection(newDoc, e.shiftKey, firstIndex - 1);
+                                this._selectedCell && (this._selectedCell[0] = newDoc);
+                                this.scrollToDoc(newDoc, {});
+                            }
                         }
                         e.stopPropagation();
                         e.preventDefault();
                     }
                     break;
+                case 'ArrowRight':
+                    if (this._selectedCell) {
+                        this._selectedCell[1] = Math.min(this._selectedCell[1] + 1, this.columnKeys.length - 1);
+                    } else if (this._selectedDocs.length > 0) {
+                        this.selectCell(this._selectedDocs[0], 0);
+                    }
+                    break;
+                case 'ArrowLeft':
+                    if (this._selectedCell) {
+                        this._selectedCell[1] = Math.max(this._selectedCell[1] - 1, 0);
+                    } else if (this._selectedDocs.length > 0) {
+                        this.selectCell(this._selectedDocs[0], 0);
+                    }
+                    break;
+                case 'Backspace': {
+                    this.removeDocument(this._selectedDocs);
+                    break;
+                }
+                case 'Escape': {
+                    this._selectedCell = undefined;
+                }
             }
         }
     };
@@ -392,6 +420,11 @@ export class CollectionSchemaView extends CollectionSubView() {
         }
     };
 
+    @action
+    selectCell = (doc: Doc, index: number) => {
+        this._selectedCell = [doc, index];
+    };
+
     sortedSelectedDocs = () => this.sortedDocs.docs.filter(doc => this._selectedDocs.includes(doc));
 
     setDropIndex = (index: number) => (this._closestDropIndex = index);
@@ -428,7 +461,7 @@ export class CollectionSchemaView extends CollectionSubView() {
             const pushedAndDraggedDocs = [...pushedDocs, ...draggedDocs];
             const removed = this.childDocs.slice().filter(doc => !pushedAndDraggedDocs.includes(doc));
             this.dataDoc[this.fieldKey ?? 'data'] = new List<Doc>([...removed, ...draggedDocs, ...pushedDocs]);
-            SelectionManager.DeselectAll();
+            this.clearSelection();
             draggedDocs.forEach(doc => {
                 const draggedView = DocumentManager.Instance.getFirstDocumentView(doc);
                 if (draggedView) DocumentManager.Instance.RemoveView(draggedView);
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 79808d8f8..f5a16cec0 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -123,6 +123,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
                         <SchemaTableCell
                             key={key}
                             Document={this.rootDoc}
+                            col={index}
                             schemaView={this.schemaView}
                             fieldKey={key}
                             columnWidth={this.schemaView?.displayColumnWidths[index] ?? CollectionSchemaView._minColWidth}
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 2325339fc..2b61ea261 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -11,13 +11,16 @@ import { CollectionSchemaView, ColumnType, FInfotoColType } from './CollectionSc
 import './CollectionSchemaView.scss';
 import { action, computed, observable } from 'mobx';
 import { extname } from 'path';
-import { Cast, DateCast } from '../../../../fields/Types';
+import { Cast, DateCast, StrCast } from '../../../../fields/Types';
 import { ImageField } from '../../../../fields/URLField';
 import { DateField } from '../../../../fields/DateField';
 import DatePicker from 'react-datepicker';
+import { Colors } from '../../global/globalEnums';
+import { SelectionManager } from '../../../util/SelectionManager';
 
 export interface SchemaTableCellProps {
     Document: Doc;
+    col: number;
     schemaView: CollectionSchemaView | undefined;
     fieldKey: string;
     columnWidth: number;
@@ -27,10 +30,23 @@ export interface SchemaTableCellProps {
 
 @observer
 export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
-    get readOnly() {
+    private _editorRef: EditableView | null = null;
+
+    @computed get readOnly() {
         return this.props.schemaView?.fieldInfos[this.props.fieldKey]?.readOnly ?? false;
     }
 
+    @computed get selected() {
+        const selected: [Doc, number] | undefined = this.props.schemaView?._selectedCell;
+        return this.props.isRowActive() && selected && selected[0] == this.props.Document && selected[1] == this.props.col;
+    }
+
+    componentDidUpdate() {
+        if (!this.selected) {
+            this._editorRef?.setIsFocused(false);
+        }
+    }
+
     get defaultCellContent() {
         const props: FieldViewProps = {
             Document: this.props.Document,
@@ -60,6 +76,7 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
         return (
             <div className="schemacell-edit-wrapper" style={{ cursor: !this.readOnly ? 'text' : 'default', pointerEvents: !this.readOnly && this.props.isRowActive() ? 'all' : 'none' }}>
                 <EditableView
+                    ref={ref => (this._editorRef = ref)}
                     contents={<FieldView {...props} />}
                     GetValue={() => Field.toKeyValueString(this.props.Document, this.props.fieldKey)}
                     SetValue={(value: string, shiftDown?: boolean, enterKey?: boolean) => {
@@ -68,20 +85,12 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
                         }
                         return KeyValueBox.SetField(this.props.Document, this.props.fieldKey, value);
                     }}
-                    editing={this.props.isRowActive() ? undefined : false}
+                    editing={this.selected ? undefined : false}
                 />
             </div>
         );
     }
 
-    getCellWithContent(content: any) {
-        return (
-            <div className="schema-table-cell" style={this.props.isRowActive() && !this.readOnly ? { width: this.props.columnWidth } : { width: this.props.columnWidth }}>
-                {content}
-            </div>
-        );
-    }
-
     get getCellType() {
         const columnTypeStr = this.props.schemaView?.fieldInfos[this.props.fieldKey]?.fieldType;
         if (columnTypeStr) {
@@ -99,7 +108,7 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
         return ColumnType.Any;
     }
 
-    render() {
+    get content() {
         const cellType: ColumnType = this.getCellType;
         switch (cellType) {
             case ColumnType.Image:
@@ -107,14 +116,27 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
             case ColumnType.Date:
             // return <SchemaDateCell {...this.props} />;
             default:
-                return this.getCellWithContent(this.defaultCellContent);
+                return this.defaultCellContent;
         }
     }
+
+    render() {
+        return (
+            <div
+                className="schema-table-cell"
+                onPointerDown={action(e => {
+                    if (!this.selected) this.props.schemaView?.selectCell(this.props.Document, this.props.col);
+                })}
+                style={{ width: this.props.columnWidth, border: this.selected ? `solid 2px ${Colors.MEDIUM_BLUE}` : undefined }}>
+                {this.content}
+            </div>
+        );
+    }
 }
 
 // mj: most of this is adapted from old schema code so I'm not sure what it does tbh
 @observer
-export class SchemaImageCell extends SchemaTableCell {
+export class SchemaImageCell extends React.Component<SchemaTableCellProps> {
     @observable _previewRef: HTMLImageElement | undefined;
 
     choosePath(url: URL) {
@@ -164,7 +186,7 @@ export class SchemaImageCell extends SchemaTableCell {
         document.body.removeChild(this._previewRef);
     };
 
-    get content() {
+    render() {
         const aspect = Doc.NativeAspect(this.props.Document); // aspect ratio
         // let width = Math.max(75, this.props.columnWidth); // get a with that is no smaller than 75px
         // const height = Math.max(75, width / aspect); // get a height either proportional to that or 75 px
@@ -173,14 +195,10 @@ export class SchemaImageCell extends SchemaTableCell {
 
         return <img src={this.url} width={width} height={height} style={{}} draggable="false" onPointerEnter={this.showHoverPreview} onPointerMove={this.moveHoverPreview} onPointerLeave={this.removeHoverPreview} />;
     }
-
-    render() {
-        return this.getCellWithContent(this.content);
-    }
 }
 
 @observer
-export class SchemaDateCell extends SchemaTableCell {
+export class SchemaDateCell extends React.Component<SchemaTableCellProps> {
     @observable _pickingDate: boolean = false;
 
     @computed get date(): DateField {
@@ -199,12 +217,7 @@ export class SchemaDateCell extends SchemaTableCell {
         //}
     };
 
-    get content() {
-        return <DatePicker dateFormat={'Pp'} selected={this.date.date} onChange={(date: any) => this.handleChange(date)} />;
-        // return !this._pickingDate ? <div onPointerDown={action(() => (this._pickingDate = true))}>{this.defaultCellContent}</div> : <DatePicker dateFormat={'Pp'} selected={this.date.date} onChange={(date: any) => this.handleChange(date)} />;
-    }
-
     render() {
-        return this.getCellWithContent(this.content);
+        return <DatePicker dateFormat={'Pp'} selected={this.date.date} onChange={(date: any) => this.handleChange(date)} />;
     }
 }
-- 
cgit v1.2.3-70-g09d2


From b82a909a63a6de414d075735453240ebc02f5aa3 Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Thu, 27 Apr 2023 13:20:52 -0400
Subject: fixed editing schema cells with keyboard only

---
 src/client/views/EditableView.tsx                  |  6 +++++
 .../collectionSchema/CollectionSchemaView.tsx      | 19 +++++++++------
 .../collections/collectionSchema/SchemaRowBox.tsx  |  6 +++--
 .../collectionSchema/SchemaTableCell.tsx           | 28 ++++++++++++++++------
 4 files changed, 43 insertions(+), 16 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaRowBox.tsx')

diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx
index 164b6c57a..d1311a60a 100644
--- a/src/client/views/EditableView.tsx
+++ b/src/client/views/EditableView.tsx
@@ -106,6 +106,12 @@ export class EditableView extends React.Component<EditableProps> {
             case ':':
                 this.props.menuCallback?.(e.currentTarget.getBoundingClientRect().x, e.currentTarget.getBoundingClientRect().y);
                 break;
+            case 'ArrowUp':
+            case 'ArrowDown':
+            case 'ArrowLeft':
+            case 'ArrowRight':
+                e.stopPropagation();
+                break;
             case 'Shift':
             case 'Alt':
             case 'Meta':
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 92a04f5ec..8cd307adf 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -1,6 +1,6 @@
 import React = require('react');
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, computed, observable, ObservableMap, untracked } from 'mobx';
+import { action, computed, observable, ObservableMap, trace, untracked } from 'mobx';
 import { observer } from 'mobx-react';
 import { computedFn } from 'mobx-utils';
 import { Doc, DocListCast, Field, StrListCast } from '../../../../fields/Doc';
@@ -170,12 +170,12 @@ export class CollectionSchemaView extends CollectionSubView() {
                         const lastDoc = this._selectedDocs.lastElement();
                         const lastIndex = this.rowIndex(lastDoc);
                         const curDoc = this.sortedDocs.docs[lastIndex];
-                        // const curDoc = this.childDocs[lastIndex];
                         if (lastIndex >= 0 && lastIndex < this.childDocs.length - 1) {
                             !e.shiftKey && this.clearSelection();
                             const newDoc = this.sortedDocs.docs[lastIndex + 1];
-                            if (this._selectedDocs.includes(newDoc)) SelectionManager.DeselectView(DocumentManager.Instance.getFirstDocumentView(curDoc));
-                            else {
+                            if (this._selectedDocs.includes(newDoc)) {
+                                SelectionManager.DeselectView(DocumentManager.Instance.getFirstDocumentView(curDoc));
+                            } else {
                                 this.addDocToSelection(newDoc, e.shiftKey, lastIndex + 1);
                                 this._selectedCell && (this._selectedCell[0] = newDoc);
                                 this.scrollToDoc(newDoc, {});
@@ -189,7 +189,6 @@ export class CollectionSchemaView extends CollectionSubView() {
                     {
                         const firstDoc = this._selectedDocs.lastElement();
                         const firstIndex = this.rowIndex(firstDoc);
-                        // const curDoc = this.childDocs[firstIndex];
                         const curDoc = this.sortedDocs.docs[firstIndex];
                         if (firstIndex > 0 && firstIndex < this.childDocs.length) {
                             !e.shiftKey && this.clearSelection();
@@ -224,7 +223,7 @@ export class CollectionSchemaView extends CollectionSubView() {
                     break;
                 }
                 case 'Escape': {
-                    this._selectedCell = undefined;
+                    this.deselectCell();
                 }
             }
         }
@@ -425,6 +424,11 @@ export class CollectionSchemaView extends CollectionSubView() {
         this._selectedCell = [doc, index];
     };
 
+    @action
+    deselectCell = () => {
+        this._selectedCell = undefined;
+    };
+
     sortedSelectedDocs = () => this.sortedDocs.docs.filter(doc => this._selectedDocs.includes(doc));
 
     setDropIndex = (index: number) => (this._closestDropIndex = index);
@@ -456,7 +460,7 @@ export class CollectionSchemaView extends CollectionSubView() {
             return true;
         }
         const draggedDocs = de.complete.docDragData?.draggedDocuments;
-        if (draggedDocs && super.onInternalDrop(e, de)) {
+        if (draggedDocs && super.onInternalDrop(e, de) && !this.sortField) {
             const pushedDocs = this.childDocs.filter((doc, index) => index >= this._closestDropIndex && !draggedDocs.includes(doc));
             const pushedAndDraggedDocs = [...pushedDocs, ...draggedDocs];
             const removed = this.childDocs.slice().filter(doc => !pushedAndDraggedDocs.includes(doc));
@@ -829,6 +833,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     }
 
     @computed get sortedDocs() {
+        trace();
         const field = StrCast(this.layoutDoc.sortField);
         const desc = BoolCast(this.layoutDoc.sortDesc);
         const docs = !field
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index f5a16cec0..9864820a3 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -28,6 +28,8 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
         return vpath.length > 1 ? (vpath[vpath.length - 2].ComponentView as CollectionSchemaView) : undefined;
     }
 
+    schemaViewFunc = () => this.schemaView;
+
     @computed get schemaDoc() {
         return this.props.DocumentView?.().props.docViewPath().lastElement()?.rootDoc;
     }
@@ -124,11 +126,11 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
                             key={key}
                             Document={this.rootDoc}
                             col={index}
-                            schemaView={this.schemaView}
+                            schemaView={this.schemaViewFunc}
                             fieldKey={key}
                             columnWidth={this.schemaView?.displayColumnWidths[index] ?? CollectionSchemaView._minColWidth}
                             isRowActive={this.props.isContentActive}
-                            setColumnValues={(field, value) => this.schemaView?.setColumnValues(field, value) ?? false}
+                            // setColumnValues={(field, value) => this.schemaView?.setColumnValues(field, value) ?? false}
                         />
                     ))}
                 </div>
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 2b61ea261..374b92d72 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -21,11 +21,11 @@ import { SelectionManager } from '../../../util/SelectionManager';
 export interface SchemaTableCellProps {
     Document: Doc;
     col: number;
-    schemaView: CollectionSchemaView | undefined;
+    schemaView: () => CollectionSchemaView | undefined;
     fieldKey: string;
     columnWidth: number;
     isRowActive: () => boolean | undefined;
-    setColumnValues: (field: string, value: string) => boolean;
+    // setColumnValues: (field: string, value: string) => boolean;
 }
 
 @observer
@@ -33,20 +33,34 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
     private _editorRef: EditableView | null = null;
 
     @computed get readOnly() {
-        return this.props.schemaView?.fieldInfos[this.props.fieldKey]?.readOnly ?? false;
+        return this.props.schemaView()?.fieldInfos[this.props.fieldKey]?.readOnly ?? false;
     }
 
     @computed get selected() {
-        const selected: [Doc, number] | undefined = this.props.schemaView?._selectedCell;
+        const selected: [Doc, number] | undefined = this.props.schemaView()?._selectedCell;
         return this.props.isRowActive() && selected && selected[0] == this.props.Document && selected[1] == this.props.col;
     }
 
     componentDidUpdate() {
         if (!this.selected) {
             this._editorRef?.setIsFocused(false);
+            document.removeEventListener('keydown', this.onKeyDown);
+        } else if (!this.readOnly) {
+            document.addEventListener('keydown', this.onKeyDown);
         }
     }
 
+    @action
+    onKeyDown = (e: KeyboardEvent) => {
+        e.stopPropagation();
+        if (e.key == 'Enter') {
+            this._editorRef?.setIsFocused(true);
+        }
+        if (e.key == 'Escape') {
+            this.props.schemaView()?.deselectCell();
+        }
+    };
+
     get defaultCellContent() {
         const props: FieldViewProps = {
             Document: this.props.Document,
@@ -81,7 +95,7 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
                     GetValue={() => Field.toKeyValueString(this.props.Document, this.props.fieldKey)}
                     SetValue={(value: string, shiftDown?: boolean, enterKey?: boolean) => {
                         if (shiftDown && enterKey) {
-                            this.props.setColumnValues(this.props.fieldKey, value);
+                            // this.props.setColumnValues(this.props.fieldKey, value);
                         }
                         return KeyValueBox.SetField(this.props.Document, this.props.fieldKey, value);
                     }}
@@ -92,7 +106,7 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
     }
 
     get getCellType() {
-        const columnTypeStr = this.props.schemaView?.fieldInfos[this.props.fieldKey]?.fieldType;
+        const columnTypeStr = this.props.schemaView()?.fieldInfos[this.props.fieldKey]?.fieldType;
         if (columnTypeStr) {
             if (columnTypeStr in FInfotoColType) {
                 return FInfotoColType[columnTypeStr];
@@ -125,7 +139,7 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
             <div
                 className="schema-table-cell"
                 onPointerDown={action(e => {
-                    if (!this.selected) this.props.schemaView?.selectCell(this.props.Document, this.props.col);
+                    if (!this.selected) this.props.schemaView()?.selectCell(this.props.Document, this.props.col);
                 })}
                 style={{ width: this.props.columnWidth, border: this.selected ? `solid 2px ${Colors.MEDIUM_BLUE}` : undefined }}>
                 {this.content}
-- 
cgit v1.2.3-70-g09d2


From ba5b687011526188bb024ddf37c254aaf285c06d Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 27 Apr 2023 16:45:59 -0400
Subject: performance tuning for schema views to avoid re-rendering each table
 cell when child docs change.

---
 .../collectionLinear/CollectionLinearView.tsx      |  20 ++--
 .../collectionSchema/CollectionSchemaView.tsx      | 105 +++++++++------------
 .../collections/collectionSchema/SchemaRowBox.tsx  |  19 ++--
 .../collectionSchema/SchemaTableCell.tsx           |  48 +++++-----
 4 files changed, 94 insertions(+), 98 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaRowBox.tsx')

diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
index 97eed7752..efd73a927 100644
--- a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
+++ b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
@@ -255,15 +255,17 @@ export class CollectionLinearView extends CollectionSubView() {
                         })}
                     />
 
-                    <div
-                        className="collectionLinearView-content"
-                        style={{
-                            height: this.dimension(),
-                            flexDirection: flexDir as any,
-                            gap: flexGap,
-                        }}>
-                        {this.childLayoutPairs.map(pair => this.getDisplayDoc(pair.layout))}
-                    </div>
+                    {!this.layoutDoc.linearViewIsExpanded ? null : (
+                        <div
+                            className="collectionLinearView-content"
+                            style={{
+                                height: this.dimension(),
+                                flexDirection: flexDir as any,
+                                gap: flexGap,
+                            }}>
+                            {this.childLayoutPairs.map(pair => this.getDisplayDoc(pair.layout))}
+                        </div>
+                    )}
                 </div>
             </div>
         );
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 8cd307adf..50a91a60a 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -1,9 +1,9 @@
 import React = require('react');
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, computed, observable, ObservableMap, trace, untracked } from 'mobx';
+import { action, computed, observable, ObservableMap, observe, reaction, trace, untracked } from 'mobx';
 import { observer } from 'mobx-react';
 import { computedFn } from 'mobx-utils';
-import { Doc, DocListCast, Field, StrListCast } from '../../../../fields/Doc';
+import { Doc, DocListCast, Field, NumListCast, StrListCast } from '../../../../fields/Doc';
 import { Id } from '../../../../fields/FieldSymbols';
 import { List } from '../../../../fields/List';
 import { listSpec } from '../../../../fields/Schema';
@@ -47,6 +47,7 @@ const defaultColumnKeys: string[] = ['title', 'type', 'author', 'creationDate',
 
 @observer
 export class CollectionSchemaView extends CollectionSubView() {
+    private _keysDisposer: any;
     private _closestDropIndex: number = 0;
     private _previewRef: HTMLDivElement | null = null;
     private _makeNewColumn: boolean = false;
@@ -58,15 +59,13 @@ export class CollectionSchemaView extends CollectionSubView() {
     public static _rowMenuWidth: number = 60;
     public static _previewDividerWidth: number = 4;
     public static _newNodeInputHeight: number = 30;
+    public fieldInfos = new ObservableMap<string, FInfo>();
 
-    @computed get _selectedDocs() {
-        return SelectionManager.Docs().filter(doc => Doc.AreProtosEqual(DocCast(doc.context), this.props.Document));
-    }
+    @observable _menuKeys: string[] = [];
     @observable _rowEles: ObservableMap = new ObservableMap<Doc, HTMLDivElement>();
     @observable _colEles: HTMLDivElement[] = [];
     @observable _displayColumnWidths: number[] | undefined;
     @observable _columnMenuIndex: number | undefined;
-    @observable _fieldInfos: [string, FInfo][] = [];
     @observable _newFieldWarning: string = '';
     @observable _makeNewField: boolean = false;
     @observable _newFieldDefault: any = 0;
@@ -76,34 +75,12 @@ export class CollectionSchemaView extends CollectionSubView() {
     @observable _filterSearchValue: string = '';
     @observable _selectedCell: [Doc, number] | undefined;
 
-    get fieldInfos() {
-        const docs = this.childDocs;
-        const keys: { [key: string]: boolean } = {};
-        // bcz: ugh.  this is untracked since otherwise a large collection of documents will blast the server for all their fields.
-        //  then as each document's fields come back, we update the documents _proxies.  Each time we do this, the whole schema will be
-        //  invalidated and re-rendered.   This workaround will inquire all of the document fields before the options button is clicked.
-        //  then by the time the options button is clicked, all of the fields should be in place.  If a new field is added while this menu
-        //  is displayed (unlikely) it won't show up until something else changes.
-        //TODO Types
-        untracked(() => docs.map(doc => Doc.GetAllPrototypes(doc).map(proto => Object.keys(proto).forEach(key => (keys[key] = false)))));
-
-        let computedKeys: { [key: string]: FInfo } = {};
-
-        Object.entries(this._documentOptions).forEach((pair: [string, FInfo]) => {
-            computedKeys[pair[0]] = pair[1];
-        });
-
-        Object.keys(keys).forEach((key: string) => {
-            if (!(key in computedKeys)) {
-                computedKeys[key] = new FInfo('');
-            }
-        });
-
-        return computedKeys;
+    @computed get _selectedDocs() {
+        return SelectionManager.Docs().filter(doc => Doc.AreProtosEqual(DocCast(doc.context), this.rootDoc));
     }
 
-    get documentKeys() {
-        return Object.keys(this.fieldInfos);
+    @computed get documentKeys() {
+        return Array.from(this.fieldInfos.keys());
     }
 
     @computed get previewWidth() {
@@ -119,20 +96,15 @@ export class CollectionSchemaView extends CollectionSubView() {
     }
 
     @computed get storedColumnWidths() {
-        let widths = Cast(
+        const widths = NumListCast(
             this.layoutDoc.columnWidths,
-            listSpec('number'),
             this.columnKeys.map(() => (this.tableWidth - CollectionSchemaView._rowMenuWidth) / this.columnKeys.length)
         );
 
         const totalWidth = widths.reduce((sum, width) => sum + width, 0);
         if (totalWidth !== this.tableWidth - CollectionSchemaView._rowMenuWidth) {
-            widths = widths.map(w => {
-                const proportion = w / totalWidth;
-                return proportion * (this.tableWidth - CollectionSchemaView._rowMenuWidth);
-            });
+            return widths.map(w => (w / totalWidth) * (this.tableWidth - CollectionSchemaView._rowMenuWidth));
         }
-
         return widths;
     }
 
@@ -148,19 +120,37 @@ export class CollectionSchemaView extends CollectionSubView() {
         return BoolCast(this.layoutDoc.sortDesc);
     }
 
-    rowIndex(doc: Doc) {
-        return this.sortedDocs.docs.indexOf(doc);
-    }
-
+    @action
     componentDidMount() {
         this.props.setContentView?.(this);
         document.addEventListener('keydown', this.onKeyDown);
+
+        Object.entries(this._documentOptions).forEach((pair: [string, FInfo]) => this.fieldInfos.set(pair[0], pair[1]));
+        this._keysDisposer = observe(
+            this.rootDoc[this.fieldKey ?? 'data'] as List<Doc>,
+            change => {
+                switch (change.type as any) {
+                    case 'splice':
+                        // prettier-ignore
+                        (change as any).added.forEach((doc: Doc) => // for each document added 
+                            Doc.GetAllPrototypes(doc).forEach(proto => // for all of its prototypes (and itself)
+                                Object.keys(proto).forEach(action(key => // check if any of its keys are new, and add them
+                                    !this.fieldInfos.get(key) && this.fieldInfos.set(key, new FInfo(''))))));
+                        break;
+                    case 'update': //let oldValue = change.oldValue; // fill this in if the entire child list will ever be reassigned with a new list
+                }
+            },
+            true
+        );
     }
 
     componentWillUnmount() {
+        this._keysDisposer?.();
         document.removeEventListener('keydown', this.onKeyDown);
     }
 
+    rowIndex = (doc: Doc) => this.sortedDocs.docs.indexOf(doc);
+
     @action
     onKeyDown = (e: KeyboardEvent) => {
         if (this._selectedDocs.length > 0) {
@@ -554,8 +544,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     onSearchKeyDown = (e: React.KeyboardEvent) => {
         switch (e.key) {
             case 'Enter':
-                const menuKeys = Object.keys(this._fieldInfos);
-                menuKeys.length > 0 && this._menuValue.length > 0 ? this.setKey(menuKeys[0]) : action(() => (this._makeNewField = true))();
+                this._menuKeys.length > 0 && this._menuValue.length > 0 ? this.setKey(this._menuKeys[0]) : action(() => (this._makeNewField = true))();
                 break;
             case 'Escape':
                 this.closeColumnMenu();
@@ -584,7 +573,7 @@ export class CollectionSchemaView extends CollectionSubView() {
         this._makeNewColumn = false;
         this._columnMenuIndex = index;
         this._menuValue = '';
-        this._fieldInfos = Object.entries(this.fieldInfos);
+        this._menuKeys = this.documentKeys;
         this._makeNewField = false;
         this._newFieldWarning = '';
         this._makeNewField = false;
@@ -630,7 +619,7 @@ export class CollectionSchemaView extends CollectionSubView() {
     @action
     updateKeySearch = (e: React.ChangeEvent<HTMLInputElement>) => {
         this._menuValue = e.target.value;
-        this._fieldInfos = Object.entries(this.fieldInfos).filter(value => value[0].toLowerCase().includes(this._menuValue.toLowerCase()));
+        this._menuKeys = this.documentKeys.filter(value => value.toLowerCase().includes(this._menuValue.toLowerCase()));
     };
 
     getFieldFilters = (field: string) => StrListCast(this.Document._docFilters).filter(filter => filter.split(':')[0] == field);
@@ -732,7 +721,7 @@ export class CollectionSchemaView extends CollectionSubView() {
                             { passive: false }
                         )
                     }>
-                    {this._fieldInfos.map(([key, info]) => (
+                    {this._menuKeys.map(key => (
                         <div
                             className="schema-search-result"
                             onPointerDown={e => {
@@ -742,13 +731,13 @@ export class CollectionSchemaView extends CollectionSubView() {
                             <p>
                                 <span className="schema-search-result-key">
                                     {key}
-                                    {info.fieldType ? ', ' : ''}
+                                    {this.fieldInfos.get(key)!.fieldType ? ', ' : ''}
                                 </span>
-                                <span className="schema-search-result-type" style={{ color: info.readOnly ? 'red' : 'inherit' }}>
-                                    {info.fieldType}
+                                <span className="schema-search-result-type" style={{ color: this.fieldInfos.get(key)!.readOnly ? 'red' : 'inherit' }}>
+                                    {this.fieldInfos.get(key)!.fieldType}
                                 </span>
                             </p>
-                            <p className="schema-search-result-desc">{info.description}</p>
+                            <p className="schema-search-result-desc">{this.fieldInfos.get(key)!.description}</p>
                         </div>
                     ))}
                 </div>
@@ -888,13 +877,7 @@ export class CollectionSchemaView extends CollectionSubView() {
                     </div>
                     {this._columnMenuIndex !== undefined && this.renderColumnMenu}
                     {this._filterColumnIndex !== undefined && this.renderFilterMenu}
-                    <CollectionSchemaViewDocs
-                        schema={this}
-                        childDocs={this.sortedDocsFunc}
-                        setRef={(ref: HTMLDivElement | null) => {
-                            this._tableContentRef = ref;
-                        }}
-                    />
+                    <CollectionSchemaViewDocs schema={this} childDocs={this.sortedDocsFunc} setRef={(ref: HTMLDivElement | null) => (this._tableContentRef = ref)} />
                     <EditableView GetValue={returnEmptyString} SetValue={this.addNewTextDoc} placeholder={"Type ':' for commands"} contents={'+ New Node'} menuCallback={this.menuCallback} height={CollectionSchemaView._newNodeInputHeight} />
                 </div>
                 {this.previewWidth > 0 && <div className="schema-preview-divider" style={{ width: CollectionSchemaView._previewDividerWidth }} onPointerDown={this.onDividerDown}></div>}
@@ -923,7 +906,7 @@ export class CollectionSchemaView extends CollectionSubView() {
                                 moveDocument={this.props.moveDocument}
                                 addDocument={this.addRow}
                                 removeDocument={this.props.removeDocument}
-                                whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
+                                whenChildContentsActiveChanged={returnFalse}
                                 addDocTab={this.props.addDocTab}
                                 pinToPres={this.props.pinToPres}
                                 bringToFront={returnFalse}
@@ -978,7 +961,7 @@ class CollectionSchemaViewDocs extends React.Component<CollectionSchemaViewDocsP
                                 bringToFront={emptyFunction}
                                 isDocumentActive={this.props.schema.props.childDocumentsActive?.() ? this.props.schema.props.isDocumentActive : this.props.schema.isContentActive}
                                 isContentActive={emptyFunction}
-                                whenChildContentsActiveChanged={active => this.props.schema.props.whenChildContentsActiveChanged(active)}
+                                whenChildContentsActiveChanged={this.props.schema.props.whenChildContentsActiveChanged}
                                 hideDecorations={true}
                                 hideTitle={true}
                                 hideDocumentButtonBar={true}
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 9864820a3..9772ce118 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -12,6 +12,8 @@ import { FieldView, FieldViewProps } from '../../nodes/FieldView';
 import { CollectionSchemaView } from './CollectionSchemaView';
 import './CollectionSchemaView.scss';
 import { SchemaTableCell } from './SchemaTableCell';
+import { computedFn } from 'mobx-utils';
+import { Doc } from '../../../../fields/Doc';
 
 @observer
 export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
@@ -24,12 +26,9 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
     bounds = () => this._ref?.getBoundingClientRect();
 
     @computed get schemaView() {
-        const vpath = this.props.docViewPath();
-        return vpath.length > 1 ? (vpath[vpath.length - 2].ComponentView as CollectionSchemaView) : undefined;
+        return this.props.DocumentView?.().props.docViewPath().lastElement()?.ComponentView as CollectionSchemaView;
     }
 
-    schemaViewFunc = () => this.schemaView;
-
     @computed get schemaDoc() {
         return this.props.DocumentView?.().props.docViewPath().lastElement()?.rootDoc;
     }
@@ -86,6 +85,11 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
         document.removeEventListener('pointermove', this.onPointerMove);
     };
 
+    getFinfo = computedFn((fieldKey: string) => this.schemaView?.fieldInfos.get(fieldKey));
+    selectCell = (doc: Doc, col: number) => this.schemaView?.selectCell(doc, col);
+    deselectCell = () => this.schemaView?.deselectCell();
+    selectedCell = () => this.schemaView?._selectedCell;
+    setColumnValues = (field: any, value: any) => this.schemaView?.setColumnValues(field, value) ?? false;
     render() {
         return (
             <div
@@ -126,11 +130,14 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
                             key={key}
                             Document={this.rootDoc}
                             col={index}
-                            schemaView={this.schemaViewFunc}
                             fieldKey={key}
                             columnWidth={this.schemaView?.displayColumnWidths[index] ?? CollectionSchemaView._minColWidth}
                             isRowActive={this.props.isContentActive}
-                            // setColumnValues={(field, value) => this.schemaView?.setColumnValues(field, value) ?? false}
+                            getFinfo={this.getFinfo}
+                            selectCell={this.selectCell}
+                            deselectCell={this.deselectCell}
+                            selectedCell={this.selectedCell}
+                            setColumnValues={this.setColumnValues}
                         />
                     ))}
                 </div>
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 374b92d72..686b21283 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -1,31 +1,34 @@
 import React = require('react');
+import { action, computed, observable } from 'mobx';
 import { observer } from 'mobx-react';
-import { Doc, DocListCast, Field, Opt } from '../../../../fields/Doc';
-import { Utils, emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnZero } from '../../../../Utils';
+import { extname } from 'path';
+import DatePicker from 'react-datepicker';
+import { DateField } from '../../../../fields/DateField';
+import { Doc, DocListCast, Field } from '../../../../fields/Doc';
+import { Cast, DateCast } from '../../../../fields/Types';
+import { ImageField } from '../../../../fields/URLField';
+import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnZero, Utils } from '../../../../Utils';
 import { Transform } from '../../../util/Transform';
 import { EditableView } from '../../EditableView';
+import { Colors } from '../../global/globalEnums';
 import { FieldView, FieldViewProps } from '../../nodes/FieldView';
 import { KeyValueBox } from '../../nodes/KeyValueBox';
 import { DefaultStyleProvider } from '../../StyleProvider';
 import { CollectionSchemaView, ColumnType, FInfotoColType } from './CollectionSchemaView';
 import './CollectionSchemaView.scss';
-import { action, computed, observable } from 'mobx';
-import { extname } from 'path';
-import { Cast, DateCast, StrCast } from '../../../../fields/Types';
-import { ImageField } from '../../../../fields/URLField';
-import { DateField } from '../../../../fields/DateField';
-import DatePicker from 'react-datepicker';
-import { Colors } from '../../global/globalEnums';
-import { SelectionManager } from '../../../util/SelectionManager';
+import { FInfo } from '../../../documents/Documents';
 
 export interface SchemaTableCellProps {
     Document: Doc;
     col: number;
-    schemaView: () => CollectionSchemaView | undefined;
+    deselectCell: () => void;
+    selectCell: (doc: Doc, col: number) => void;
+    selectedCell: () => [Doc, number] | undefined;
     fieldKey: string;
     columnWidth: number;
     isRowActive: () => boolean | undefined;
-    // setColumnValues: (field: string, value: string) => boolean;
+    getFinfo: (fieldKey: string) => FInfo | undefined;
+    setColumnValues: (field: string, value: string) => boolean;
 }
 
 @observer
@@ -33,11 +36,11 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
     private _editorRef: EditableView | null = null;
 
     @computed get readOnly() {
-        return this.props.schemaView()?.fieldInfos[this.props.fieldKey]?.readOnly ?? false;
+        return this.props.getFinfo(this.props.fieldKey)?.readOnly ?? false;
     }
 
     @computed get selected() {
-        const selected: [Doc, number] | undefined = this.props.schemaView()?._selectedCell;
+        const selected: [Doc, number] | undefined = this.props.selectedCell();
         return this.props.isRowActive() && selected && selected[0] == this.props.Document && selected[1] == this.props.col;
     }
 
@@ -57,11 +60,12 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
             this._editorRef?.setIsFocused(true);
         }
         if (e.key == 'Escape') {
-            this.props.schemaView()?.deselectCell();
+            this.props.deselectCell();
         }
     };
-
-    get defaultCellContent() {
+    colWidthFunc = () => this.props.columnWidth;
+    colRowHeightFunc = () => CollectionSchemaView._rowHeight;
+    @computed get defaultCellContent() {
         const props: FieldViewProps = {
             Document: this.props.Document,
             docFilters: returnEmptyFilter,
@@ -81,8 +85,8 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
             whenChildContentsActiveChanged: emptyFunction,
             ScreenToLocalTransform: Transform.Identity,
             focus: emptyFunction,
-            PanelWidth: () => this.props.columnWidth,
-            PanelHeight: () => CollectionSchemaView._rowHeight,
+            PanelWidth: this.colWidthFunc,
+            PanelHeight: this.colRowHeightFunc,
             addDocTab: returnFalse,
             pinToPres: returnZero,
         };
@@ -95,7 +99,7 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
                     GetValue={() => Field.toKeyValueString(this.props.Document, this.props.fieldKey)}
                     SetValue={(value: string, shiftDown?: boolean, enterKey?: boolean) => {
                         if (shiftDown && enterKey) {
-                            // this.props.setColumnValues(this.props.fieldKey, value);
+                            this.props.setColumnValues(this.props.fieldKey, value);
                         }
                         return KeyValueBox.SetField(this.props.Document, this.props.fieldKey, value);
                     }}
@@ -106,7 +110,7 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
     }
 
     get getCellType() {
-        const columnTypeStr = this.props.schemaView()?.fieldInfos[this.props.fieldKey]?.fieldType;
+        const columnTypeStr = this.props.getFinfo(this.props.fieldKey)?.fieldType;
         if (columnTypeStr) {
             if (columnTypeStr in FInfotoColType) {
                 return FInfotoColType[columnTypeStr];
@@ -139,7 +143,7 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
             <div
                 className="schema-table-cell"
                 onPointerDown={action(e => {
-                    if (!this.selected) this.props.schemaView()?.selectCell(this.props.Document, this.props.col);
+                    if (!this.selected) this.props.selectCell(this.props.Document, this.props.col);
                 })}
                 style={{ width: this.props.columnWidth, border: this.selected ? `solid 2px ${Colors.MEDIUM_BLUE}` : undefined }}>
                 {this.content}
-- 
cgit v1.2.3-70-g09d2


From 223dde9f35408c229a4da583083d10cbf81fc264 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 27 Apr 2023 22:23:42 -0400
Subject: fixed some undo issues with schema fill down.  added bool cell view. 
 added UI for showing/setting values on layout vs data docs.

---
 .../collections/collectionSchema/SchemaRowBox.tsx  |   3 +-
 .../collectionSchema/SchemaTableCell.tsx           | 156 ++++++++++++---------
 src/client/views/nodes/KeyValueBox.tsx             |   2 -
 3 files changed, 89 insertions(+), 72 deletions(-)

(limited to 'src/client/views/collections/collectionSchema/SchemaRowBox.tsx')

diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 9772ce118..ca9e0bda0 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -90,6 +90,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
     deselectCell = () => this.schemaView?.deselectCell();
     selectedCell = () => this.schemaView?._selectedCell;
     setColumnValues = (field: any, value: any) => this.schemaView?.setColumnValues(field, value) ?? false;
+    columnWidth = computedFn((index: number) => () => this.schemaView?.displayColumnWidths[index] ?? CollectionSchemaView._minColWidth);
     render() {
         return (
             <div
@@ -131,7 +132,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
                             Document={this.rootDoc}
                             col={index}
                             fieldKey={key}
-                            columnWidth={this.schemaView?.displayColumnWidths[index] ?? CollectionSchemaView._minColWidth}
+                            columnWidth={this.columnWidth(index)}
                             isRowActive={this.props.isContentActive}
                             getFinfo={this.getFinfo}
                             selectCell={this.selectCell}
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 4f4986b90..1fa4312e1 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -5,10 +5,13 @@ import { extname } from 'path';
 import DatePicker from 'react-datepicker';
 import { DateField } from '../../../../fields/DateField';
 import { Doc, DocListCast, Field } from '../../../../fields/Doc';
-import { Cast, DateCast } from '../../../../fields/Types';
+import { BoolCast, Cast, DateCast } from '../../../../fields/Types';
 import { ImageField } from '../../../../fields/URLField';
 import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnZero, Utils } from '../../../../Utils';
+import { FInfo } from '../../../documents/Documents';
+import { dropActionType } from '../../../util/DragManager';
 import { Transform } from '../../../util/Transform';
+import { undoBatch } from '../../../util/UndoManager';
 import { EditableView } from '../../EditableView';
 import { Colors } from '../../global/globalEnums';
 import { FieldView, FieldViewProps } from '../../nodes/FieldView';
@@ -16,7 +19,6 @@ import { KeyValueBox } from '../../nodes/KeyValueBox';
 import { DefaultStyleProvider } from '../../StyleProvider';
 import { CollectionSchemaView, ColumnType, FInfotoColType } from './CollectionSchemaView';
 import './CollectionSchemaView.scss';
-import { FInfo } from '../../../documents/Documents';
 
 export interface SchemaTableCellProps {
     Document: Doc;
@@ -25,7 +27,7 @@ export interface SchemaTableCellProps {
     selectCell: (doc: Doc, col: number) => void;
     selectedCell: () => [Doc, number] | undefined;
     fieldKey: string;
-    columnWidth: number;
+    columnWidth: () => number;
     isRowActive: () => boolean | undefined;
     getFinfo: (fieldKey: string) => FInfo | undefined;
     setColumnValues: (field: string, value: string) => boolean;
@@ -33,95 +35,78 @@ export interface SchemaTableCellProps {
 
 @observer
 export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
-    private _editorRef: EditableView | null = null;
-
-    @computed get readOnly() {
-        return this.props.getFinfo(this.props.fieldKey)?.readOnly ?? false;
-    }
-
-    @computed get selected() {
-        const selected: [Doc, number] | undefined = this.props.selectedCell();
-        return this.props.isRowActive() && selected && selected[0] == this.props.Document && selected[1] == this.props.col;
+    public static colRowHeightFunc() {
+        return CollectionSchemaView._rowHeight;
     }
-
-    componentDidUpdate() {
-        if (!this.selected) {
-            this._editorRef?.setIsFocused(false);
-            document.removeEventListener('keydown', this.onKeyDown);
-        } else if (!this.readOnly) {
-            document.addEventListener('keydown', this.onKeyDown);
-        }
-    }
-
-    @action
-    onKeyDown = (e: KeyboardEvent) => {
-        e.stopPropagation();
-        if (e.key == 'Enter') {
-            this._editorRef?.setIsFocused(true);
-        }
-        if (e.key == 'Escape') {
-            this.props.deselectCell();
+    public static renderProps(props: SchemaTableCellProps) {
+        const { Document, fieldKey, getFinfo, columnWidth, isRowActive } = props;
+        let protoCount = 0;
+        let doc: Doc | undefined = Document;
+        while (doc) {
+            if (Object.keys(doc).includes(fieldKey.replace(/^_/, ''))) {
+                break;
+            }
+            protoCount++;
+            doc = doc.proto;
         }
-    };
-    colWidthFunc = () => this.props.columnWidth;
-    colRowHeightFunc = () => CollectionSchemaView._rowHeight;
-    @computed get defaultCellContent() {
-        const props: FieldViewProps = {
-            Document: this.props.Document,
+        const parenCount = Math.max(0, protoCount - 1);
+        const color = protoCount === 0 || (fieldKey.startsWith('_') && Document[fieldKey] === undefined) ? 'black' : 'blue';
+        const textDecoration = color !== 'black' && parenCount ? 'underline' : '';
+        const fieldProps: FieldViewProps = {
             docFilters: returnEmptyFilter,
             docRangeFilters: returnEmptyFilter,
             searchFilterDocs: returnEmptyDoclist,
             styleProvider: DefaultStyleProvider,
             docViewPath: returnEmptyDoclist,
-            fieldKey: this.props.fieldKey,
             rootSelected: returnFalse,
             isSelected: returnFalse,
             setHeight: returnFalse,
             select: emptyFunction,
-            dropAction: 'alias',
+            dropAction: 'alias' as dropActionType,
             bringToFront: emptyFunction,
             renderDepth: 1,
             isContentActive: returnFalse,
             whenChildContentsActiveChanged: emptyFunction,
             ScreenToLocalTransform: Transform.Identity,
             focus: emptyFunction,
-            PanelWidth: this.colWidthFunc,
-            PanelHeight: this.colRowHeightFunc,
             addDocTab: returnFalse,
             pinToPres: returnZero,
+            Document,
+            fieldKey,
+            PanelWidth: columnWidth,
+            PanelHeight: SchemaTableCell.colRowHeightFunc,
         };
-        let protoCount = 0;
-        let doc: Doc | undefined = this.props.Document;
-        while (doc) {
-            if (Object.keys(doc).includes(this.props.fieldKey.replace(/^_/, ''))) {
-                break;
-            }
-            protoCount++;
-            doc = doc.proto;
-        }
-        const parenCount = Math.max(0, protoCount - 1);
-        const color = protoCount === 0 ? 'black' : 'blue';
+        const readOnly = getFinfo(fieldKey)?.readOnly ?? false;
+        const cursor = !readOnly ? 'text' : 'default';
+        const pointerEvents: 'all' | 'none' = !readOnly && isRowActive() ? 'all' : 'none';
+        return { color, textDecoration, fieldProps, cursor, pointerEvents };
+    }
+
+    @computed get selected() {
+        const selected: [Doc, number] | undefined = this.props.selectedCell();
+        return this.props.isRowActive() && selected?.[0] === this.props.Document && selected[1] === this.props.col;
+    }
+
+    @computed get defaultCellContent() {
+        const { color, textDecoration, fieldProps } = SchemaTableCell.renderProps(this.props);
 
         return (
             <div
                 className="schemacell-edit-wrapper"
                 style={{
                     color,
-                    textDecoration: parenCount ? 'underline' : undefined,
-                    cursor: !this.readOnly ? 'text' : 'default',
-                    pointerEvents: !this.readOnly && this.props.isRowActive() ? 'all' : 'none',
+                    textDecoration,
                 }}>
                 <EditableView
-                    ref={ref => (this._editorRef = ref)}
-                    contents={<FieldView {...props} />}
+                    contents={<FieldView {...fieldProps} />}
+                    editing={this.selected ? undefined : false}
                     GetValue={() => Field.toKeyValueString(this.props.Document, this.props.fieldKey)}
-                    SetValue={(value: string, shiftDown?: boolean, enterKey?: boolean) => {
+                    SetValue={undoBatch((value: string, shiftDown?: boolean, enterKey?: boolean) => {
                         if (shiftDown && enterKey) {
                             this.props.setColumnValues(this.props.fieldKey, value);
                         }
                         return KeyValueBox.SetField(this.props.Document, this.props.fieldKey, value);
-                    }}
-                    editing={this.selected ? undefined : false}
+                    })}
                 />
             </div>
         );
@@ -146,13 +131,12 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
 
     get content() {
         const cellType: ColumnType = this.getCellType;
+        // prettier-ignore
         switch (cellType) {
-            case ColumnType.Image:
-                return <SchemaImageCell {...this.props} />;
-            case ColumnType.Date:
-            // return <SchemaDateCell {...this.props} />;
-            default:
-                return this.defaultCellContent;
+            case ColumnType.Image: return <SchemaImageCell {...this.props} />;
+            case ColumnType.Boolean: return <SchemaBoolCell {...this.props} />;
+            case ColumnType.Date: // return <SchemaDateCell {...this.props} />;
+            default:  return this.defaultCellContent;
         }
     }
 
@@ -160,10 +144,8 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
         return (
             <div
                 className="schema-table-cell"
-                onPointerDown={action(e => {
-                    if (!this.selected) this.props.selectCell(this.props.Document, this.props.col);
-                })}
-                style={{ width: this.props.columnWidth, border: this.selected ? `solid 2px ${Colors.MEDIUM_BLUE}` : undefined }}>
+                onPointerDown={action(e => !this.selected && this.props.selectCell(this.props.Document, this.props.col))}
+                style={{ width: this.props.columnWidth(), border: this.selected ? `solid 2px ${Colors.MEDIUM_BLUE}` : undefined }}>
                 {this.content}
             </div>
         );
@@ -257,3 +239,39 @@ export class SchemaDateCell extends React.Component<SchemaTableCellProps> {
         return <DatePicker dateFormat={'Pp'} selected={this.date.date} onChange={(date: any) => this.handleChange(date)} />;
     }
 }
+@observer
+export class SchemaBoolCell extends React.Component<SchemaTableCellProps> {
+    @computed get selected() {
+        const selected: [Doc, number] | undefined = this.props.selectedCell();
+        return this.props.isRowActive() && selected?.[0] === this.props.Document && selected[1] === this.props.col;
+    }
+    render() {
+        const { color, textDecoration, fieldProps, cursor, pointerEvents } = SchemaTableCell.renderProps(this.props);
+        return (
+            <div className="schemaBoolCell" style={{ display: 'flex', color, textDecoration, cursor, pointerEvents }}>
+                <input
+                    style={{ marginRight: 4 }}
+                    type="checkbox"
+                    checked={BoolCast(this.props.Document[this.props.fieldKey])}
+                    onChange={undoBatch((value: React.ChangeEvent<HTMLInputElement> | undefined) => {
+                        if ((value?.nativeEvent as any).shiftKey) {
+                            this.props.setColumnValues(this.props.fieldKey, (color === 'black' ? '=' : '') + value?.target?.checked.toString());
+                        }
+                        KeyValueBox.SetField(this.props.Document, this.props.fieldKey.replace(/^_/, ''), (color === 'black' ? '=' : '') + value?.target?.checked.toString());
+                    })}
+                />
+                <EditableView
+                    contents={<FieldView {...fieldProps} />}
+                    editing={this.selected ? undefined : false}
+                    GetValue={() => (color === 'black' ? '=' : '') + Field.toKeyValueString(this.props.Document, this.props.fieldKey)}
+                    SetValue={undoBatch((value: string, shiftDown?: boolean, enterKey?: boolean) => {
+                        if (shiftDown && enterKey) {
+                            this.props.setColumnValues(this.props.fieldKey, value);
+                        }
+                        return KeyValueBox.SetField(this.props.Document, this.props.fieldKey.replace(/^_/, ''), value);
+                    })}
+                />
+            </div>
+        );
+    }
+}
diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx
index 57018fb93..11220c300 100644
--- a/src/client/views/nodes/KeyValueBox.tsx
+++ b/src/client/views/nodes/KeyValueBox.tsx
@@ -20,14 +20,12 @@ import { ImageBox } from './ImageBox';
 import './KeyValueBox.scss';
 import { KeyValuePair } from './KeyValuePair';
 import React = require('react');
-import e = require('express');
 
 export type KVPScript = {
     script: CompiledScript;
     type: 'computed' | 'script' | false;
     onDelegate: boolean;
 };
-
 @observer
 export class KeyValueBox extends React.Component<FieldViewProps> {
     public static LayoutString() {
-- 
cgit v1.2.3-70-g09d2

