From 47ecf8d30f4aa5e25a659fc7f3c0c1487420150e Mon Sep 17 00:00:00 2001
From: Sam Wilkins <abdullah_ahmed@brown.edu>
Date: Thu, 9 May 2019 20:59:10 -0400
Subject: merge with master, but haven't reconciled internal and external
 linking

---
 .../views/collections/CollectionSchemaView.tsx     | 184 ++++++++++-----------
 1 file changed, 88 insertions(+), 96 deletions(-)

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

diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index 08c9740d0..ae949b2ed 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -2,19 +2,14 @@ import React = require("react");
 import { library } from '@fortawesome/fontawesome-svg-core';
 import { faCog, faPlus } from '@fortawesome/free-solid-svg-icons';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, computed, observable, untracked } from "mobx";
+import { action, computed, observable, untracked, runInAction } from "mobx";
 import { observer } from "mobx-react";
 import ReactTable, { CellInfo, ComponentPropsGetterR, ReactTableDefaults } from "react-table";
+import { MAX_ROW_HEIGHT } from '../../views/globalCssVariables.scss';
 import "react-table/react-table.css";
-import { Document } from "../../../fields/Document";
-import { Field, Opt } from "../../../fields/Field";
-import { Key } from "../../../fields/Key";
-import { KeyStore } from "../../../fields/KeyStore";
-import { ListField } from "../../../fields/ListField";
-import { emptyDocFunction, emptyFunction, returnFalse } from "../../../Utils";
-import { Server } from "../../Server";
+import { emptyFunction, returnFalse, returnZero } from "../../../Utils";
 import { SetupDrag } from "../../util/DragManager";
-import { CompileScript, ToField } from "../../util/Scripting";
+import { CompileScript } from "../../util/Scripting";
 import { Transform } from "../../util/Transform";
 import { COLLECTION_BORDER_WIDTH } from "../../views/globalCssVariables.scss";
 import { anchorPoints, Flyout } from "../DocumentDecorations";
@@ -24,44 +19,47 @@ import { DocumentView } from "../nodes/DocumentView";
 import { FieldView, FieldViewProps } from "../nodes/FieldView";
 import "./CollectionSchemaView.scss";
 import { CollectionSubView } from "./CollectionSubView";
+import { Opt, Field, Doc, DocListCast } from "../../../new_fields/Doc";
+import { Cast, FieldValue, NumCast } from "../../../new_fields/Types";
+import { listSpec } from "../../../new_fields/Schema";
+import { List } from "../../../new_fields/List";
+import { Id } from "../../../new_fields/RefField";
 
 
 // bcz: need to add drag and drop of rows and columns.  This seems like it might work for rows: https://codesandbox.io/s/l94mn1q657
 
 
 @observer
