From 7f42c98318899a51cb64080fc4f4e315e43bb150 Mon Sep 17 00:00:00 2001
From: 0x85FB9C51 <77808164+0x85FB9C51@users.noreply.github.com>
Date: Tue, 6 Jul 2021 23:47:38 -0400
Subject: reoganization of schema view files, partial

---
 .../views/collections/schemaView/SchemaTable.tsx   | 599 +++++++++++++++++++++
 1 file changed, 599 insertions(+)
 create mode 100644 src/client/views/collections/schemaView/SchemaTable.tsx

(limited to 'src/client/views/collections/schemaView/SchemaTable.tsx')

diff --git a/src/client/views/collections/schemaView/SchemaTable.tsx b/src/client/views/collections/schemaView/SchemaTable.tsx
new file mode 100644
index 000000000..c305f6806
--- /dev/null
+++ b/src/client/views/collections/schemaView/SchemaTable.tsx
@@ -0,0 +1,599 @@
+import React = require("react");
+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 ReactTable, { CellInfo, Column, ComponentPropsGetterR, Resize, SortingRule } from "react-table";
+import "react-table/react-table.css";
+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, emptyPath, 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 { COLLECTION_BORDER_WIDTH, SCHEMA_DIVIDER_WIDTH } from '../../globalCssVariables.scss';
+import { ContextMenu } from "../../ContextMenu";
+import '../DocumentDecorations.scss';
+import { DocumentView } from "../../nodes/DocumentView";
+import { DefaultStyleProvider } from "../../StyleProvider";
+import { CellProps, CollectionSchemaButtons, CollectionSchemaCell, CollectionSchemaCheckboxCell, CollectionSchemaDateCell, CollectionSchemaDocCell, CollectionSchemaImageCell, CollectionSchemaListCell, CollectionSchemaNumberCell, CollectionSchemaStringCell } from "./CollectionSchemaCells";
+import { CollectionSchemaAddColumnHeader, KeysDropdown } from "./CollectionSchemaHeaders";
+import { MovableColumn, MovableRow } from "./CollectionSchemaMovableTableHOC";
+import "./CollectionSchemaView.scss";
+import { CollectionView } from "../CollectionView";
+
+
+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;
+    onDrop: (e: React.DragEvent<Element>, options: DocumentOptions, completed?: (() => void) | undefined) => void;
+    addDocTab: (document: Doc, where: string) => boolean;
+    pinToPres: (document: Doc) => 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: "hand" }}>
+                    <FontAwesomeIcon icon={sortIcon} size="lg" />
+                </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 = () => {
+        let index = 0;
+        let found = this.props.columns.findIndex(col => col.heading.toUpperCase() === "New field".toUpperCase()) > -1;
+        while (found) {
+            index++;
+            found = this.props.columns.findIndex(col => col.heading.toUpperCase() === ("New field (" + index + ")").toUpperCase()) > -1;
+        }
+        this.props.columns.push(new SchemaHeaderField(`New field ${index ? "(" + index + ")" : ""}`, "#f1efeb"));
+    }
+
+    @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}
+            SubComponent={!hasCollectionChild ? undefined : row => (row.original.type !== DocumentType.COL) ? (null) :
+                <div 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, "add:right");
+    }
+
+    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 ? 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}
+                        layerProvider={undefined}
+                        docViewPath={returnEmptyDoclist}
+                        freezeDimensions={true}
+                        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>;
+    }
+}
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From 0ac0b74de8578062aa7f700779613ff0e18a12ea Mon Sep 17 00:00:00 2001
From: 0x85FB9C51 <77808164+0x85FB9C51@users.noreply.github.com>
Date: Thu, 8 Jul 2021 09:48:51 -0400
Subject: fixed file path mess

---
 src/client/views/collections/CollectionView.tsx    |  2 +-
 .../schemaView/CollectionSchemaCells.tsx           |  2 +-
 .../schemaView/CollectionSchemaHeaders.tsx         |  3 +-
 .../schemaView/CollectionSchemaMovableTableHOC.tsx | 18 +++++-----
 .../schemaView/CollectionSchemaView.tsx            | 38 +++++++++++-----------
 .../views/collections/schemaView/SchemaTable.tsx   |  2 +-
 src/client/views/search/SearchBox.tsx              |  4 +--
 7 files changed, 35 insertions(+), 34 deletions(-)

(limited to 'src/client/views/collections/schemaView/SchemaTable.tsx')

diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index fb60265e3..e5b1721f9 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -29,7 +29,7 @@ import CollectionMapView from './CollectionMapView';
 import { CollectionMulticolumnView } from './collectionMulticolumn/CollectionMulticolumnView';
 import { CollectionMultirowView } from './collectionMulticolumn/CollectionMultirowView';
 import { CollectionPileView } from './CollectionPileView';
-import { CollectionSchemaView } from "./CollectionSchemaView";
+import { CollectionSchemaView } from "./schemaView/CollectionSchemaView";
 import { CollectionStackingView } from './CollectionStackingView';
 import { SubCollectionViewProps } from './CollectionSubView';
 import { CollectionTimeView } from './CollectionTimeView';
diff --git a/src/client/views/collections/schemaView/CollectionSchemaCells.tsx b/src/client/views/collections/schemaView/CollectionSchemaCells.tsx
index 2549beaae..f2df87d71 100644
--- a/src/client/views/collections/schemaView/CollectionSchemaCells.tsx
+++ b/src/client/views/collections/schemaView/CollectionSchemaCells.tsx
@@ -24,7 +24,7 @@ import { CompileScript } from "../../../util/Scripting";
 import { SearchUtil } from "../../../util/SearchUtil";
 import { SnappingManager } from "../../../util/SnappingManager";
 import { undoBatch } from "../../../util/UndoManager";
-import '../DocumentDecorations.scss';
+import '../../../views/DocumentDecorations.scss';
 import { EditableView } from "../../EditableView";
 import { MAX_ROW_HEIGHT } from '../../globalCssVariables.scss';
 import { DocumentIconContainer } from "../../nodes/DocumentIcon";
diff --git a/src/client/views/collections/schemaView/CollectionSchemaHeaders.tsx b/src/client/views/collections/schemaView/CollectionSchemaHeaders.tsx
index b825d6d96..ab3076224 100644
--- a/src/client/views/collections/schemaView/CollectionSchemaHeaders.tsx
+++ b/src/client/views/collections/schemaView/CollectionSchemaHeaders.tsx
@@ -10,7 +10,8 @@ import { ScriptField } from "../../../../fields/ScriptField";
 import { Cast, StrCast } from "../../../../fields/Types";
 import { undoBatch } from "../../../util/UndoManager";
 import { SearchBox } from "../../search/SearchBox";
-import { ColumnType } from "../CollectionSchemaView";
+import { ColumnType } from "./CollectionSchemaView";
+import { ColumnType2 } from "../CollectionSchemaView";
 import "./CollectionSchemaView.scss";
 import { CollectionView } from "../CollectionView";
 
diff --git a/src/client/views/collections/schemaView/CollectionSchemaMovableTableHOC.tsx b/src/client/views/collections/schemaView/CollectionSchemaMovableTableHOC.tsx
index 149677976..e1066caf4 100644
--- a/src/client/views/collections/schemaView/CollectionSchemaMovableTableHOC.tsx
+++ b/src/client/views/collections/schemaView/CollectionSchemaMovableTableHOC.tsx
@@ -2,15 +2,15 @@ import React = require("react");
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 import { action } from "mobx";
 import { ReactTableDefaults, RowInfo, TableCellRenderer } from "react-table";