-class KeyToggle extends React.Component<{ keyId: string, checked: boolean, toggle: (key: Key) => void }> {
-    @observable key: Key | undefined;
-
+class KeyToggle extends React.Component<{ keyName: string, checked: boolean, toggle: (key: string) => void }> {
     constructor(props: any) {
         super(props);
-        Server.GetField(this.props.keyId, action((field: Opt<Field>) => field instanceof Key && (this.key = field)));
     }
 
     render() {
-        return !this.key ? (null) :
-            (<div key={this.key.Id}>
-                <input type="checkbox" checked={this.props.checked} onChange={() => this.key && this.props.toggle(this.key)} />
-                {this.key.Name}
-            </div>);
+        return (
+            <div key={this.props.keyName}>
+                <input type="checkbox" checked={this.props.checked} onChange={() => this.props.toggle(this.props.keyName)} />
+                {this.props.keyName}
+            </div>
+        );
     }
 }
 
 @observer
-export class CollectionSchemaView extends CollectionSubView {
+export class CollectionSchemaView extends CollectionSubView(doc => doc) {
     private _mainCont?: HTMLDivElement;
     private _startSplitPercent = 0;
     private DIVIDER_WIDTH = 4;
 
-    @observable _columns: Array<Key> = [KeyStore.Title, KeyStore.Data, KeyStore.Author];
+    @observable _columns: Array<string> = ["title", "data", "author"];
     @observable _selectedIndex = 0;
     @observable _columnsPercentage = 0;
-    @observable _keys: Key[] = [];
+    @observable _keys: string[] = [];
     @observable _newKeyName: string = "";
 
-    @computed get splitPercentage() { return this.props.Document.GetNumber(KeyStore.SchemaSplitPercentage, 0); }
-    @computed get columns() { return this.props.Document.GetList(KeyStore.ColumnsKey, [] as Key[]); }
-    @computed get borderWidth() { return COLLECTION_BORDER_WIDTH; }
+    @computed get splitPercentage() { return NumCast(this.props.Document.schemaSplitPercentage); }
+    @computed get columns() { return Cast(this.props.Document.schemaColumns, listSpec("string"), []); }
+    @computed get borderWidth() { return Number(COLLECTION_BORDER_WIDTH); }
 
     renderCell = (rowProps: CellInfo) => {
         let props: FieldViewProps = {
@@ -73,43 +71,38 @@ export class CollectionSchemaView extends CollectionSubView {
             isTopMost: false,
             selectOnLoad: false,
             ScreenToLocalTransform: Transform.Identity,
-            focus: emptyDocFunction,
+            focus: emptyFunction,
             active: returnFalse,
             whenActiveChanged: emptyFunction,
+            PanelHeight: returnZero,
+            PanelWidth: returnZero,
         };
         let contents = (
             <FieldView {...props} />
         );
         let reference = React.createRef<HTMLDivElement>();
         let onItemDown = SetupDrag(reference, () => props.Document, this.props.moveDocument);
-        let applyToDoc = (doc: Document, run: (args?: { [name: string]: any }) => any) => {
+        let applyToDoc = (doc: Doc, run: (args?: { [name: string]: any }) => any) => {
             const res = run({ this: doc });
             if (!res.success) return false;
             const field = res.result;
-            if (field instanceof Field) {
-                doc.Set(props.fieldKey, field);
-                return true;
-            } else {
-                let dataField = ToField(field);
-                if (dataField) {
-                    doc.Set(props.fieldKey, dataField);
-                    return true;
-                }
-            }
-            return false;
+            doc[props.fieldKey] = field;
+            return true;
         };
         return (
-            <div className="collectionSchemaView-cellContents" onPointerDown={onItemDown} style={{ height: "56px" }} key={props.Document.Id} ref={reference}>
+            <div className="collectionSchemaView-cellContents" onPointerDown={onItemDown} key={props.Document[Id]} ref={reference}>
                 <EditableView
                     display={"inline"}
                     contents={contents}
-                    height={56}
+                    height={Number(MAX_ROW_HEIGHT)}
                     GetValue={() => {
-                        let field = props.Document.Get(props.fieldKey);
-                        if (field && field instanceof Field) {
-                            return field.ToScriptString();
+                        let field = props.Document[props.fieldKey];
+                        if (field) {
+                            //TODO Types
+                            // return field.ToScriptString();
+                            return String(field);
                         }
-                        return field || "";
+                        return "";
                     }}
                     SetValue={(value: string) => {
                         let script = CompileScript(value, { addReturn: true, params: { this: Document.name } });
@@ -118,21 +111,18 @@ export class CollectionSchemaView extends CollectionSubView {
                         }
                         return applyToDoc(props.Document, script.run);
                     }}
-                    OnFillDown={(value: string) => {
+                    OnFillDown={async (value: string) => {
                         let script = CompileScript(value, { addReturn: true, params: { this: Document.name } });
                         if (!script.compiled) {
                             return;
                         }
                         const run = script.run;
                         //TODO This should be able to be refactored to compile the script once
-                        this.props.Document.GetTAsync<ListField<Document>>(this.props.fieldKey, ListField).then((val) => {
-                            if (val) {
-                                val.Data.forEach(doc => applyToDoc(doc, run));
-                            }
-                        });
+                        const val = await DocListCast(this.props.Document[this.props.fieldKey])
+                        val && val.forEach(doc => applyToDoc(doc, run));
                     }}>
                 </EditableView>
-            </div>
+            </div >
         );
     }
 
@@ -163,36 +153,37 @@ export class CollectionSchemaView extends CollectionSubView {
     }
 
     @action
-    toggleKey = (key: Key) => {
-        this.props.Document.GetOrCreateAsync<ListField<Key>>(KeyStore.ColumnsKey, ListField,
-            (field) => {
-                const index = field.Data.indexOf(key);
-                if (index === -1) {
-                    this.columns.push(key);
-                } else {
-                    this.columns.splice(index, 1);
-                }
-
-            });
+    toggleKey = (key: string) => {
+        let list = Cast(this.props.Document.schemaColumns, listSpec("string"));
+        if (list === undefined) {
+            this.props.Document.schemaColumns = list = new List<string>([key]);
+        } else {
+            const index = list.indexOf(key);
+            if (index === -1) {
+                list.push(key);
+            } else {
+                list.splice(index, 1);
+            }
+        }
     }
 
     //toggles preview side-panel of schema
     @action
     toggleExpander = (event: React.ChangeEvent<HTMLInputElement>) => {
-        this.props.Document.SetNumber(KeyStore.SchemaSplitPercentage, this.splitPercentage === 0 ? 33 : 0);
+        this.props.Document.schemaSplitPercentage = this.splitPercentage === 0 ? 33 : 0;
     }
 
     @action
     onDividerMove = (e: PointerEvent): void => {
         let nativeWidth = this._mainCont!.getBoundingClientRect();
-        this.props.Document.SetNumber(KeyStore.SchemaSplitPercentage, Math.max(0, 100 - Math.round((e.clientX - nativeWidth.left) / nativeWidth.width * 100)));
+        this.props.Document.schemaSplitPercentage = Math.max(0, 100 - Math.round((e.clientX - nativeWidth.left) / nativeWidth.width * 100));
     }
     @action
     onDividerUp = (e: PointerEvent): void => {
         document.removeEventListener("pointermove", this.onDividerMove);
         document.removeEventListener('pointerup', this.onDividerUp);
         if (this._startSplitPercent === this.splitPercentage) {
-            this.props.Document.SetNumber(KeyStore.SchemaSplitPercentage, this.splitPercentage === 0 ? 33 : 0);
+            this.props.Document.schemaSplitPercentage = this.splitPercentage === 0 ? 33 : 0;
         }
     }
     onDividerDown = (e: React.PointerEvent) => {
@@ -205,8 +196,7 @@ export class CollectionSchemaView extends CollectionSubView {
 
     onPointerDown = (e: React.PointerEvent): void => {
         if (e.button === 0 && !e.altKey && !e.ctrlKey && !e.metaKey) {
-            if (this.props.isSelected())
-                e.stopPropagation();
+            if (this.props.isSelected()) e.stopPropagation();
             else e.preventDefault();
         }
     }
@@ -219,7 +209,7 @@ export class CollectionSchemaView extends CollectionSubView {
 
     @action
     addColumn = () => {
-        this.columns.push(new Key(this._newKeyName));
+        this.columns.push(this._newKeyName);
         this._newKeyName = "";
     }
 
@@ -234,21 +224,22 @@ export class CollectionSchemaView extends CollectionSubView {
         this.previewScript = e.currentTarget.value;
     }
 
-    get previewDocument(): Document | undefined {
-        const children = this.props.Document.GetList(this.props.fieldKey, [] as Document[]);
-        const selected = children.length > this._selectedIndex ? children[this._selectedIndex] : undefined;
-        return selected ? (this.previewScript ? selected.Get(new Key(this.previewScript)) as Document : selected) : undefined;
+    get previewDocument(): Doc | undefined {
+        const children = Cast(this.props.Document[this.props.fieldKey], listSpec(Doc), []);
+        const selected = children.length > this._selectedIndex ? FieldValue(children[this._selectedIndex]) : undefined;
+        return selected ? (this.previewScript ? FieldValue(Cast(selected[this.previewScript], Doc)) : selected) : undefined;
     }
-    get tableWidth() { return this.props.PanelWidth() * (1 - this.splitPercentage / 100); }
-    get previewRegionHeight() { return this.props.PanelHeight(); }
-    get previewRegionWidth() { return this.props.PanelWidth() * this.splitPercentage / 100 - this.DIVIDER_WIDTH; }
+    get tableWidth() { return (this.props.PanelWidth() - 2 * this.borderWidth - this.DIVIDER_WIDTH) * (1 - this.splitPercentage / 100); }
+    get previewRegionHeight() { return this.props.PanelHeight() - 2 * this.borderWidth; }
+    get previewRegionWidth() { return (this.props.PanelWidth() - 2 * this.borderWidth - this.DIVIDER_WIDTH) * this.splitPercentage / 100; }
 
-    private previewDocNativeWidth = () => this.previewDocument!.GetNumber(KeyStore.NativeWidth, this.previewRegionWidth);
-    private previewDocNativeHeight = () => this.previewDocument!.GetNumber(KeyStore.NativeHeight, this.previewRegionHeight);
+    private previewDocNativeWidth = () => Cast(this.previewDocument!.nativeWidth, "number", this.previewRegionWidth);
+    private previewDocNativeHeight = () => Cast(this.previewDocument!.nativeHeight, "number", this.previewRegionHeight);
     private previewContentScaling = () => {
         let wscale = this.previewRegionWidth / (this.previewDocNativeWidth() ? this.previewDocNativeWidth() : this.previewRegionWidth);
-        if (wscale * this.previewDocNativeHeight() > this.previewRegionHeight)
+        if (wscale * this.previewDocNativeHeight() > this.previewRegionHeight) {
             return this.previewRegionHeight / (this.previewDocNativeHeight() ? this.previewDocNativeHeight() : this.previewRegionHeight);
+        }
         return wscale;
     }
     private previewPanelWidth = () => this.previewDocNativeWidth() * this.previewContentScaling();
@@ -256,23 +247,26 @@ export class CollectionSchemaView extends CollectionSubView {
     get previewPanelCenteringOffset() { return (this.previewRegionWidth - this.previewDocNativeWidth() * this.previewContentScaling()) / 2; }
     getPreviewTransform = (): Transform => this.props.ScreenToLocalTransform().translate(
         - this.borderWidth - this.DIVIDER_WIDTH - this.tableWidth - this.previewPanelCenteringOffset,
-        - this.borderWidth).scale(1 / this.previewContentScaling());
+        - this.borderWidth).scale(1 / this.previewContentScaling())
 
     @computed
     get previewPanel() {
         // let doc = CompileScript(this.previewScript, { this: selected }, true)();
-        return !this.previewDocument ? (null) : (
-            <div className="collectionSchemaView-previewRegion" style={{ width: `calc(${this.props.Document.GetNumber(KeyStore.SchemaSplitPercentage, 0)}% - ${this.DIVIDER_WIDTH}px)` }}>
+        const previewDoc = this.previewDocument;
+        return !previewDoc ? (null) : (
+            <div className="collectionSchemaView-previewRegion" style={{ width: `${this.previewRegionWidth}px` }}>
                 <div className="collectionSchemaView-previewDoc" style={{ transform: `translate(${this.previewPanelCenteringOffset}px, 0px)` }}>
-                    <DocumentView Document={this.previewDocument} isTopMost={false} selectOnLoad={false}
+                    <DocumentView Document={previewDoc} isTopMost={false} selectOnLoad={false}
+                        toggleMinimized={emptyFunction}
                         addDocument={this.props.addDocument} removeDocument={this.props.removeDocument}
                         ScreenToLocalTransform={this.getPreviewTransform}
                         ContentScaling={this.previewContentScaling}
                         PanelWidth={this.previewPanelWidth} PanelHeight={this.previewPanelHeight}
                         ContainingCollectionView={this.props.CollectionView}
-                        focus={emptyDocFunction}
+                        focus={emptyFunction}
                         parentActive={this.props.active}
                         whenActiveChanged={this.props.whenActiveChanged}
+                        bringToFront={emptyFunction}
                     />
                 </div>
                 <input className="collectionSchemaView-input" value={this.previewScript} onChange={this.onPreviewScriptChange}
@@ -282,24 +276,25 @@ export class CollectionSchemaView extends CollectionSubView {
     }
 
     get documentKeysCheckList() {
-        const docs = this.props.Document.GetList(this.props.fieldKey, [] as Document[]);
-        let keys: { [id: string]: boolean } = {};
+        const docs = Cast(this.props.Document[this.props.fieldKey], listSpec(Doc), []).filter(d => d).map(d => d as Doc);
+        let 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.
-        untracked(() => docs.map(doc => doc.GetAllPrototypes().map(proto => proto._proxies.forEach((val: any, key: string) => keys[key] = false))));
+        //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.Id] = true);
+        this.columns.forEach(key => keys[key] = true);
         return Array.from(Object.keys(keys)).map(item =>
-            (<KeyToggle checked={keys[item]} key={item} keyId={item} toggle={this.toggleKey} />));
+            (<KeyToggle checked={keys[item]} key={item} keyName={item} toggle={this.toggleKey} />));
     }
 
     get tableOptionsPanel() {
         return !this.props.active() ? (null) :
             (<Flyout
-                anchorPoint={anchorPoints.LEFT_TOP}
+                anchorPoint={anchorPoints.RIGHT_TOP}
                 content={<div>
                     <div id="schema-options-header"><h5><b>Options</b></h5></div>
                     <div id="options-flyout-div">
@@ -327,19 +322,16 @@ export class CollectionSchemaView extends CollectionSubView {
     render() {
         library.add(faCog);
         library.add(faPlus);
-        if (!this.previewDocument)
-            return (null);
-
-        const children = this.props.Document.GetList(this.props.fieldKey, [] as Document[]);
+        const children = this.children;
         return (
             <div className="collectionSchemaView-container" onPointerDown={this.onPointerDown} onWheel={this.onWheel}
                 onDrop={(e: React.DragEvent) => this.onDrop(e, {})} ref={this.createTarget}>
-                <div className="collectionSchemaView-tableContainer" style={{ width: `calc(100% - ${this.splitPercentage}%)` }}>
+                <div className="collectionSchemaView-tableContainer" style={{ width: `${this.tableWidth}px` }}>
                     <ReactTable data={children} page={0} pageSize={children.length} showPagination={false}
                         columns={this.columns.map(col => ({
-                            Header: col.Name,
-                            accessor: (doc: Document) => [doc, col],
-                            id: col.Id
+                            Header: col,
+                            accessor: (doc: Doc) => [doc, col],
+                            id: col
                         }))}
                         column={{ ...ReactTableDefaults.column, Cell: this.renderCell, }}
                         getTrProps={this.getTrProps}
-- 
cgit v1.2.3-70-g09d2