-import { Doc } from "../../../fields/Doc";
-import { SchemaHeaderField } from "../../../fields/SchemaHeaderField";
-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 { Doc } from "../../../../fields/Doc";
+import { SchemaHeaderField } from "../../../../fields/SchemaHeaderField";
+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 "./CollectionSchemaView.scss";
 
 export interface MovableColumnProps {
diff --git a/src/client/views/collections/schemaView/CollectionSchemaView.tsx b/src/client/views/collections/schemaView/CollectionSchemaView.tsx
index b33c437a9..ef28f75c8 100644
--- a/src/client/views/collections/schemaView/CollectionSchemaView.tsx
+++ b/src/client/views/collections/schemaView/CollectionSchemaView.tsx
@@ -5,27 +5,27 @@ import { observer } from "mobx-react";
 import Measure from "react-measure";
 import { Resize } from "react-table";
 import "react-table/react-table.css";
-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, emptyPath, returnFalse, setupMoveUpEvents, returnEmptyDoclist, returnTrue } from "../../../Utils";
-import { SelectionManager } from "../../util/SelectionManager";
-import { SnappingManager } from "../../util/SnappingManager";
-import { Transform } from "../../util/Transform";
-import { undoBatch } from "../../util/UndoManager";
-import { COLLECTION_BORDER_WIDTH, SCHEMA_DIVIDER_WIDTH } from '../../views/globalCssVariables.scss';
-import { ContextMenu } from "../ContextMenu";
-import { ContextMenuProps } from "../ContextMenuItem";
-import '../DocumentDecorations.scss';
-import { DocumentView } from "../nodes/DocumentView";
-import { DefaultStyleProvider } from "../StyleProvider";
+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, emptyPath, returnFalse, setupMoveUpEvents, returnEmptyDoclist, returnTrue } from "../../../../Utils";
+import { SelectionManager } from "../../../util/SelectionManager";
+import { SnappingManager } from "../../../util/SnappingManager";
+import { Transform } from "../../../util/Transform";
+import { undoBatch } from "../../../util/UndoManager";
+import { COLLECTION_BORDER_WIDTH, SCHEMA_DIVIDER_WIDTH } from '../../globalCssVariables.scss';
+import { ContextMenu } from "../../ContextMenu";
+import { ContextMenuProps } from "../../ContextMenuItem";
+import '../../../views/DocumentDecorations.scss';
+import { DocumentView } from "../../nodes/DocumentView";
+import { DefaultStyleProvider } from "../../StyleProvider";
 import "./CollectionSchemaView.scss";
-import { CollectionSubView } from "./CollectionSubView";
+import { CollectionSubView } from "../CollectionSubView";
 import { SchemaTable } from "./SchemaTable";
-import { DocUtils } from "../../documents/Documents";
+import { DocUtils } from "../../../documents/Documents";
 // 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 {
diff --git a/src/client/views/collections/schemaView/SchemaTable.tsx b/src/client/views/collections/schemaView/SchemaTable.tsx
index c305f6806..05d77a739 100644
--- a/src/client/views/collections/schemaView/SchemaTable.tsx
+++ b/src/client/views/collections/schemaView/SchemaTable.tsx
@@ -23,7 +23,7 @@ import { Transform } from "../../../util/Transform";
 import { undoBatch } from "../../../util/UndoManager";
 import { COLLECTION_BORDER_WIDTH, SCHEMA_DIVIDER_WIDTH } from '../../globalCssVariables.scss';
 import { ContextMenu } from "../../ContextMenu";
-import '../DocumentDecorations.scss';
+import '../../../views/DocumentDecorations.scss';
 import { DocumentView } from "../../nodes/DocumentView";
 import { DefaultStyleProvider } from "../../StyleProvider";
 import { CellProps, CollectionSchemaButtons, CollectionSchemaCell, CollectionSchemaCheckboxCell, CollectionSchemaDateCell, CollectionSchemaDocCell, CollectionSchemaImageCell, CollectionSchemaListCell, CollectionSchemaNumberCell, CollectionSchemaStringCell } from "./CollectionSchemaCells";
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index 5c168d8a9..a671c955d 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -18,7 +18,7 @@ import { SetupDrag } from '../../util/DragManager';
 import { SearchUtil } from '../../util/SearchUtil';
 import { Transform } from '../../util/Transform';
 import { CollectionDockingView } from "../collections/CollectionDockingView";
-import { CollectionSchemaView, ColumnType } from "../collections/CollectionSchemaView";
+import { CollectionSchemaView, ColumnType } from "../collections/schemaView/CollectionSchemaView";
 import { CollectionViewType } from '../collections/CollectionView';
 import { ViewBoxBaseComponent } from "../DocComponent";
 import { FieldView, FieldViewProps } from '../nodes/FieldView';
@@ -119,7 +119,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
 
     getFinalQuery(query: string): string {
         //alters the query so it looks in the correct fields
-        //if this is true, th`en not all of the field boxes are checked
+        //if this is true, then not all of the field boxes are checked
         //TODO: data
         const initialfilters = Cast(this.props.Document._docFilters, listSpec("string"), []);
 
-- 
cgit v1.2.3-70-g09d2


From dda6b85a142f5b47cb01e63777cc031aa556d491 Mon Sep 17 00:00:00 2001
From: 0x85FB9C51 <77808164+0x85FB9C51@users.noreply.github.com>
Date: Sat, 10 Jul 2021 15:51:32 -0400
Subject: Seperated a file into two for organizaitonal purposes

---
 .../schemaView/CollectionSchemaMovableColumn.tsx   | 261 +++++++++++++++++++++
 .../schemaView/CollectionSchemaMovableRow.tsx      | 147 ++++++++++++
 .../schemaView/CollectionSchemaMovableTableHOC.tsx | 261 ---------------------
 .../views/collections/schemaView/SchemaTable.tsx   |   3 +-
 4 files changed, 410 insertions(+), 262 deletions(-)
 create mode 100644 src/client/views/collections/schemaView/CollectionSchemaMovableColumn.tsx
 create mode 100644 src/client/views/collections/schemaView/CollectionSchemaMovableRow.tsx
 delete mode 100644 src/client/views/collections/schemaView/CollectionSchemaMovableTableHOC.tsx

(limited to 'src/client/views/collections/schemaView/SchemaTable.tsx')

diff --git a/src/client/views/collections/schemaView/CollectionSchemaMovableColumn.tsx b/src/client/views/collections/schemaView/CollectionSchemaMovableColumn.tsx
new file mode 100644
index 000000000..e1066caf4
--- /dev/null
+++ b/src/client/views/collections/schemaView/CollectionSchemaMovableColumn.tsx
@@ -0,0 +1,261 @@
+import React = require("react");
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { action } from "mobx";
+import { ReactTableDefaults, RowInfo, TableCellRenderer } from "react-table";
+import { Doc } from "../../../../fields/Doc";
+import { SchemaHeaderField } from "../../../../fields/SchemaHeaderField";
+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 "./CollectionSchemaView.scss";
+
+export interface MovableColumnProps {
+    columnRenderer: TableCellRenderer;
+    columnValue: SchemaHeaderField;
+    allColumns: SchemaHeaderField[];
+    reorderColumns: (toMove: SchemaHeaderField, relativeTo: SchemaHeaderField, before: boolean, columns: SchemaHeaderField[]) => void;
+    ScreenToLocalTransform: () => Transform;
+}
+export class MovableColumn extends React.Component<MovableColumnProps> {
+    private _header?: React.RefObject<HTMLDivElement> = React.createRef();
+    private _colDropDisposer?: DragManager.DragDropDisposer;
+    private _startDragPosition: { x: number, y: number } = { x: 0, y: 0 };
+    private _sensitivity: number = 16;
+    private _dragRef: React.RefObject<HTMLDivElement> = React.createRef();
+
+    onPointerEnter = (e: React.PointerEvent): void => {
+        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);
+    }
+    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.right - rect.left) / 2), rect.top);
+        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));
+        }
+    }
+
+    colDrop = (e: Event, de: DragManager.DropEvent) => {
+        document.removeEventListener("pointermove", this.onDragMove, true);
+        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.right - rect.left) / 2), rect.top);
+        const before = x[0] < bounds[0];
+        const colDragData = de.complete.columnDragData;
+        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();
+
+            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 (e.buttons === 1) {
+            const [dx, dy] = this.props.ScreenToLocalTransform().transformDirection(e.clientX - this._startDragPosition.x, e.clientY - this._startDragPosition.y);
+            if (Math.abs(dx) + Math.abs(dy) > this._sensitivity) {
+                document.removeEventListener("pointermove", this.onPointerMove);
+                e.stopPropagation();
+
+                document.addEventListener("pointermove", onRowMove);
+                document.addEventListener("pointerup", onRowUp);
+            }
+        }
+    }
+
+    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 (!(e.target as any)?.tagName.includes("INPUT")) {
+            this._startDragPosition = { x: dx, y: dy };
+            document.addEventListener("pointermove", this.onPointerMove);
+        }
+    }
+
+
+    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>
+        );
+    }
+}
+
+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<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;
+
+        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;
+    }
+
+    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);
+    }
+
+    @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;
+
+        if (!rowInfo) {
+            return <ReactTableDefaults.TrComponent>{children}</ReactTableDefaults.TrComponent>;
+        }
+
+        const { original } = rowInfo;
+        const doc = FieldValue(Cast(original, Doc));
+
+        if (!doc) return (null);
+
+        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";
+
+        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" style={{ left: 5 }} onClick={undoBatch(() => this.props.removeDoc(this.props.rowInfo.original))}><FontAwesomeIcon icon="trash" size="sm" /></div>
+                            <div className="row-option" style={{ cursor: "grab", left: 25 }} ref={reference} onPointerDown={onItemDown}><FontAwesomeIcon icon="grip-vertical" size="sm" /></div>
+                            <div className="row-option" style={{ left: 40 }} onClick={() => this.props.addDocTab(this.props.rowInfo.original, "add:right")}><FontAwesomeIcon icon="external-link-alt" size="sm" /></div>
+                        </div>
+                        {children}
+                    </ReactTableDefaults.TrComponent>
+                </div>
+            </div>
+        );
+    }
+}
\ No newline at end of file
diff --git a/src/client/views/collections/schemaView/CollectionSchemaMovableRow.tsx b/src/client/views/collections/schemaView/CollectionSchemaMovableRow.tsx
new file mode 100644
index 000000000..f48906ba5
--- /dev/null
+++ b/src/client/views/collections/schemaView/CollectionSchemaMovableRow.tsx
@@ -0,0 +1,147 @@
+import React = require("react");
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { action } from "mobx";
+import { ReactTableDefaults, RowInfo, TableCellRenderer } from "react-table";
+import { Doc } from "../../../../fields/Doc";
+import { SchemaHeaderField } from "../../../../fields/SchemaHeaderField";
+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 "./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 class MovableRow extends React.Component<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;
+
+        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;
+    }
+
+    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);
+    }
+
+    @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;
+
+        if (!rowInfo) {
+            return <ReactTableDefaults.TrComponent>{children}</ReactTableDefaults.TrComponent>;
+        }
+
+        const { original } = rowInfo;
+        const doc = FieldValue(Cast(original, Doc));
+
+        if (!doc) return (null);
+
+        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";
+
+        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" style={{ left: 5 }} onClick={undoBatch(() => this.props.removeDoc(this.props.rowInfo.original))}><FontAwesomeIcon icon="trash" size="sm" /></div>
+                            <div className="row-option" style={{ cursor: "grab", left: 25 }} ref={reference} onPointerDown={onItemDown}><FontAwesomeIcon icon="grip-vertical" size="sm" /></div>
+                            <div className="row-option" style={{ left: 40 }} onClick={() => this.props.addDocTab(this.props.rowInfo.original, "add:right")}><FontAwesomeIcon icon="external-link-alt" size="sm" /></div>
+                        </div>
+                        {children}
+                    </ReactTableDefaults.TrComponent>
+                </div>
+            </div>
+        );
+    }
+}
\ No newline at end of file
diff --git a/src/client/views/collections/schemaView/CollectionSchemaMovableTableHOC.tsx b/src/client/views/collections/schemaView/CollectionSchemaMovableTableHOC.tsx
deleted file mode 100644
index e1066caf4..000000000
--- a/src/client/views/collections/schemaView/CollectionSchemaMovableTableHOC.tsx
+++ /dev/null
@@ -1,261 +0,0 @@
-import React = require("react");
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { action } from "mobx";
-import { ReactTableDefaults, RowInfo, TableCellRenderer } from "react-table";
-import { Doc } from "../../../../fields/Doc";
-import { SchemaHeaderField } from "../../../../fields/SchemaHeaderField";
-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 "./CollectionSchemaView.scss";
-
-export interface MovableColumnProps {
-    columnRenderer: TableCellRenderer;
-    columnValue: SchemaHeaderField;
-    allColumns: SchemaHeaderField[];
-    reorderColumns: (toMove: SchemaHeaderField, relativeTo: SchemaHeaderField, before: boolean, columns: SchemaHeaderField[]) => void;
-    ScreenToLocalTransform: () => Transform;
-}
-export class MovableColumn extends React.Component<MovableColumnProps> {
-    private _header?: React.RefObject<HTMLDivElement> = React.createRef();
-    private _colDropDisposer?: DragManager.DragDropDisposer;
-    private _startDragPosition: { x: number, y: number } = { x: 0, y: 0 };
-    private _sensitivity: number = 16;
-    private _dragRef: React.RefObject<HTMLDivElement> = React.createRef();
-
-    onPointerEnter = (e: React.PointerEvent): void => {
-        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);
-    }
-    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.right - rect.left) / 2), rect.top);
-        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));
-        }
-    }
-
-    colDrop = (e: Event, de: DragManager.DropEvent) => {
-        document.removeEventListener("pointermove", this.onDragMove, true);
-        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.right - rect.left) / 2), rect.top);
-        const before = x[0] < bounds[0];
-        const colDragData = de.complete.columnDragData;
-        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();
-
-            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 (e.buttons === 1) {
-            const [dx, dy] = this.props.ScreenToLocalTransform().transformDirection(e.clientX - this._startDragPosition.x, e.clientY - this._startDragPosition.y);
-            if (Math.abs(dx) + Math.abs(dy) > this._sensitivity) {
-                document.removeEventListener("pointermove", this.onPointerMove);
-                e.stopPropagation();
-
-                document.addEventListener("pointermove", onRowMove);
-                document.addEventListener("pointerup", onRowUp);
-            }
-        }
-    }
-
-    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 (!(e.target as any)?.tagName.includes("INPUT")) {
-            this._startDragPosition = { x: dx, y: dy };
-            document.addEventListener("pointermove", this.onPointerMove);
-        }
-    }
-
-
-    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>
-        );
-    }
-}
-
-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<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;
-
-        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;
-    }
-
-    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);
-    }
-
-    @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;
-
-        if (!rowInfo) {
-            return <ReactTableDefaults.TrComponent>{children}</ReactTableDefaults.TrComponent>;
-        }
-
-        const { original } = rowInfo;
-        const doc = FieldValue(Cast(original, Doc));
-
-        if (!doc) return (null);
-
-        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";
-
-        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" style={{ left: 5 }} onClick={undoBatch(() => this.props.removeDoc(this.props.rowInfo.original))}><FontAwesomeIcon icon="trash" size="sm" /></div>
-                            <div className="row-option" style={{ cursor: "grab", left: 25 }} ref={reference} onPointerDown={onItemDown}><FontAwesomeIcon icon="grip-vertical" size="sm" /></div>
-                            <div className="row-option" style={{ left: 40 }} onClick={() => this.props.addDocTab(this.props.rowInfo.original, "add:right")}><FontAwesomeIcon icon="external-link-alt" size="sm" /></div>
-                        </div>
-                        {children}
-                    </ReactTableDefaults.TrComponent>
-                </div>
-            </div>
-        );
-    }
-}
\ No newline at end of file
diff --git a/src/client/views/collections/schemaView/SchemaTable.tsx b/src/client/views/collections/schemaView/SchemaTable.tsx
index 05d77a739..a735d4257 100644
--- a/src/client/views/collections/schemaView/SchemaTable.tsx
+++ b/src/client/views/collections/schemaView/SchemaTable.tsx
@@ -28,7 +28,8 @@ import { DocumentView } from "../../nodes/DocumentView";
 import { DefaultStyleProvider } from "../../StyleProvider";
 import { CellProps, CollectionSchemaButtons, CollectionSchemaCell, CollectionSchemaCheckboxCell, CollectionSchemaDateCell, CollectionSchemaDocCell, CollectionSchemaImageCell, CollectionSchemaListCell, CollectionSchemaNumberCell, CollectionSchemaStringCell } from "./CollectionSchemaCells";
 import { CollectionSchemaAddColumnHeader, KeysDropdown } from "./CollectionSchemaHeaders";
-import { MovableColumn, MovableRow } from "./CollectionSchemaMovableTableHOC";
+import { MovableColumn } from "./CollectionSchemaMovableColumn";
+import { MovableRow } from "./CollectionSchemaMovableRow";
 import "./CollectionSchemaView.scss";
 import { CollectionView } from "../CollectionView";
 
-- 
cgit v1.2.3-70-g09d2


From a5c099cb5ae455064f65989dc977870ce2c3f7fc Mon Sep 17 00:00:00 2001
From: 0x85FB9C51 <77808164+0x85FB9C51@users.noreply.github.com>
Date: Sat, 10 Jul 2021 16:57:45 -0400
Subject: added indentation for visibility of hierarchy

---
 src/client/util/SelectionManager.ts                |   2 +-
 .../schemaView/CollectionSchemaHeaders.tsx         |   1 -
 .../schemaView/CollectionSchemaMovableColumn.tsx   | 133 ---------------------
 .../views/collections/schemaView/SchemaTable.tsx   |   3 +-
 src/fields/SchemaHeaderField.ts                    |   2 +-
 5 files changed, 4 insertions(+), 137 deletions(-)

(limited to 'src/client/views/collections/schemaView/SchemaTable.tsx')

diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts
index ca5ef75d2..a624d5b7c 100644
--- a/src/client/util/SelectionManager.ts
+++ b/src/client/util/SelectionManager.ts
@@ -1,7 +1,7 @@
 import { action, observable, ObservableMap } from "mobx";
 import { computedFn } from "mobx-utils";
 import { Doc, Opt } from "../../fields/Doc";
-import { CollectionSchemaView } from "../views/collections/CollectionSchemaView";
+import { CollectionSchemaView } from "../views/collections/schemaView/CollectionSchemaView";
 import { CollectionViewType } from "../views/collections/CollectionView";
 import { DocumentView } from "../views/nodes/DocumentView";
 
diff --git a/src/client/views/collections/schemaView/CollectionSchemaHeaders.tsx b/src/client/views/collections/schemaView/CollectionSchemaHeaders.tsx
index ab3076224..b2115b22e 100644
--- a/src/client/views/collections/schemaView/CollectionSchemaHeaders.tsx
+++ b/src/client/views/collections/schemaView/CollectionSchemaHeaders.tsx
@@ -11,7 +11,6 @@ import { Cast, StrCast } from "../../../../fields/Types";
 import { undoBatch } from "../../../util/UndoManager";
 import { SearchBox } from "../../search/SearchBox";
 import { ColumnType } from "./CollectionSchemaView";
-import { ColumnType2 } from "../CollectionSchemaView";
 import "./CollectionSchemaView.scss";
 import { CollectionView } from "../CollectionView";
 
diff --git a/src/client/views/collections/schemaView/CollectionSchemaMovableColumn.tsx b/src/client/views/collections/schemaView/CollectionSchemaMovableColumn.tsx
index e1066caf4..456c38c68 100644
--- a/src/client/views/collections/schemaView/CollectionSchemaMovableColumn.tsx
+++ b/src/client/views/collections/schemaView/CollectionSchemaMovableColumn.tsx
@@ -126,136 +126,3 @@ export class MovableColumn extends React.Component<MovableColumnProps> {
         );
     }
 }
-
-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<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;
-
-        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;
-    }
-
-    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);
-    }
-
-    @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;
-
-        if (!rowInfo) {
-            return <ReactTableDefaults.TrComponent>{children}</ReactTableDefaults.TrComponent>;
-        }
-
-        const { original } = rowInfo;
-        const doc = FieldValue(Cast(original, Doc));
-
-        if (!doc) return (null);
-
-        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";
-
-        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" style={{ left: 5 }} onClick={undoBatch(() => this.props.removeDoc(this.props.rowInfo.original))}><FontAwesomeIcon icon="trash" size="sm" /></div>
-                            <div className="row-option" style={{ cursor: "grab", left: 25 }} ref={reference} onPointerDown={onItemDown}><FontAwesomeIcon icon="grip-vertical" size="sm" /></div>
-                            <div className="row-option" style={{ left: 40 }} onClick={() => this.props.addDocTab(this.props.rowInfo.original, "add:right")}><FontAwesomeIcon icon="external-link-alt" size="sm" /></div>
-                        </div>
-                        {children}
-                    </ReactTableDefaults.TrComponent>
-                </div>
-            </div>
-        );
-    }
-}
\ No newline at end of file
diff --git a/src/client/views/collections/schemaView/SchemaTable.tsx b/src/client/views/collections/schemaView/SchemaTable.tsx
index a735d4257..0d5c9e077 100644
--- a/src/client/views/collections/schemaView/SchemaTable.tsx
+++ b/src/client/views/collections/schemaView/SchemaTable.tsx
@@ -458,8 +458,9 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
             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 className="reactTable-sub"><SchemaTable {...this.props} Document={row.original} dataDoc={undefined} childDocs={undefined} /></div>}
+                <div style={{ paddingLeft: 57 + "px" }} className="reactTable-sub"><SchemaTable {...this.props} Document={row.original} dataDoc={undefined} childDocs={undefined} /></div>}
 
         />;
     }
diff --git a/src/fields/SchemaHeaderField.ts b/src/fields/SchemaHeaderField.ts
index 88de3a19f..74cf934f2 100644
--- a/src/fields/SchemaHeaderField.ts
+++ b/src/fields/SchemaHeaderField.ts
@@ -3,7 +3,7 @@ import { serializable, primitive } from "serializr";
 import { ObjectField } from "./ObjectField";
 import { Copy, ToScriptString, ToString, OnUpdate } from "./FieldSymbols";
 import { scriptingGlobal } from "../client/util/Scripting";
-import { ColumnType } from "../client/views/collections/CollectionSchemaView";
+import { ColumnType } from "../client/views/collections/schemaView/CollectionSchemaView";
 
 export const PastelSchemaPalette = new Map<string, string>([
     // ["pink1", "#FFB4E8"],
-- 
cgit v1.2.3-70-g09d2

